aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaat <maat-pub@mageia.biz>2020-05-08 21:52:11 +0200
committerMaat <maat-pub@mageia.biz>2020-05-08 21:52:11 +0200
commit8ea437e30605e0f66b5220bf904a61d7c1d11ddd (patch)
treee0db2bb4a012d5b06a633160b19f62f4868ecd28
parent36bc1870f21fac04736a1049c1d5b8e127d729f4 (diff)
parent2fdd46b36431ae0f58bb2e78e42553168db9a0ff (diff)
downloadforums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar
forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar.gz
forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar.bz2
forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.tar.xz
forums-8ea437e30605e0f66b5220bf904a61d7c1d11ddd.zip
Merge remote-tracking branch 'upstream/prep-release-3.2.9'
-rw-r--r--.appveyor.yml145
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md6
-rw-r--r--.gitignore6
-rw-r--r--.travis.yml35
-rw-r--r--LICENSE281
-rw-r--r--README.md16
-rw-r--r--Vagrantfile25
-rw-r--r--build/build.xml283
-rw-r--r--build/build_helper.php6
-rw-r--r--build/code_sniffer/phpbb/Sniffs/Namespaces/UnusedUseSniff.php5
-rw-r--r--build/generate_package_json.php127
-rwxr-xr-xbuild/package.php39
-rwxr-xr-xcomposer.pharbin1585196 -> 1933813 bytes
-rwxr-xr-xgit-tools/hooks/commit-msg9
-rw-r--r--phpBB/adm/index.php5
-rw-r--r--phpBB/adm/style/acp_attachments.html125
-rw-r--r--phpBB/adm/style/acp_ban.html2
-rw-r--r--phpBB/adm/style/acp_board.html5
-rw-r--r--phpBB/adm/style/acp_contact.html2
-rw-r--r--phpBB/adm/style/acp_database.html10
-rw-r--r--phpBB/adm/style/acp_ext_details.html24
-rw-r--r--phpBB/adm/style/acp_ext_list.html8
-rw-r--r--phpBB/adm/style/acp_forums.html8
-rw-r--r--phpBB/adm/style/acp_groups.html13
-rw-r--r--phpBB/adm/style/acp_help_phpbb.html61
-rw-r--r--phpBB/adm/style/acp_icons.html10
-rw-r--r--phpBB/adm/style/acp_language.html2
-rw-r--r--phpBB/adm/style/acp_main.html27
-rw-r--r--phpBB/adm/style/acp_modules.html2
-rw-r--r--phpBB/adm/style/acp_permission_roles.html4
-rw-r--r--phpBB/adm/style/acp_permissions.html11
-rw-r--r--phpBB/adm/style/acp_posting_buttons.html25
-rw-r--r--phpBB/adm/style/acp_profile.html2
-rw-r--r--phpBB/adm/style/acp_prune_forums.html4
-rw-r--r--phpBB/adm/style/acp_ranks.html2
-rw-r--r--phpBB/adm/style/acp_search.html2
-rw-r--r--phpBB/adm/style/acp_send_statistics.html64
-rw-r--r--phpBB/adm/style/acp_styles.html8
-rw-r--r--phpBB/adm/style/acp_users.html4
-rw-r--r--phpBB/adm/style/acp_users_overview.html2
-rw-r--r--phpBB/adm/style/acp_users_prefs.html4
-rw-r--r--phpBB/adm/style/acp_users_signature.html2
-rw-r--r--phpBB/adm/style/admin.css235
-rw-r--r--phpBB/adm/style/admin.js14
-rw-r--r--phpBB/adm/style/ajax.js115
-rw-r--r--phpBB/adm/style/captcha_recaptcha.html26
-rw-r--r--phpBB/adm/style/install_convert.html134
-rw-r--r--phpBB/adm/style/install_error.html8
-rw-r--r--phpBB/adm/style/install_footer.html21
-rw-r--r--phpBB/adm/style/install_header.html54
-rw-r--r--phpBB/adm/style/install_install.html77
-rw-r--r--phpBB/adm/style/install_main.html6
-rw-r--r--phpBB/adm/style/install_update.html491
-rw-r--r--phpBB/adm/style/install_update_diff.html255
-rw-r--r--phpBB/adm/style/installer_convert.html87
-rw-r--r--phpBB/adm/style/installer_footer.html32
-rw-r--r--phpBB/adm/style/installer_form.html57
-rw-r--r--phpBB/adm/style/installer_header.html58
-rw-r--r--phpBB/adm/style/installer_install.html13
-rw-r--r--phpBB/adm/style/installer_main.html6
-rw-r--r--phpBB/adm/style/installer_update.html13
-rw-r--r--phpBB/adm/style/installer_update_file_status.html80
-rw-r--r--phpBB/adm/style/overall_footer.html6
-rw-r--r--phpBB/adm/style/overall_header.html22
-rw-r--r--phpBB/adm/style/permission_mask.html27
-rw-r--r--phpBB/adm/style/permissions.js4
-rw-r--r--phpBB/adm/style/progress_bar.html4
-rw-r--r--phpBB/adm/style/simple_footer.html6
-rw-r--r--phpBB/adm/style/simple_header.html2
-rw-r--r--phpBB/adm/style/tooltip.js341
-rw-r--r--phpBB/app.php4
-rw-r--r--phpBB/assets/cookieconsent/cookieconsent.min.css6
-rw-r--r--phpBB/assets/cookieconsent/cookieconsent.min.js1
-rw-r--r--phpBB/assets/css/font-awesome.min.css4
-rw-r--r--phpBB/assets/fonts/FontAwesome.otfbin0 -> 134808 bytes
-rw-r--r--phpBB/assets/fonts/fontawesome-webfont.eotbin0 -> 165742 bytes
-rw-r--r--phpBB/assets/fonts/fontawesome-webfont.svg2671
-rw-r--r--phpBB/assets/fonts/fontawesome-webfont.ttfbin0 -> 165548 bytes
-rw-r--r--phpBB/assets/fonts/fontawesome-webfont.woffbin0 -> 98024 bytes
-rw-r--r--phpBB/assets/fonts/fontawesome-webfont.woff2bin0 -> 77160 bytes
-rw-r--r--phpBB/assets/javascript/core.js45
-rw-r--r--phpBB/assets/javascript/editor.js79
-rw-r--r--phpBB/assets/javascript/installer.js615
-rw-r--r--phpBB/assets/javascript/jquery.min.js9
-rw-r--r--phpBB/assets/javascript/plupload.js61
-rw-r--r--phpBB/assets/plupload/plupload.full.min.js18
-rwxr-xr-xphpBB/bin/phpbbcli.php37
-rw-r--r--phpBB/common.php48
-rw-r--r--phpBB/composer.json59
-rw-r--r--phpBB/composer.lock2270
-rw-r--r--phpBB/config/auth.yml101
-rw-r--r--phpBB/config/avatar.yml68
-rw-r--r--phpBB/config/captcha.yml59
-rw-r--r--phpBB/config/console.yml162
-rw-r--r--phpBB/config/content.yml72
-rw-r--r--phpBB/config/cron.yml162
-rw-r--r--phpBB/config/db.yml76
-rw-r--r--phpBB/config/default/config.yml1
-rw-r--r--phpBB/config/default/container/parameters.yml (renamed from phpBB/config/parameters.yml)0
-rw-r--r--phpBB/config/default/container/services.yml175
-rw-r--r--phpBB/config/default/container/services_attachment.yml40
-rw-r--r--phpBB/config/default/container/services_auth.yml110
-rw-r--r--phpBB/config/default/container/services_avatar.yml73
-rw-r--r--phpBB/config/default/container/services_captcha.yml59
-rw-r--r--phpBB/config/default/container/services_console.yml295
-rw-r--r--phpBB/config/default/container/services_content.yml73
-rw-r--r--phpBB/config/default/container/services_cron.yml235
-rw-r--r--phpBB/config/default/container/services_db.yml71
-rw-r--r--phpBB/config/default/container/services_event.yml26
-rw-r--r--phpBB/config/default/container/services_feed.yml126
-rw-r--r--phpBB/config/default/container/services_files.yml57
-rw-r--r--phpBB/config/default/container/services_filesystem.yml3
-rw-r--r--phpBB/config/default/container/services_help.yml27
-rw-r--r--phpBB/config/default/container/services_hook.yml7
-rw-r--r--phpBB/config/default/container/services_http.yml23
-rw-r--r--phpBB/config/default/container/services_language.yml22
-rw-r--r--phpBB/config/default/container/services_migrator.yml64
-rw-r--r--phpBB/config/default/container/services_mimetype_guesser.yml36
-rw-r--r--phpBB/config/default/container/services_module.yml10
-rw-r--r--phpBB/config/default/container/services_notification.yml224
-rw-r--r--phpBB/config/default/container/services_password.yml136
-rw-r--r--phpBB/config/default/container/services_php.yml3
-rw-r--r--phpBB/config/default/container/services_profilefield.yml102
-rw-r--r--phpBB/config/default/container/services_report.yml53
-rw-r--r--phpBB/config/default/container/services_routing.yml79
-rw-r--r--phpBB/config/default/container/services_text_formatter.yml79
-rw-r--r--phpBB/config/default/container/services_text_reparser.yml109
-rw-r--r--phpBB/config/default/container/services_twig.yml68
-rw-r--r--phpBB/config/default/container/services_user.yml20
-rw-r--r--phpBB/config/default/container/tables.yml78
-rw-r--r--phpBB/config/default/routing/feed.yml35
-rw-r--r--phpBB/config/default/routing/help.yml7
-rw-r--r--phpBB/config/default/routing/report.yml17
-rw-r--r--phpBB/config/default/routing/routing.yml24
-rw-r--r--phpBB/config/development/config.yml13
-rw-r--r--phpBB/config/development/container/environment.yml3
-rw-r--r--phpBB/config/development/container/parameters.yml2
-rw-r--r--phpBB/config/development/container/services.yml2
-rw-r--r--phpBB/config/development/routing/environment.yml2
-rw-r--r--phpBB/config/event.yml41
-rw-r--r--phpBB/config/feed.yml113
-rw-r--r--phpBB/config/installer/config.yml2
-rw-r--r--phpBB/config/installer/container/environment.yml3
-rw-r--r--phpBB/config/installer/container/parameters.yml5
-rw-r--r--phpBB/config/installer/container/services.yml104
-rw-r--r--phpBB/config/installer/container/services_file_updater.yml38
-rw-r--r--phpBB/config/installer/container/services_install_console.yml61
-rw-r--r--phpBB/config/installer/container/services_install_controller.yml73
-rw-r--r--phpBB/config/installer/container/services_install_data.yml55
-rw-r--r--phpBB/config/installer/container/services_install_database.yml71
-rw-r--r--phpBB/config/installer/container/services_install_filesystem.yml28
-rw-r--r--phpBB/config/installer/container/services_install_finish.yml44
-rw-r--r--phpBB/config/installer/container/services_install_navigation.yml42
-rw-r--r--phpBB/config/installer/container/services_install_obtain_data.yml59
-rw-r--r--phpBB/config/installer/container/services_install_requirements.yml37
-rw-r--r--phpBB/config/installer/container/services_installer.yml119
-rw-r--r--phpBB/config/installer/container/services_update_database.yml40
-rw-r--r--phpBB/config/installer/container/services_update_filesystem.yml72
-rw-r--r--phpBB/config/installer/container/services_update_obtain_data.yml53
-rw-r--r--phpBB/config/installer/container/services_update_requirements.yml41
-rw-r--r--phpBB/config/installer/routing/environment.yml2
-rw-r--r--phpBB/config/installer/routing/installer.yml67
-rw-r--r--phpBB/config/mimetype_guesser.yml36
-rw-r--r--phpBB/config/notification.yml390
-rw-r--r--phpBB/config/password.yml131
-rw-r--r--phpBB/config/production/config.yml2
-rw-r--r--phpBB/config/production/container/environment.yml3
-rw-r--r--phpBB/config/production/container/parameters.yml2
-rw-r--r--phpBB/config/production/container/services.yml2
-rw-r--r--phpBB/config/production/routing/environment.yml2
-rw-r--r--phpBB/config/profilefield.yml102
-rw-r--r--phpBB/config/routing.yml9
-rw-r--r--phpBB/config/services.yml188
-rw-r--r--phpBB/config/tables.yml23
-rw-r--r--phpBB/config/test/config.yml5
-rw-r--r--phpBB/config/test/container/environment.yml3
-rw-r--r--phpBB/config/test/container/parameters.yml2
-rw-r--r--phpBB/config/test/container/services.yml2
-rw-r--r--phpBB/config/test/routing/environment.yml2
-rw-r--r--phpBB/config/user.yml19
-rw-r--r--phpBB/cron.php4
-rw-r--r--phpBB/develop/add_permissions.php14
-rw-r--r--phpBB/develop/benchmark.php2
-rw-r--r--phpBB/develop/check_flash_bbcodes.php10
-rw-r--r--phpBB/develop/create_schema_files.php10
-rw-r--r--phpBB/develop/create_search_index.php2
-rw-r--r--phpBB/develop/create_variable_overview.php4
-rw-r--r--phpBB/develop/fill.php4
-rw-r--r--phpBB/develop/generate_utf_tables.php290
-rw-r--r--phpBB/develop/imageset_to_css.php2
-rw-r--r--phpBB/develop/lang_duplicates.php2
-rw-r--r--phpBB/develop/lang_migrate_help_lang.php307
-rw-r--r--phpBB/develop/mysql_upgrader.php9
-rw-r--r--phpBB/develop/regex_idn.php2
-rw-r--r--phpBB/develop/search_fill.php2
-rw-r--r--phpBB/develop/test.gifbin0 -> 1131 bytes
-rw-r--r--phpBB/develop/unicode_testing.php37
-rw-r--r--phpBB/develop/update_email_hash.php2
-rw-r--r--phpBB/develop/utf_normalizer_test.php394
-rw-r--r--phpBB/docs/CHANGELOG.html1326
-rw-r--r--phpBB/docs/CREDITS.txt25
-rw-r--r--phpBB/docs/FAQ.html10
-rw-r--r--phpBB/docs/INSTALL.html70
-rw-r--r--phpBB/docs/README.html35
-rw-r--r--phpBB/docs/coding-guidelines.html30
-rw-r--r--phpBB/docs/events.md1130
-rw-r--r--phpBB/docs/install-config.sample.yml38
-rw-r--r--phpBB/docs/nginx.sample.conf35
-rw-r--r--phpBB/docs/sphinx.sample.conf9
-rw-r--r--phpBB/docs/update-config.sample.yml3
-rw-r--r--phpBB/docs/vagrant.md123
-rw-r--r--phpBB/download/file.php38
-rw-r--r--phpBB/faq.php99
-rw-r--r--phpBB/feed.php236
-rw-r--r--phpBB/images/icons/misc/fire.gifbin278 -> 1486 bytes
-rw-r--r--phpBB/images/icons/misc/heart.gifbin284 -> 2017 bytes
-rw-r--r--phpBB/images/icons/misc/radioactive.gifbin300 -> 2069 bytes
-rw-r--r--phpBB/images/icons/misc/star.gifbin267 -> 1914 bytes
-rw-r--r--phpBB/images/icons/misc/thinking.gifbin284 -> 1414 bytes
-rw-r--r--phpBB/images/icons/smile/alert.gifbin271 -> 1399 bytes
-rw-r--r--phpBB/images/icons/smile/info.gifbin294 -> 1572 bytes
-rw-r--r--phpBB/images/icons/smile/mrgreen.gifbin297 -> 2123 bytes
-rw-r--r--phpBB/images/icons/smile/question.gifbin296 -> 2056 bytes
-rw-r--r--phpBB/images/icons/smile/redface.gifbin2463 -> 4740 bytes
-rw-r--r--phpBB/includes/acp/acp_attachments.php320
-rw-r--r--phpBB/includes/acp/acp_ban.php3
-rw-r--r--phpBB/includes/acp/acp_bbcodes.php112
-rw-r--r--phpBB/includes/acp/acp_board.php112
-rw-r--r--phpBB/includes/acp/acp_bots.php40
-rw-r--r--phpBB/includes/acp/acp_captcha.php19
-rw-r--r--phpBB/includes/acp/acp_contact.php6
-rw-r--r--phpBB/includes/acp/acp_database.php1841
-rw-r--r--phpBB/includes/acp/acp_disallow.php11
-rw-r--r--phpBB/includes/acp/acp_email.php32
-rw-r--r--phpBB/includes/acp/acp_extensions.php222
-rw-r--r--phpBB/includes/acp/acp_forums.php334
-rw-r--r--phpBB/includes/acp/acp_groups.php120
-rw-r--r--phpBB/includes/acp/acp_help_phpbb.php143
-rw-r--r--phpBB/includes/acp/acp_icons.php84
-rw-r--r--phpBB/includes/acp/acp_inactive.php37
-rw-r--r--phpBB/includes/acp/acp_jabber.php49
-rw-r--r--phpBB/includes/acp/acp_language.php79
-rw-r--r--phpBB/includes/acp/acp_logs.php32
-rw-r--r--phpBB/includes/acp/acp_main.php62
-rw-r--r--phpBB/includes/acp/acp_modules.php651
-rw-r--r--phpBB/includes/acp/acp_permission_roles.php36
-rw-r--r--phpBB/includes/acp/acp_permissions.php165
-rw-r--r--phpBB/includes/acp/acp_php_info.php3
-rw-r--r--phpBB/includes/acp/acp_profile.php130
-rw-r--r--phpBB/includes/acp/acp_prune.php125
-rw-r--r--phpBB/includes/acp/acp_ranks.php24
-rw-r--r--phpBB/includes/acp/acp_reasons.php25
-rw-r--r--phpBB/includes/acp/acp_search.php60
-rw-r--r--phpBB/includes/acp/acp_send_statistics.php91
-rw-r--r--phpBB/includes/acp/acp_styles.php92
-rw-r--r--phpBB/includes/acp/acp_update.php26
-rw-r--r--phpBB/includes/acp/acp_users.php458
-rw-r--r--phpBB/includes/acp/acp_words.php22
-rw-r--r--phpBB/includes/acp/auth.php105
-rw-r--r--phpBB/includes/acp/info/acp_attachments.php1
-rw-r--r--phpBB/includes/acp/info/acp_ban.php1
-rw-r--r--phpBB/includes/acp/info/acp_bbcodes.php1
-rw-r--r--phpBB/includes/acp/info/acp_board.php1
-rw-r--r--phpBB/includes/acp/info/acp_bots.php1
-rw-r--r--phpBB/includes/acp/info/acp_captcha.php1
-rw-r--r--phpBB/includes/acp/info/acp_database.php1
-rw-r--r--phpBB/includes/acp/info/acp_disallow.php1
-rw-r--r--phpBB/includes/acp/info/acp_email.php1
-rw-r--r--phpBB/includes/acp/info/acp_extensions.php1
-rw-r--r--phpBB/includes/acp/info/acp_forums.php1
-rw-r--r--phpBB/includes/acp/info/acp_groups.php1
-rw-r--r--phpBB/includes/acp/info/acp_help_phpbb.php34
-rw-r--r--phpBB/includes/acp/info/acp_icons.php1
-rw-r--r--phpBB/includes/acp/info/acp_inactive.php1
-rw-r--r--phpBB/includes/acp/info/acp_jabber.php1
-rw-r--r--phpBB/includes/acp/info/acp_language.php1
-rw-r--r--phpBB/includes/acp/info/acp_logs.php1
-rw-r--r--phpBB/includes/acp/info/acp_main.php1
-rw-r--r--phpBB/includes/acp/info/acp_modules.php1
-rw-r--r--phpBB/includes/acp/info/acp_permission_roles.php1
-rw-r--r--phpBB/includes/acp/info/acp_permissions.php1
-rw-r--r--phpBB/includes/acp/info/acp_php_info.php1
-rw-r--r--phpBB/includes/acp/info/acp_profile.php1
-rw-r--r--phpBB/includes/acp/info/acp_prune.php1
-rw-r--r--phpBB/includes/acp/info/acp_ranks.php1
-rw-r--r--phpBB/includes/acp/info/acp_reasons.php1
-rw-r--r--phpBB/includes/acp/info/acp_search.php1
-rw-r--r--phpBB/includes/acp/info/acp_send_statistics.php35
-rw-r--r--phpBB/includes/acp/info/acp_styles.php1
-rw-r--r--phpBB/includes/acp/info/acp_update.php1
-rw-r--r--phpBB/includes/acp/info/acp_users.php1
-rw-r--r--phpBB/includes/acp/info/acp_words.php1
-rw-r--r--phpBB/includes/bbcode.php109
-rw-r--r--phpBB/includes/compatibility_globals.php79
-rw-r--r--phpBB/includes/constants.php29
-rw-r--r--phpBB/includes/diff/diff.php102
-rw-r--r--phpBB/includes/diff/engine.php10
-rw-r--r--phpBB/includes/diff/renderer.php26
-rw-r--r--phpBB/includes/functions.php1317
-rw-r--r--phpBB/includes/functions_acp.php70
-rw-r--r--phpBB/includes/functions_admin.php581
-rw-r--r--phpBB/includes/functions_compatibility.php325
-rw-r--r--phpBB/includes/functions_compress.php80
-rw-r--r--phpBB/includes/functions_content.php296
-rw-r--r--phpBB/includes/functions_convert.php131
-rw-r--r--phpBB/includes/functions_display.php172
-rw-r--r--phpBB/includes/functions_download.php114
-rw-r--r--phpBB/includes/functions_install.php545
-rw-r--r--phpBB/includes/functions_jabber.php19
-rw-r--r--phpBB/includes/functions_mcp.php98
-rw-r--r--phpBB/includes/functions_messenger.php301
-rw-r--r--phpBB/includes/functions_module.php26
-rw-r--r--phpBB/includes/functions_posting.php783
-rw-r--r--phpBB/includes/functions_privmsgs.php332
-rw-r--r--phpBB/includes/functions_transfer.php13
-rw-r--r--phpBB/includes/functions_upload.php1118
-rw-r--r--phpBB/includes/functions_url_matcher.php112
-rw-r--r--phpBB/includes/functions_user.php455
-rw-r--r--phpBB/includes/hooks/index.php2
-rw-r--r--phpBB/includes/mcp/info/mcp_ban.php1
-rw-r--r--phpBB/includes/mcp/info/mcp_logs.php1
-rw-r--r--phpBB/includes/mcp/info/mcp_main.php1
-rw-r--r--phpBB/includes/mcp/info/mcp_notes.php1
-rw-r--r--phpBB/includes/mcp/info/mcp_pm_reports.php1
-rw-r--r--phpBB/includes/mcp/info/mcp_queue.php1
-rw-r--r--phpBB/includes/mcp/info/mcp_reports.php1
-rw-r--r--phpBB/includes/mcp/info/mcp_warn.php1
-rw-r--r--phpBB/includes/mcp/mcp_ban.php9
-rw-r--r--phpBB/includes/mcp/mcp_forum.php159
-rw-r--r--phpBB/includes/mcp/mcp_front.php11
-rw-r--r--phpBB/includes/mcp/mcp_logs.php41
-rw-r--r--phpBB/includes/mcp/mcp_main.php314
-rw-r--r--phpBB/includes/mcp/mcp_notes.php47
-rw-r--r--phpBB/includes/mcp/mcp_pm_reports.php28
-rw-r--r--phpBB/includes/mcp/mcp_post.php45
-rw-r--r--phpBB/includes/mcp/mcp_queue.php214
-rw-r--r--phpBB/includes/mcp/mcp_reports.php134
-rw-r--r--phpBB/includes/mcp/mcp_topic.php153
-rw-r--r--phpBB/includes/mcp/mcp_warn.php64
-rw-r--r--phpBB/includes/message_parser.php450
-rw-r--r--phpBB/includes/questionnaire/questionnaire.php18
-rw-r--r--phpBB/includes/sphinxapi.php45
-rw-r--r--phpBB/includes/startup.php126
-rw-r--r--phpBB/includes/ucp/info/ucp_attachments.php1
-rw-r--r--phpBB/includes/ucp/info/ucp_auth_link.php1
-rw-r--r--phpBB/includes/ucp/info/ucp_groups.php1
-rw-r--r--phpBB/includes/ucp/info/ucp_main.php1
-rw-r--r--phpBB/includes/ucp/info/ucp_notifications.php3
-rw-r--r--phpBB/includes/ucp/info/ucp_pm.php1
-rw-r--r--phpBB/includes/ucp/info/ucp_prefs.php1
-rw-r--r--phpBB/includes/ucp/info/ucp_profile.php1
-rw-r--r--phpBB/includes/ucp/info/ucp_zebra.php1
-rw-r--r--phpBB/includes/ucp/ucp_activate.php24
-rw-r--r--phpBB/includes/ucp/ucp_attachments.php58
-rw-r--r--phpBB/includes/ucp/ucp_auth_link.php5
-rw-r--r--phpBB/includes/ucp/ucp_confirm.php4
-rw-r--r--phpBB/includes/ucp/ucp_groups.php147
-rw-r--r--phpBB/includes/ucp/ucp_login_link.php28
-rw-r--r--phpBB/includes/ucp/ucp_main.php111
-rw-r--r--phpBB/includes/ucp/ucp_notifications.php30
-rw-r--r--phpBB/includes/ucp/ucp_pm.php71
-rw-r--r--phpBB/includes/ucp/ucp_pm_compose.php256
-rw-r--r--phpBB/includes/ucp/ucp_pm_options.php73
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewfolder.php43
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewmessage.php54
-rw-r--r--phpBB/includes/ucp/ucp_prefs.php66
-rw-r--r--phpBB/includes/ucp/ucp_profile.php269
-rw-r--r--phpBB/includes/ucp/ucp_register.php185
-rw-r--r--phpBB/includes/ucp/ucp_remind.php122
-rw-r--r--phpBB/includes/ucp/ucp_resend.php6
-rw-r--r--phpBB/includes/ucp/ucp_zebra.php30
-rw-r--r--phpBB/includes/utf/data/utf_canonical_comp.php2
-rw-r--r--phpBB/includes/utf/data/utf_canonical_decomp.php2
-rw-r--r--phpBB/includes/utf/data/utf_compatibility_decomp.php2
-rw-r--r--phpBB/includes/utf/data/utf_nfc_qc.php2
-rw-r--r--phpBB/includes/utf/data/utf_nfkc_qc.php2
-rw-r--r--phpBB/includes/utf/data/utf_normalizer_common.php4
-rw-r--r--phpBB/includes/utf/utf_normalizer.php1509
-rw-r--r--phpBB/includes/utf/utf_tools.php795
-rw-r--r--phpBB/index.php25
-rw-r--r--phpBB/install/app.php63
-rw-r--r--phpBB/install/convert/controller/convertor.php865
-rw-r--r--phpBB/install/convert/convert.php60
-rw-r--r--phpBB/install/convert/convertor.php1614
-rw-r--r--phpBB/install/convertors/convert_phpbb20.php7
-rw-r--r--phpBB/install/convertors/functions_phpbb20.php91
-rw-r--r--phpBB/install/data/confusables.php9
-rw-r--r--phpBB/install/data/new_normalizer.php197
-rw-r--r--phpBB/install/database_update.php244
-rw-r--r--phpBB/install/index.html11
-rw-r--r--phpBB/install/index.php834
-rw-r--r--phpBB/install/install_convert.php2150
-rw-r--r--phpBB/install/install_install.php2331
-rw-r--r--phpBB/install/install_main.php78
-rw-r--r--phpBB/install/install_update.php1782
-rwxr-xr-xphpBB/install/phpbbcli.php52
-rw-r--r--phpBB/install/phpinfo.php20
-rw-r--r--phpBB/install/schemas/schema_data.sql71
-rw-r--r--phpBB/install/startup.php143
-rw-r--r--phpBB/language/en/acp/attachments.php10
-rw-r--r--phpBB/language/en/acp/board.php74
-rw-r--r--phpBB/language/en/acp/common.php39
-rw-r--r--phpBB/language/en/acp/database.php13
-rw-r--r--phpBB/language/en/acp/extensions.php1
-rw-r--r--phpBB/language/en/acp/forums.php3
-rw-r--r--phpBB/language/en/acp/groups.php7
-rw-r--r--phpBB/language/en/acp/permissions.php2
-rw-r--r--phpBB/language/en/acp/permissions_phpbb.php7
-rw-r--r--phpBB/language/en/acp/posting.php5
-rw-r--r--phpBB/language/en/acp/profile.php6
-rw-r--r--phpBB/language/en/acp/search.php5
-rw-r--r--phpBB/language/en/acp/styles.php84
-rw-r--r--phpBB/language/en/captcha_qa.php2
-rw-r--r--phpBB/language/en/captcha_recaptcha.php8
-rw-r--r--phpBB/language/en/cli.php96
-rw-r--r--phpBB/language/en/common.php37
-rw-r--r--phpBB/language/en/email/admin_activate.txt2
-rw-r--r--phpBB/language/en/email/forum_notify.txt1
-rw-r--r--phpBB/language/en/email/newtopic_notify.txt5
-rw-r--r--phpBB/language/en/email/report_pm.txt2
-rw-r--r--phpBB/language/en/email/test.txt9
-rw-r--r--phpBB/language/en/email/topic_notify.txt1
-rw-r--r--phpBB/language/en/help/bbcode.php66
-rw-r--r--phpBB/language/en/help/faq.php186
-rw-r--r--phpBB/language/en/help_bbcode.php115
-rw-r--r--phpBB/language/en/help_faq.php355
-rw-r--r--phpBB/language/en/install.php1003
-rw-r--r--phpBB/language/en/mcp.php1
-rw-r--r--phpBB/language/en/migrator.php8
-rw-r--r--phpBB/language/en/posting.php8
-rw-r--r--phpBB/language/en/ucp.php11
-rw-r--r--phpBB/language/en/viewforum.php3
-rw-r--r--phpBB/language/en/viewtopic.php1
-rw-r--r--phpBB/mcp.php34
-rw-r--r--phpBB/memberlist.php409
-rw-r--r--phpBB/phpbb/attachment/delete.php480
-rw-r--r--phpBB/phpbb/attachment/manager.php99
-rw-r--r--phpBB/phpbb/attachment/resync.php124
-rw-r--r--phpBB/phpbb/attachment/upload.php334
-rw-r--r--phpBB/phpbb/auth/auth.php11
-rw-r--r--phpBB/phpbb/auth/provider/db.php1
-rw-r--r--phpBB/phpbb/auth/provider/ldap.php4
-rw-r--r--phpBB/phpbb/auth/provider/oauth/oauth.php141
-rw-r--r--phpBB/phpbb/auth/provider/oauth/service/twitter.php102
-rw-r--r--phpBB/phpbb/auth/provider/oauth/token_storage.php254
-rw-r--r--phpBB/phpbb/auth/provider/provider_interface.php7
-rw-r--r--phpBB/phpbb/avatar/driver/driver.php7
-rw-r--r--phpBB/phpbb/avatar/driver/gravatar.php12
-rw-r--r--phpBB/phpbb/avatar/driver/local.php14
-rw-r--r--phpBB/phpbb/avatar/driver/remote.php60
-rw-r--r--phpBB/phpbb/avatar/driver/upload.php70
-rw-r--r--phpBB/phpbb/avatar/manager.php25
-rw-r--r--phpBB/phpbb/cache/driver/apcu.php74
-rw-r--r--phpBB/phpbb/cache/driver/base.php22
-rw-r--r--phpBB/phpbb/cache/driver/dummy.php153
-rw-r--r--phpBB/phpbb/cache/driver/eaccelerator.php4
-rw-r--r--phpBB/phpbb/cache/driver/file.php47
-rw-r--r--phpBB/phpbb/cache/driver/memcached.php4
-rw-r--r--phpBB/phpbb/cache/driver/memory.php23
-rw-r--r--phpBB/phpbb/cache/driver/null.php151
-rw-r--r--phpBB/phpbb/cache/driver/redis.php4
-rw-r--r--phpBB/phpbb/cache/service.php4
-rw-r--r--phpBB/phpbb/captcha/char_cube3d.php2
-rw-r--r--phpBB/phpbb/captcha/colour_manager.php2
-rw-r--r--phpBB/phpbb/captcha/gd.php59
-rw-r--r--phpBB/phpbb/captcha/gd_wave.php5
-rw-r--r--phpBB/phpbb/captcha/plugins/captcha_abstract.php26
-rw-r--r--phpBB/phpbb/captcha/plugins/gd.php27
-rw-r--r--phpBB/phpbb/captcha/plugins/gd_wave.php4
-rw-r--r--phpBB/phpbb/captcha/plugins/nogd.php2
-rw-r--r--phpBB/phpbb/captcha/plugins/qa.php69
-rw-r--r--phpBB/phpbb/captcha/plugins/recaptcha.php139
-rw-r--r--phpBB/phpbb/composer.json4
-rw-r--r--phpBB/phpbb/console/application.php71
-rw-r--r--phpBB/phpbb/console/command/cache/purge.php8
-rw-r--r--phpBB/phpbb/console/command/command.php45
-rw-r--r--phpBB/phpbb/console/command/config/command.php2
-rw-r--r--phpBB/phpbb/console/command/config/delete.php9
-rw-r--r--phpBB/phpbb/console/command/config/get.php7
-rw-r--r--phpBB/phpbb/console/command/config/increment.php7
-rw-r--r--phpBB/phpbb/console/command/config/set.php7
-rw-r--r--phpBB/phpbb/console/command/config/set_atomic.php7
-rw-r--r--phpBB/phpbb/console/command/cron/cron_list.php41
-rw-r--r--phpBB/phpbb/console/command/cron/run.php7
-rw-r--r--phpBB/phpbb/console/command/db/console_migrator_output_handler.php2
-rw-r--r--phpBB/phpbb/console/command/db/list_command.php81
-rw-r--r--phpBB/phpbb/console/command/db/migrate.php61
-rw-r--r--phpBB/phpbb/console/command/db/migration_command.php56
-rw-r--r--phpBB/phpbb/console/command/db/revert.php74
-rw-r--r--phpBB/phpbb/console/command/dev/migration_tips.php2
-rw-r--r--phpBB/phpbb/console/command/extension/disable.php14
-rw-r--r--phpBB/phpbb/console/command/extension/enable.php28
-rw-r--r--phpBB/phpbb/console/command/extension/purge.php7
-rw-r--r--phpBB/phpbb/console/command/extension/show.php28
-rw-r--r--phpBB/phpbb/console/command/fixup/fix_left_right_ids.php5
-rw-r--r--phpBB/phpbb/console/command/fixup/recalculate_email_hash.php17
-rw-r--r--phpBB/phpbb/console/command/fixup/update_hashes.php6
-rw-r--r--phpBB/phpbb/console/command/reparser/list_all.php72
-rw-r--r--phpBB/phpbb/console/command/reparser/reparse.php242
-rw-r--r--phpBB/phpbb/console/command/thumbnail/delete.php160
-rw-r--r--phpBB/phpbb/console/command/thumbnail/generate.php186
-rw-r--r--phpBB/phpbb/console/command/thumbnail/recreate.php72
-rw-r--r--phpBB/phpbb/console/command/update/check.php331
-rw-r--r--phpBB/phpbb/console/command/user/activate.php218
-rw-r--r--phpBB/phpbb/console/command/user/add.php334
-rw-r--r--phpBB/phpbb/console/command/user/delete.php170
-rw-r--r--phpBB/phpbb/console/command/user/reclean.php158
-rw-r--r--phpBB/phpbb/console/exception_subscriber.php65
-rw-r--r--phpBB/phpbb/content_visibility.php130
-rw-r--r--phpBB/phpbb/controller/exception.php2
-rw-r--r--phpBB/phpbb/controller/helper.php128
-rw-r--r--phpBB/phpbb/controller/provider.php92
-rw-r--r--phpBB/phpbb/controller/resolver.php36
-rw-r--r--phpBB/phpbb/cron/task/core/prune_all_forums.php23
-rw-r--r--phpBB/phpbb/cron/task/core/prune_forum.php2
-rw-r--r--phpBB/phpbb/cron/task/core/prune_shadow_topics.php2
-rw-r--r--phpBB/phpbb/cron/task/core/queue.php19
-rw-r--r--phpBB/phpbb/cron/task/core/tidy_plupload.php18
-rw-r--r--phpBB/phpbb/cron/task/core/update_hashes.php6
-rw-r--r--phpBB/phpbb/cron/task/text_reparser/reparser.php168
-rw-r--r--phpBB/phpbb/datetime.php6
-rw-r--r--phpBB/phpbb/db/driver/driver.php182
-rw-r--r--phpBB/phpbb/db/driver/mssql.php476
-rw-r--r--phpBB/phpbb/db/driver/mssql_base.php8
-rw-r--r--phpBB/phpbb/db/driver/mssql_odbc.php32
-rw-r--r--phpBB/phpbb/db/driver/mssqlnative.php39
-rw-r--r--phpBB/phpbb/db/driver/mysql.php56
-rw-r--r--phpBB/phpbb/db/driver/mysqli.php52
-rw-r--r--phpBB/phpbb/db/driver/oracle.php67
-rw-r--r--phpBB/phpbb/db/driver/postgres.php45
-rw-r--r--phpBB/phpbb/db/driver/sqlite.php378
-rw-r--r--phpBB/phpbb/db/driver/sqlite3.php36
-rw-r--r--phpBB/phpbb/db/extractor/base_extractor.php252
-rw-r--r--phpBB/phpbb/db/extractor/exception/extractor_not_initialized_exception.php24
-rw-r--r--phpBB/phpbb/db/extractor/exception/invalid_format_exception.php22
-rw-r--r--phpBB/phpbb/db/extractor/extractor_interface.php80
-rw-r--r--phpBB/phpbb/db/extractor/factory.php75
-rw-r--r--phpBB/phpbb/db/extractor/mssql_extractor.php415
-rw-r--r--phpBB/phpbb/db/extractor/mysql_extractor.php403
-rw-r--r--phpBB/phpbb/db/extractor/oracle_extractor.php263
-rw-r--r--phpBB/phpbb/db/extractor/postgres_extractor.php339
-rw-r--r--phpBB/phpbb/db/extractor/sqlite3_extractor.php151
-rw-r--r--phpBB/phpbb/db/html_migrator_output_handler.php48
-rw-r--r--phpBB/phpbb/db/log_wrapper_migrator_output_handler.php95
-rw-r--r--phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php4
-rw-r--r--phpBB/phpbb/db/migration/data/v30x/release_3_0_6_rc1.php44
-rw-r--r--phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php14
-rw-r--r--phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php2
-rw-r--r--phpBB/phpbb/db/migration/data/v310/acp_prune_users_module.php11
-rw-r--r--phpBB/phpbb/db/migration/data/v310/auth_provider_oauth.php11
-rw-r--r--phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php4
-rw-r--r--phpBB/phpbb/db/migration/data/v310/dev.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v310/extensions.php4
-rw-r--r--phpBB/phpbb/db/migration/data/v310/notifications.php7
-rw-r--r--phpBB/phpbb/db/migration/data/v310/softdelete_mcp_modules.php8
-rw-r--r--phpBB/phpbb/db/migration/data/v310/style_update_p1.php12
-rw-r--r--phpBB/phpbb/db/migration/data/v310/teampage.php4
-rw-r--r--phpBB/phpbb/db/migration/data/v310/timezone.php2
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php1
-rw-r--r--phpBB/phpbb/db/migration/data/v31x/v3112.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v320/.htaccess33
-rw-r--r--phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php48
-rw-r--r--phpBB/phpbb/db/migration/data/v320/allowed_schemes_links.php31
-rw-r--r--phpBB/phpbb/db/migration/data/v320/announce_global_permission.php43
-rw-r--r--phpBB/phpbb/db/migration/data/v320/cookie_notice.php31
-rw-r--r--phpBB/phpbb/db/migration/data/v320/default_data_type_ids.php361
-rw-r--r--phpBB/phpbb/db/migration/data/v320/dev.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v320/font_awesome_update.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v320/icons_alt.php46
-rw-r--r--phpBB/phpbb/db/migration/data/v320/log_post_id.php46
-rw-r--r--phpBB/phpbb/db/migration/data/v320/notifications_board.php75
-rw-r--r--phpBB/phpbb/db/migration/data/v320/oauth_states.php56
-rw-r--r--phpBB/phpbb/db/migration/data/v320/remote_upload_validation.php31
-rw-r--r--phpBB/phpbb/db/migration/data/v320/remove_outdated_media.php95
-rw-r--r--phpBB/phpbb/db/migration/data/v320/remove_profilefield_wlm.php152
-rw-r--r--phpBB/phpbb/db/migration/data/v320/report_id_auto_increment.php46
-rw-r--r--phpBB/phpbb/db/migration/data/v320/text_reparser.php121
-rw-r--r--phpBB/phpbb/db/migration/data/v320/v320.php40
-rw-r--r--phpBB/phpbb/db/migration/data/v320/v320a1.php44
-rw-r--r--phpBB/phpbb/db/migration/data/v320/v320a2.php38
-rw-r--r--phpBB/phpbb/db/migration/data/v320/v320b1.php39
-rw-r--r--phpBB/phpbb/db/migration/data/v320/v320b2.php40
-rw-r--r--phpBB/phpbb/db/migration/data/v320/v320rc1.php40
-rw-r--r--phpBB/phpbb/db/migration/data/v320/v320rc2.php40
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/.htaccess33
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/cookie_notice_p2.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/disable_remote_avatar.php34
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/email_force_sender.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/enable_accurate_pm_button.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/f_list_topics_permission_add.php31
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/fix_user_styles.php54
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/forum_topics_per_page_type.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/jquery_update.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/load_user_activity_limit.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php84
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/remove_imagick.php31
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/smtp_dynamic_data.php42
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/timezone_p3.php29
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php39
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_emoji_permission.php44
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p1.php46
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p2.php46
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p3.php46
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_notifications_table_reduce_column_sizes.php48
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_notifications_table_remove_duplicates.php55
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_notifications_table_temp_index.php46
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/user_notifications_table_unique_index.php51
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v321.php38
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v321rc1.php39
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v322.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v322rc1.php41
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v323.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v323rc1.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v323rc2.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v324.php38
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v324rc1.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v325.php38
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v325rc1.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v326.php39
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v326rc1.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v327.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v327rc1.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v328.php36
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v328rc1.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v329.php37
-rw-r--r--phpBB/phpbb/db/migration/data/v32x/v329rc1.php36
-rw-r--r--phpBB/phpbb/db/migration/migration.php40
-rw-r--r--phpBB/phpbb/db/migration/migration_interface.php70
-rw-r--r--phpBB/phpbb/db/migration/profilefield_base_migration.php1
-rw-r--r--phpBB/phpbb/db/migration/schema_generator.php13
-rw-r--r--phpBB/phpbb/db/migration/tool/config.php2
-rw-r--r--phpBB/phpbb/db/migration/tool/config_text.php2
-rw-r--r--phpBB/phpbb/db/migration/tool/module.php315
-rw-r--r--phpBB/phpbb/db/migration/tool/permission.php2
-rw-r--r--phpBB/phpbb/db/migrator.php129
-rw-r--r--phpBB/phpbb/db/migrator_output_handler_interface.php31
-rw-r--r--phpBB/phpbb/db/null_migrator_output_handler.php24
-rw-r--r--phpBB/phpbb/db/output_handler/html_migrator_output_handler.php46
-rw-r--r--phpBB/phpbb/db/output_handler/installer_migrator_output_handler.php46
-rw-r--r--phpBB/phpbb/db/output_handler/log_wrapper_migrator_output_handler.php101
-rw-r--r--phpBB/phpbb/db/output_handler/migrator_output_handler_interface.php31
-rw-r--r--phpBB/phpbb/db/output_handler/null_migrator_output_handler.php24
-rw-r--r--phpBB/phpbb/db/sql_insert_buffer.php4
-rw-r--r--phpBB/phpbb/db/tools.php2825
-rw-r--r--phpBB/phpbb/db/tools/factory.php43
-rw-r--r--phpBB/phpbb/db/tools/mssql.php880
-rw-r--r--phpBB/phpbb/db/tools/postgres.php614
-rw-r--r--phpBB/phpbb/db/tools/tools.php1956
-rw-r--r--phpBB/phpbb/db/tools/tools_interface.php202
-rw-r--r--phpBB/phpbb/debug/debug.php80
-rw-r--r--phpBB/phpbb/debug/error_handler.php31
-rw-r--r--phpBB/phpbb/di/container_builder.php749
-rw-r--r--phpBB/phpbb/di/extension/container_configuration.php52
-rw-r--r--phpBB/phpbb/di/extension/core.php107
-rw-r--r--phpBB/phpbb/di/extension/ext.php67
-rw-r--r--phpBB/phpbb/di/ordered_service_collection.php117
-rw-r--r--phpBB/phpbb/di/pass/collection_pass.php22
-rw-r--r--phpBB/phpbb/di/proxy_instantiator.php72
-rw-r--r--phpBB/phpbb/di/service_collection.php27
-rw-r--r--phpBB/phpbb/di/service_collection_iterator.php2
-rw-r--r--phpBB/phpbb/event/data.php12
-rw-r--r--phpBB/phpbb/event/dispatcher.php7
-rw-r--r--phpBB/phpbb/event/kernel_exception_subscriber.php40
-rw-r--r--phpBB/phpbb/event/kernel_request_subscriber.php82
-rw-r--r--phpBB/phpbb/event/kernel_terminate_subscriber.php2
-rw-r--r--phpBB/phpbb/event/md_exporter.php49
-rw-r--r--phpBB/phpbb/event/php_exporter.php73
-rw-r--r--phpBB/phpbb/exception/version_check_exception.php21
-rw-r--r--phpBB/phpbb/extension/base.php12
-rw-r--r--phpBB/phpbb/extension/di/extension_base.php138
-rw-r--r--phpBB/phpbb/extension/exception.php6
-rw-r--r--phpBB/phpbb/extension/manager.php95
-rw-r--r--phpBB/phpbb/extension/metadata_manager.php115
-rw-r--r--phpBB/phpbb/feed/attachments_base.php2
-rw-r--r--phpBB/phpbb/feed/base.php249
-rw-r--r--phpBB/phpbb/feed/controller/feed.php411
-rw-r--r--phpBB/phpbb/feed/exception/feed_exception.php21
-rw-r--r--phpBB/phpbb/feed/exception/feed_unavailable_exception.php19
-rw-r--r--phpBB/phpbb/feed/exception/no_feed_exception.php22
-rw-r--r--phpBB/phpbb/feed/exception/no_forum_exception.php22
-rw-r--r--phpBB/phpbb/feed/exception/no_topic_exception.php22
-rw-r--r--phpBB/phpbb/feed/exception/unauthorized_exception.php19
-rw-r--r--phpBB/phpbb/feed/exception/unauthorized_forum_exception.php22
-rw-r--r--phpBB/phpbb/feed/exception/unauthorized_topic_exception.php22
-rw-r--r--phpBB/phpbb/feed/factory.php127
-rw-r--r--phpBB/phpbb/feed/feed_interface.php67
-rw-r--r--phpBB/phpbb/feed/forum.php98
-rw-r--r--phpBB/phpbb/feed/forums.php49
-rw-r--r--phpBB/phpbb/feed/helper.php123
-rw-r--r--phpBB/phpbb/feed/news.php43
-rw-r--r--phpBB/phpbb/feed/overall.php46
-rw-r--r--phpBB/phpbb/feed/post_base.php39
-rw-r--r--phpBB/phpbb/feed/quote_helper.php36
-rw-r--r--phpBB/phpbb/feed/topic.php107
-rw-r--r--phpBB/phpbb/feed/topic_base.php38
-rw-r--r--phpBB/phpbb/feed/topics.php42
-rw-r--r--phpBB/phpbb/feed/topics_active.php60
-rw-r--r--phpBB/phpbb/file_downloader.php2
-rw-r--r--phpBB/phpbb/files/factory.php58
-rw-r--r--phpBB/phpbb/files/filespec.php584
-rw-r--r--phpBB/phpbb/files/types/base.php65
-rw-r--r--phpBB/phpbb/files/types/form.php138
-rw-r--r--phpBB/phpbb/files/types/local.php136
-rw-r--r--phpBB/phpbb/files/types/remote.php207
-rw-r--r--phpBB/phpbb/files/types/type_interface.php38
-rw-r--r--phpBB/phpbb/files/upload.php390
-rw-r--r--phpBB/phpbb/filesystem.php35
-rw-r--r--phpBB/phpbb/filesystem/exception/filesystem_exception.php42
-rw-r--r--phpBB/phpbb/filesystem/filesystem.php916
-rw-r--r--phpBB/phpbb/filesystem/filesystem_interface.php284
-rw-r--r--phpBB/phpbb/finder.php6
-rw-r--r--phpBB/phpbb/group/helper.php294
-rw-r--r--phpBB/phpbb/help/controller/bbcode.php85
-rw-r--r--phpBB/phpbb/help/controller/controller.php76
-rw-r--r--phpBB/phpbb/help/controller/faq.php165
-rw-r--r--phpBB/phpbb/help/controller/help.php164
-rw-r--r--phpBB/phpbb/help/manager.php137
-rw-r--r--phpBB/phpbb/hook/finder.php13
-rw-r--r--phpBB/phpbb/install/console/command/install/config/show.php123
-rw-r--r--phpBB/phpbb/install/console/command/install/config/validate.php124
-rw-r--r--phpBB/phpbb/install/console/command/install/install.php210
-rw-r--r--phpBB/phpbb/install/console/command/update/config/show.php123
-rw-r--r--phpBB/phpbb/install/console/command/update/config/validate.php124
-rw-r--r--phpBB/phpbb/install/console/command/update/update.php182
-rw-r--r--phpBB/phpbb/install/controller/archive_download.php93
-rw-r--r--phpBB/phpbb/install/controller/helper.php413
-rw-r--r--phpBB/phpbb/install/controller/install.php172
-rw-r--r--phpBB/phpbb/install/controller/installer_index.php81
-rw-r--r--phpBB/phpbb/install/controller/timeout_check.php80
-rw-r--r--phpBB/phpbb/install/controller/update.php166
-rw-r--r--phpBB/phpbb/install/event/kernel_exception_subscriber.php126
-rw-r--r--phpBB/phpbb/install/exception/cannot_build_container_exception.php22
-rw-r--r--phpBB/phpbb/install/exception/file_updater_failure_exception.php22
-rw-r--r--phpBB/phpbb/install/exception/installer_config_not_writable_exception.php22
-rw-r--r--phpBB/phpbb/install/exception/installer_exception.php24
-rw-r--r--phpBB/phpbb/install/exception/invalid_dbms_exception.php22
-rw-r--r--phpBB/phpbb/install/exception/jump_to_restart_point_exception.php44
-rw-r--r--phpBB/phpbb/install/exception/resource_limit_reached_exception.php22
-rw-r--r--phpBB/phpbb/install/exception/user_interaction_required_exception.php25
-rw-r--r--phpBB/phpbb/install/helper/config.php452
-rw-r--r--phpBB/phpbb/install/helper/container_factory.php191
-rw-r--r--phpBB/phpbb/install/helper/database.php439
-rw-r--r--phpBB/phpbb/install/helper/file_updater/compression_file_updater.php133
-rw-r--r--phpBB/phpbb/install/helper/file_updater/factory.php69
-rw-r--r--phpBB/phpbb/install/helper/file_updater/file_updater.php202
-rw-r--r--phpBB/phpbb/install/helper/file_updater/file_updater_interface.php49
-rw-r--r--phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php136
-rw-r--r--phpBB/phpbb/install/helper/install_helper.php60
-rw-r--r--phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php509
-rw-r--r--phpBB/phpbb/install/helper/iohandler/cli_iohandler.php323
-rw-r--r--phpBB/phpbb/install/helper/iohandler/exception/iohandler_not_implemented_exception.php19
-rw-r--r--phpBB/phpbb/install/helper/iohandler/factory.php79
-rw-r--r--phpBB/phpbb/install/helper/iohandler/iohandler_base.php209
-rw-r--r--phpBB/phpbb/install/helper/iohandler/iohandler_interface.php222
-rw-r--r--phpBB/phpbb/install/helper/navigation/convertor_navigation.php78
-rw-r--r--phpBB/phpbb/install/helper/navigation/install_navigation.php75
-rw-r--r--phpBB/phpbb/install/helper/navigation/main_navigation.php48
-rw-r--r--phpBB/phpbb/install/helper/navigation/navigation_interface.php43
-rw-r--r--phpBB/phpbb/install/helper/navigation/navigation_provider.php121
-rw-r--r--phpBB/phpbb/install/helper/navigation/update_navigation.php80
-rw-r--r--phpBB/phpbb/install/helper/update_helper.php113
-rw-r--r--phpBB/phpbb/install/installer.php350
-rw-r--r--phpBB/phpbb/install/installer_configuration.php147
-rw-r--r--phpBB/phpbb/install/module/install_data/module.php28
-rw-r--r--phpBB/phpbb/install/module/install_data/task/add_bots.php263
-rw-r--r--phpBB/phpbb/install/module/install_data/task/add_languages.php121
-rw-r--r--phpBB/phpbb/install/module/install_data/task/add_modules.php568
-rw-r--r--phpBB/phpbb/install/module/install_data/task/create_search_index.php134
-rw-r--r--phpBB/phpbb/install/module/install_database/module.php28
-rw-r--r--phpBB/phpbb/install/module/install_database/task/add_config_settings.php368
-rw-r--r--phpBB/phpbb/install/module/install_database/task/add_default_data.php184
-rw-r--r--phpBB/phpbb/install/module/install_database/task/add_tables.php151
-rw-r--r--phpBB/phpbb/install/module/install_database/task/create_schema.php234
-rw-r--r--phpBB/phpbb/install/module/install_database/task/create_schema_file.php164
-rw-r--r--phpBB/phpbb/install/module/install_database/task/set_up_database.php164
-rw-r--r--phpBB/phpbb/install/module/install_filesystem/module.php28
-rw-r--r--phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php244
-rw-r--r--phpBB/phpbb/install/module/install_finish/module.php28
-rw-r--r--phpBB/phpbb/install/module/install_finish/task/install_extensions.php207
-rw-r--r--phpBB/phpbb/install/module/install_finish/task/notify_user.php174
-rw-r--r--phpBB/phpbb/install/module/install_finish/task/populate_migrations.php93
-rw-r--r--phpBB/phpbb/install/module/obtain_data/install_module.php33
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php218
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_board_data.php185
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_database_data.php270
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php173
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_file_updater_method.php167
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_server_data.php202
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_update_files.php113
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_update_ftp_data.php163
-rw-r--r--phpBB/phpbb/install/module/obtain_data/task/obtain_update_settings.php123
-rw-r--r--phpBB/phpbb/install/module/obtain_data/update_module.php33
-rw-r--r--phpBB/phpbb/install/module/requirements/abstract_requirements_module.php71
-rw-r--r--phpBB/phpbb/install/module/requirements/install_module.php25
-rw-r--r--phpBB/phpbb/install/module/requirements/task/check_filesystem.php279
-rw-r--r--phpBB/phpbb/install/module/requirements/task/check_server_environment.php209
-rw-r--r--phpBB/phpbb/install/module/requirements/task/check_update.php198
-rw-r--r--phpBB/phpbb/install/module/requirements/update_module.php25
-rw-r--r--phpBB/phpbb/install/module/update_database/module.php33
-rw-r--r--phpBB/phpbb/install/module/update_database/task/update.php234
-rw-r--r--phpBB/phpbb/install/module/update_database/task/update_extensions.php263
-rw-r--r--phpBB/phpbb/install/module/update_filesystem/module.php33
-rw-r--r--phpBB/phpbb/install/module/update_filesystem/task/diff_files.php253
-rw-r--r--phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php133
-rw-r--r--phpBB/phpbb/install/module/update_filesystem/task/file_check.php248
-rw-r--r--phpBB/phpbb/install/module/update_filesystem/task/show_file_status.php170
-rw-r--r--phpBB/phpbb/install/module/update_filesystem/task/update_files.php294
-rw-r--r--phpBB/phpbb/install/module_base.php213
-rw-r--r--phpBB/phpbb/install/module_interface.php63
-rw-r--r--phpBB/phpbb/install/task_base.php53
-rw-r--r--phpBB/phpbb/install/task_interface.php61
-rw-r--r--phpBB/phpbb/install/updater_configuration.php44
-rw-r--r--phpBB/phpbb/language/exception/invalid_plural_rule_exception.php22
-rw-r--r--phpBB/phpbb/language/exception/language_exception.php22
-rw-r--r--phpBB/phpbb/language/exception/language_file_not_found.php22
-rw-r--r--phpBB/phpbb/language/language.php673
-rw-r--r--phpBB/phpbb/language/language_file_helper.php72
-rw-r--r--phpBB/phpbb/language/language_file_loader.php206
-rw-r--r--phpBB/phpbb/log/dummy.php81
-rw-r--r--phpBB/phpbb/log/log.php35
-rw-r--r--phpBB/phpbb/log/log_interface.php16
-rw-r--r--phpBB/phpbb/log/null.php81
-rw-r--r--phpBB/phpbb/message/admin_form.php30
-rw-r--r--phpBB/phpbb/message/form.php6
-rw-r--r--phpBB/phpbb/message/message.php6
-rw-r--r--phpBB/phpbb/message/topic_form.php8
-rw-r--r--phpBB/phpbb/module/exception/module_exception.php19
-rw-r--r--phpBB/phpbb/module/exception/module_not_found_exception.php19
-rw-r--r--phpBB/phpbb/module/module_manager.php564
-rw-r--r--phpBB/phpbb/notification/exception.php6
-rw-r--r--phpBB/phpbb/notification/manager.php618
-rw-r--r--phpBB/phpbb/notification/method/base.php130
-rw-r--r--phpBB/phpbb/notification/method/board.php399
-rw-r--r--phpBB/phpbb/notification/method/email.php33
-rw-r--r--phpBB/phpbb/notification/method/jabber.php35
-rw-r--r--phpBB/phpbb/notification/method/messenger_base.php44
-rw-r--r--phpBB/phpbb/notification/method/method_interface.php104
-rw-r--r--phpBB/phpbb/notification/type/admin_activate_user.php28
-rw-r--r--phpBB/phpbb/notification/type/approve_post.php25
-rw-r--r--phpBB/phpbb/notification/type/approve_topic.php26
-rw-r--r--phpBB/phpbb/notification/type/base.php170
-rw-r--r--phpBB/phpbb/notification/type/bookmark.php34
-rw-r--r--phpBB/phpbb/notification/type/disapprove_post.php29
-rw-r--r--phpBB/phpbb/notification/type/disapprove_topic.php29
-rw-r--r--phpBB/phpbb/notification/type/group_request.php18
-rw-r--r--phpBB/phpbb/notification/type/group_request_approved.php10
-rw-r--r--phpBB/phpbb/notification/type/pm.php38
-rw-r--r--phpBB/phpbb/notification/type/post.php93
-rw-r--r--phpBB/phpbb/notification/type/post_in_queue.php23
-rw-r--r--phpBB/phpbb/notification/type/quote.php60
-rw-r--r--phpBB/phpbb/notification/type/report_pm.php48
-rw-r--r--phpBB/phpbb/notification/type/report_pm_closed.php27
-rw-r--r--phpBB/phpbb/notification/type/report_post.php28
-rw-r--r--phpBB/phpbb/notification/type/report_post_closed.php27
-rw-r--r--phpBB/phpbb/notification/type/topic.php42
-rw-r--r--phpBB/phpbb/notification/type/topic_in_queue.php23
-rw-r--r--phpBB/phpbb/notification/type/type_interface.php16
-rw-r--r--phpBB/phpbb/pagination.php15
-rw-r--r--phpBB/phpbb/passwords/driver/base.php12
-rw-r--r--phpBB/phpbb/passwords/driver/bcrypt.php32
-rw-r--r--phpBB/phpbb/passwords/driver/md5_phpbb2.php2
-rw-r--r--phpBB/phpbb/passwords/driver/rehashable_driver_interface.php25
-rw-r--r--phpBB/phpbb/passwords/manager.php59
-rw-r--r--phpBB/phpbb/path_helper.php28
-rw-r--r--phpBB/phpbb/permissions.php3
-rw-r--r--phpBB/phpbb/plupload/plupload.php85
-rw-r--r--phpBB/phpbb/profilefields/manager.php10
-rw-r--r--phpBB/phpbb/profilefields/type/type_bool.php2
-rw-r--r--phpBB/phpbb/profilefields/type/type_date.php2
-rw-r--r--phpBB/phpbb/profilefields/type/type_dropdown.php6
-rw-r--r--phpBB/phpbb/profilefields/type/type_url.php15
-rw-r--r--phpBB/phpbb/report/controller/report.php319
-rw-r--r--phpBB/phpbb/report/exception/already_reported_exception.php19
-rw-r--r--phpBB/phpbb/report/exception/empty_report_exception.php22
-rw-r--r--phpBB/phpbb/report/exception/entity_not_found_exception.php19
-rw-r--r--phpBB/phpbb/report/exception/factory_invalid_argument_exception.php21
-rw-r--r--phpBB/phpbb/report/exception/invalid_report_exception.php21
-rw-r--r--phpBB/phpbb/report/exception/pm_reporting_disabled_exception.php22
-rw-r--r--phpBB/phpbb/report/exception/report_permission_denied_exception.php19
-rw-r--r--phpBB/phpbb/report/handler_factory.php56
-rw-r--r--phpBB/phpbb/report/report_handler.php104
-rw-r--r--phpBB/phpbb/report/report_handler_interface.php43
-rw-r--r--phpBB/phpbb/report/report_handler_pm.php137
-rw-r--r--phpBB/phpbb/report/report_handler_post.php175
-rw-r--r--phpBB/phpbb/report/report_reason_list_provider.php78
-rw-r--r--phpBB/phpbb/request/deactivated_super_global.php2
-rw-r--r--phpBB/phpbb/request/request.php86
-rw-r--r--phpBB/phpbb/request/request_interface.php22
-rw-r--r--phpBB/phpbb/request/type_cast_helper.php66
-rw-r--r--phpBB/phpbb/request/type_cast_helper_interface.php14
-rw-r--r--phpBB/phpbb/routing/file_locator.php33
-rw-r--r--phpBB/phpbb/routing/helper.php162
-rw-r--r--phpBB/phpbb/routing/loader_resolver.php50
-rw-r--r--phpBB/phpbb/routing/resources_locator/chained_resources_locator.php47
-rw-r--r--phpBB/phpbb/routing/resources_locator/default_resources_locator.php105
-rw-r--r--phpBB/phpbb/routing/resources_locator/installer_resources_locator.php78
-rw-r--r--phpBB/phpbb/routing/resources_locator/resources_locator_interface.php27
-rw-r--r--phpBB/phpbb/routing/router.php395
-rw-r--r--phpBB/phpbb/search/base.php12
-rw-r--r--phpBB/phpbb/search/fulltext_mysql.php138
-rw-r--r--phpBB/phpbb/search/fulltext_native.php208
-rw-r--r--phpBB/phpbb/search/fulltext_postgres.php104
-rw-r--r--phpBB/phpbb/search/fulltext_sphinx.php76
-rw-r--r--phpBB/phpbb/search/sphinx/config.php4
-rw-r--r--phpBB/phpbb/search/sphinx/config_section.php6
-rw-r--r--phpBB/phpbb/session.php133
-rw-r--r--phpBB/phpbb/template/asset.php15
-rw-r--r--phpBB/phpbb/template/assets_bag.php95
-rw-r--r--phpBB/phpbb/template/base.php29
-rw-r--r--phpBB/phpbb/template/context.php275
-rw-r--r--phpBB/phpbb/template/exception/user_object_not_available.php22
-rw-r--r--phpBB/phpbb/template/template.php27
-rw-r--r--phpBB/phpbb/template/twig/environment.php138
-rw-r--r--phpBB/phpbb/template/twig/extension.php19
-rw-r--r--phpBB/phpbb/template/twig/extension/routing.php43
-rw-r--r--phpBB/phpbb/template/twig/lexer.php22
-rw-r--r--phpBB/phpbb/template/twig/loader.php32
-rw-r--r--phpBB/phpbb/template/twig/node/event.php6
-rw-r--r--phpBB/phpbb/template/twig/node/includeasset.php32
-rw-r--r--phpBB/phpbb/template/twig/node/includecss.php16
-rw-r--r--phpBB/phpbb/template/twig/node/includejs.php18
-rw-r--r--phpBB/phpbb/template/twig/twig.php63
-rw-r--r--phpBB/phpbb/textformatter/cache_interface.php31
-rw-r--r--phpBB/phpbb/textformatter/data_access.php252
-rw-r--r--phpBB/phpbb/textformatter/parser_interface.php112
-rw-r--r--phpBB/phpbb/textformatter/renderer_interface.php92
-rw-r--r--phpBB/phpbb/textformatter/s9e/bbcode_merger.php199
-rw-r--r--phpBB/phpbb/textformatter/s9e/factory.php678
-rw-r--r--phpBB/phpbb/textformatter/s9e/link_helper.php115
-rw-r--r--phpBB/phpbb/textformatter/s9e/parser.php417
-rw-r--r--phpBB/phpbb/textformatter/s9e/quote_helper.php87
-rw-r--r--phpBB/phpbb/textformatter/s9e/renderer.php313
-rw-r--r--phpBB/phpbb/textformatter/s9e/utils.php152
-rw-r--r--phpBB/phpbb/textformatter/utils_interface.php79
-rw-r--r--phpBB/phpbb/textreparser/base.php269
-rw-r--r--phpBB/phpbb/textreparser/manager.php148
-rw-r--r--phpBB/phpbb/textreparser/plugins/contact_admin_info.php69
-rw-r--r--phpBB/phpbb/textreparser/plugins/forum_description.php30
-rw-r--r--phpBB/phpbb/textreparser/plugins/forum_rules.php30
-rw-r--r--phpBB/phpbb/textreparser/plugins/group_description.php30
-rw-r--r--phpBB/phpbb/textreparser/plugins/pm_text.php32
-rw-r--r--phpBB/phpbb/textreparser/plugins/poll_option.php74
-rw-r--r--phpBB/phpbb/textreparser/plugins/poll_title.php42
-rw-r--r--phpBB/phpbb/textreparser/plugins/post_text.php32
-rw-r--r--phpBB/phpbb/textreparser/plugins/user_signature.php65
-rw-r--r--phpBB/phpbb/textreparser/reparser_interface.php46
-rw-r--r--phpBB/phpbb/textreparser/row_based_plugin.php117
-rw-r--r--phpBB/phpbb/tree/nestedset.php8
-rw-r--r--phpBB/phpbb/user.php422
-rw-r--r--phpBB/phpbb/user_loader.php19
-rw-r--r--phpBB/phpbb/version_helper.php43
-rw-r--r--phpBB/phpbb/viewonline_helper.php6
-rw-r--r--phpBB/posting.php302
-rw-r--r--phpBB/report.php323
-rw-r--r--phpBB/search.php119
-rw-r--r--phpBB/styles/all/template/feed.xml.twig37
-rw-r--r--phpBB/styles/prosilver/style.cfg6
-rw-r--r--phpBB/styles/prosilver/template/ajax.js6
-rw-r--r--phpBB/styles/prosilver/template/attachment.html83
-rw-r--r--phpBB/styles/prosilver/template/bbcode.html43
-rw-r--r--phpBB/styles/prosilver/template/captcha_recaptcha.html19
-rw-r--r--phpBB/styles/prosilver/template/confirm_delete_body.html4
-rw-r--r--phpBB/styles/prosilver/template/display_options.html27
-rw-r--r--phpBB/styles/prosilver/template/faq_body.html4
-rw-r--r--phpBB/styles/prosilver/template/forum_fn.js65
-rw-r--r--phpBB/styles/prosilver/template/forumlist_body.html69
-rw-r--r--phpBB/styles/prosilver/template/index_body.html1
-rw-r--r--phpBB/styles/prosilver/template/jumpbox.html50
-rw-r--r--phpBB/styles/prosilver/template/login_body.html1
-rw-r--r--phpBB/styles/prosilver/template/login_body_oauth.html10
-rw-r--r--phpBB/styles/prosilver/template/login_forum.html1
-rw-r--r--phpBB/styles/prosilver/template/mcp_approve.html4
-rw-r--r--phpBB/styles/prosilver/template/mcp_ban.html18
-rw-r--r--phpBB/styles/prosilver/template/mcp_forum.html52
-rw-r--r--phpBB/styles/prosilver/template/mcp_front.html8
-rw-r--r--phpBB/styles/prosilver/template/mcp_header.html10
-rw-r--r--phpBB/styles/prosilver/template/mcp_logs.html21
-rw-r--r--phpBB/styles/prosilver/template/mcp_move.html2
-rw-r--r--phpBB/styles/prosilver/template/mcp_notes_front.html2
-rw-r--r--phpBB/styles/prosilver/template/mcp_notes_user.html22
-rw-r--r--phpBB/styles/prosilver/template/mcp_post.html32
-rw-r--r--phpBB/styles/prosilver/template/mcp_queue.html24
-rw-r--r--phpBB/styles/prosilver/template/mcp_reports.html26
-rw-r--r--phpBB/styles/prosilver/template/mcp_topic.html27
-rw-r--r--phpBB/styles/prosilver/template/mcp_warn_front.html2
-rw-r--r--phpBB/styles/prosilver/template/mcp_warn_list.html20
-rw-r--r--phpBB/styles/prosilver/template/mcp_warn_post.html2
-rw-r--r--phpBB/styles/prosilver/template/mcp_warn_user.html2
-rw-r--r--phpBB/styles/prosilver/template/mcp_whois.html14
-rw-r--r--phpBB/styles/prosilver/template/memberlist_body.html52
-rw-r--r--phpBB/styles/prosilver/template/memberlist_team.html2
-rw-r--r--phpBB/styles/prosilver/template/memberlist_view.html2
-rw-r--r--phpBB/styles/prosilver/template/message_body.html8
-rw-r--r--phpBB/styles/prosilver/template/navbar_footer.html60
-rw-r--r--phpBB/styles/prosilver/template/navbar_header.html168
-rw-r--r--phpBB/styles/prosilver/template/notification_dropdown.html4
-rw-r--r--phpBB/styles/prosilver/template/overall_footer.html91
-rw-r--r--phpBB/styles/prosilver/template/overall_header.html93
-rw-r--r--phpBB/styles/prosilver/template/pagination.html10
-rw-r--r--phpBB/styles/prosilver/template/plupload.html14
-rw-r--r--phpBB/styles/prosilver/template/posting_attach_body.html22
-rw-r--r--phpBB/styles/prosilver/template/posting_buttons.html82
-rw-r--r--phpBB/styles/prosilver/template/posting_editor.html12
-rw-r--r--phpBB/styles/prosilver/template/posting_layout.html12
-rw-r--r--phpBB/styles/prosilver/template/posting_pm_header.html4
-rw-r--r--phpBB/styles/prosilver/template/posting_pm_layout.html4
-rw-r--r--phpBB/styles/prosilver/template/posting_poll_body.html4
-rw-r--r--phpBB/styles/prosilver/template/posting_preview.html2
-rw-r--r--phpBB/styles/prosilver/template/posting_review.html13
-rw-r--r--phpBB/styles/prosilver/template/posting_smilies.html12
-rw-r--r--phpBB/styles/prosilver/template/posting_topic_review.html41
-rw-r--r--phpBB/styles/prosilver/template/quickreply_editor.html2
-rw-r--r--phpBB/styles/prosilver/template/report_body.html4
-rw-r--r--phpBB/styles/prosilver/template/search_results.html127
-rw-r--r--phpBB/styles/prosilver/template/simple_footer.html24
-rw-r--r--phpBB/styles/prosilver/template/simple_header.html10
-rw-r--r--phpBB/styles/prosilver/template/timezone_option.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_agreement.html10
-rw-r--r--phpBB/styles/prosilver/template/ucp_attachments.html28
-rw-r--r--phpBB/styles/prosilver/template/ucp_auth_link_oauth.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_avatar_options_local.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_footer.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_groups_manage.html18
-rw-r--r--phpBB/styles/prosilver/template/ucp_groups_membership.html14
-rw-r--r--phpBB/styles/prosilver/template/ucp_header.html14
-rw-r--r--phpBB/styles/prosilver/template/ucp_main_bookmarks.html40
-rw-r--r--phpBB/styles/prosilver/template/ucp_main_front.html26
-rw-r--r--phpBB/styles/prosilver/template/ucp_main_subscribed.html59
-rw-r--r--phpBB/styles/prosilver/template/ucp_notifications.html12
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_history.html25
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_message_header.html61
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_viewfolder.html32
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_viewmessage.html55
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html18
-rw-r--r--phpBB/styles/prosilver/template/ucp_prefs_personal.html4
-rw-r--r--phpBB/styles/prosilver/template/ucp_prefs_post.html12
-rw-r--r--phpBB/styles/prosilver/template/ucp_prefs_view.html14
-rw-r--r--phpBB/styles/prosilver/template/ucp_profile_profile_info.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_profile_reg_details.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_profile_signature.html1
-rw-r--r--phpBB/styles/prosilver/template/ucp_register.html4
-rw-r--r--phpBB/styles/prosilver/template/ucp_remind.html13
-rw-r--r--phpBB/styles/prosilver/template/ucp_zebra_foes.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_zebra_friends.html2
-rw-r--r--phpBB/styles/prosilver/template/viewforum_body.html139
-rw-r--r--phpBB/styles/prosilver/template/viewonline_body.html18
-rw-r--r--phpBB/styles/prosilver/template/viewtopic_body.html132
-rw-r--r--phpBB/styles/prosilver/template/viewtopic_print.html20
-rw-r--r--phpBB/styles/prosilver/template/viewtopic_topic_tools.html43
-rw-r--r--phpBB/styles/prosilver/theme/base.css115
-rw-r--r--phpBB/styles/prosilver/theme/bidi.css247
-rw-r--r--phpBB/styles/prosilver/theme/buttons.css223
-rw-r--r--phpBB/styles/prosilver/theme/colours.css639
-rw-r--r--phpBB/styles/prosilver/theme/common.css359
-rw-r--r--phpBB/styles/prosilver/theme/content.css103
-rw-r--r--phpBB/styles/prosilver/theme/cp.css79
-rw-r--r--phpBB/styles/prosilver/theme/en/stylesheet.css6
-rw-r--r--phpBB/styles/prosilver/theme/forms.css91
-rw-r--r--phpBB/styles/prosilver/theme/icons.css96
-rw-r--r--phpBB/styles/prosilver/theme/images/alert_close.pngbin2097 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_read.gifbin728 -> 3549 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_read_locked.gifbin738 -> 3558 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_read_locked_mine.gifbin753 -> 3558 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_read_mine.gifbin724 -> 3580 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_unread.gifbin730 -> 3531 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_unread_locked.gifbin745 -> 3534 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_unread_locked_mine.gifbin755 -> 3564 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/announce_unread_mine.gifbin765 -> 3560 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/arrow_down.gifbin51 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/arrow_left.gifbin49 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/arrow_right.gifbin49 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/arrow_up.gifbin51 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/bg_button.gifbin182 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/feed.gifbin1089 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/forum_link.gifbin708 -> 3500 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/forum_read.gifbin662 -> 3448 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/forum_read_locked.gifbin681 -> 3444 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/forum_read_subforum.gifbin725 -> 3641 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/forum_unread.gifbin667 -> 3440 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/forum_unread_locked.gifbin677 -> 3442 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/forum_unread_subforum.gifbin725 -> 3637 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/gradient.gifbin549 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_acp.gifbin389 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_back_top.gifbin204 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_bookmark.gifbin218 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_bump.gifbin148 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_contact.pngbin340 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_delete_cookies.gifbin108 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_faq.gifbin255 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_home.gifbin306 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_logout.gifbin219 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_mark.gifbin360 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_mcp.gifbin342 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_members.gifbin264 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_notification.gifbin551 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_pages.gifbin105 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_pm.gifbin576 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_post_target.gifbin124 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_post_target_unread.gifbin89 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_print.gifbin204 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_profile.gifbin538 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_register.gifbin231 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_search.gifbin334 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_sendemail.gifbin303 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_subscribe.gifbin216 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_team.gifbin1009 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_textbox_search.gifbin335 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_topic_attach.gifbin82 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_topic_deleted.pngbin1205 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_topic_latest.gifbin124 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_topic_newest.gifbin93 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_topic_poll.gifbin120 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_topic_reported.gifbin246 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_topic_unapproved.gifbin253 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_ucp.gifbin254 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icon_unsubscribe.gifbin214 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icons_button.pngbin8037 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/icons_pagination.pngbin1043 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_read.gifbin625 -> 3198 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_read_locked.gifbin646 -> 3248 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_read_locked_mine.gifbin662 -> 3295 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_read_mine.gifbin633 -> 3241 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_unread.gifbin622 -> 3191 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_unread_locked.gifbin626 -> 3246 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_unread_locked_mine.gifbin682 -> 3316 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/sticky_unread_mine.gifbin643 -> 3275 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/subforum_read.gifbin124 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/subforum_unread.gifbin124 -> 0 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_moved.gifbin667 -> 3459 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_read.gifbin653 -> 3482 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_read_hot.gifbin1469 -> 3548 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_read_hot_mine.gifbin1519 -> 3570 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_read_locked.gifbin722 -> 3458 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_read_locked_mine.gifbin723 -> 3416 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_read_mine.gifbin669 -> 3492 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_unread.gifbin652 -> 3327 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_unread_hot.gifbin1431 -> 3551 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_unread_hot_mine.gifbin1364 -> 3582 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_unread_locked.gifbin719 -> 3349 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_unread_locked_mine.gifbin738 -> 3375 bytes
-rw-r--r--phpBB/styles/prosilver/theme/images/topic_unread_mine.gifbin678 -> 3393 bytes
-rw-r--r--phpBB/styles/prosilver/theme/imageset.css376
-rw-r--r--phpBB/styles/prosilver/theme/links.css87
-rw-r--r--phpBB/styles/prosilver/theme/normalize.css424
-rw-r--r--phpBB/styles/prosilver/theme/plupload.css14
-rw-r--r--phpBB/styles/prosilver/theme/print.css15
-rw-r--r--phpBB/styles/prosilver/theme/responsive.css875
-rw-r--r--phpBB/styles/prosilver/theme/stylesheet.css24
-rw-r--r--phpBB/styles/prosilver/theme/tweaks.css12
-rw-r--r--phpBB/styles/prosilver/theme/utilities.css66
-rw-r--r--phpBB/styles/subsilver2/style.cfg32
-rw-r--r--phpBB/styles/subsilver2/template/attachment.html125
-rw-r--r--phpBB/styles/subsilver2/template/bbcode.html69
-rw-r--r--phpBB/styles/subsilver2/template/breadcrumbs.html14
-rw-r--r--phpBB/styles/subsilver2/template/captcha_default.html17
-rw-r--r--phpBB/styles/subsilver2/template/captcha_qa.html8
-rw-r--r--phpBB/styles/subsilver2/template/captcha_recaptcha.html36
-rw-r--r--phpBB/styles/subsilver2/template/confirm_body.html28
-rw-r--r--phpBB/styles/subsilver2/template/confirm_delete_body.html55
-rw-r--r--phpBB/styles/subsilver2/template/faq_body.html63
-rw-r--r--phpBB/styles/subsilver2/template/forumlist_body.html98
-rw-r--r--phpBB/styles/subsilver2/template/index.htm16
-rw-r--r--phpBB/styles/subsilver2/template/index_body.html144
-rw-r--r--phpBB/styles/subsilver2/template/jumpbox.html19
-rw-r--r--phpBB/styles/subsilver2/template/login_body.html111
-rw-r--r--phpBB/styles/subsilver2/template/login_body_oauth.html7
-rw-r--r--phpBB/styles/subsilver2/template/login_forum.html56
-rw-r--r--phpBB/styles/subsilver2/template/mcp_approve.html49
-rw-r--r--phpBB/styles/subsilver2/template/mcp_ban.html120
-rw-r--r--phpBB/styles/subsilver2/template/mcp_footer.html27
-rw-r--r--phpBB/styles/subsilver2/template/mcp_forum.html99
-rw-r--r--phpBB/styles/subsilver2/template/mcp_front.html147
-rw-r--r--phpBB/styles/subsilver2/template/mcp_header.html60
-rw-r--r--phpBB/styles/subsilver2/template/mcp_logs.html46
-rw-r--r--phpBB/styles/subsilver2/template/mcp_message.html14
-rw-r--r--phpBB/styles/subsilver2/template/mcp_move.html48
-rw-r--r--phpBB/styles/subsilver2/template/mcp_notes_front.html22
-rw-r--r--phpBB/styles/subsilver2/template/mcp_notes_user.html125
-rw-r--r--phpBB/styles/subsilver2/template/mcp_post.html214
-rw-r--r--phpBB/styles/subsilver2/template/mcp_queue.html76
-rw-r--r--phpBB/styles/subsilver2/template/mcp_reports.html67
-rw-r--r--phpBB/styles/subsilver2/template/mcp_topic.html158
-rw-r--r--phpBB/styles/subsilver2/template/mcp_warn_front.html74
-rw-r--r--phpBB/styles/subsilver2/template/mcp_warn_list.html43
-rw-r--r--phpBB/styles/subsilver2/template/mcp_warn_post.html67
-rw-r--r--phpBB/styles/subsilver2/template/mcp_warn_user.html80
-rw-r--r--phpBB/styles/subsilver2/template/mcp_whois.html15
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_body.html117
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_email.html107
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_group.html17
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_im.html43
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_search.html129
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_team.html50
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_view.html207
-rw-r--r--phpBB/styles/subsilver2/template/message_body.html16
-rw-r--r--phpBB/styles/subsilver2/template/overall_footer.html29
-rw-r--r--phpBB/styles/subsilver2/template/overall_header.html262
-rw-r--r--phpBB/styles/subsilver2/template/pagination.html11
-rw-r--r--phpBB/styles/subsilver2/template/posting_attach_body.html83
-rw-r--r--phpBB/styles/subsilver2/template/posting_body.html434
-rw-r--r--phpBB/styles/subsilver2/template/posting_buttons.html91
-rw-r--r--phpBB/styles/subsilver2/template/posting_poll_body.html37
-rw-r--r--phpBB/styles/subsilver2/template/posting_preview.html71
-rw-r--r--phpBB/styles/subsilver2/template/posting_progress_bar.html44
-rw-r--r--phpBB/styles/subsilver2/template/posting_review.html99
-rw-r--r--phpBB/styles/subsilver2/template/posting_smilies.html38
-rw-r--r--phpBB/styles/subsilver2/template/posting_topic_review.html112
-rw-r--r--phpBB/styles/subsilver2/template/profilefields/bool.html7
-rw-r--r--phpBB/styles/subsilver2/template/profilefields/date.html5
-rw-r--r--phpBB/styles/subsilver2/template/profilefields/dropdown.html5
-rw-r--r--phpBB/styles/subsilver2/template/profilefields/int.html3
-rw-r--r--phpBB/styles/subsilver2/template/profilefields/string.html3
-rw-r--r--phpBB/styles/subsilver2/template/profilefields/text.html3
-rw-r--r--phpBB/styles/subsilver2/template/profilefields/url.html3
-rw-r--r--phpBB/styles/subsilver2/template/quickreply_editor.html30
-rw-r--r--phpBB/styles/subsilver2/template/report_body.html49
-rw-r--r--phpBB/styles/subsilver2/template/search_body.html110
-rw-r--r--phpBB/styles/subsilver2/template/search_results.html165
-rw-r--r--phpBB/styles/subsilver2/template/searchbox.html1
-rw-r--r--phpBB/styles/subsilver2/template/simple_footer.html15
-rw-r--r--phpBB/styles/subsilver2/template/simple_header.html23
-rw-r--r--phpBB/styles/subsilver2/template/timezone.js21
-rw-r--r--phpBB/styles/subsilver2/template/timezone_option.html28
-rw-r--r--phpBB/styles/subsilver2/template/ucp_agreement.html87
-rw-r--r--phpBB/styles/subsilver2/template/ucp_attachments.html58
-rw-r--r--phpBB/styles/subsilver2/template/ucp_auth_link.html19
-rw-r--r--phpBB/styles/subsilver2/template/ucp_auth_link_oauth.html34
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html13
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_local.html42
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html10
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html12
-rw-r--r--phpBB/styles/subsilver2/template/ucp_footer.html13
-rw-r--r--phpBB/styles/subsilver2/template/ucp_groups_manage.html229
-rw-r--r--phpBB/styles/subsilver2/template/ucp_groups_membership.html93
-rw-r--r--phpBB/styles/subsilver2/template/ucp_header.html165
-rw-r--r--phpBB/styles/subsilver2/template/ucp_login_link.html74
-rw-r--r--phpBB/styles/subsilver2/template/ucp_main_bookmarks.html86
-rw-r--r--phpBB/styles/subsilver2/template/ucp_main_drafts.html96
-rw-r--r--phpBB/styles/subsilver2/template/ucp_main_front.html76
-rw-r--r--phpBB/styles/subsilver2/template/ucp_main_subscribed.html95
-rw-r--r--phpBB/styles/subsilver2/template/ucp_notifications.html141
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_history.html86
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_message_footer.html47
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_message_header.html34
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_options.html192
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html131
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html136
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html122
-rw-r--r--phpBB/styles/subsilver2/template/ucp_prefs_personal.html71
-rw-r--r--phpBB/styles/subsilver2/template/ucp_prefs_post.html35
-rw-r--r--phpBB/styles/subsilver2/template/ucp_prefs_view.html77
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html50
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_avatar.html50
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_profile_info.html44
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_reg_details.html49
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_signature.html132
-rw-r--r--phpBB/styles/subsilver2/template/ucp_register.html103
-rw-r--r--phpBB/styles/subsilver2/template/ucp_remind.html28
-rw-r--r--phpBB/styles/subsilver2/template/ucp_resend.html29
-rw-r--r--phpBB/styles/subsilver2/template/ucp_zebra_foes.html28
-rw-r--r--phpBB/styles/subsilver2/template/ucp_zebra_friends.html30
-rw-r--r--phpBB/styles/subsilver2/template/viewforum_body.html381
-rw-r--r--phpBB/styles/subsilver2/template/viewonline_body.html57
-rw-r--r--phpBB/styles/subsilver2/template/viewonline_whois.html12
-rw-r--r--phpBB/styles/subsilver2/template/viewtopic_body.html462
-rw-r--r--phpBB/styles/subsilver2/template/viewtopic_print.html136
-rw-r--r--phpBB/styles/subsilver2/theme/en/button_pm_new.gifbin1135 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/button_pm_reply.gifbin1667 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/button_topic_locked.gifbin1101 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/button_topic_new.gifbin1164 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/button_topic_reply.gifbin1234 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_aim.gifbin580 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_email.gifbin659 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_icq.gifbin574 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_jabber.gifbin674 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_msnm.gifbin1503 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_pm.gifbin706 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_www.gifbin604 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_contact_yahoo.gifbin663 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_post_delete.gifbin314 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_post_edit.gifbin662 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_post_info.gifbin305 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_post_quote.gifbin666 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_post_report.gifbin308 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_user_offline.gifbin547 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_user_online.gifbin520 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_user_profile.gifbin667 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_user_search.gifbin608 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/icon_user_warn.gifbin673 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/en/stylesheet.css116
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_read.gifbin307 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_read_locked.gifbin304 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_read_locked_mine.gifbin324 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_read_mine.gifbin328 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_unread.gifbin289 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_unread_locked.gifbin292 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_unread_locked_mine.gifbin308 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/announce_unread_mine.gifbin305 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/background.gifbin666 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/cellpic.gifbin722 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/cellpic1.gifbin246 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/cellpic2.jpgbin480 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/cellpic2_rtl.jpgbin601 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/cellpic3.gifbin257 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/created_by.jpgbin15319 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/forum_link.gifbin714 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/forum_read.gifbin677 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/forum_read_locked.gifbin673 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/forum_read_subforum.gifbin705 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/forum_unread.gifbin663 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/forum_unread_locked.gifbin660 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/forum_unread_subforum.gifbin688 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_faq.gifbin219 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_groups.gifbin222 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_login.gifbin233 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_members.gifbin223 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_message.gifbin232 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_notification.gifbin543 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_profile.gifbin238 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_register.gifbin224 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_mini_search.gifbin238 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_post_target.gifbin122 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_post_target_unread.gifbin122 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_topic_attach.gifbin217 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_topic_deleted.pngbin1205 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_topic_latest.gifbin135 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_topic_newest.gifbin133 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_topic_reported.gifbin462 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/icon_topic_unapproved.gifbin334 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/index.htm16
-rw-r--r--phpBB/styles/subsilver2/theme/images/no_avatar.gifbin930 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/poll_center.gifbin92 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/poll_left.gifbin113 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/poll_right.gifbin113 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/site_logo.gifbin7151 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/spacer.gifbin43 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_read.gifbin344 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_read_locked.gifbin338 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_read_locked_mine.gifbin336 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_read_mine.gifbin352 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_unread.gifbin325 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_unread_locked.gifbin324 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_unread_locked_mine.gifbin336 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/sticky_unread_mine.gifbin339 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_moved.gifbin660 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_read.gifbin344 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_read_hot.gifbin1902 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_read_hot_mine.gifbin1903 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_read_locked.gifbin333 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_read_locked_mine.gifbin337 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_read_mine.gifbin350 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_unread.gifbin336 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_unread_hot.gifbin1888 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_unread_hot_mine.gifbin1895 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_unread_locked.gifbin459 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_unread_locked_mine.gifbin334 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/topic_unread_mine.gifbin350 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/upload_bar.gifbin12892 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/images/whosonline.gifbin929 -> 0 bytes
-rw-r--r--phpBB/styles/subsilver2/theme/stylesheet.css1256
-rw-r--r--phpBB/ucp.php24
-rw-r--r--phpBB/viewforum.php117
-rw-r--r--phpBB/viewonline.php37
-rw-r--r--phpBB/viewtopic.php247
-rw-r--r--tests/RUNNING_TESTS.md42
-rw-r--r--tests/attachment/delete_test.php127
-rw-r--r--tests/attachment/fixtures/resync.xml137
-rw-r--r--tests/attachment/manager_test.php131
-rw-r--r--tests/attachment/resync_test.php74
-rw-r--r--tests/attachment/upload_test.php429
-rw-r--r--tests/auth/provider_apache_test.php7
-rw-r--r--tests/auth/provider_db_test.php7
-rw-r--r--tests/auth/provider_oauth_token_storage_test.php12
-rw-r--r--tests/avatar/driver/barfoo.php52
-rw-r--r--tests/avatar/driver/foobar.php52
-rw-r--r--tests/avatar/manager_test.php31
-rw-r--r--tests/bbcode/parser_test.php10
-rw-r--r--tests/bbcode/url_bbcode_test.php5
-rw-r--r--tests/bootstrap.php9
-rw-r--r--tests/cache/apc_driver_test.php6
-rw-r--r--tests/cache/apcu_driver_test.php75
-rw-r--r--tests/cache/cache_memory.php2
-rw-r--r--tests/cache/cache_memory_test.php2
-rw-r--r--tests/cache/dummy_driver_test.php77
-rw-r--r--tests/cache/null_driver_test.php77
-rw-r--r--tests/captcha/qa_test.php13
-rw-r--r--tests/composer.json5
-rw-r--r--tests/composer.lock63
-rw-r--r--tests/compress/compress_test.php1
-rw-r--r--tests/console/cache/purge_test.php9
-rw-r--r--tests/console/config/config_test.php7
-rw-r--r--tests/console/cron/cron_list_test.php13
-rw-r--r--tests/console/cron/run_test.php15
-rw-r--r--tests/console/fixtures/png.pngbin0 -> 129 bytes
-rw-r--r--tests/console/fixtures/thumbnail.xml40
-rw-r--r--tests/console/fixtures/txt.txt2
-rw-r--r--tests/console/thumbnail_test.php122
-rw-r--r--tests/console/update/check_test.php110
-rw-r--r--tests/console/user/activate_test.php86
-rw-r--r--tests/console/user/add_test.php134
-rw-r--r--tests/console/user/base.php126
-rw-r--r--tests/console/user/delete_test.php93
-rw-r--r--tests/console/user/fixtures/config.xml63
-rw-r--r--tests/console/user/reclean_test.php49
-rw-r--r--tests/content_visibility/delete_post_test.php20
-rw-r--r--tests/content_visibility/get_forums_visibility_sql_test.php4
-rw-r--r--tests/content_visibility/get_global_visibility_sql_test.php4
-rw-r--r--tests/content_visibility/get_visibility_sql_test.php4
-rw-r--r--tests/content_visibility/set_post_visibility_test.php11
-rw-r--r--tests/content_visibility/set_topic_visibility_test.php7
-rw-r--r--tests/controller/common_helper_route.php136
-rw-r--r--tests/controller/config/test/routing/environment.yml (renamed from tests/controller/config/routing.yml)0
-rw-r--r--tests/controller/controller_test.php82
-rw-r--r--tests/controller/ext/vendor2/bar/config/services.yml3
-rw-r--r--tests/controller/ext/vendor2/bar/config/test/routing/environment.yml3
-rw-r--r--tests/controller/ext/vendor2/bar/controller.php18
-rw-r--r--tests/controller/ext/vendor2/foo/config/routing.yml4
-rw-r--r--tests/controller/ext/vendor2/foo/controller.php17
-rw-r--r--tests/controller/helper_route_adm_subdir_test.php1
-rw-r--r--tests/controller/helper_route_adm_test.php1
-rw-r--r--tests/controller/helper_route_root_test.php1
-rw-r--r--tests/controller/helper_route_slash_test.php1
-rw-r--r--tests/controller/helper_route_unclean_path_test.php1
-rw-r--r--tests/cron/manager_test.php2
-rw-r--r--tests/datetime/from_format_test.php12
-rw-r--r--tests/dbal/auto_increment_test.php5
-rw-r--r--tests/dbal/boolean_processor_test.php321
-rw-r--r--tests/dbal/connect_test.php6
-rw-r--r--tests/dbal/cross_join_test.php3
-rw-r--r--tests/dbal/db_tools_test.php66
-rw-r--r--tests/dbal/ext/foo/bar/acp/acp_test_info.php37
-rw-r--r--tests/dbal/ext/foo/bar/acp/acp_test_module.php25
-rw-r--r--tests/dbal/ext/foo/bar/composer.json24
-rw-r--r--tests/dbal/ext/foo/bar/ucp/ucp_test_info.php37
-rw-r--r--tests/dbal/ext/foo/bar/ucp/ucp_test_module.php25
-rw-r--r--tests/dbal/fixtures/boolean_processor.xml90
-rw-r--r--tests/dbal/migration/revert_table.php39
-rw-r--r--tests/dbal/migration/revert_table_with_dependency.php52
-rw-r--r--tests/dbal/migrator_test.php53
-rw-r--r--tests/dbal/migrator_tool_module_test.php228
-rw-r--r--tests/dbal/migrator_tool_permission_test.php8
-rw-r--r--tests/dbal/schema_test.php2
-rw-r--r--tests/dbal/select_test.php3
-rw-r--r--tests/dbal/write_sequence_test.php2
-rw-r--r--tests/dbal/write_test.php4
-rw-r--r--tests/di/create_container_test.php95
-rw-r--r--tests/di/fixtures/config.php4
-rw-r--r--tests/di/fixtures/config/production/config.yml2
-rw-r--r--tests/di/fixtures/config/production/container/environment.yml32
-rw-r--r--tests/di/fixtures/config/services.yml17
-rw-r--r--tests/di/fixtures/config/test/config.yml2
-rw-r--r--tests/di/fixtures/config/test/container/environment.yml29
-rw-r--r--tests/di/fixtures/ext/vendor/disabled/config/test/container/environment.yml (renamed from tests/di/fixtures/ext/vendor/disabled/config/services.yml)0
-rw-r--r--tests/di/fixtures/ext/vendor/enabled-2/config/test/container/environment.yml2
-rw-r--r--tests/di/fixtures/ext/vendor/enabled-3/config/services.yml2
-rw-r--r--tests/di/fixtures/ext/vendor/enabled/config/default/container/environment.yml (renamed from tests/di/fixtures/ext/vendor/enabled/config/services.yml)0
-rw-r--r--tests/di/fixtures/ext/vendor/enabled_4/di/extension.php32
-rw-r--r--tests/di/fixtures/ext/vendor/enabled_4/environment.yml2
-rw-r--r--tests/di/fixtures/other_config/production/config.yml2
-rw-r--r--tests/di/fixtures/other_config/production/container/environment.yml32
-rw-r--r--tests/di/fixtures/other_config/services.yml17
-rw-r--r--tests/di/fixtures/other_config/test/config.yml2
-rw-r--r--tests/di/fixtures/other_config/test/container/environment.yml29
-rw-r--r--tests/di/ordered_service_collection_test.php51
-rw-r--r--tests/di/service_collection_test.php47
-rw-r--r--tests/download/http_byte_range_test.php62
-rw-r--r--tests/email/email_parsing_test.php150
-rw-r--r--tests/error_collector_test.php15
-rw-r--r--tests/event/dispatcher_test.php16
-rw-r--r--tests/event/exception_listener_test.php10
-rw-r--r--tests/event/fixtures/event_migration.test30
-rw-r--r--tests/event/fixtures/extra_description.test2
-rw-r--r--tests/event/md_exporter_test.php12
-rw-r--r--tests/event/php_exporter_test.php21
-rw-r--r--tests/extension/ext/vendor2/bar/acp/a_info.php1
-rw-r--r--tests/extension/ext/vendor2/bar/migrations/bar.php7
-rw-r--r--tests/extension/ext/vendor2/bar/migrations/foo.php54
-rw-r--r--tests/extension/ext/vendor2/foo/acp/a_info.php1
-rw-r--r--tests/extension/ext/vendor2/foo/acp/fail_info.php1
-rw-r--r--tests/extension/ext/vendor2/foo/mcp/a_info.php1
-rw-r--r--tests/extension/extension_base_test.php12
-rw-r--r--tests/extension/finder_test.php5
-rw-r--r--tests/extension/includes/acp/info/acp_foobar.php1
-rw-r--r--tests/extension/manager_test.php9
-rw-r--r--tests/extension/metadata_manager_test.php92
-rw-r--r--tests/extension/modules_test.php61
-rw-r--r--tests/feed/attachments_base_test.php21
-rw-r--r--tests/feed/attachments_mock_feed.php5
-rw-r--r--tests/files/type_foo.php31
-rw-r--r--tests/files/types_base_test.php93
-rw-r--r--tests/files/types_form_test.php172
-rw-r--r--tests/files/types_local_test.php161
-rw-r--r--tests/files/types_remote_test.php132
-rw-r--r--tests/files/upload_test.php128
-rw-r--r--tests/filesystem/clean_path_test.php2
-rw-r--r--tests/filesystem/is_absolute_test.php68
-rw-r--r--tests/filesystem/realpath_test.php90
-rw-r--r--tests/functional/acp_attachments_test.php78
-rw-r--r--tests/functional/acp_bbcodes_test.php46
-rw-r--r--tests/functional/acp_profile_field_test.php15
-rw-r--r--tests/functional/acp_smilies_test.php43
-rw-r--r--tests/functional/browse_test.php14
-rw-r--r--tests/functional/controllers_compatibility_test.php56
-rw-r--r--tests/functional/download_test.php5
-rw-r--r--tests/functional/extension_acp_test.php4
-rw-r--r--tests/functional/extension_controller_test.php2
-rw-r--r--tests/functional/extension_global_lang_test.php2
-rw-r--r--tests/functional/extension_module_test.php13
-rw-r--r--tests/functional/extension_permission_lang_test.php2
-rw-r--r--tests/functional/feed_test.php137
-rw-r--r--tests/functional/fileupload_form_test.php10
-rw-r--r--tests/functional/fileupload_remote_test.php78
-rw-r--r--tests/functional/fixtures/ext/foo/bar/acp/main_info.php1
-rw-r--r--tests/functional/fixtures/ext/foo/bar/config/services.yml14
-rw-r--r--tests/functional/fixtures/ext/foo/bar/ucp/main_info.php1
-rw-r--r--tests/functional/forum_style_test.php24
-rw-r--r--tests/functional/metadata_manager_test.php2
-rw-r--r--tests/functional/notification_test.php8
-rw-r--r--tests/functional/permission_roles_test.php84
-rw-r--r--tests/functional/plupload_test.php26
-rw-r--r--tests/functional/posting_test.php188
-rw-r--r--tests/functional/private_messages_test.php41
-rw-r--r--tests/functional/prune_shadow_topic_test.php2
-rw-r--r--tests/functional/registration_test.php54
-rw-r--r--tests/functional/report_post_captcha_test.php7
-rw-r--r--tests/functional/search/base.php7
-rw-r--r--tests/functional/ucp_groups_test.php68
-rw-r--r--tests/functional/user_password_reset_test.php57
-rw-r--r--tests/functional/visibility_softdelete_test.php4
-rw-r--r--tests/functional/visit_installer_test.php30
-rw-r--r--tests/functions/build_hidden_fields_for_query_params_test.php2
-rw-r--r--tests/functions/build_url_test.php4
-rw-r--r--tests/functions/convert_30_dbms_to_31_test.php4
-rw-r--r--tests/functions/fixtures/validate_email.xml24
-rw-r--r--tests/functions/fixtures/validate_username.xml2
-rw-r--r--tests/functions/generate_string_list.php12
-rw-r--r--tests/functions/get_formatted_filesize_test.php2
-rw-r--r--tests/functions/get_preg_expression_test.php2
-rw-r--r--tests/functions/get_remote_file_test.php5
-rw-r--r--tests/functions/is_absolute_test.php60
-rw-r--r--tests/functions/language_select_test.php2
-rw-r--r--tests/functions/make_clickable_email_test.php8
-rw-r--r--tests/functions/make_clickable_test.php18
-rw-r--r--tests/functions/obtain_online_test.php3
-rw-r--r--tests/functions/parse_cfg_file_test.php2
-rw-r--r--tests/functions/quoteattr_test.php2
-rw-r--r--tests/functions/style_select_test.php2
-rw-r--r--tests/functions/user_delete_test.php17
-rw-r--r--tests/functions/validate_email_test.php1
-rw-r--r--tests/functions/validate_password_test.php1
-rw-r--r--tests/functions/validate_string_test.php1
-rw-r--r--tests/functions/validate_user_email_test.php13
-rw-r--r--tests/functions/validate_username_test.php13
-rw-r--r--tests/functions_acp/validate_config_vars_test.php107
-rw-r--r--tests/functions_acp/validate_range_test.php1
-rw-r--r--tests/functions_content/get_username_string_test.php3
-rw-r--r--tests/functions_content/phpbb_clean_search_string_test.php2
-rw-r--r--tests/functions_content/phpbb_format_quote_test.php57
-rw-r--r--tests/functions_install/ignore_new_file_on_update_test.php45
-rw-r--r--tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml83
-rw-r--r--tests/functions_privmsgs/get_max_setting_from_group_test.php64
-rw-r--r--tests/functions_user/delete_user_test.php13
-rw-r--r--tests/functions_user/fixtures/delete_user.xml9
-rw-r--r--tests/functions_user/group_user_attributes_test.php4
-rw-r--r--tests/group/helper_get_name_string_test.php115
-rw-r--r--tests/group/helper_get_name_test.php31
-rw-r--r--tests/group/helper_get_rank_test.php43
-rw-r--r--tests/group/helper_test_case.php123
-rw-r--r--tests/groupposition/legend_test.php43
-rw-r--r--tests/groupposition/teampage_test.php51
-rw-r--r--tests/help/manager_test.php184
-rw-r--r--tests/installer/database_helper_test.php157
-rw-r--r--tests/installer/installer_config_test.php80
-rw-r--r--tests/installer/mocks/test_installer_module.php20
-rw-r--r--tests/installer/mocks/test_installer_task_mock.php44
-rw-r--r--tests/installer/module_base_test.php65
-rw-r--r--tests/installer/navigation_provider_test.php34
-rw-r--r--tests/language/language_test.php243
-rw-r--r--tests/lint_test.php7
-rw-r--r--tests/lock/db_test.php3
-rw-r--r--tests/log/add_test.php10
-rw-r--r--tests/log/delete_test.php8
-rw-r--r--tests/log/fixtures/delete_log.xml16
-rw-r--r--tests/log/fixtures/empty_log.xml1
-rw-r--r--tests/log/fixtures/full_log.xml12
-rw-r--r--tests/log/function_add_log_test.php7
-rw-r--r--tests/log/function_view_log_test.php19
-rw-r--r--tests/migrator/convert_timezones_test.php9
-rw-r--r--tests/migrator/get_callable_from_step_test.php136
-rw-r--r--tests/migrator/schema_generator_test.php5
-rw-r--r--tests/mock/container_builder.php15
-rw-r--r--tests/mock/controller_helper.php14
-rw-r--r--tests/mock/extension_manager.php7
-rw-r--r--tests/mock/fileupload.php3
-rw-r--r--tests/mock/migrator.php4
-rw-r--r--tests/mock/notification_manager.php7
-rw-r--r--tests/mock/notification_type_post.php6
-rw-r--r--tests/mock/phpbb_di_container_builder.php18
-rw-r--r--tests/mock/request.php5
-rw-r--r--tests/mock/router.php27
-rw-r--r--tests/mock/session_testable.php2
-rw-r--r--tests/mock/sql_insert_buffer.php2
-rw-r--r--tests/network/checkdnsrr_test.php4
-rw-r--r--tests/network/ftp_fsock_pasv_epsv_test.php1
-rw-r--r--tests/network/inet_ntop_pton_test.php2
-rw-r--r--tests/network/ip_normalise_test.php2
-rw-r--r--tests/notification/base.php69
-rw-r--r--tests/notification/convert_test.php3
-rw-r--r--tests/notification/ext/test/notification/type/test.php5
-rw-r--r--tests/notification/fixtures/services_notification.yml76
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.bookmark.xml12
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.post.xml17
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml16
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.quote.xml12
-rw-r--r--tests/notification/fixtures/submit_post_notification.type.topic.xml10
-rw-r--r--tests/notification/group_request_test.php25
-rw-r--r--tests/notification/manager_helper.php31
-rw-r--r--tests/notification/notification_test.php52
-rw-r--r--tests/notification/submit_post_base.php73
-rw-r--r--tests/notification/submit_post_type_quote_test.php39
-rw-r--r--tests/notification/submit_post_type_topic_test.php2
-rw-r--r--tests/notification/user_list_trim_test.php25
-rw-r--r--tests/pagination/config/test/routing/environment.yml (renamed from tests/pagination/config/routing.yml)0
-rw-r--r--tests/pagination/pagination_test.php36
-rw-r--r--tests/passwords/drivers_test.php23
-rw-r--r--tests/passwords/manager_test.php54
-rw-r--r--tests/path_helper/path_helper_test.php47
-rw-r--r--tests/plupload/plupload_test.php81
-rw-r--r--tests/privmsgs/delete_user_pms_test.php4
-rw-r--r--tests/profilefields/type_bool_test.php7
-rw-r--r--tests/profilefields/type_date_test.php7
-rw-r--r--tests/profilefields/type_dropdown_test.php7
-rw-r--r--tests/profilefields/type_googleplus_test.php8
-rw-r--r--tests/profilefields/type_int_test.php7
-rw-r--r--tests/profilefields/type_string_test.php24
-rw-r--r--tests/profilefields/type_url_test.php73
-rw-r--r--tests/random/gen_rand_string_test.php12
-rw-r--r--tests/regex/censor_test.php16
-rw-r--r--tests/regex/email_test.php2
-rw-r--r--tests/regex/ipv4_test.php2
-rw-r--r--tests/regex/ipv6_test.php2
-rw-r--r--tests/regex/password_complexity_test.php1
-rw-r--r--tests/regex/table_prefix_test.php2
-rw-r--r--tests/regex/url_test.php2
-rw-r--r--tests/request/request_var_test.php3
-rw-r--r--tests/request/type_cast_helper_test.php12
-rw-r--r--tests/search/fixtures/posts.xml5
-rw-r--r--tests/search/native_test.php8
-rw-r--r--tests/security/base.php6
-rw-r--r--tests/security/extract_current_page_test.php1
-rw-r--r--tests/security/hash_test.php2
-rw-r--r--tests/security/redirect_test.php5
-rw-r--r--tests/session/append_sid_test.php2
-rw-r--r--tests/session/check_ban_test.php8
-rw-r--r--tests/session/extract_page_test.php19
-rw-r--r--tests/session/garbage_collection_test.php1
-rw-r--r--tests/session/session_key_test.php1
-rw-r--r--tests/session/testable_factory.php6
-rw-r--r--tests/template/asset_test.php49
-rw-r--r--tests/template/context_test.php96
-rw-r--r--tests/template/includephp_test.php3
-rw-r--r--tests/template/template_allfolder_test.php32
-rw-r--r--tests/template/template_events_test.php28
-rw-r--r--tests/template/template_includecss_test.php45
-rw-r--r--tests/template/template_includejs_test.php32
-rw-r--r--tests/template/template_parser_test.php1
-rw-r--r--tests/template/template_test.php280
-rw-r--r--tests/template/template_test_case.php56
-rw-r--r--tests/template/template_test_case_with_tree.php27
-rw-r--r--tests/template/templates/loop_advanced_twig.html19
-rw-r--r--tests/template/templates/loop_expressions.html4
-rw-r--r--tests/template/templates/loop_expressions_twig.html11
-rw-r--r--tests/template/templates/loop_expressions_twig2.html11
-rw-r--r--tests/template/templates/loop_include1_twig.html1
-rw-r--r--tests/template/templates/loop_include_twig.html4
-rw-r--r--tests/template/templates/loop_nested.html3
-rw-r--r--tests/template/templates/loop_nested2_twig.html6
-rw-r--r--tests/template/templates/loop_nested_deep_multilevel_ref_twig.html13
-rw-r--r--tests/template/templates/loop_nested_include1_twig.html5
-rw-r--r--tests/template/templates/loop_nested_include_twig.html4
-rw-r--r--tests/template/templates/loop_nested_multilevel_ref_twig.html10
-rw-r--r--tests/template/templates/loop_nested_twig.html6
-rw-r--r--tests/template/templates/loop_reuse_twig.html6
-rw-r--r--tests/template/templates/loop_size_twig.html39
-rw-r--r--tests/template/templates/loop_twig.html21
-rw-r--r--tests/template/templates/loop_underscore_twig.html21
-rw-r--r--tests/template/templates/loop_vars_twig.html13
-rw-r--r--tests/test_framework/mock/phpbb_mock_null_installer_task.php30
-rw-r--r--tests/test_framework/phpbb_database_test_case.php88
-rw-r--r--tests/test_framework/phpbb_database_test_connection_manager.php43
-rw-r--r--tests/test_framework/phpbb_functional_test_case.php374
-rw-r--r--tests/test_framework/phpbb_session_test_case.php3
-rw-r--r--tests/test_framework/phpbb_test_case_helpers.php307
-rw-r--r--tests/test_framework/phpbb_ui_test_case.php324
-rw-r--r--tests/text_formatter/s9e/bbcode_merger_test.php296
-rw-r--r--tests/text_formatter/s9e/default_formatting_test.php317
-rw-r--r--tests/text_formatter/s9e/factory_test.php314
-rw-r--r--tests/text_formatter/s9e/fixtures/default_formatting.xml466
-rw-r--r--tests/text_formatter/s9e/fixtures/default_lang.xml20
-rw-r--r--tests/text_formatter/s9e/fixtures/factory.xml115
-rw-r--r--tests/text_formatter/s9e/fixtures/inttext_token.xml27
-rw-r--r--tests/text_formatter/s9e/fixtures/local_url.xml28
-rw-r--r--tests/text_formatter/s9e/fixtures/malformed_bbcode.xml28
-rw-r--r--tests/text_formatter/s9e/fixtures/preserve_comments.xml28
-rw-r--r--tests/text_formatter/s9e/fixtures/smilies_duplicate.xml33
-rw-r--r--tests/text_formatter/s9e/fixtures/smilies_special_chars.xml23
-rw-r--r--tests/text_formatter/s9e/fixtures/style_inheritance.xml66
-rw-r--r--tests/text_formatter/s9e/fixtures/styles.xml36
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html40
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html40
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html40
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/prosilver/template/bbcode.html75
-rw-r--r--tests/text_formatter/s9e/fixtures/styles/unsafe/template/bbcode.html40
-rw-r--r--tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml28
-rw-r--r--tests/text_formatter/s9e/fixtures/unsafe_default_bbcodes.xml24
-rw-r--r--tests/text_formatter/s9e/link_helper_test.php35
-rw-r--r--tests/text_formatter/s9e/parser_test.php258
-rw-r--r--tests/text_formatter/s9e/renderer_test.php481
-rw-r--r--tests/text_formatter/s9e/utils_test.php276
-rw-r--r--tests/text_processing/censor_text_test.php3
-rw-r--r--tests/text_processing/decode_message_test.php113
-rw-r--r--tests/text_processing/fixtures/empty.xml3
-rw-r--r--tests/text_processing/fixtures/smilies.xml443
-rw-r--r--tests/text_processing/generate_text_for_display_test.php202
-rw-r--r--tests/text_processing/generate_text_for_edit_test.php89
-rw-r--r--tests/text_processing/generate_text_for_storage_test.php178
-rw-r--r--tests/text_processing/make_clickable_test.php3
-rw-r--r--tests/text_processing/message_parser_test.php540
-rw-r--r--tests/text_processing/smilies_test.php49
-rw-r--r--tests/text_processing/strip_bbcode_test.php39
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10002.html2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10002.txt2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10122.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10122.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10268.html4
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10268.txt4
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10425.html3
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10425.txt3
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10587.html2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10587.txt2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10922.html9
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10922.txt9
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10989.html8
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-10989.txt8
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-11153.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-11153.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-11153.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-11742.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-11742.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-12195.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-12195.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-12221.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-12221.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13425.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13425.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13425.xml23
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13451.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13451.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13641.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13641.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13641.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13921.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13921.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-13921.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14260.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14260.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14405.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14405.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14663.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14663.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14663.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14706.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14706.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14740.html2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14740.txt2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14740.xml40
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14790.html4
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14790.txt4
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14846.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14846.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-14846.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15008.before.php18
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15008.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15008.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15016.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15016.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15016.xml43
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15163.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15163.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15163.xml23
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15261.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15261.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15261.xml14
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15348.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15348.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-15348.xml33
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16053.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16053.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16053.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16074.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16074.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16252.after.php18
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16252.before.php17
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16252.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-16252.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-3981.before.php21
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-3981.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-3981.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-7187.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-7187.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-7187.xml33
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-7275.after.php19
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-7275.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-7275.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-7275.xml49
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-8419.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-8419.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-8419.xml28
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9073.html2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9073.txt2
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9073.xml14
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9377.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9377.txt1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9377.xml41
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9791.html1
-rw-r--r--tests/text_processing/tickets_data/PHPBB3-9791.txt1
-rw-r--r--tests/text_processing/tickets_test.php90
-rw-r--r--tests/text_reparser/base_test.php84
-rw-r--r--tests/text_reparser/fixtures/base.xml27
-rw-r--r--tests/text_reparser/fixtures/config_text.xml7
-rw-r--r--tests/text_reparser/manager_test.php117
-rw-r--r--tests/text_reparser/plugins/contact_admin_info_test.php95
-rw-r--r--tests/text_reparser/plugins/fixtures/contact_admin_info.xml23
-rw-r--r--tests/text_reparser/plugins/fixtures/forums.xml113
-rw-r--r--tests/text_reparser/plugins/fixtures/groups.xml69
-rw-r--r--tests/text_reparser/plugins/fixtures/poll_options.xml133
-rw-r--r--tests/text_reparser/plugins/fixtures/polls.xml109
-rw-r--r--tests/text_reparser/plugins/fixtures/posts.xml91
-rw-r--r--tests/text_reparser/plugins/fixtures/privmsgs.xml113
-rw-r--r--tests/text_reparser/plugins/fixtures/users.xml91
-rw-r--r--tests/text_reparser/plugins/forum_description_test.php26
-rw-r--r--tests/text_reparser/plugins/forum_rules_test.php26
-rw-r--r--tests/text_reparser/plugins/group_description_test.php26
-rw-r--r--tests/text_reparser/plugins/pm_text_test.php26
-rw-r--r--tests/text_reparser/plugins/poll_option_test.php129
-rw-r--r--tests/text_reparser/plugins/poll_title_test.php26
-rw-r--r--tests/text_reparser/plugins/post_text_test.php26
-rw-r--r--tests/text_reparser/plugins/test_row_based_plugin.php150
-rw-r--r--tests/text_reparser/plugins/user_signature_test.php26
-rw-r--r--tests/tree/nestedset_forum_base.php23
-rw-r--r--tests/ui/permission_roles_test.php90
-rw-r--r--tests/ui/quick_links_test.php7
-rw-r--r--tests/upload/filespec_test.php277
-rw-r--r--tests/upload/fileupload_test.php150
-rw-r--r--tests/upload/fixture/bmpbin0 -> 64 bytes
-rw-r--r--tests/upload/fixture/iffbin0 -> 120 bytes
-rw-r--r--tests/upload/fixture/iff_mayabin0 -> 88 bytes
-rw-r--r--tests/upload/fixture/jp2bin0 -> 528 bytes
-rw-r--r--tests/upload/fixture/jpxbin0 -> 528 bytes
-rw-r--r--tests/upload/fixture/psdbin0 -> 6374 bytes
-rw-r--r--tests/upload/fixture/tif_compressedbin0 -> 236 bytes
-rw-r--r--tests/upload/fixture/tif_msbbin0 -> 222 bytes
-rw-r--r--tests/upload/fixture/wbmpbin0 -> 5 bytes
-rw-r--r--tests/upload/imagesize_test.php97
-rw-r--r--tests/user/lang_test.php119
-rw-r--r--tests/user/user_loader_test.php2
-rw-r--r--tests/utf/normalizer_test.php327
-rw-r--r--tests/utf/utf8_clean_string_test.php2
-rw-r--r--tests/utf/utf8_wordwrap_test.php2
-rw-r--r--tests/version/version_fetch_test.php3
-rw-r--r--tests/version/version_helper_remote_test.php15
-rw-r--r--tests/version/version_test.php31
-rw-r--r--tests/viewonline/helper_test.php2
-rw-r--r--tests/wrapper/gmgetdate_test.php2
-rw-r--r--tests/wrapper/mt_rand_test.php2
-rw-r--r--tests/wrapper/phpbb_php_ini_fake.php2
-rw-r--r--tests/wrapper/phpbb_php_ini_test.php46
-rw-r--r--tests/wrapper/version_compare_test.php4
-rwxr-xr-xtravis/check-executable-files.sh7
-rwxr-xr-xtravis/check-image-icc-profiles.sh3
-rwxr-xr-xtravis/check-sami-parse-errors.sh3
-rwxr-xr-xtravis/ext-sniff.sh5
-rwxr-xr-xtravis/install-phpbb-test-dependencies.sh16
-rwxr-xr-xtravis/phing-sniff.sh3
-rwxr-xr-xtravis/setup-database.sh8
-rwxr-xr-xtravis/setup-mariadb.sh2
-rwxr-xr-xtravis/setup-php-extensions.sh20
-rwxr-xr-xtravis/setup-phpbb.sh13
-rwxr-xr-xtravis/setup-webserver.sh71
-rwxr-xr-xvagrant/after.sh33
-rw-r--r--vagrant/bootstrap.yaml40
-rw-r--r--vagrant/phpbb-install-config.yml51
1892 files changed, 92708 insertions, 50503 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000000..dfb8fea7d3
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,145 @@
+build: false
+clone_folder: c:\projects\phpbb
+version: '{build}'
+
+services:
+ - iis
+
+environment:
+ matrix:
+ - db: mssql
+ db_version: sql2012sp1
+ php: 7.0
+ - db: mssql
+ db_version: sql2014
+ php: 7.0
+ - db: mssql
+ db_version: sql2016
+ php: 7.1.12
+# - db: mssql
+# db_version: sql2017
+# php: 7.1
+# - db: mariadb
+# php: 7.1
+# - db: mysqli
+# php: 7.1
+# - db: sqlite
+# php: 7.1
+# - db: postgresql
+# php: 7.1
+
+hosts:
+ phpbb.test: 127.0.0.1
+
+init:
+ - SET PATH=%systemroot%\system32\inetsrv\;C:\Program Files\OpenSSL;C:\tools\php;c:\php;%PATH%
+ - SET ANSICON=121x90 (121x90)
+ - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f
+
+before_test:
+ - ps: |
+ Set-Service wuauserv -StartupType Manual
+ choco install chocolatey -y --version 0.10.13 --allow-downgrade
+ choco install php -y --version ((choco search php --exact --all-versions -r | select-string -pattern $env:php | sort { [version]($_ -split '\|' | select -last 1) } -Descending | Select-Object -first 1) -replace '[php|]','')
+ Get-ChildItem -Path "c:\tools\php$($env:php -replace '([0-9])[.]([0-9])[.]?([0-9]+)?','$1$2')" -Recurse |
+ Move-Item -destination "c:\tools\php"
+ cd c:\tools\php
+ cat php.ini-development | %{$_ -replace "memory_limit = 128M","memory_limit = 1024M"} | Out-File -Encoding "Default" php.ini
+ Add-Content php.ini "`n date.timezone=UTC"
+ Add-Content php.ini "`n display_errors=On"
+ Add-Content php.ini "`n extension_dir=ext"
+ Add-Content php.ini "`n extension=php_openssl.dll"
+ Add-Content php.ini "`n extension=php_mbstring.dll"
+ Add-Content php.ini "`n extension=php_curl.dll"
+ Add-Content php.ini "`n extension=php_gd2.dll"
+ Add-Content php.ini "`n extension=php_tidy.dll"
+ Add-Content php.ini "`n extension=php_fileinfo.dll"
+ Add-Content php.ini "`n extension=php_pdo_sqlite.dll"
+ Add-Content php.ini "`n extension=php_sqlite3.dll"
+ Add-Content php.ini "`n extension=php_pdo_mysql.dll"
+ Add-Content php.ini "`n extension=php_mysqli.dll"
+ Add-Content php.ini "`n extension=php_pdo_pgsql.dll"
+ Add-Content php.ini "`n extension=php_pgsql.dll"
+
+ # Get MSSQL driver
+ if ($env:db -eq "mssql") {
+ cd c:\tools\php\ext
+ $DLLVersion = "4.1.6.1"
+ curl -o php_sqlsrv-$($DLLVersion)-$($env:php -replace '([0-9])[.]([0-9])[.]?([0-9]+)?','$1.$2')-nts-vc14-x64.zip https://windows.php.net/downloads/pecl/releases/sqlsrv/$($:DLLVersion)/php_sqlsrv-$($DLLVersion)-$($env:php -replace '([0-9])[.]([0-9])[.]?([0-9]+)?','$1.$2')-nts-vc14-x64.zip
+ 7z x -y php_sqlsrv-$($DLLVersion)-$($env:php -replace '([0-9])[.]([0-9])[.]?([0-9]+)?','$1.$2')-nts-vc14-x64.zip > $null
+ curl -o php_pdo_sqlsrv-$($DLLVersion)-$($env:php -replace '([0-9])[.]([0-9])[.]?([0-9]+)?','$1.$2')-nts-vc14-x64.zip https://windows.php.net/downloads/pecl/releases/pdo_sqlsrv/$($DLLVersion)/php_pdo_sqlsrv-$($DLLVersion)-$($env:php -replace '([0-9])[.]([0-9])[.]?([0-9]+)?','$1.$2')-nts-vc14-x64.zip
+ 7z x -y php_pdo_sqlsrv-$($DLLVersion)-$($env:php -replace '([0-9])[.]([0-9])[.]?([0-9]+)?','$1.$2')-nts-vc14-x64.zip > $null
+ Remove-Item c:\tools\php\* -include .zip
+ cd c:\tools\php
+ Add-Content php.ini "`nextension=php_sqlsrv.dll"
+ Add-Content php.ini "`nextension=php_pdo_sqlsrv.dll"
+ Add-Content php.ini "`n"
+
+ $instanceName = $env:db_version.ToUpper()
+ Start-Service "MSSQL`$$instanceName"
+ Set-Variable -Name "sqlServerPath" -Value "(local)\$($env:db_version.ToUpper())"
+
+ # Create database write test config
+ sqlcmd -S $sqlServerPath -Q "Use [master]; CREATE DATABASE [phpbb_test] COLLATE Latin1_General_CI_AS"
+ $data = "<?php`n`n`$dbms = 'phpbb\\db\\driver\\mssqlnative';`n`$dbhost = '.\\$env:db_version';`n`$dbport = '';`n`$dbname = 'phpbb_test';`n`$dbuser = 'sa';`n`$dbpasswd = 'Password12!';`n`$phpbb_functional_url = 'http://phpbb.test/';"; $data | Out-File -Encoding "Default" "c:\\projects\\phpbb\\tests\\test_config.php"
+ }
+ elseif ($env:db -eq "mysqli") {
+ Start-Service MySQL57
+ $env:MYSQL_PWD="Password12!"
+ $cmd = '"C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql" -e "create database phpbb_test;" --user=root'
+ iex "& $cmd"
+ $data = "<?php`n`n`$dbms = 'phpbb\\db\\driver\\mysqli';`n`$dbhost = 'localhost';`n`$dbport = '';`n`$dbname = 'phpbb_test';`n`$dbuser = 'root';`n`$dbpasswd = 'Password12!';`n`$phpbb_functional_url = 'http://phpbb.test/';"; $data | Out-File -Encoding "Default" "c:\\projects\\phpbb\\tests\\test_config.php"
+ }
+ elseif ($env:db -eq "postgresql") {
+ Start-Service postgresql-x64-9.5
+ $env:PGUSER="postgres"
+ $env:PGPASSWORD="Password12!"
+ $Env:Path="C:\Program Files\PostgreSQL\9.6\bin\;$($Env:Path)"
+ createdb phpbb_test
+ $data = "<?php`n`n`$dbms = 'phpbb\\db\\driver\\postgres';`n`$dbhost = 'localhost';`n`$dbport = '';`n`$dbname = 'phpbb_test';`n`$dbuser = 'postgres';`n`$dbpasswd = 'Password12!';`n`$phpbb_functional_url = 'http://phpbb.test/';"; $data | Out-File -Encoding "Default" "c:\\projects\\phpbb\\tests\\test_config.php"
+ }
+ elseif ($env:db -eq "mariadb") {
+ appveyor-retry choco install mariadb -y --force
+ $env:MYSQL_PWD=""
+ $cmd = '"C:\Program Files\MariaDB 10.2\bin\mysql" -e "create database phpbb_test;" --user=root'
+ iex "& $cmd"
+ $data = "<?php`n`n`$dbms = 'phpbb\\db\\driver\\mysqli';`n`$dbhost = 'localhost';`n`$dbport = '';`n`$dbname = 'phpbb_test';`n`$dbuser = 'root';`n`$dbpasswd = '';`n`$phpbb_functional_url = 'http://phpbb.test/';"; $data | Out-File -Encoding "Default" "c:\\projects\\phpbb\\tests\\test_config.php"
+ }
+ elseif ($env:db -eq "sqlite") {
+ # install sqlite
+ appveyor-retry choco install sqlite -y
+ sqlite3 c:\projects\test.db "create table aTable(field1 int); drop table aTable;"
+ $data = "<?php`n`n`$dbms = 'phpbb\\db\\driver\\sqlite3';`n`$dbhost = 'c:\\projects\\test.db';`n`$dbport = '';`n`$dbname = '';`n`$dbuser = '';`n`$dbpasswd = '';`n`$phpbb_functional_url = 'http://phpbb.test/';"; $data | Out-File -Encoding "Default" "c:\\projects\\phpbb\\tests\\test_config.php"
+ }
+
+ # Install PhantomJS
+ choco install phantomjs -y
+ Start-Process "phantomjs" "--webdriver=8910" | Out-Null
+ - ps: |
+ cd c:\projects\phpbb\phpBB
+ (Get-Content c:\projects\phpbb\phpBB\web.config).replace("<configuration>", "<configuration>`n`t<system.web>`n`t`t<customErrors mode=`"Off`"/>`n`t</system.web>") | Set-Content c:\projects\phpbb\phpBB\web.config
+ (Get-Content c:\projects\phpbb\phpBB\web.config).replace("`t</system.webServer>", "`t`t<httpErrors errorMode=`"Detailed`" />`n`t</system.webServer>") | Set-Content c:\projects\phpbb\phpBB\web.config
+ - cd c:\projects\phpbb\phpBB
+ - php ..\composer.phar install
+ - choco install urlrewrite -y
+ - ps: New-WebSite -Name 'phpBBTest' -PhysicalPath 'c:\projects\phpbb\phpBB' -Force
+ - ps: Import-Module WebAdministration; Set-ItemProperty 'IIS:\Sites\phpBBTest' -name Bindings -value @{protocol='http';bindingInformation='*:80:phpbb.test'}
+ - echo Change default anonymous user AUTH to ApplicationPool
+ - appcmd set config -section:anonymousAuthentication /username:"" --password
+ - echo Setup FAST-CGI configuration
+ - appcmd set config /section:system.webServer/fastCGI /+[fullPath='C:\tools\php\php-cgi.exe']
+ - echo Setup FACT-CGI handler
+ - appcmd set config /section:system.webServer/handlers /+[name='PHP-FastCGI',path='*.php',verb='*',modules='FastCgiModule',scriptProcessor='C:\tools\php\php-cgi.exe',resourceType='Either']
+ - iisreset
+ - NET START W3SVC
+ - mkdir "C:\projects\phpbb\phpBB\cache\test"
+ - mkdir "C:\projects\phpbb\phpBB\cache\installer"
+ - icacls "C:\projects\phpbb\phpBB\cache" /grant Users:F /T
+ - icacls "C:\projects\phpbb\phpBB\files" /grant Users:F /T
+ - icacls "C:\projects\phpbb\phpBB\store" /grant Users:F /T
+ - icacls "C:\projects\phpbb\phpBB\images\avatars\upload" /grant Users:F /T
+
+test_script:
+ - cd c:\projects\phpbb
+ - php -e phpBB\vendor\phpunit\phpunit\phpunit --verbose
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 39eb83e454..cacfcf1118 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,9 +1,9 @@
Checklist:
-- [ ] Correct branch: master for new features; 3.2.x, 3.1.x for fixes
+- [ ] Correct branch: master for new features; 3.2.x for fixes
- [ ] Tests pass
-- [ ] Code follows coding guidelines: [master / 3.2.x](https://area51.phpbb.com/docs/master/coding-guidelines.html), [3.1.x](https://area51.phpbb.com/docs/31x/coding-guidelines.html)
-- [ ] Commit follows commit message [format](https://wiki.phpbb.com/Git#Commit_Messages)
+- [ ] Code follows coding guidelines: [master](https://area51.phpbb.com/docs/dev/master/development/coding_guidelines.html) and [3.2.x](https://area51.phpbb.com/docs/dev/3.2.x/development/coding_guidelines.html)
+- [ ] Commit follows commit message [format](https://area51.phpbb.com/docs/dev/3.2.x/development/git.html)
Tracker ticket (set the ticket ID to **your ticket ID**):
diff --git a/.gitignore b/.gitignore
index 606b9c1daf..bb60e45080 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,7 @@
!/phpBB/cache/.htaccess
!/phpBB/cache/index.html
/phpBB/composer.phar
-/phpBB/config*.php
+/phpBB/config*.php*
/phpBB/ext/*
/phpBB/cache/*
/phpBB/files/*
@@ -17,9 +17,11 @@
/phpBB/store/*
/phpBB/styles/*
!/phpBB/styles/prosilver
-!/phpBB/styles/subsilver2
+!/phpBB/styles/all
/phpBB/vendor
/tests/phpbb_unit_tests.sqlite*
/tests/test_config*.php
/tests/tmp/*
/tests/vendor
+/vagrant/phpbb-install-config.yml
+.vagrant
diff --git a/.travis.yml b/.travis.yml
index a46d825612..3f3cf2b018 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,12 @@
language: php
+dist: trusty
matrix:
include:
- - php: 5.3.3
- env: DB=mysqli
- - php: 5.3
- env: DB=mysqli # MyISAM
- php: 5.4
- env: DB=mysqli
+ env: DB=none;NOTESTS=1
+ - php: 5.4
+ env: DB=mysqli # MyISAM
- php: 5.4
env: DB=mysql
- php: 5.4
@@ -22,28 +21,34 @@ matrix:
env: DB=mysqli
- php: 5.6
env: DB=mysqli
- - php: hhvm
+ - php: 7.0
+ env: DB=mysqli
+ - php: 7.1
+ env: DB=mysqli
+ - php: 7.2
+ env: DB=mysqli
+ - php: nightly
env: DB=mysqli
allow_failures:
- - php: hhvm
+ - php: nightly
fast_finish: true
services:
- redis-server
install:
- - travis/setup-phpbb.sh $DB $TRAVIS_PHP_VERSION
+ - travis/setup-phpbb.sh $DB $TRAVIS_PHP_VERSION $NOTESTS
before_script:
- - travis/setup-database.sh $DB $TRAVIS_PHP_VERSION
+ - travis/setup-database.sh $DB $TRAVIS_PHP_VERSION $NOTESTS
- phantomjs --webdriver=8910 > /dev/null &
script:
- - travis/phing-sniff.sh $DB $TRAVIS_PHP_VERSION
- - travis/check-sami-parse-errors.sh $DB $TRAVIS_PHP_VERSION
- - travis/check-image-icc-profiles.sh $DB $TRAVIS_PHP_VERSION
- - travis/check-executable-files.sh $DB $TRAVIS_PHP_VERSION ./
+ - travis/phing-sniff.sh $DB $TRAVIS_PHP_VERSION $NOTESTS
+ - travis/check-sami-parse-errors.sh $DB $TRAVIS_PHP_VERSION $NOTESTS
+ - travis/check-image-icc-profiles.sh $DB $TRAVIS_PHP_VERSION $NOTESTS
+ - travis/check-executable-files.sh $DB $TRAVIS_PHP_VERSION $NOTESTS ./
- sh -c "if [ '$SLOWTESTS' != '1' -a '$DB' = 'mysqli' ]; then phpBB/vendor/bin/phpunit tests/lint_test.php; fi"
- - sh -c "if [ '$SLOWTESTS' != '1' ]; then phpBB/vendor/bin/phpunit --configuration travis/phpunit-$DB-travis.xml; fi"
+ - sh -c "if [ '$NOTESTS' != '1' -a '$SLOWTESTS' != '1' ]; then phpBB/vendor/bin/phpunit --configuration travis/phpunit-$DB-travis.xml --verbose --stop-on-error; fi"
- sh -c "if [ '$SLOWTESTS' = '1' ]; then phpBB/vendor/bin/phpunit --configuration travis/phpunit-$DB-travis.xml --group slow; fi"
- - sh -c "if [ '$TRAVIS_PHP_VERSION' = '5.3.3' -a '$DB' = 'mysqli' -a '$TRAVIS_PULL_REQUEST' != 'false' ]; then git-tools/commit-msg-hook-range.sh origin/$TRAVIS_BRANCH..FETCH_HEAD; fi"
+ - sh -c "set -x;if [ '$NOTESTS' = '1' -a '$TRAVIS_PULL_REQUEST' != 'false' ]; then git remote set-branches --add origin $TRAVIS_BRANCH && git fetch && git-tools/commit-msg-hook-range.sh origin/$TRAVIS_BRANCH..$TRAVIS_PULL_REQUEST_SHA; fi"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000..ce992b2ce7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,281 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/README.md b/README.md
index f465d7496e..92cd5b9867 100644
--- a/README.md
+++ b/README.md
@@ -20,16 +20,22 @@ To be able to run an installation from the repo (and not from a pre-built packag
1. [Create an account on phpBB.com](http://www.phpbb.com/community/ucp.php?mode=register)
2. [Create a ticket (unless there already is one)](http://tracker.phpbb.com/secure/CreateIssue!default.jspa)
-3. Read our [Coding guidelines](https://wiki.phpbb.com/Coding_guidelines) and [Git Contribution Guidelines](http://wiki.phpbb.com/Git)
+3. Read our [Coding guidelines](https://area51.phpbb.com/docs/dev/development/coding_guidelines.html) and [Git Contribution Guidelines](https://area51.phpbb.com/docs/dev/development/git.html)
4. Send us a pull request
+## VAGRANT
+
+Read our [Vagrant documentation](phpBB/docs/vagrant.md) to find out how to use Vagrant to develop and contribute to phpBB.
+
## AUTOMATED TESTING
-We have unit and functional tests in order to prevent regressions. You can view the bamboo continuous integration [here](http://bamboo.phpbb.com) or check our travis builds below:
+We have unit and functional tests in order to prevent regressions. You can view the bamboo continuous integration [here](https://bamboo.phpbb.com) or check our travis builds below:
-* [![Build Status](https://secure.travis-ci.org/phpbb/phpbb.png?branch=master)](http://travis-ci.org/phpbb/phpbb) **master** - Latest development version
-* [![Build Status](https://secure.travis-ci.org/phpbb/phpbb.png?branch=3.2.x)](http://travis-ci.org/phpbb/phpbb) **3.2.x** - Development of version 3.2.x
-* [![Build Status](https://secure.travis-ci.org/phpbb/phpbb.png?branch=3.1.x)](http://travis-ci.org/phpbb/phpbb) **3.1.x** - Development of version 3.1.x
+Travis CI | AppVeyor | Branch | Description
+---------- | -------- | ------- | -----------
+[![Build Status](https://travis-ci.org/phpbb/phpbb.svg?branch=master)](http://travis-ci.org/phpbb/phpbb) | [![Build status](https://ci.appveyor.com/api/projects/status/8g98ybngd2f3axy1/branch/master?svg=true)](https://ci.appveyor.com/project/phpBB/phpbb/branch/master) | **master** | Latest development version
+[![Build Status](https://travis-ci.org/phpbb/phpbb.svg?branch=3.3.x)](http://travis-ci.org/phpbb/phpbb) | [![Build status](https://ci.appveyor.com/api/projects/status/8g98ybngd2f3axy1/branch/3.3.x?svg=true)](https://ci.appveyor.com/project/phpBB/phpbb/branch/3.3.x) | **3.3.x** | Development of version 3.3.x
+[![Build Status](https://travis-ci.org/phpbb/phpbb.svg?branch=3.2.x)](http://travis-ci.org/phpbb/phpbb) | [![Build status](https://ci.appveyor.com/api/projects/status/8g98ybngd2f3axy1/branch/3.2.x?svg=true)](https://ci.appveyor.com/project/phpBB/phpbb/branch/3.2.x) | **3.2.x** | Development of version 3.2.x
## LICENSE
diff --git a/Vagrantfile b/Vagrantfile
new file mode 100644
index 0000000000..ab225c9ad9
--- /dev/null
+++ b/Vagrantfile
@@ -0,0 +1,25 @@
+require 'json'
+require 'yaml'
+
+VAGRANTFILE_API_VERSION ||= "2"
+confDir = $confDir ||= File.expand_path("phpBB/vendor/laravel/homestead", File.dirname(__FILE__))
+
+homesteadYamlPath = "vagrant/bootstrap.yaml"
+afterScriptPath = "vagrant/after.sh"
+aliasesPath = "vagrant/aliases"
+
+require File.expand_path(confDir + '/scripts/homestead.rb')
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ if File.exists? aliasesPath then
+ config.vm.provision "file", source: aliasesPath, destination: "~/.bash_aliases"
+ end
+
+ if File.exists? homesteadYamlPath then
+ Homestead.configure(config, YAML::load(File.read(homesteadYamlPath)))
+ end
+
+ if File.exists? afterScriptPath then
+ config.vm.provision "shell", path: afterScriptPath
+ end
+end
diff --git a/build/build.xml b/build/build.xml
index 20ecfefc61..a95d8bedf5 100644
--- a/build/build.xml
+++ b/build/build.xml
@@ -2,9 +2,9 @@
<project name="phpBB" description="The phpBB forum software" default="all" basedir="../">
<!-- a few settings for the build -->
- <property name="newversion" value="3.1.11" />
- <property name="prevversion" value="3.1.10" />
- <property name="olderversions" value="3.0.14, 3.1.0, 3.1.1, 3.1.2, 3.1.3, 3.1.4, 3.1.5, 3.1.6, 3.1.7, 3.1.7-pl1, 3.1.8, 3.1.9, 3.1.11-RC1" />
+ <property name="newversion" value="3.2.9" />
+ <property name="prevversion" value="3.2.8" />
+ <property name="olderversions" value="3.1.0, 3.1.1, 3.1.2, 3.1.3, 3.1.4, 3.1.5, 3.1.6, 3.1.7, 3.1.7-pl1, 3.1.8, 3.1.9, 3.1.10, 3.1.11, 3.1.12, 3.2.0-a1, 3.2.0-a2, 3.2.0-b1, 3.2.0-b2, 3.2.0-RC1, 3.2.0-RC2, 3.2.0, 3.2.1, 3.2.2, 3.2.3, 3.2.4, 3.2.5, 3.2.6, 3.2.7, 3.2.9-RC1" />
<!-- no configuration should be needed beyond this point -->
<property name="oldversions" value="${olderversions}, ${prevversion}" />
@@ -142,6 +142,7 @@
<phingcall target="export">
<property name="revision" value="release-${version}" />
+ <property name="version" value="${version}" />
<property name="dir" value="build/old_versions/release-${version}" />
<property name="skip-composer" value="true" />
</phingcall>
@@ -183,9 +184,6 @@
<exec dir="build" escape="false"
command="LC_ALL=C diff -crNEBZbd old_versions/release-${prevversion}/styles/prosilver new_version/phpBB3/styles/prosilver >
save/phpbb-${prevversion}_to_${newversion}_prosilver.patch" />
- <exec dir="build" escape="false"
- command="LC_ALL=C diff -crNEBZbd old_versions/release-${prevversion}/styles/subsilver2 new_version/phpBB3/styles/subsilver2 >
- save/phpbb-${prevversion}_to_${newversion}_subsilver2.patch" />
<exec dir="build" escape="false"
command="git shortlog --summary --numbered release-${prevversion}...HEAD >
@@ -290,12 +288,62 @@
</else>
</if>
+ <!-- Checkout latest viglink to ext folder -->
+ <available file="${dir}/ext" type="dir" property="add-viglink-ext" />
+ <exec dir="${dir}"
+ command='php -r "echo version_compare(&apos;${version}&apos;, &apos;3.2.0-RC2&apos;, &apos;>=&apos;) ? &apos;true&apos; : &apos;false&apos;;"'
+ checkreturn="true"
+ outputProperty='viglink-available' />
+ <if>
+ <and>
+ <equals arg1="${add-viglink-ext}" arg2="1" trim="true" />
+ <or>
+ <equals arg1="${revision}" arg2="HEAD" trim="true" />
+ <equals arg1="${viglink-available}" arg2="1" trim="true" />
+ </or>
+ </and>
+ <then>
+ <exec dir="${dir}/ext" command="mkdir phpbb" passthru="true" />
+
+ <exec dir="${dir}/ext/phpbb" command="git clone https://github.com/phpbb-extensions/viglink.git viglink" passthru="true" checkreturn="true" />
+ <if>
+ <equals arg1="${revision}" arg2="HEAD" trim="true" />
+ <then>
+ <exec dir="${dir}/ext/phpbb/viglink"
+ command="git rev-parse release-phpbb-${version}"
+ returnProperty='viglink_head_tag_exists' />
+ <if>
+ <equals arg1="${viglink_head_tag_exists}" arg2="0" trim="true" />
+ <then>
+ <exec dir="${dir}/ext/phpbb/viglink" command="git checkout release-phpbb-${version}" passthru="true" />
+ </then>
+ <else>
+ <exec dir="${dir}/ext/phpbb/viglink" command="git checkout master" passthru="true" />
+ </else>
+ </if>
+ </then>
+ <else>
+ <exec dir="${dir}/ext/phpbb/viglink" command="git checkout release-phpbb-${version}" passthru="true" />
+ </else>
+ </if>
+ <delete dir="${dir}/ext/phpbb/viglink/.git" />
+ <delete dir="${dir}/ext/phpbb/viglink/tests" />
+ <delete dir="${dir}/ext/phpbb/viglink/travis" />
+ <delete file="${dir}/ext/phpbb/viglink/.gitattributes" />
+ <delete file="${dir}/ext/phpbb/viglink/.travis.yml" />
+ <delete file="${dir}/ext/phpbb/viglink/phpunit.xml.dist" />
+ <delete file="${dir}/ext/phpbb/viglink/README.md" />
+ </then>
+ </if>
+
<!-- Create schema.json -->
<exec dir="${dir}" command="php develop/create_schema_files.php" />
<delete file="${dir}/config.php" />
<delete dir="${dir}/develop" />
<delete dir="${dir}/install/data" />
+ <delete dir="${dir}/config/development" />
+ <delete dir="${dir}/config/test" />
<echo msg="Setting permissions for checkout of ${revision} in ${dir}" />
<!-- set permissions of all files to 644, directories to 755 -->
@@ -310,6 +358,50 @@
<target name="clean-vendor-dir">
<!-- Delete unrelated files from vendor/, see PHPBB3-12390 -->
+ <delete dir="${dir}/vendor/bantu/ini-get-wrapper/tests" />
+ <delete file="${dir}/vendor/bantu/ini-get-wrapper/.gitignore" />
+ <delete file="${dir}/vendor/bantu/ini-get-wrapper/.scrutinizer.yml" />
+ <delete file="${dir}/vendor/bantu/ini-get-wrapper/.travis.yml" />
+ <delete file="${dir}/vendor/bantu/ini-get-wrapper/phpunit.xml.dist" />
+ <delete file="${dir}/vendor/bantu/ini-get-wrapper/README.md" />
+
+ <delete dir="${dir}/vendor/google/recaptcha/examples" />
+ <delete dir="${dir}/vendor/google/recaptcha/tests" />
+ <delete file="${dir}/vendor/google/recaptcha/.gitignore" />
+ <delete file="${dir}/vendor/google/recaptcha/.travis.yml" />
+ <delete file="${dir}/vendor/google/recaptcha/CONTRIBUTING.md" />
+ <delete file="${dir}/vendor/google/recaptcha/phpunit.xml.dist" />
+ <delete file="${dir}/vendor/google/recaptcha/README.md" />
+
+ <delete dir="${dir}/vendor/guzzlehttp/guzzle/build" />
+ <delete dir="${dir}/vendor/guzzlehttp/guzzle/docs" />
+ <delete dir="${dir}/vendor/guzzlehttp/guzzle/tests" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/CHANGELOG.md" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/.editorconfig" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/.gitignore" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/Makefile" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/phpunit.xml.dist" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/README.md" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/.travis.yml" />
+ <delete file="${dir}/vendor/guzzlehttp/guzzle/UPGRADING.md" />
+
+ <delete dir="${dir}/vendor/guzzlehttp/ringphp/docs" />
+ <delete dir="${dir}/vendor/guzzlehttp/ringphp/tests" />
+ <delete file="${dir}/vendor/guzzlehttp/ringphp/CHANGELOG.md" />
+ <delete file="${dir}/vendor/guzzlehttp/ringphp/.gitignore" />
+ <delete file="${dir}/vendor/guzzlehttp/ringphp/Makefile" />
+ <delete file="${dir}/vendor/guzzlehttp/ringphp/phpunit.xml.dist" />
+ <delete file="${dir}/vendor/guzzlehttp/ringphp/README.rst" />
+ <delete file="${dir}/vendor/guzzlehttp/ringphp/.travis.yml" />
+
+ <delete dir="${dir}/vendor/guzzlehttp/streams/tests" />
+ <delete file="${dir}/vendor/guzzlehttp/streams/CHANGELOG.rst" />
+ <delete file="${dir}/vendor/guzzlehttp/streams/.gitignore" />
+ <delete file="${dir}/vendor/guzzlehttp/streams/Makefile" />
+ <delete file="${dir}/vendor/guzzlehttp/streams/phpunit.xml.dist" />
+ <delete file="${dir}/vendor/guzzlehttp/streams/README.rst" />
+ <delete file="${dir}/vendor/guzzlehttp/streams/.travis.yml" />
+
<delete dir="${dir}/vendor/lusitanian/oauth/examples" />
<delete dir="${dir}/vendor/lusitanian/oauth/tests" />
<delete file="${dir}/vendor/lusitanian/oauth/.gitignore" />
@@ -318,69 +410,121 @@
<delete file="${dir}/vendor/lusitanian/oauth/phpunit.xml.dist" />
<delete file="${dir}/vendor/lusitanian/oauth/README.md" />
+ <delete dir="${dir}/vendor/paragonie/random_compat/dist" />
+ <delete dir="${dir}/vendor/paragonie/random_compat/other" />
+ <delete file="${dir}/vendor/paragonie/random_compat/CHANGELOG.md" />
+ <delete file="${dir}/vendor/paragonie/random_compat/ERRATA.md" />
+ <delete file="${dir}/vendor/paragonie/random_compat/README.md" />
+ <delete file="${dir}/vendor/paragonie/random_compat/SECURITY.md" />
+
+ <delete file="${dir}/vendor/patchwork/utf8/.travis.yml" />
+ <delete file="${dir}/vendor/patchwork/utf8/CHANGELOG.md" />
+ <delete file="${dir}/vendor/patchwork/utf8/phpunit.xml.dist" />
+ <delete file="${dir}/vendor/patchwork/utf8/README.md" />
+
<delete dir="${dir}/vendor/psr/log/Psr/Log/Test" />
<delete file="${dir}/vendor/psr/log/.gitignore" />
<delete file="${dir}/vendor/psr/log/README.md" />
- <delete dir="${dir}/vendor/symfony/config/Symfony/Component/Config/Tests" />
- <delete file="${dir}/vendor/symfony/config/Symfony/Component/Config/.gitignore" />
- <delete file="${dir}/vendor/symfony/config/Symfony/Component/Config/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/config/Symfony/Component/Config/README.md" />
- <delete file="${dir}/vendor/symfony/config/Symfony/Component/Config/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/console/Symfony/Component/Console/Tests" />
- <delete file="${dir}/vendor/symfony/console/Symfony/Component/Console/.gitignore" />
- <delete file="${dir}/vendor/symfony/console/Symfony/Component/Console/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/console/Symfony/Component/Console/README.md" />
- <delete file="${dir}/vendor/symfony/console/Symfony/Component/Console/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/debug/Symfony/Component/Debug/Tests" />
- <delete file="${dir}/vendor/symfony/debug/Symfony/Component/Debug/.gitignore" />
- <delete file="${dir}/vendor/symfony/debug/Symfony/Component/Debug/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/debug/Symfony/Component/Debug/README.md" />
- <delete file="${dir}/vendor/symfony/debug/Symfony/Component/Debug/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Tests" />
- <delete file="${dir}/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/.gitignore" />
- <delete file="${dir}/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/README.md" />
- <delete file="${dir}/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Tests" />
- <delete file="${dir}/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/.gitignore" />
- <delete file="${dir}/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/README.md" />
- <delete file="${dir}/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/filesystem/Symfony/Component/Filesystem/Tests" />
- <delete file="${dir}/vendor/symfony/filesystem/Symfony/Component/Filesystem/.gitignore" />
- <delete file="${dir}/vendor/symfony/filesystem/Symfony/Component/Filesystem/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/filesystem/Symfony/Component/Filesystem/README.md" />
- <delete file="${dir}/vendor/symfony/filesystem/Symfony/Component/Filesystem/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Tests" />
- <delete file="${dir}/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/.gitignore" />
- <delete file="${dir}/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/README.md" />
- <delete file="${dir}/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Tests" />
- <delete file="${dir}/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/.gitignore" />
- <delete file="${dir}/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/README.md" />
- <delete file="${dir}/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/routing/Symfony/Component/Routing/Tests" />
- <delete file="${dir}/vendor/symfony/routing/Symfony/Component/Routing/.gitignore" />
- <delete file="${dir}/vendor/symfony/routing/Symfony/Component/Routing/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/routing/Symfony/Component/Routing/README.md" />
- <delete file="${dir}/vendor/symfony/routing/Symfony/Component/Routing/phpunit.xml.dist" />
-
- <delete dir="${dir}/vendor/symfony/yaml/Symfony/Component/Yaml/Tests" />
- <delete file="${dir}/vendor/symfony/yaml/Symfony/Component/Yaml/.gitignore" />
- <delete file="${dir}/vendor/symfony/yaml/Symfony/Component/Yaml/CHANGELOG.md" />
- <delete file="${dir}/vendor/symfony/yaml/Symfony/Component/Yaml/README.md" />
- <delete file="${dir}/vendor/symfony/yaml/Symfony/Component/Yaml/phpunit.xml.dist" />
+ <delete dir="${dir}/vendor/react/promise/tests" />
+ <delete file="${dir}/vendor/react/promise/CHANGELOG.md" />
+ <delete file="${dir}/vendor/react/promise/.gitignore" />
+ <delete file="${dir}/vendor/react/promise/phpunit.xml.dist" />
+ <delete file="${dir}/vendor/react/promise/README.md" />
+ <delete file="${dir}/vendor/react/promise/.travis.yml" />
+
+ <delete dir="${dir}/vendor/s9e/text-formatter/.git" />
+
+ <delete dir="${dir}/vendor/symfony/config/.git" />
+ <delete dir="${dir}/vendor/symfony/config/Tests" />
+ <delete file="${dir}/vendor/symfony/config/.gitignore" />
+ <delete file="${dir}/vendor/symfony/config/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/config/README.md" />
+ <delete file="${dir}/vendor/symfony/config/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/console/.git" />
+ <delete dir="${dir}/vendor/symfony/console/Tests" />
+ <delete file="${dir}/vendor/symfony/console/.gitignore" />
+ <delete file="${dir}/vendor/symfony/console/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/console/README.md" />
+ <delete file="${dir}/vendor/symfony/console/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/debug/.git" />
+ <delete dir="${dir}/vendor/symfony/debug/Tests" />
+ <delete file="${dir}/vendor/symfony/debug/.gitignore" />
+ <delete file="${dir}/vendor/symfony/debug/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/debug/README.md" />
+ <delete file="${dir}/vendor/symfony/debug/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/dependency-injection/.git" />
+ <delete dir="${dir}/vendor/symfony/dependency-injection/Tests" />
+ <delete file="${dir}/vendor/symfony/dependency-injection/.gitignore" />
+ <delete file="${dir}/vendor/symfony/dependency-injection/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/dependency-injection/README.md" />
+ <delete file="${dir}/vendor/symfony/dependency-injection/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/event-dispatcher/.git" />
+ <delete dir="${dir}/vendor/symfony/event-dispatcher/Tests" />
+ <delete file="${dir}/vendor/symfony/event-dispatcher/.gitignore" />
+ <delete file="${dir}/vendor/symfony/event-dispatcher/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/event-dispatcher/README.md" />
+ <delete file="${dir}/vendor/symfony/event-dispatcher/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/filesystem/.git" />
+ <delete dir="${dir}/vendor/symfony/filesystem/Tests" />
+ <delete file="${dir}/vendor/symfony/filesystem/.gitignore" />
+ <delete file="${dir}/vendor/symfony/filesystem/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/filesystem/README.md" />
+ <delete file="${dir}/vendor/symfony/filesystem/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/finder/.git" />
+ <delete dir="${dir}/vendor/symfony/finder/Tests" />
+ <delete file="${dir}/vendor/symfony/finder/.gitignore" />
+ <delete file="${dir}/vendor/symfony/finder/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/finder/README.md" />
+ <delete file="${dir}/vendor/symfony/finder/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/http-foundation/.git" />
+ <delete dir="${dir}/vendor/symfony/http-foundation/Tests" />
+ <delete file="${dir}/vendor/symfony/http-foundation/.gitignore" />
+ <delete file="${dir}/vendor/symfony/http-foundation/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/http-foundation/README.md" />
+ <delete file="${dir}/vendor/symfony/http-foundation/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/http-kernel/.git" />
+ <delete dir="${dir}/vendor/symfony/http-kernel/Tests" />
+ <delete file="${dir}/vendor/symfony/http-kernel/.gitignore" />
+ <delete file="${dir}/vendor/symfony/http-kernel/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/http-kernel/README.md" />
+ <delete file="${dir}/vendor/symfony/http-kernel/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/proxy-manager-bridge/.git" />
+ <delete dir="${dir}/vendor/symfony/proxy-manager-bridge/Tests" />
+ <delete file="${dir}/vendor/symfony/proxy-manager-bridge/.gitignore" />
+ <delete file="${dir}/vendor/symfony/proxy-manager-bridge/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/proxy-manager-bridge/README.md" />
+ <delete file="${dir}/vendor/symfony/proxy-manager-bridge/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/routing/.git" />
+ <delete dir="${dir}/vendor/symfony/routing/Tests" />
+ <delete file="${dir}/vendor/symfony/routing/.gitignore" />
+ <delete file="${dir}/vendor/symfony/routing/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/routing/README.md" />
+ <delete file="${dir}/vendor/symfony/routing/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/twig-bridge/.git" />
+ <delete dir="${dir}/vendor/symfony/twig-bridge/Tests" />
+ <delete file="${dir}/vendor/symfony/twig-bridge/.gitignore" />
+ <delete file="${dir}/vendor/symfony/twig-bridge/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/twig-bridge/README.md" />
+ <delete file="${dir}/vendor/symfony/twig-bridge/phpunit.xml.dist" />
+
+ <delete dir="${dir}/vendor/symfony/yaml/.git" />
+ <delete dir="${dir}/vendor/symfony/yaml/Tests" />
+ <delete file="${dir}/vendor/symfony/yaml/.gitignore" />
+ <delete file="${dir}/vendor/symfony/yaml/CHANGELOG.md" />
+ <delete file="${dir}/vendor/symfony/yaml/README.md" />
+ <delete file="${dir}/vendor/symfony/yaml/phpunit.xml.dist" />
<delete dir="${dir}/vendor/twig/twig/doc" />
<delete dir="${dir}/vendor/twig/twig/ext" />
@@ -391,6 +535,15 @@
<delete file="${dir}/vendor/twig/twig/CHANGELOG" />
<delete file="${dir}/vendor/twig/twig/phpunit.xml.dist" />
<delete file="${dir}/vendor/twig/twig/README.rst" />
+
+ <delete file="${dir}/vendor/zendframework/zend-code/CONTRIBUTING.md" />
+ <delete file="${dir}/vendor/zendframework/zend-code/README.md" />
+
+ <delete file="${dir}/vendor/zendframework/zend-eventmanager/CONTRIBUTING.md" />
+ <delete file="${dir}/vendor/zendframework/zend-eventmanager/README.md" />
+
+ <delete file="${dir}/vendor/zendframework/zend-stdlib/CONTRIBUTING.md" />
+ <delete file="${dir}/vendor/zendframework/zend-stdlib/README.md" />
</target>
<target name="clean-diff-dir">
diff --git a/build/build_helper.php b/build/build_helper.php
index 3ff1b89eab..c33e2419c6 100644
--- a/build/build_helper.php
+++ b/build/build_helper.php
@@ -33,14 +33,14 @@ class build_package
var $status_begun = false;
var $num_dots = 0;
- function build_package($versions, $verbose = false)
+ function __construct($versions, $verbose = false)
{
$this->versions = $versions;
$this->verbose = $verbose;
// Get last two entries
- $_latest = $this->versions[sizeof($this->versions) - 1];
- $_before = $this->versions[sizeof($this->versions) - 2];
+ $_latest = $this->versions[count($this->versions) - 1];
+ $_before = $this->versions[count($this->versions) - 2];
$this->locations = array(
'new_version' => dirname(dirname(__FILE__)) . '/phpBB/',
diff --git a/build/code_sniffer/phpbb/Sniffs/Namespaces/UnusedUseSniff.php b/build/code_sniffer/phpbb/Sniffs/Namespaces/UnusedUseSniff.php
index 3125e4f05f..b3cdbf7496 100644
--- a/build/code_sniffer/phpbb/Sniffs/Namespaces/UnusedUseSniff.php
+++ b/build/code_sniffer/phpbb/Sniffs/Namespaces/UnusedUseSniff.php
@@ -87,6 +87,11 @@ class phpbb_Sniffs_Namespaces_UnusedUseSniff implements PHP_CodeSniffer_Sniff
$old_simple_statement = $simple_statement;
$simple_class_name_start = $phpcsFile->findNext(array(T_NS_SEPARATOR, T_STRING), ($simple_statement + 1));
+
+ if ($simple_class_name_start === false) {
+ continue;
+ }
+
$simple_class_name_end = $phpcsFile->findNext($find, ($simple_statement + 1), null, true);
$simple_class_name = trim($phpcsFile->getTokensAsString($simple_class_name_start, ($simple_class_name_end - $simple_class_name_start)));
diff --git a/build/generate_package_json.php b/build/generate_package_json.php
new file mode 100644
index 0000000000..152f38958a
--- /dev/null
+++ b/build/generate_package_json.php
@@ -0,0 +1,127 @@
+#!/usr/bin/env php
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+if (version_compare(PHP_VERSION, '7.0-dev', '<'))
+{
+ die('generate_package_json.php requires at least PHP 7.0.');
+}
+
+define('IN_PHPBB', true);
+include_once('../phpBB/includes/functions.php');
+
+$json_data = new \stdClass();
+$json_data->metadata = new stdClass();
+
+$json_data->metadata->current_version_date = '';
+$json_data->metadata->current_version = '';
+$json_data->metadata->download_path = '';
+$json_data->metadata->show_update_package = true;
+$json_data->metadata->historic = false;
+
+$json_data->package = [];
+
+// Open build.xml
+$build_xml = simplexml_load_file('build.xml');
+$current_version = (string) $build_xml->xpath('/project/property[@name=\'newversion\']/@value')[0]->value;
+$previous_version = (string) $build_xml->xpath('/project/property[@name=\'prevversion\']/@value')[0]->value;
+$older_verions = explode(', ', (string) $build_xml->xpath('/project/property[@name=\'olderversions\']/@value')[0]->value);
+
+// Clean and sort version info
+$older_verions[] = $previous_version;
+$older_verions = array_filter($older_verions, function($version) {
+ preg_match(get_preg_expression('semantic_version'), $version, $matches);
+ return empty($matches['prerelease']) || strpos($matches['prerelease'], 'pl') !== false;
+});
+usort($older_verions, function($version_a, $version_b)
+{
+ return phpbb_version_compare($version_b, $version_a);
+});
+
+// Set metadata
+$json_data->metadata->current_version = $current_version;
+$json_data->metadata->current_version_date = date('Y-m-d');
+$json_data->metadata->download_path = 'https://download.phpbb.com/pub/release/' . preg_replace('#([0-9]+\.[0-9]+)(\..+)#', '$1', $current_version) . '/' . $current_version . '/';
+
+// Add package, patch files, and changed files
+phpbb_add_package_file(
+ $json_data->package,
+ 'phpBB ' . $current_version,
+ 'phpBB-' . $current_version,
+ 'full',
+ ''
+);
+phpbb_add_package_file(
+ $json_data->package,
+ 'phpBB ' . $current_version . ' Patch Files',
+ 'phpBB-' . $current_version . '-patch',
+ 'update',
+ 'patch'
+);
+phpbb_add_package_file(
+ $json_data->package,
+ 'phpBB ' . $current_version . ' Changed Files',
+ 'phpBB-' . $current_version . '-files',
+ 'update',
+ 'files'
+);
+
+// Loop through packages and assign to packages array
+foreach ($older_verions as $version)
+{
+ phpbb_add_package_file(
+ $json_data->package,
+ 'phpBB ' . $version . ' to ' . $current_version . ' Update Package',
+ 'phpBB-' . $version . '_to_' . $current_version,
+ 'update',
+ 'update',
+ $version
+ );
+}
+
+echo(json_encode($json_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
+
+function phpbb_add_package_file(array &$package_list, $name, $file_name, $type, $subtype, $from = '')
+{
+ if (!file_exists(__DIR__ . '/new_version/release_files/' . $file_name . '.zip'))
+ {
+ trigger_error('File does not exist: ' . __DIR__ . '/new_version/release_files/' . $file_name . '.zip');
+ return;
+ }
+
+ $package_file = new stdClass();
+ $package_file->name = $name;
+ $package_file->filename = $file_name;
+ $package_file->type = $type;
+ if (!empty($subtype))
+ {
+ $package_file->subtype = $subtype;
+ }
+ if (!empty($from))
+ {
+ $package_file->from = $from;
+ }
+ $package_file->files = [];
+
+ foreach (['zip', 'tar.bz2'] as $extension)
+ {
+ $file_path = 'new_version/release_files/' . $file_name . '.' . $extension;
+ $filedata = new stdClass();
+ $filedata->filesize = filesize($file_path);
+ $filedata->checksum = trim(preg_replace('/(^\w+)(.+)/', '$1', file_get_contents($file_path . '.sha256')));
+ $filedata->filetype = $extension;
+ $package_file->files[] = $filedata;
+ }
+
+ $package_list[] = $package_file;
+}
diff --git a/build/package.php b/build/package.php
index d168957ca5..18798d0602 100755
--- a/build/package.php
+++ b/build/package.php
@@ -33,7 +33,7 @@ echo "Now all three package types (patch, files, release) are built as well as t
// Go trough all versions making a diff if we even have old versions
// For phpBB 3.0.x we might choose a different update method, rendering the things below useless...
-if (sizeof($package->old_packages))
+if (count($package->old_packages))
{
chdir($package->locations['old_versions']);
@@ -76,7 +76,7 @@ if (sizeof($package->old_packages))
// Create Directories along the way?
$file = explode('/', $file);
// Remove filename portion
- $file[sizeof($file)-1] = '';
+ $file[count($file)-1] = '';
chdir($dest_filename_dir);
foreach ($file as $entry)
@@ -169,7 +169,7 @@ if (sizeof($package->old_packages))
// Create Directories along the way?
$file = explode('/', $file);
// Remove filename portion
- $file[sizeof($file)-1] = '';
+ $file[count($file)-1] = '';
chdir($dest_filename_dir . '/install/update/old');
foreach ($file as $entry)
@@ -196,9 +196,10 @@ if (sizeof($package->old_packages))
*/
$copy_relative_directories = array(
'config/' => array(
+ 'recursive' => true,
'copied' => false,
'copy' => array(
- 'config/*.yml' => 'config',
+ 'config/*' => 'config',
),
),
);
@@ -213,7 +214,7 @@ if (sizeof($package->old_packages))
// Create Directories along the way?
$file = explode('/', $file);
// Remove filename portion
- $file[sizeof($file)-1] = '';
+ $file[count($file)-1] = '';
chdir($dest_filename_dir . '/install/update/new');
foreach ($file as $entry)
@@ -256,7 +257,15 @@ if (sizeof($package->old_packages))
}
$source_dir_files = $package->locations['old_versions'] . $package->get('simple_name') . '/' . $source_dir_files;
$destination_dir = $dest_filename_dir . '/install/update/new/' . $destination_dir;
- $package->run_command('cp ' . $source_dir_files . ' ' . $destination_dir);
+
+ if (isset($data['recursive']) && $data['recursive'])
+ {
+ $package->run_command('cp -Rp ' . $source_dir_files . ' ' . $destination_dir);
+ }
+ else
+ {
+ $package->run_command('cp ' . $source_dir_files . ' ' . $destination_dir);
+ }
}
$copy_relative_directories[$reference]['copied'] = true;
}
@@ -272,7 +281,7 @@ if (sizeof($package->old_packages))
'adm/style/admin.css' => 'adm/style',
'adm/style/admin.js' => 'adm/style',
'adm/style/ajax.js' => 'adm/style',
- 'adm/style/install_*' => 'adm/style',
+ 'adm/style/installer_*' => 'adm/style',
'assets/javascript/*' => 'assets/javascript',
);
@@ -312,7 +321,7 @@ $update_info = array(
\'version\' => array(\'from\' => \'' . str_replace('_to_', '', $package->old_packages[$_package_name]) . '\', \'to\' => \'' . $package->get('new_version_number') . '\'),
';
- if (sizeof($file_contents['all']))
+ if (count($file_contents['all']))
{
$index_contents .= "\t'files' => array(\n\t\t'" . implode("',\n\t\t'", $file_contents['all']) . "',\n\t),\n";
}
@@ -321,7 +330,7 @@ $update_info = array(
$index_contents .= "\t'files' => array(),\n";
}
- if (sizeof($file_contents['binary']))
+ if (count($file_contents['binary']))
{
$index_contents .= "\t'binary' => array(\n\t\t'" . implode("',\n\t\t'", $file_contents['binary']) . "',\n\t),\n";
}
@@ -330,7 +339,7 @@ $update_info = array(
$index_contents .= "\t'binary' => array(),\n";
}
- if (sizeof($file_contents['deleted']))
+ if (count($file_contents['deleted']))
{
$index_contents .= "\t'deleted' => array(\n\t\t'" . implode("',\n\t\t'", $file_contents['deleted']) . "',\n\t),\n";
}
@@ -371,7 +380,7 @@ $compress_programs = array(
'zip' => 'zip -r'
);
-if (sizeof($package->old_packages))
+if (count($package->old_packages))
{
// Build Patch Files
chdir($package->get('patch_directory'));
@@ -470,22 +479,14 @@ chdir($package->get('dest_dir') . '/install');
// $package->run_command('rm -v database_update.php');
$package->run_command('rm -v install_update.php');
-chdir($package->get('dest_dir'));
-$package->run_command('mv -v styles/subsilver2 ../subsilver2');
-$package->run_command('cp -p docs/COPYING ../subsilver2/license.txt');
-
chdir($package->locations['package_dir']);
foreach ($compress_programs as $extension => $compress_command)
{
$package->begin_status('Packaging phpBB for ' . $extension);
$package->run_command('rm -v ./release_files/' . $package->get('release_filename') . ".{$extension}");
- $package->run_command('rm -v ./release_files/subsilver2_' . $package->get('new_version_number') . ".{$extension}");
// Build Package
$package->run_command("$compress_command ./release_files/" . $package->get('release_filename') . '.' . $extension . ' ' . $package->get('package_name'));
-
- // Build subSilver2 Package
- $package->run_command("$compress_command ./release_files/subsilver2_" . $package->get('new_version_number') . '.' . $extension . ' subsilver2');
}
// Microsoft Web PI packaging
diff --git a/composer.phar b/composer.phar
index fca2a8d72d..8c3f0fada9 100755
--- a/composer.phar
+++ b/composer.phar
Binary files differ
diff --git a/git-tools/hooks/commit-msg b/git-tools/hooks/commit-msg
index 136606252c..b73005b34d 100755
--- a/git-tools/hooks/commit-msg
+++ b/git-tools/hooks/commit-msg
@@ -147,6 +147,15 @@ then
quit $ERR_LENGTH;
fi
+# Check for CR/LF line breaks
+if grep -q $'\r$' "$1"
+then
+ complain "The commit message uses CR/LF line breaks, which are not permitted." >&2
+ complain >&2
+
+ quit $ERR_EOF;
+fi
+
lines=$(wc -l "$1" | awk '{ print $1; }');
expecting=header;
in_description=0;
diff --git a/phpBB/adm/index.php b/phpBB/adm/index.php
index 519f6c8310..d27f56f28b 100644
--- a/phpBB/adm/index.php
+++ b/phpBB/adm/index.php
@@ -41,6 +41,7 @@ if (!isset($user->data['session_admin']) || !$user->data['session_admin'])
// check specific permissions but this is a catchall
if (!$auth->acl_get('a_'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_ADMIN');
}
@@ -50,8 +51,8 @@ define('IN_ADMIN', true);
// Some oft used variables
$safe_mode = (@ini_get('safe_mode') == '1' || strtolower(@ini_get('safe_mode')) === 'on') ? true : false;
$file_uploads = (@ini_get('file_uploads') == '1' || strtolower(@ini_get('file_uploads')) === 'on') ? true : false;
-$module_id = request_var('i', '');
-$mode = request_var('mode', '');
+$module_id = $request->variable('i', '');
+$mode = $request->variable('mode', '');
// Set custom style for admin area
$template->set_custom_style(array(
diff --git a/phpBB/adm/style/acp_attachments.html b/phpBB/adm/style/acp_attachments.html
index e1f7f140c9..7a66f170ac 100644
--- a/phpBB/adm/style/acp_attachments.html
+++ b/phpBB/adm/style/acp_attachments.html
@@ -37,12 +37,6 @@
<!-- IF S_ATTACHMENT_SETTINGS -->
- <!-- IF not S_THUMBNAIL_SUPPORT -->
- <div class="errorbox">
- <p>{L_NO_THUMBNAIL_SUPPORT}</p>
- </div>
- <!-- ENDIF -->
-
<form id="attachsettings" method="post" action="{U_ACTION}">
<!-- BEGIN options -->
<!-- IF options.S_LEGEND -->
@@ -116,7 +110,7 @@
<!-- ELSEIF S_EXTENSION_GROUPS -->
<!-- IF S_EDIT_GROUP -->
- <script type="text/javascript" defer="defer">
+ <script>
// <![CDATA[
function update_image(newimage)
{
@@ -329,42 +323,71 @@
<fieldset class="tabulated">
<legend>{L_TITLE}</legend>
- <table class="table1 zebra-table fixed-width-table">
- <thead>
- <tr>
- <th>{L_FILENAME}</th>
- <th style="width: 15%;">{L_FILEDATE}</th>
- <th style="width: 15%;">{L_FILESIZE}</th>
- <th style="width: 15%;">{L_ATTACH_POST_ID}</th>
- <th style="width: 15%;">{L_ATTACH_TO_POST}</th>
- <th style="width: 15%;">{L_DELETE}</th>
- </tr>
- </thead>
- <tbody>
- <!-- BEGIN orphan -->
+ <div class="pagination top-pagination">
+ <!-- IF .pagination or TOTAL_FILES -->
+ {L_NUMBER_FILES}{L_COLON} {TOTAL_FILES} &bull; {L_TOTAL_SIZE}{L_COLON} {TOTAL_SIZE}
+ <!-- IF .pagination -->
+ &bull; <!-- INCLUDE pagination.html -->
+ <!-- ELSE -->
+ &bull; {PAGE_NUMBER}
+ <!-- ENDIF -->
+ <!-- ENDIF -->
+ </div>
+
+ <!-- IF .orphan -->
+ <table class="table1 zebra-table fixed-width-table">
+ <thead>
<tr>
- <td><a href="{orphan.U_FILE}">{orphan.REAL_FILENAME}</a></td>
- <td>{orphan.FILETIME}</td>
- <td>{orphan.FILESIZE}</td>
- <td><strong>{L_ATTACH_ID}{L_COLON} </strong><input type="number" min="0" max="9999999999" name="post_id[{orphan.ATTACH_ID}]" value="{orphan.POST_ID}" style="width: 75%;" /></td>
- <td><input type="checkbox" class="radio" name="add[{orphan.ATTACH_ID}]" /></td>
- <td><input type="checkbox" class="radio" name="delete[{orphan.ATTACH_ID}]" /></td>
+ <th>{L_FILENAME}</th>
+ <th style="width: 15%;">{L_FILEDATE}</th>
+ <th style="width: 15%;">{L_FILESIZE}</th>
+ <th style="width: 15%;">{L_ATTACH_POST_ID}</th>
+ <th style="width: 15%;">{L_ATTACH_TO_POST}</th>
+ <th style="width: 15%;">{L_DELETE}</th>
</tr>
- <!-- END orphan -->
- <tr class="row4">
- <td colspan="4">&nbsp;</td>
- <td class="small"><a href="#" onclick="marklist('orphan', 'add', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('orphan', 'add', false); return false;">{L_UNMARK_ALL}</a></td>
- <td class="small"><a href="#" onclick="marklist('orphan', 'delete', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('orphan', 'delete', false); return false;">{L_UNMARK_ALL}</a></td>
- </tr>
- </tbody>
- </table>
+ </thead>
+ <tbody>
+ <!-- BEGIN orphan -->
+ <tr>
+ <td><a href="{orphan.U_FILE}">{orphan.REAL_FILENAME}</a></td>
+ <td>{orphan.FILETIME}</td>
+ <td>{orphan.FILESIZE}</td>
+ <td><strong>{L_ATTACH_ID}{L_COLON} </strong><input type="number" min="0" max="9999999999" name="post_id[{orphan.ATTACH_ID}]" value="{orphan.POST_ID}" style="width: 75%;" /></td>
+ <td><input type="checkbox" class="radio" name="add[{orphan.ATTACH_ID}]" /></td>
+ <td><input type="checkbox" class="radio" name="delete[{orphan.ATTACH_ID}]" /></td>
+ </tr>
+ <!-- END orphan -->
+ <tr class="row4">
+ <td colspan="4">&nbsp;</td>
+ <td class="small"><a href="#" onclick="marklist('orphan', 'add', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('orphan', 'add', false); return false;">{L_UNMARK_ALL}</a></td>
+ <td class="small"><a href="#" onclick="marklist('orphan', 'delete', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('orphan', 'delete', false); return false;">{L_UNMARK_ALL}</a></td>
+ </tr>
+ </tbody>
+ </table>
+ <!-- ELSE -->
+ <div class="errorbox">
+ <p>{L_NO_ATTACHMENTS}</p>
+ </div>
+ <!-- ENDIF -->
+
+ <!-- IF TOTAL_FILES -->
+ <div class="pagination">
+ {L_NUMBER_FILES}{L_COLON} {TOTAL_FILES} &bull; {L_TOTAL_SIZE}{L_COLON} {TOTAL_SIZE}
+ <!-- IF .pagination -->
+ &bull; <!-- INCLUDE pagination.html -->
+ <!-- ELSE -->
+ &bull; {PAGE_NUMBER}
+ <!-- ENDIF -->
+ </div>
+ <!-- ENDIF -->
- <br />
+ <!-- IF .orphan -->
+ <p class="submit-buttons">
+ <input class="button1" type="submit" id="submit" name="submit" value="{L_SUBMIT}" />&nbsp;
+ <input class="button2" type="reset" id="reset" name="reset" value="{L_RESET}" />
+ </p>
+ <!-- ENDIF -->
- <p class="submit-buttons">
- <input class="button1" type="submit" id="submit" name="submit" value="{L_SUBMIT}" />&nbsp;
- <input class="button2" type="reset" id="reset" name="reset" value="{L_RESET}" />
- </p>
{S_FORM_TOKEN}
</fieldset>
</form>
@@ -398,17 +421,25 @@
</tr>
</thead>
<tbody>
- <!-- BEGIN attachments -->
+ {% for attachments in attachments %}
<tr>
<td>
- <!-- IF attachments.S_IN_MESSAGE -->{L_EXTENSION_GROUP}{L_COLON} <strong><!-- IF attachments.EXT_GROUP_NAME -->{attachments.EXT_GROUP_NAME}<!-- ELSE -->{L_NO_EXT_GROUP}<!-- ENDIF --></strong><br />{attachments.L_DOWNLOAD_COUNT}<br />{L_IN} {L_PRIVATE_MESSAGE}
- <!-- ELSE --><a href="{attachments.U_FILE}" style="font-weight: bold;">{attachments.REAL_FILENAME}</a><br /><!-- IF attachments.COMMENT -->{attachments.COMMENT}<br /><!-- ENDIF -->{attachments.L_DOWNLOAD_COUNT}<br />{L_TOPIC}{L_COLON} <a href="{attachments.U_VIEW_TOPIC}">{attachments.TOPIC_TITLE}</a><!-- ENDIF -->
+ {{ lang('EXTENSION_GROUP') ~ lang('COLON') }} <strong>{{ attachments.EXT_GROUP_NAME }}</strong>
+ {% if attachments.S_IN_MESSAGE %}
+ <br>{{ attachments.L_DOWNLOAD_COUNT }}
+ <br>{{ lang('IN') }} {{ lang('PRIVATE_MESSAGE') }}
+ {% else %}
+ <br><a href="{{ attachments.U_FILE }}"><strong>{{ attachments.REAL_FILENAME }}</strong></a>
+ {% if attachments.COMMENT %}<br>{{ attachments.COMMENT }}{% endif %}
+ <br>{{ attachments.L_DOWNLOAD_COUNT }}
+ <br>{{ lang('TOPIC') ~ lang('COLON') }} <a href="{{ attachments.U_VIEW_TOPIC }}">{{ attachments.TOPIC_TITLE }}</a>
+ {% endif %}
</td>
- <td>{attachments.FILETIME}<br />{L_POST_BY_AUTHOR} {attachments.ATTACHMENT_POSTER}</td>
- <td class="centered-text">{attachments.FILESIZE}</td>
- <td class="centered-text"><input type="checkbox" class="radio" name="delete[{attachments.ATTACH_ID}]" /></td>
+ <td>{{ attachments.FILETIME }}<br>{{ lang('POST_BY_AUTHOR') }} {{ attachments.ATTACHMENT_POSTER }}</td>
+ <td class="centered-text">{{ attachments.FILESIZE }}</td>
+ <td class="centered-text"><input type="checkbox" class="radio" name="delete[{{ attachments.ATTACH_ID }}]" /></td>
</tr>
- <!-- END attachments -->
+ {% endfor %}
</tbody>
</table>
<!-- ELSE -->
@@ -440,7 +471,7 @@
<input class="button2" type="submit" name="submit" value="{L_DELETE_MARKED}" /><br />
<p class="small">
<a href="#" onclick="marklist('attachments', 'delete', true); return false;">{L_MARK_ALL}</a> &bull;
- <a href="#" onclick="marklist('attachments', 'delete', false); return false;">{L_UNMARK_ALL}</a>
+ <a href="#" onclick="marklist('attachments', 'delete', false); return false;">{L_UNMARK_ALL}</a>
</p>
</fieldset>
<!-- ENDIF -->
diff --git a/phpBB/adm/style/acp_ban.html b/phpBB/adm/style/acp_ban.html
index f2249941a5..d0eab75ad8 100644
--- a/phpBB/adm/style/acp_ban.html
+++ b/phpBB/adm/style/acp_ban.html
@@ -8,7 +8,7 @@
<p>{L_EXPLAIN}</p>
-<script type="text/javascript">
+<script>
// <![CDATA[
var ban_length = new Array();
diff --git a/phpBB/adm/style/acp_board.html b/phpBB/adm/style/acp_board.html
index 64592a5de2..fe3e250099 100644
--- a/phpBB/adm/style/acp_board.html
+++ b/phpBB/adm/style/acp_board.html
@@ -18,10 +18,11 @@
<!-- BEGIN options -->
<!-- IF options.S_LEGEND -->
<!-- IF not options.S_FIRST_ROW -->
- </fieldset>
+ </fieldset>
<!-- ENDIF -->
+
<fieldset>
- <legend>{options.LEGEND}</legend>
+ <legend>{options.LEGEND}</legend>
<!-- ELSE -->
<dl>
diff --git a/phpBB/adm/style/acp_contact.html b/phpBB/adm/style/acp_contact.html
index 828fd4b659..d63fd08a3a 100644
--- a/phpBB/adm/style/acp_contact.html
+++ b/phpBB/adm/style/acp_contact.html
@@ -1,6 +1,6 @@
<!-- INCLUDE overall_header.html -->
-<script type="text/javascript">
+<script>
// <![CDATA[
var form_name = 'acp_contact';
diff --git a/phpBB/adm/style/acp_database.html b/phpBB/adm/style/acp_database.html
index 39f06319f9..d3433a8aa6 100644
--- a/phpBB/adm/style/acp_database.html
+++ b/phpBB/adm/style/acp_database.html
@@ -20,7 +20,6 @@
<p class="submit-buttons">
<input class="button1" type="submit" id="submit" name="submit" value="{L_START_RESTORE}" />&nbsp;
<input class="button2" type="submit" id="delete" name="delete" value="{L_DELETE_BACKUP}" />&nbsp;
- <input class="button2" type="submit" id="download" name="download" value="{L_DOWNLOAD_BACKUP}" />
</p>
{S_FORM_TOKEN}
</fieldset>
@@ -36,7 +35,7 @@
<p>{L_ACP_BACKUP_EXPLAIN}</p>
- <script type="text/javascript">
+ <script>
// <![CDATA[
function selector(bool)
@@ -69,13 +68,6 @@
<!-- END methods --></dd>
</dl>
<dl>
- <dt><label for="where">{L_ACTION}{L_COLON}</label></dt>
- <dd>
- <label><input id="where" type="radio" class="radio" name="where" value="store" checked="checked" /> {L_STORE_LOCAL}</label>
- <label><input type="radio" class="radio" name="where" value="download" /> {L_DOWNLOAD}</label>
- </dd>
- </dl>
- <dl>
<dt><label for="table">{L_TABLE_SELECT}{L_COLON}</label></dt>
<dd><select id="table" name="table[]" size="10" multiple="multiple">
<!-- BEGIN tables -->
diff --git a/phpBB/adm/style/acp_ext_details.html b/phpBB/adm/style/acp_ext_details.html
index bd9eca623a..bbddf2e6b6 100644
--- a/phpBB/adm/style/acp_ext_details.html
+++ b/phpBB/adm/style/acp_ext_details.html
@@ -7,19 +7,17 @@
<h1>{L_EXTENSIONS_ADMIN}</h1>
<!-- IF S_VERSIONCHECK -->
- <div class="<!-- IF S_UP_TO_DATE -->successbox<!-- ELSE -->errorbox<!-- ENDIF -->">
- <p>{UP_TO_DATE_MSG} - <a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a></p>
- </div>
- <!-- ELSE IF S_VERSIONCHECK_STATUS == 0 -->
- <div class="errorbox notice">
- <p>{L_VERSIONCHECK_FAIL}</p>
- <p>{VERSIONCHECK_FAIL_REASON}</p>
- <p><a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a></p>
- </div>
- <!-- ELSE IF S_VERSIONCHECK_STATUS == 1 -->
- <div class="errorbox notice">
- <p>{VERSIONCHECK_FAIL_REASON}</p>
- </div>
+ <!-- IF S_VERSIONCHECK_FAIL -->
+ <div class="errorbox notice">
+ <p>{L_VERSIONCHECK_FAIL}</p>
+ <p>{VERSIONCHECK_FAIL_REASON}</p>
+ <p><a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a></p>
+ </div>
+ <!-- ELSE -->
+ <div class="<!-- IF S_UP_TO_DATE -->successbox<!-- ELSE -->errorbox<!-- ENDIF -->">
+ <p>{UP_TO_DATE_MSG} - <a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a></p>
+ </div>
+ <!-- ENDIF -->
<!-- ENDIF -->
<!-- EVENT acp_ext_details_notice -->
diff --git a/phpBB/adm/style/acp_ext_list.html b/phpBB/adm/style/acp_ext_list.html
index af9e00a614..8e2c7452a3 100644
--- a/phpBB/adm/style/acp_ext_list.html
+++ b/phpBB/adm/style/acp_ext_list.html
@@ -7,7 +7,7 @@
<p>{L_EXTENSIONS_EXPLAIN}</p>
<fieldset class="quick">
- <span class="small"><a href="https://www.phpbb.com/go/customise/extensions/3.1" target="_blank">{L_BROWSE_EXTENSIONS_DATABASE}</a> &bull; <a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE_ALL}</a> &bull; <a href="javascript:phpbb.toggleDisplay('version_check_settings');">{L_SETTINGS}</a></span>
+ <span class="small"><a href="https://www.phpbb.com/go/customise/extensions/3.2" target="_blank">{L_BROWSE_EXTENSIONS_DATABASE}</a> &bull; <a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE_ALL}</a> &bull; <a href="javascript:phpbb.toggleDisplay('version_check_settings');">{L_SETTINGS}</a></span>
</fieldset>
<form id="version_check_settings" method="post" action="{U_ACTION}" style="display:none">
@@ -51,7 +51,8 @@
<td><strong title="{enabled.NAME}">{enabled.META_DISPLAY_NAME}</strong><!-- EVENT acp_ext_list_enabled_name_after --></td>
<td style="text-align: center;">
<!-- IF enabled.S_VERSIONCHECK -->
- <strong <!-- IF enabled.S_UP_TO_DATE -->style="color: #228822;"<!-- ELSE -->style="color: #BC2A4D;"<!-- ENDIF -->>{enabled.META_VERSION}</strong>
+ <strong class="<!-- IF enabled.S_UP_TO_DATE -->current-ext<!-- ELSE -->outdated-ext<!-- ENDIF -->">{enabled.META_VERSION}</strong>
+ <!-- IF not enabled.S_UP_TO_DATE --><i class="fa fa-exclamation-circle outdated-ext" aria-hidden="true"></i><!-- ENDIF -->
<!-- ELSE -->
{enabled.META_VERSION}
<!-- ENDIF -->
@@ -76,7 +77,8 @@
<td><strong title="{disabled.NAME}">{disabled.META_DISPLAY_NAME}</strong><!-- EVENT acp_ext_list_disabled_name_after --></td>
<td style="text-align: center;">
<!-- IF disabled.S_VERSIONCHECK -->
- <strong <!-- IF disabled.S_UP_TO_DATE -->style="color: #228822;"<!-- ELSE -->style="color: #BC2A4D;"<!-- ENDIF -->>{disabled.META_VERSION}</strong>
+ <strong class="<!-- IF disabled.S_UP_TO_DATE -->current-ext<!-- ELSE -->outdated-ext<!-- ENDIF -->">{disabled.META_VERSION}</strong>
+ <!-- IF not disabled.S_UP_TO_DATE --><i class="fa fa-exclamation-circle outdated-ext" aria-hidden="true"></i><!-- ENDIF -->
<!-- ELSE -->
{disabled.META_VERSION}
<!-- ENDIF -->
diff --git a/phpBB/adm/style/acp_forums.html b/phpBB/adm/style/acp_forums.html
index 965438ff67..20bcd2e9f9 100644
--- a/phpBB/adm/style/acp_forums.html
+++ b/phpBB/adm/style/acp_forums.html
@@ -4,7 +4,7 @@
<!-- IF S_EDIT_FORUM -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
/**
* Handle displaying/hiding several options based on the forum type
@@ -405,7 +405,7 @@
<!-- ELSEIF S_CONTINUE_SYNC -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
var close_waitscreen = 0;
// no scrollbars...
@@ -421,7 +421,7 @@
<!-- ELSE -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
/**
* Popup search progress bar
@@ -447,7 +447,7 @@
<!-- ENDIF -->
<!-- IF S_RESYNCED -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
var close_waitscreen = 1;
// ]]>
diff --git a/phpBB/adm/style/acp_groups.html b/phpBB/adm/style/acp_groups.html
index 1412744cc9..723a190899 100644
--- a/phpBB/adm/style/acp_groups.html
+++ b/phpBB/adm/style/acp_groups.html
@@ -36,10 +36,12 @@
<dl>
<dt><label for="group_type">{L_GROUP_TYPE}{L_COLON}</label><br /><span>{L_GROUP_TYPE_EXPLAIN}</span></dt>
<dd>
+ {% EVENT acp_group_types_prepend %}
<label><input name="group_type" type="radio" class="radio" id="group_type" value="{GROUP_TYPE_FREE}"{GROUP_FREE} /> {L_GROUP_OPEN}</label>
<label><input name="group_type" type="radio" class="radio" value="{GROUP_TYPE_OPEN}"{GROUP_OPEN} /> {L_GROUP_REQUEST}</label>
<label><input name="group_type" type="radio" class="radio" value="{GROUP_TYPE_CLOSED}"{GROUP_CLOSED} /> {L_GROUP_CLOSED}</label>
<label><input name="group_type" type="radio" class="radio" value="{GROUP_TYPE_HIDDEN}"{GROUP_HIDDEN} /> {L_GROUP_HIDDEN}</label>
+ {% EVENT acp_group_types_append %}
</dd>
</dl>
<!-- ELSE -->
@@ -267,11 +269,12 @@
<!-- EVENT acp_groups_manage_before -->
<table class="table1">
- <col class="col1" /><col class="col1" /><col class="col2" /><col class="col2" /><col class="col2" />
+ <col class="col1" /><col class="col1" /><col class="col1" /><col class="col2" /><col class="col2" /><col class="col2" />
<thead>
<tr>
<th style="width: 50%">{L_GROUP}</th>
<th>{L_TOTAL_MEMBERS}</th>
+ <th>{L_PENDING_MEMBERS}</th>
<th colspan="2">{L_OPTIONS}</th>
<th>{L_ACTION}</th>
</tr>
@@ -281,7 +284,7 @@
<!-- IF groups.S_SPECIAL -->
<!-- IF groups.S_FIRST_ROW -->
<tr>
- <td colspan="5" class="row3">{L_NO_GROUPS_CREATED}</td>
+ <td colspan="6" class="row3">{L_NO_GROUPS_CREATED}</td>
</tr>
<!-- ENDIF -->
</tbody>
@@ -302,11 +305,12 @@
<p>{L_SPECIAL_GROUPS_EXPLAIN}</p>
<table class="table1">
- <col class="col1" /><col class="col1" /><col class="col2" /><col class="col2" /><col class="col2" />
+ <col class="col1" /><col class="col1" /><col class="col1" /><col class="col2" /><col class="col2" />
<thead>
<tr>
<th style="width: 50%">{L_GROUP}</th>
<th>{L_TOTAL_MEMBERS}</th>
+ <th>{L_PENDING_MEMBERS}</th>
<th colspan="2">{L_OPTIONS}</th>
<th>{L_ACTION}</th>
</tr>
@@ -314,8 +318,9 @@
<tbody>
<!-- ELSE -->
<tr>
- <td><strong>{groups.GROUP_NAME}</strong></td>
+ <td><strong<!-- IF groups.GROUP_COLOR --> style="color: #{groups.GROUP_COLOR}"<!-- ENDIF -->>{groups.GROUP_NAME}</strong></td>
<td style="text-align: center;">{groups.TOTAL_MEMBERS}</td>
+ <td style="text-align: center;">{groups.PENDING_MEMBERS}</td>
<td style="text-align: center;"><a href="{groups.U_EDIT}">{L_SETTINGS}</a></td>
<td style="text-align: center;"><a href="{groups.U_LIST}">{L_MEMBERS}</a></td>
<td style="text-align: center;"><!-- IF not groups.S_GROUP_SPECIAL and groups.U_DELETE --><a href="{groups.U_DELETE}" data-ajax="row_delete">{L_DELETE}</a><!-- ELSE -->{L_DELETE}<!-- ENDIF --></td>
diff --git a/phpBB/adm/style/acp_help_phpbb.html b/phpBB/adm/style/acp_help_phpbb.html
new file mode 100644
index 0000000000..478ecc162a
--- /dev/null
+++ b/phpBB/adm/style/acp_help_phpbb.html
@@ -0,0 +1,61 @@
+<!-- INCLUDE overall_header.html -->
+
+<a id="maincontent"></a>
+
+<h1>{L_ACP_HELP_PHPBB}</h1>
+
+<form id="acp_help_phpbb" method="post" action="{U_ACTION}" data-ajax-action="{U_COLLECT_STATS}">
+<div class="send-stats-row">
+ <!-- EVENT acp_help_phpbb_stats_before -->
+ <div class="send-stats-tile">
+ <h2><i class="icon fa-bar-chart"></i>{L_SEND_STATISTICS}</h2>
+ <p>{L_EXPLAIN_SEND_STATISTICS}</p>
+ <div class="send-stats-row">
+ <div class="send-stats-data-row send-stats-data-only-row">
+ <a id="trigger-configlist" data-ajax="toggle_link" data-overlay="false" data-toggle-text="{L_HIDE_STATISTICS}"><span>{L_SHOW_STATISTICS}</span><i class="icon fa-angle-down"></i></a>
+ </div>
+ <div class="send-stats-data-row">
+ <div class="configlist" id="configlist">
+ <!-- BEGIN providers -->
+ <fieldset>
+ <legend>{providers.NAME}</legend>
+ <!-- BEGIN values -->
+ <dl>
+ <dt>{providers.values.KEY}</dt>
+ <dd>{providers.values.VALUE}</dd>
+ </dl>
+ <!-- END values -->
+ </fieldset>
+ <!-- END providers -->
+ </div>
+ </div>
+ </div>
+ <dl class="send-stats-settings">
+ <dt>
+ <input name="help_send_statistics" id="help_send_statistics" type="checkbox"<!-- IF S_COLLECT_STATS --> checked="checked"<!-- ENDIF --> />
+ <label for="help_send_statistics"></label>
+ </dt>
+ <dd>{L_SEND_STATISTICS_LONG}</dd>
+ </dl>
+ </div>
+ <!-- EVENT acp_help_phpbb_stats_after -->
+ <fieldset>
+ <p class="submit-buttons">
+ <input type="hidden" name="systemdata" value="{RAW_DATA}" />
+ <input type="hidden" name="help_send_statistics_time" value="{COLLECT_STATS_TIME}" />
+ <input class="button1" type="submit" id="submit" name="submit" value="{L_SUBMIT}" />
+ </p>
+ {S_FORM_TOKEN}
+ </fieldset>
+</div>
+</form>
+<form action="{U_COLLECT_STATS}" method="post" target="questionaire_result" id="questionnaire-form">
+ <fieldset>
+ <p class="submit-buttons">
+ <input type="hidden" name="systemdata" value="{RAW_DATA}" />
+ <input class="button1" type="submit" id="submit_stats" name="submit" value="{L_SEND_STATISTICS}" />
+ </p>
+ </fieldset>
+</form>
+
+<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/adm/style/acp_icons.html b/phpBB/adm/style/acp_icons.html
index e0d2840bb5..45fe7f8ebc 100644
--- a/phpBB/adm/style/acp_icons.html
+++ b/phpBB/adm/style/acp_icons.html
@@ -4,7 +4,7 @@
<!-- IF S_EDIT -->
- <script type="text/javascript" defer="defer">
+ <script>
// <![CDATA[
<!-- IF S_ADD_CODE -->
@@ -89,6 +89,9 @@
<!-- ENDIF -->
<td>{L_WIDTH}</td>
<td>{L_HEIGHT}</td>
+ <!-- IF not S_SMILIES -->
+ <td>{L_ALT_TEXT}</td>
+ <!-- ENDIF -->
<td>{L_DISPLAY_ON_POSTING}</td>
<!-- IF ID or S_ADD -->
<td>{L_ORDER}</td>
@@ -102,7 +105,7 @@
<!-- BEGIN items -->
<tr>
- <td style="text-align: center;"><img src="{items.IMG_SRC}" alt="" title="" /><input type="hidden" name="image[{items.IMG}]" value="1" /></td>
+ <td style="text-align: center;"><img src="{items.IMG_SRC}" alt="{items.TEXT_ALT}" title="{items.TEXT_ALT}" /><input type="hidden" name="image[{items.IMG}]" value="1" /></td>
<td style="vertical-align: top;">[{items.IMG}]</td>
<!-- IF S_SMILIES -->
<td><input class="text post" type="text" name="code[{items.IMG}]" value="{items.CODE}" size="10" maxlength="50" /></td>
@@ -110,6 +113,9 @@
<!-- ENDIF -->
<td><input class="text post" type="number" min="0" max="999" name="width[{items.IMG}]" value="{items.WIDTH}" /></td>
<td><input class="text post" type="number" min="0" max="999" name="height[{items.IMG}]" value="{items.HEIGHT}" /></td>
+ <!-- IF not S_SMILIES -->
+ <td><input class="text post" type="text" name="alt[{items.IMG}]" value="{items.ALT}" size="10" maxlength="50" /></td>
+ <!-- ENDIF -->
<td>
<input type="checkbox" class="radio" name="display_on_posting[{items.IMG}]"{items.POSTING_CHECKED} onclick="toggle_select('{items.A_IMG}', this.checked, '{items.S_ROW_COUNT}');"/>
<!-- IF items.S_ID -->
diff --git a/phpBB/adm/style/acp_language.html b/phpBB/adm/style/acp_language.html
index f708eb1508..79fef94207 100644
--- a/phpBB/adm/style/acp_language.html
+++ b/phpBB/adm/style/acp_language.html
@@ -69,7 +69,7 @@
<p>{L_ACP_LANGUAGE_PACKS_EXPLAIN}</p>
<fieldset class="quick">
- <span class="small"><a href="https://www.phpbb.com/go/customise/language-packs/3.1" target="_blank">{L_BROWSE_LANGUAGE_PACKS_DATABASE}</a></span>
+ <span class="small"><a href="https://www.phpbb.com/go/customise/language-packs/3.2" target="_blank">{L_BROWSE_LANGUAGE_PACKS_DATABASE}</a></span>
</fieldset>
<table class="table1 zebra-table">
diff --git a/phpBB/adm/style/acp_main.html b/phpBB/adm/style/acp_main.html
index 1bdb7b8d2a..12477a4b77 100644
--- a/phpBB/adm/style/acp_main.html
+++ b/phpBB/adm/style/acp_main.html
@@ -130,8 +130,6 @@
<td>{L_FILES_PER_DAY}{L_COLON} </td>
<td><strong>{FILES_PER_DAY}</strong></td>
</tr>
-
-
<tr>
<td>{L_BOARD_STARTED}{L_COLON} </td>
<td><strong>{START_DATE}</strong></td>
@@ -150,22 +148,31 @@
<td>{L_GZIP_COMPRESSION}{L_COLON} </td>
<td><strong>{GZIP_COMPRESSION}</strong></td>
</tr>
- <!-- IF S_TOTAL_ORPHAN or S_VERSIONCHECK -->
<tr>
+ <td>{L_PHP_VERSION}{L_COLON} </td>
+ <td><strong>{PHP_VERSION_INFO}</strong></td>
+ <!-- IF S_TOTAL_ORPHAN -->
+ <td>{L_NUMBER_ORPHAN}{L_COLON} </td>
+ <td>
+ <!-- IF TOTAL_ORPHAN > 0 -->
+ <a href="{U_ATTACH_ORPHAN}" title="{L_MORE_INFORMATION}"><strong>{TOTAL_ORPHAN}</strong></a>
+ <!-- ELSE -->
+ <strong>{TOTAL_ORPHAN}</strong>
+ <!-- ENDIF -->
+ </td>
+ <!-- ELSE -->
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <!-- ENDIF -->
+ </tr>
<!-- IF S_VERSIONCHECK -->
+ <tr>
<td>{L_BOARD_VERSION}{L_COLON} </td>
<td>
<strong><a href="{U_VERSIONCHECK}" <!-- IF S_VERSION_UP_TO_DATE -->style="color: #228822;" <!-- ELSEIF not S_VERSIONCHECK_FAIL -->style="color: #BC2A4D;" <!-- ENDIF -->title="{L_MORE_INFORMATION}">{BOARD_VERSION}</a></strong> [&nbsp;<a href="{U_VERSIONCHECK_FORCE}">{L_VERSIONCHECK_FORCE_UPDATE}</a>&nbsp;]
</td>
- <!-- ENDIF -->
- <!-- IF S_TOTAL_ORPHAN -->
- <td>{L_NUMBER_ORPHAN}{L_COLON} </td>
- <td><strong>{TOTAL_ORPHAN}</strong></td>
- <!-- ENDIF -->
- <!-- IF not S_TOTAL_ORPHAN or not S_VERSIONCHECK -->
<td>&nbsp;</td>
<td>&nbsp;</td>
- <!-- ENDIF -->
</tr>
<!-- ENDIF -->
</tbody>
diff --git a/phpBB/adm/style/acp_modules.html b/phpBB/adm/style/acp_modules.html
index 3c97706e6a..f4040daaed 100644
--- a/phpBB/adm/style/acp_modules.html
+++ b/phpBB/adm/style/acp_modules.html
@@ -4,7 +4,7 @@
<!-- IF S_EDIT_MODULE -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
function display_options(value)
{
diff --git a/phpBB/adm/style/acp_permission_roles.html b/phpBB/adm/style/acp_permission_roles.html
index b3137f134c..670d5e14c0 100644
--- a/phpBB/adm/style/acp_permission_roles.html
+++ b/phpBB/adm/style/acp_permission_roles.html
@@ -4,7 +4,7 @@
<!-- IF S_EDIT -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
var active_pmask = '0';
var active_fmask = '0';
@@ -20,7 +20,7 @@
// ]]>
</script>
- <script type="text/javascript" src="style/permissions.js"></script>
+ <script src="style/permissions.js"></script>
<a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">&laquo; {L_BACK}</a>
diff --git a/phpBB/adm/style/acp_permissions.html b/phpBB/adm/style/acp_permissions.html
index a4d33ed78b..7766052c59 100644
--- a/phpBB/adm/style/acp_permissions.html
+++ b/phpBB/adm/style/acp_permissions.html
@@ -329,14 +329,9 @@
<br class="responsive-hide" /><br class="responsive-hide" />
<!-- include tooltip file -->
- <script type="text/javascript" src="style/tooltip.js"></script>
- <script type="text/javascript">
- // <![CDATA[
- window.onload = function(){enable_tooltips_select('set-permissions', '{LA_ROLE_DESCRIPTION}', 'role')};
- // ]]>
- </script>
-
- <form id="set-permissions" method="post" action="{U_ACTION}">
+ <!-- INCLUDEJS tooltip.js -->
+
+ <form id="set-permissions" method="post" action="{U_ACTION}" data-role-description="{L_ROLE_DESCRIPTION}">
{S_HIDDEN_FIELDS}
diff --git a/phpBB/adm/style/acp_posting_buttons.html b/phpBB/adm/style/acp_posting_buttons.html
index c3c42f8e82..614d6fae40 100644
--- a/phpBB/adm/style/acp_posting_buttons.html
+++ b/phpBB/adm/style/acp_posting_buttons.html
@@ -1,31 +1,10 @@
-<script type="text/javascript">
+<script>
// <![CDATA[
// Define the bbCode tags
var bbcode = new Array();
var bbtags = new Array('[b]','[/b]','[i]','[/i]','[u]','[/u]','[quote]','[/quote]','[code]','[/code]','[list]','[/list]','[list=]','[/list]','[img]','[/img]','[url]','[/url]','[flash=]', '[/flash]','[size=]','[/size]'<!-- BEGIN custom_tags -->, {custom_tags.BBCODE_NAME}<!-- END custom_tags -->);
- // Helpline messages
- var help_line = {
- b: '{LA_BBCODE_B_HELP}',
- i: '{LA_BBCODE_I_HELP}',
- u: '{LA_BBCODE_U_HELP}',
- q: '{LA_BBCODE_Q_HELP}',
- c: '{LA_BBCODE_C_HELP}',
- l: '{LA_BBCODE_L_HELP}',
- o: '{LA_BBCODE_O_HELP}',
- p: '{LA_BBCODE_P_HELP}',
- w: '{LA_BBCODE_W_HELP}',
- a: '{LA_BBCODE_A_HELP}',
- s: '{LA_BBCODE_S_HELP}',
- f: '{LA_BBCODE_F_HELP}',
- y: '{LA_BBCODE_Y_HELP}',
- d: '{LA_BBCODE_D_HELP}'
- <!-- BEGIN custom_tags -->
- ,cb_{custom_tags.BBCODE_ID}{L_COLON} '{custom_tags.A_BBCODE_HELPLINE}'
- <!-- END custom_tags -->
- }
-
// ]]>
</script>
@@ -65,7 +44,7 @@
</select>
<!-- EVENT acp_posting_buttons_custom_tags_before -->
<!-- BEGIN custom_tags -->
- <input type="button" class="button2" name="addbbcode{custom_tags.BBCODE_ID}" value="{custom_tags.BBCODE_TAG}" onclick="bbstyle({custom_tags.BBCODE_ID})" title="{custom_tags.BBCODE_HELPLINE}" />
+ <input type="button" class="button2" name="addbbcode{custom_tags.BBCODE_ID}" value="{custom_tags.BBCODE_TAG}" onclick="bbstyle({custom_tags.BBCODE_ID})" title="{{ custom_tags.BBCODE_HELPLINE|e('html_attr') }}" />
<!-- END custom_tags -->
</div>
<!-- EVENT acp_posting_buttons_after -->
diff --git a/phpBB/adm/style/acp_profile.html b/phpBB/adm/style/acp_profile.html
index bd3935b464..25bf97efd5 100644
--- a/phpBB/adm/style/acp_profile.html
+++ b/phpBB/adm/style/acp_profile.html
@@ -238,7 +238,7 @@
<form id="profile_fields" method="post" action="{U_ACTION}">
<fieldset class="quick">
- <input class="text small" type="text" name="field_ident" /> <select name="field_type">{S_TYPE_OPTIONS}</select>
+ <select name="field_type">{S_TYPE_OPTIONS}</select>
<input class="button1" type="submit" name="submit" value="{L_CREATE_NEW_FIELD}" />
<input type="hidden" name="create" value="1" />
{S_FORM_TOKEN}
diff --git a/phpBB/adm/style/acp_prune_forums.html b/phpBB/adm/style/acp_prune_forums.html
index b8c681ea00..ef3880e851 100644
--- a/phpBB/adm/style/acp_prune_forums.html
+++ b/phpBB/adm/style/acp_prune_forums.html
@@ -94,7 +94,9 @@
<dd><label><input type="radio" class="radio" name="prune_sticky" value="1" /> {L_YES}</label>
<label><input type="radio" class="radio" id="sticky" name="prune_sticky" value="0" checked="checked" /> {L_NO}</label></dd>
</dl>
-
+
+ <!-- EVENT acp_prune_forums_settings_append -->
+
<p class="quick">
{S_HIDDEN_FIELDS}
{S_FORM_TOKEN}
diff --git a/phpBB/adm/style/acp_ranks.html b/phpBB/adm/style/acp_ranks.html
index e67c9acd80..d373657114 100644
--- a/phpBB/adm/style/acp_ranks.html
+++ b/phpBB/adm/style/acp_ranks.html
@@ -6,7 +6,7 @@
<a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">&laquo; {L_BACK}</a>
- <script type="text/javascript">
+ <script>
// <![CDATA[
function update_image(newimage)
{
diff --git a/phpBB/adm/style/acp_search.html b/phpBB/adm/style/acp_search.html
index f7ad3c5e89..99620058dc 100644
--- a/phpBB/adm/style/acp_search.html
+++ b/phpBB/adm/style/acp_search.html
@@ -69,7 +69,7 @@
<!-- ELSEIF S_INDEX -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
/**
* Popup search progress bar
diff --git a/phpBB/adm/style/acp_send_statistics.html b/phpBB/adm/style/acp_send_statistics.html
deleted file mode 100644
index 480e438e1f..0000000000
--- a/phpBB/adm/style/acp_send_statistics.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<a id="maincontent"></a>
-
-<h1>{L_SEND_STATISTICS}</h1>
-
-<p>{L_EXPLAIN_SEND_STATISTICS}</p>
-
-<script type="text/javascript">
-//<![CDATA[
-var iframect = 0;
-
-function iframe_updated()
-{
- if (iframect++ == 0)
- {
- return;
- }
-
- phpbb.toggleDisplay('questionnaire-form', -1);
- phpbb.toggleDisplay('questionnaire-thanks', 1);
-}
-//]]>
-</script>
-
-<iframe onload="iframe_updated();" name="questionaire_result" style="display: none;"></iframe>
-
-<form action="{U_COLLECT_STATS}" method="post" target="questionaire_result" id="questionnaire-form">
-
- <p><a href="{U_ACP_MAIN}">{L_DONT_SEND_STATISTICS}</a></p>
-
- <p>{L_EXPLAIN_SHOW_STATISTICS}</p>
-
- <p id="show-button"><input type="button" class="button2" onclick="phpbb.toggleDisplay('configlist', 1); phpbb.toggleDisplay('show-button', -1);" value="{L_SHOW_STATISTICS}" /></p>
-
- <div id="configlist">
- <input type="button" class="button2" onclick="phpbb.toggleDisplay('show-button', 1); phpbb.toggleDisplay('configlist', -1);" value="{L_HIDE_STATISTICS}" />
- <p class="submit-buttons">
- <input class="button1" type="submit" id="submit" name="submit" value="{L_SEND_STATISTICS}" />
- </p>
-
- <!-- BEGIN providers -->
- <fieldset>
- <legend>{providers.NAME}</legend>
- <!-- BEGIN values -->
- <dl>
- <dt>{providers.values.KEY}</dt>
- <dd>{providers.values.VALUE}</dd>
- </dl>
- <!-- END values -->
- </fieldset>
- <!-- END providers -->
- </div>
- <p class="submit-buttons">
- <input type="hidden" name="systemdata" value="{RAW_DATA}" />
- <input class="button1" type="submit" id="submit" name="submit" value="{L_SEND_STATISTICS}" />
- </p>
-</form>
-
-<div id="questionnaire-thanks" class="successbox">
- <p><strong>{L_THANKS_SEND_STATISTICS}</strong><br /><br /><a href="{U_ACP_MAIN}">&laquo; {L_GO_ACP_MAIN}</a></p>
-</div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/adm/style/acp_styles.html b/phpBB/adm/style/acp_styles.html
index 43c2f96a65..cfa804090f 100644
--- a/phpBB/adm/style/acp_styles.html
+++ b/phpBB/adm/style/acp_styles.html
@@ -33,7 +33,7 @@
<!-- IF L_EXPLAIN --><p>{L_EXPLAIN}</p><!-- ENDIF -->
<fieldset class="quick">
- <span class="small"><a href="https://www.phpbb.com/go/customise/styles/3.1" target="_blank">{L_BROWSE_STYLES_DATABASE}</a></span>
+ <span class="small"><a href="https://www.phpbb.com/go/customise/styles/3.2" target="_blank">{L_BROWSE_STYLES_DATABASE}</a></span>
</fieldset>
<form id="acp_styles" method="post" action="{U_ACTION}">
@@ -96,6 +96,7 @@
<thead>
<tr>
<th>{L_STYLE_NAME}</th>
+ <th width="10%" style="white-space: nowrap; text-align: center;">{L_STYLE_PHPBB_VERSION}</th>
<!-- IF not STYLES_LIST_HIDE_COUNT --><th width="10%" style="white-space: nowrap; text-align: center;">{L_STYLE_USED_BY}</th><!-- ENDIF -->
<th width="25%" style="white-space: nowrap; text-align: center;">{L_ACTIONS}</th>
{STYLES_LIST_EXTRA}
@@ -129,6 +130,7 @@
<span class="style-path"><br />{L_STYLE_PATH}{L_COLON} {styles_list.STYLE_PATH_FULL}</span>
<!-- ENDIF -->
</td>
+ <td class="{$ROW_CLASS} users">{styles_list.STYLE_PHPBB_VERSION}</td>
<!-- IF not STYLES_LIST_HIDE_COUNT -->
<td class="{$ROW_CLASS} users">{styles_list.USERS}</td>
<!-- ENDIF -->
@@ -144,7 +146,9 @@
{styles_list.EXTRA}
<td class="{$ROW_CLASS} mark" width="20">
<!-- IF styles_list.STYLE_ID -->
- <input class="checkbox" type="checkbox" name="ids[]" value="{styles_list.STYLE_ID}" />
+ {% if styles_list.STYLE_NAME !== 'prosilver' %}
+ <input class="checkbox" type="checkbox" name="ids[]" value="{styles_list.STYLE_ID}" />
+ {% endif %}
<!-- ELSE -->
<!-- IF styles_list.COMMENT != '' -->
&nbsp;
diff --git a/phpBB/adm/style/acp_users.html b/phpBB/adm/style/acp_users.html
index 18c3d84f96..50b6ec9bc9 100644
--- a/phpBB/adm/style/acp_users.html
+++ b/phpBB/adm/style/acp_users.html
@@ -231,6 +231,10 @@
<!-- INCLUDE permission_mask.html -->
+<!-- ELSE -->
+
+ <!-- EVENT acp_users_mode_add -->
+
<!-- ENDIF -->
<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/adm/style/acp_users_overview.html b/phpBB/adm/style/acp_users_overview.html
index 506101c3f7..2af669a41f 100644
--- a/phpBB/adm/style/acp_users_overview.html
+++ b/phpBB/adm/style/acp_users_overview.html
@@ -79,7 +79,7 @@
<!-- IF not S_USER_FOUNDER or S_FOUNDER -->
- <script type="text/javascript">
+ <script>
// <![CDATA[
function display_reason(option)
diff --git a/phpBB/adm/style/acp_users_prefs.html b/phpBB/adm/style/acp_users_prefs.html
index 61904adc23..358f3d5248 100644
--- a/phpBB/adm/style/acp_users_prefs.html
+++ b/phpBB/adm/style/acp_users_prefs.html
@@ -1,4 +1,4 @@
-<script type="text/javascript">
+<script>
// <![CDATA[
var default_dateformat = '{A_DEFAULT_DATEFORMAT}';
// ]]>
@@ -33,7 +33,7 @@
<dt><label for="notifymethod">{L_NOTIFY_METHOD}{L_COLON}</label><br /><span>{L_NOTIFY_METHOD_EXPLAIN}</span></dt>
<dd><label><input type="radio" class="radio" name="notifymethod" value="0"<!-- IF NOTIFY_EMAIL --> id="notifymethod" checked="checked"<!-- ENDIF --> /> {L_NOTIFY_METHOD_EMAIL}</label>
<label><input type="radio" class="radio" name="notifymethod" value="1"<!-- IF NOTIFY_IM --> id="notifymethod" checked="checked"<!-- ENDIF --><!-- IF S_JABBER_DISABLED --> disabled="disabled"<!-- ENDIF --> /> {L_NOTIFY_METHOD_IM}</label>
- <label><input type="radio" class="radio" name="notifymethod" value="2"<!-- IF NOTIFY_BOTH --> id="notifymethod" checked="checked"<!-- ENDIF --> /> {L_NOTIFY_METHOD_BOTH}</label></dd>
+ <label><input type="radio" class="radio" name="notifymethod" value="2"<!-- IF NOTIFY_BOTH --> id="notifymethod" checked="checked"<!-- ENDIF --><!-- IF S_JABBER_DISABLED --> disabled="disabled"<!-- ENDIF --> /> {L_NOTIFY_METHOD_BOTH}</label></dd>
</dl>
<dl>
<dt><label for="notifypm">{L_NOTIFY_ON_PM}{L_COLON}</label></dt>
diff --git a/phpBB/adm/style/acp_users_signature.html b/phpBB/adm/style/acp_users_signature.html
index c7ec5cc0eb..180c24c96d 100644
--- a/phpBB/adm/style/acp_users_signature.html
+++ b/phpBB/adm/style/acp_users_signature.html
@@ -1,4 +1,4 @@
-<script type="text/javascript">
+<script>
// <![CDATA[
var form_name = 'user_signature';
diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css
index 0c00e5339e..7cf6c22236 100644
--- a/phpBB/adm/style/admin.css
+++ b/phpBB/adm/style/admin.css
@@ -1,4 +1,4 @@
-/* phpBB 3.1 Admin Style Sheet
+/* phpBB 3.2 Admin Style Sheet
------------------------------------------------------------------------
Original author: subBlue ( http://www.subblue.com/ )
Copyright (c) phpBB Limited <https://www.phpbb.com>
@@ -525,7 +525,6 @@ li {
padding: 0;
border-right: 1px solid #CCCFD3;
position: relative;
- z-index: 1;
}
.rtl #menu {
@@ -841,6 +840,7 @@ table.zebra-table tbody tr:nth-child(odd) {
}
.row2 {
+ word-break: break-all;
background-color: #DCEBFE;
}
@@ -1782,7 +1782,7 @@ li.pagination ul {
/* Action Highlighting
---------------------------------------- */
-.successbox, .errorbox {
+.successbox, .errorbox, .warningbox {
padding: 8px;
margin: 10px 0;
color: #FFFFFF;
@@ -1806,6 +1806,10 @@ li.pagination ul {
background-color: #BC2A4D;
}
+.warningbox {
+ background-color: #fca600;
+}
+
.successbox h3, .errorbox h3 {
color: #FFFFFF;
margin: 0 0 0.5em;
@@ -1832,10 +1836,33 @@ li.pagination ul {
font-weight: bold;
}
+#log-container {
+ display: none;
+ max-height: 300px;
+ padding: 8px;
+ margin: 10px 0;
+ clear: both;
+ overflow-y: auto;
+ background-color: #FFFFFF;
+}
+
+#log-container.show_log_container {
+ display: block;
+ border: 1px solid #DBD7D1;
+}
+
+.log {
+ font-size: 0.8em;
+}
+
.notice {
background-color: #62A5CC;
}
+.download-box {
+ margin: 10px 0 10px 0;
+}
+
/* Special cases for the error page */
#errorpage #page-header a {
font-weight: bold;
@@ -2433,6 +2460,9 @@ fieldset.permissions .padding {
text-align: left;
}
+.rtl .dropdown li {
+ text-align: right;
+}
.wrap .dropdown li, .dropdown.wrap li {
white-space: normal;
}
@@ -2441,10 +2471,59 @@ fieldset.permissions .padding {
display: none !important;
}
+.roles-options > .dropdown {
+ left: auto;
+ top: 3.2em;
+ width: 250px;
+}
+
+.rtl .roles-options > .dropdown {
+ right: auto;
+}
+
+.roles-options {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+ width: 250px;
+}
+
+.roles-options > span {
+ border: 1px solid #DEDEDE;
+ border-radius: 3px;
+ padding: 4px;
+ width: 250px;
+ display: none;
+ background: url('../images/arrow_down.gif') no-repeat 245px .7em;
+}
+
+.rtl .roles-options > span {
+ background: url('../images/arrow_down.gif') no-repeat 7px .7em;
+}
+
+.roles-options li {
+ list-style: none;
+}
+
+.roles-highlight {
+ background-color: #1e90ff;
+ color: #fff;
+}
+
/* Classes for additional tasks
---------------------------------------- */
+.current-ext {
+ color: #228822;
+}
+
+.outdated-ext {
+ color: #BC2A4D;
+}
+
.phpinfo {
overflow: auto;
width: 99%;
@@ -2489,3 +2568,153 @@ fieldset.permissions .padding {
clear: both;
display: block;
}
+
+#progress-bar {
+ position: relative;
+ width: 90%;
+ text-align: center;
+ height: 25px;
+ margin: 20px auto;
+ border: 1px solid #cecece;
+}
+
+#progress-bar #progress-bar-text {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ color: #000;
+}
+
+#progress-bar #progress-bar-filler {
+ display: block;
+ position: relative;
+ top: 0;
+ left: 0;
+ background-color: #3c84ad;
+ width: 0;
+ height: 25px;
+ overflow: hidden;
+ color: #fff;
+}
+
+#progress-bar p {
+ line-height: 25px;
+ font-weight: bold;
+}
+
+.send-stats-row {
+ margin: 15px 0;
+}
+
+.send-stats-row:before {
+ display: table;
+ content: " ";
+}
+
+.send-stats-tile {
+ position: relative;
+ padding: 14px;
+ margin-bottom: 20px;
+ background-color: #eff0f2;
+ border-radius: 6px;
+ box-shadow: rgba(0,0,0,0.3) 1px 1px 5px;
+}
+
+.send-stats-tile h2 {
+ margin-top: 0;
+ text-align: center;
+ padding-bottom: 1em;
+}
+
+.send-stats-tile i {
+ padding-right: 0.3em;
+}
+
+.icon {
+ font-family: FontAwesome;
+ font-style: normal;
+}
+
+.send-stats-data-row {
+ background: #f9f9f9;
+ border-radius: 6px;
+ border: #DEDEDE 1px solid;
+ padding: 10px;
+ border-top-width: 0;
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+}
+
+.send-stats-data-hidden .configlist {
+ display: none;
+}
+
+.send-stats-data-only-row {
+ border-radius: 6px !important;
+ border-bottom-width: 1px !important;
+}
+
+.send-stats-data-hidden {
+ padding: 0;
+ border: none;
+}
+
+.send-stats-row > .send-stats-data-row:first-child {
+ background-color: #d9edf7;
+ border-bottom-width: 0;
+ border-top-right-radius: 6px;
+ border-top-left-radius: 6px;
+ border-top-width: 1px;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+.send-stats-settings dt, .send-stats-settings dd {
+ min-width: 25px;
+}
+
+.send-stats-settings dd {
+ line-height: 1.5em;
+}
+
+.send-stats-settings input {
+ display: none;
+}
+
+.send-stats-settings input[type=checkbox] + label:before {
+ content: "\f096";
+ font-family: FontAwesome;
+ font-size: 1.5em;
+}
+
+.send-stats-settings input[type=checkbox]:checked + label:before {
+ content: "\f14a";
+ color: #3c763d;
+}
+
+.send-stats-data-row a:hover span {
+ text-decoration: underline;
+}
+
+.send-stats-data-row a {
+ text-decoration: none;
+ cursor: default;
+}
+
+.send-stats-data-row i {
+ padding-left: 6px;
+}
+
+.configlist {
+ word-wrap: break-word;
+ word-break: break-all;
+}
+
+/* stylelint-disable declaration-property-unit-whitelist */
+.emoji {
+ min-height: 18px;
+ min-width: 18px;
+ height: 1em;
+ width: 1em;
+}
+/* stylelint-enable declaration-property-unit-whitelist */
diff --git a/phpBB/adm/style/admin.js b/phpBB/adm/style/admin.js
index 253fd46a62..551c78a4a3 100644
--- a/phpBB/adm/style/admin.js
+++ b/phpBB/adm/style/admin.js
@@ -243,8 +243,16 @@ function parse_document(container)
parse_document($('body'));
- // Hide configlist and success message in send statistics page
- phpbb.toggleDisplay('configlist', -1);
- phpbb.toggleDisplay('questionnaire-thanks', -1);
+ $('#questionnaire-form').css('display', 'none');
+ var $triggerConfiglist = $('#trigger-configlist');
+
+ $triggerConfiglist.on('click', function () {
+ var $configlist = $('#configlist');
+ $configlist.closest('.send-stats-data-row').toggleClass('send-stats-data-hidden');
+ $configlist.closest('.send-stats-row').find('.send-stats-data-row:first-child').toggleClass('send-stats-data-only-row');
+ $(this).find('i').toggleClass('fa-angle-down fa-angle-up');
+ });
+
+ $('#configlist').closest('.send-stats-data-row').addClass('send-stats-data-hidden');
});
})(jQuery);
diff --git a/phpBB/adm/style/ajax.js b/phpBB/adm/style/ajax.js
index 77fd28fbe6..895bb056e5 100644
--- a/phpBB/adm/style/ajax.js
+++ b/phpBB/adm/style/ajax.js
@@ -4,6 +4,101 @@
'use strict';
+
+phpbb.prepareSendStats = function () {
+ var $form = $('#acp_help_phpbb');
+ var $dark = $('#darkenwrapper');
+ var $loadingIndicator;
+
+ $form.on('submit', function (event) {
+ var $this = $(this),
+ currentTime = Math.floor(new Date().getTime() / 1000),
+ statsTime = parseInt($this.find('input[name=help_send_statistics_time]').val(), 10);
+
+ event.preventDefault();
+ $this.unbind('submit');
+
+ // Skip ajax request if form is submitted too early or send stats
+ // checkbox is not checked
+ if (!$this.find('input[name=help_send_statistics]').is(':checked') ||
+ statsTime > currentTime) {
+ $form.find('input[type=submit]').click();
+ setTimeout(function () {
+ $form.find('input[type=submit]').click();
+ }, 300);
+ return;
+ }
+
+ /**
+ * Handler for AJAX errors
+ */
+ function errorHandler(jqXHR, textStatus, errorThrown) {
+ if (typeof console !== 'undefined' && console.log) {
+ console.log('AJAX error. status: ' + textStatus + ', message: ' + errorThrown);
+ }
+ phpbb.clearLoadingTimeout();
+ var errorText = '';
+
+ if (typeof errorThrown === 'string' && errorThrown.length > 0) {
+ errorText = errorThrown;
+ } else {
+ errorText = $dark.attr('data-ajax-error-text-' + textStatus);
+ if (typeof errorText !== 'string' || !errorText.length) {
+ errorText = $dark.attr('data-ajax-error-text');
+ }
+ }
+ phpbb.alert($dark.attr('data-ajax-error-title'), errorText);
+ }
+
+ /**
+ * This is a private function used to handle the callbacks, refreshes
+ * and alert. It calls the callback, refreshes the page if necessary, and
+ * displays an alert to the user and removes it after an amount of time.
+ *
+ * It cannot be called from outside this function, and is purely here to
+ * avoid repetition of code.
+ *
+ * @param {object} res The object sent back by the server.
+ */
+ function returnHandler(res) {
+ phpbb.clearLoadingTimeout();
+
+ // If a confirmation is not required, display an alert and call the
+ // callbacks.
+ $dark.fadeOut(phpbb.alertTime);
+
+ if ($loadingIndicator) {
+ $loadingIndicator.fadeOut(phpbb.alertTime);
+ }
+
+ var $sendStatisticsSuccess = $('<input />', {
+ type: 'hidden',
+ name: 'send_statistics_response',
+ value: res
+ });
+ $sendStatisticsSuccess.appendTo('p.submit-buttons');
+
+ // Finish actual form submission
+ $form.find('input[type=submit]').click();
+ }
+
+ $loadingIndicator = phpbb.loadingIndicator();
+
+ $.ajax({
+ url: $this.attr('data-ajax-action').replace('&amp;', '&'),
+ type: 'POST',
+ data: 'systemdata=' + encodeURIComponent($this.find('input[name=systemdata]').val()),
+ success: returnHandler,
+ error: errorHandler,
+ cache: false
+ }).always(function() {
+ if ($loadingIndicator && $loadingIndicator.is(':visible')) {
+ $loadingIndicator.fadeOut(phpbb.alertTime);
+ }
+ });
+ });
+};
+
/**
* The following callbacks are for reording items. row_down
* is triggered when an item is moved down, and row_up is triggered when
@@ -70,6 +165,7 @@ function submitPermissions() {
var $form = $('form#set-permissions'),
fieldsetList = $form.find('fieldset[id^=perm]'),
formDataSets = [],
+ dataSetIndex = 0,
$submitAllButton = $form.find('input[type=submit][name^=action]')[0],
$submitButton = $form.find('input[type=submit][data-clicked=true]')[0];
@@ -84,10 +180,21 @@ function submitPermissions() {
}
$.each(fieldsetList, function (key, value) {
+ dataSetIndex = Math.floor(key / 5);
+ var $fieldset = $('fieldset#' + value.id);
if (key % 5 === 0) {
- formDataSets[Math.floor(key / 5)] = $form.find('fieldset#' + value.id).serialize();
+ formDataSets[dataSetIndex] = $fieldset.find('select:visible, input:not([data-name])').serialize();
+ } else {
+ formDataSets[dataSetIndex] += '&' + $fieldset.find('select:visible, input:not([data-name])').serialize();
+ }
+
+ // Find proper role value
+ var roleInput = $fieldset.find('input[name^=role][data-name]');
+ if (roleInput.val()) {
+ formDataSets[dataSetIndex] += '&' + roleInput.attr('name') + '=' + roleInput.val();
} else {
- formDataSets[Math.floor(key / 5)] += '&' + $form.find('fieldset#' + value.id).serialize();
+ formDataSets[dataSetIndex] += '&' + roleInput.attr('name') + '=' +
+ $fieldset.find('select[name="' + roleInput.attr('name') + '"]').val();
}
});
@@ -215,6 +322,10 @@ $(function() {
$(this).attr('data-clicked', true);
});
}
+
+ if ($('#acp_help_phpbb')) {
+ phpbb.prepareSendStats();
+ }
});
diff --git a/phpBB/adm/style/captcha_recaptcha.html b/phpBB/adm/style/captcha_recaptcha.html
index d3038fd714..3f61c76cb1 100644
--- a/phpBB/adm/style/captcha_recaptcha.html
+++ b/phpBB/adm/style/captcha_recaptcha.html
@@ -1,32 +1,12 @@
<!-- IF S_RECAPTCHA_AVAILABLE -->
<dl>
<dd>
- <script type="text/javascript">
- // <![CDATA[
- var RecaptchaOptions = {
- lang : '{LA_RECAPTCHA_LANG}',
- theme : 'clean'
- };
- // ]]>
- </script>
- <script type="text/javascript" src="{RECAPTCHA_SERVER}/challenge?k={RECAPTCHA_PUBKEY}{RECAPTCHA_ERRORGET}"></script>
- <script type="text/javascript">
- // <![CDATA[
- <!-- IF S_CONTENT_DIRECTION eq 'rtl' -->
- document.getElementById('recaptcha_table').style.direction = 'ltr';
- <!-- ENDIF -->
- // ]]>
- </script>
-
-
<noscript>
- <div>
- <object data="{RECAPTCHA_SERVER}/noscript?k={RECAPTCHA_PUBKEY}{RECAPTCHA_ERRORGET}" type="text/html" height="300" width="500"></object><br />
- <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
- <input type="hidden" name="recaptcha_response_field" value="manual_challenge" />
- </div>
+ <div>{L_RECAPTCHA_NOSCRIPT}</div>
</noscript>
+ <script src="{RECAPTCHA_SERVER}.js?hl={LA_RECAPTCHA_LANG}" async defer></script>
+ <div class="g-recaptcha" data-sitekey="{RECAPTCHA_PUBKEY}"></div>
</dd>
</dl>
<!-- ELSE -->
diff --git a/phpBB/adm/style/install_convert.html b/phpBB/adm/style/install_convert.html
deleted file mode 100644
index 7e22404f56..0000000000
--- a/phpBB/adm/style/install_convert.html
+++ /dev/null
@@ -1,134 +0,0 @@
-<!-- INCLUDE install_header.html -->
-
-<!-- IF S_NOT_INSTALLED -->
-
- <h1>{TITLE}</h1>
-
- <p>{BODY}</p>
-
-<!-- ELSE -->
-
- <form id="install_convert" method="post" action="{U_ACTION}">
-
- <h1>{TITLE}</h1>
-
- <p>{BODY}</p>
-
- <!-- IF S_ERROR_BOX -->
- <div class="errorbox">
- <h3>{ERROR_TITLE}</h3>
- <p>{ERROR_MSG}</p>
- </div>
- <!-- ENDIF -->
-
- <!-- IF S_LIST -->
- <table class="table1">
- <caption>{L_AVAILABLE_CONVERTORS}</caption>
- <col class="col1" /><col class="col2" /><col class="col1" /><col class="col2" />
- <thead>
- <tr>
- <th>{L_SOFTWARE}</th>
- <th>{L_VERSION}</th>
- <th>{L_AUTHOR}</th>
- <th>{L_OPTIONS}</th>
- </tr>
- </thead>
- <tbody>
- <!-- IF .convertors -->
- <!-- BEGIN convertors -->
- <tr>
- <td>{convertors.SOFTWARE}</td>
- <td>{convertors.VERSION}</td>
- <td>{convertors.AUTHOR}</td>
- <td><a href="{convertors.U_CONVERT}">{L_CONVERT}</a></td>
- </tr>
- <!-- END convertors -->
- <!-- ELSE -->
- <tr>
- <td>{L_NO_CONVERTORS}</td>
- <td>-</td>
- <td>-</td>
- <td>-</td>
- </tr>
- <!-- ENDIF -->
- </tbody>
- </table>
- <!-- ENDIF -->
-
- <!-- IF S_CONTINUE -->
- </form>
-
- <fieldset class="submit-buttons">
- <form method="post" action="{U_NEW_ACTION}">
- <input class="button1" type="submit" name="submit_new" value="{L_NEW}" />
- </form>
- <br />
- <form method="post" action="{U_CONTINUE_ACTION}">
- <input class="button1" type="submit" name="submit_cont" value="{L_CONTINUE}" />
- </form>
- </fieldset>
-
- <form method="post" action="{U_ACTION}">
- <!-- ENDIF -->
-
- <!-- IF .checks -->
- <fieldset>
-
- <!-- BEGIN checks -->
- <!-- IF checks.S_LEGEND -->
- <!-- IF not checks.S_FIRST_ROW -->
- </fieldset>
-
- <fieldset>
- <!-- ENDIF -->
- <legend>{checks.LEGEND}</legend>
- <!-- IF checks.LEGEND_EXPLAIN --><p>{checks.LEGEND_EXPLAIN}</p><!-- ENDIF -->
- <!-- ELSE -->
-
- <dl>
- <dt><label>{checks.TITLE}{L_COLON}</label><!-- IF checks.S_EXPLAIN --><br /><span class="explain">{checks.TITLE_EXPLAIN}</span><!-- ENDIF --></dt>
- <dd>{checks.RESULT}</dd>
- </dl>
- <!-- ENDIF -->
- <!-- END checks -->
-
- </fieldset>
- <!-- ENDIF -->
-
- <!-- IF .options -->
- <fieldset>
-
- <!-- BEGIN options -->
- <!-- IF options.S_LEGEND -->
- <!-- IF not options.S_FIRST_ROW -->
- </fieldset>
-
- <fieldset>
- <!-- ENDIF -->
- <legend>{options.LEGEND}</legend>
- <!-- ELSE -->
-
- <dl>
- <dt><label for="{options.KEY}">{options.TITLE}{L_COLON}</label><!-- IF options.S_EXPLAIN --><br /><span class="explain">{options.TITLE_EXPLAIN}</span><!-- ENDIF --></dt>
- <dd>{options.CONTENT}</dd>
- </dl>
-
- <!-- ENDIF -->
- <!-- END options -->
-
- </fieldset>
- <!-- ENDIF -->
-
- <!-- IF L_SUBMIT -->
- <!-- IF L_MESSAGE --><p>{L_MESSAGE}</p><!-- ENDIF -->
-
- <fieldset class="submit-buttons">
- {S_HIDDEN}
- <!-- IF L_SUBMIT --><input class="button1<!-- IF S_REFRESH --> disabled<!-- ENDIF -->" type="submit" id="submit" <!-- IF S_REFRESH -->disabled="disabled" <!-- ELSE --> onclick="this.className = 'button1 disabled';" onsubmit="this.disabled = 'disabled';" <!-- ENDIF -->name="submit" value="{L_SUBMIT}" /><!-- ENDIF -->
- </fieldset>
- <!-- ENDIF -->
-
- </form>
-<!-- ENDIF -->
-
-<!-- INCLUDE install_footer.html -->
diff --git a/phpBB/adm/style/install_error.html b/phpBB/adm/style/install_error.html
deleted file mode 100644
index 3f7c8b9ed4..0000000000
--- a/phpBB/adm/style/install_error.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!-- INCLUDE install_header.html -->
-
-<div class="errorbox">
- <h3>{MESSAGE_TITLE}</h3>
- <p>{MESSAGE_TEXT}</p>
-</div>
-
-<!-- INCLUDE install_footer.html -->
diff --git a/phpBB/adm/style/install_footer.html b/phpBB/adm/style/install_footer.html
deleted file mode 100644
index 8e7599dc3f..0000000000
--- a/phpBB/adm/style/install_footer.html
+++ /dev/null
@@ -1,21 +0,0 @@
- </div>
- </div><!-- /#main -->
- </div>
- </div><!-- /#acp -->
- </div>
-
- <div id="page-footer">
- <div class="copyright">
- Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited
- </div>
- </div>
-</div>
-
-<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
-<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js">\x3C/script>');</script><!-- ENDIF -->
-<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
-<!-- INCLUDEJS admin.js -->
-{$SCRIPTS}
-
-</body>
-</html>
diff --git a/phpBB/adm/style/install_header.html b/phpBB/adm/style/install_header.html
deleted file mode 100644
index cfafe7917f..0000000000
--- a/phpBB/adm/style/install_header.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!DOCTYPE html>
-<html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">
-<head>
-<meta charset="utf-8">
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="viewport" content="width=device-width, initial-scale=1" />
-<!-- IF META -->{META}<!-- ENDIF -->
-<title>{PAGE_TITLE}</title>
-
-<link href="{T_TEMPLATE_PATH}/admin.css" rel="stylesheet" type="text/css" media="screen" />
-</head>
-
-<body class="{S_CONTENT_DIRECTION} nojs">
-<div id="wrap">
- <div id="page-header">
- <h1>{L_INSTALL_PANEL}</h1>
- <p id="skip"><a href="#acp">{L_SKIP}</a></p>
- <!-- IF S_LANG_SELECT -->
- <form method="post" action="#">
- <fieldset class="nobg">
- <label for="language">{L_SELECT_LANG}{L_COLON}</label>
- {S_LANG_SELECT}
- <input class="button1" type="submit" id="change_lang" name="change_lang" value="{L_CHANGE}" />
- </fieldset>
- </form>
- <!-- ENDIF -->
- </div>
-
- <div id="page-body">
- <div id="tabs">
- <ul>
- <!-- BEGIN t_block1 -->
- <li class="tab<!-- IF t_block1.S_SELECTED --> activetab<!-- ENDIF -->"><a href="{t_block1.U_TITLE}">{t_block1.L_TITLE}</a></li>
- <!-- END t_block1 -->
- </ul>
- </div>
-
- <div id="acp">
- <div id="content">
- <div id="menu">
- <div class="menu-block no-header">
- <ul>
- <!-- BEGIN l_block1 -->
- <li<!-- IF l_block1.S_SELECTED --> id="activemenu"<!-- ENDIF -->><a href="{l_block1.U_TITLE}"><span>{l_block1.L_TITLE}</span></a></li>
- <!-- END l_block1 -->
- <!-- BEGIN l_block2 -->
- <li<!-- IF l_block2.S_SELECTED --> id="activemenu"<!-- ENDIF -->><span<!-- IF l_block2.S_COMPLETE --> class="completed"<!-- ENDIF -->>{l_block2.L_TITLE}</span></li>
- <!-- END l_block2 -->
- </ul>
- </div>
- </div>
-
- <div id="main" class="install-body">
- <div class="main">
diff --git a/phpBB/adm/style/install_install.html b/phpBB/adm/style/install_install.html
deleted file mode 100644
index 1a809a3588..0000000000
--- a/phpBB/adm/style/install_install.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<!-- INCLUDE install_header.html -->
-
-<form id="install_install" method="post" action="{U_ACTION}" onsubmit="submit.disabled = 'disabled';">
-
-<!-- IF TITLE --><h1>{TITLE}</h1><!-- ENDIF -->
-<!-- IF BODY --><p>{BODY}</p><!-- ENDIF -->
-
-<!-- IF .checks -->
- <fieldset>
-
- <!-- BEGIN checks -->
- <!-- IF checks.S_LEGEND -->
- <!-- IF not checks.S_FIRST_ROW -->
- </fieldset>
-
- <fieldset>
- <!-- ENDIF -->
- <legend>{checks.LEGEND}</legend>
- <!-- IF checks.LEGEND_EXPLAIN --><p>{checks.LEGEND_EXPLAIN}</p><!-- ENDIF -->
- <!-- ELSE -->
-
- <dl>
- <dt>{checks.TITLE}{L_COLON}<!-- IF checks.S_EXPLAIN --><br /><span class="explain">{checks.TITLE_EXPLAIN}</span><!-- ENDIF --></dt>
- <dd>{checks.RESULT}</dd>
- </dl>
- <!-- ENDIF -->
- <!-- END checks -->
-
- </fieldset>
-<!-- ENDIF -->
-
-<!-- IF .options -->
- <fieldset>
-
- <!-- BEGIN options -->
- <!-- IF options.S_LEGEND -->
- <!-- IF not options.S_FIRST_ROW -->
- </fieldset>
-
- <fieldset>
- <!-- ENDIF -->
- <legend>{options.LEGEND}</legend>
- <!-- ELSE -->
-
- <dl>
- <dt><label for="{options.KEY}">{options.TITLE}{L_COLON}</label><!-- IF options.S_EXPLAIN --><br /><span class="explain">{options.TITLE_EXPLAIN}</span><!-- ENDIF --></dt>
- <dd>{options.CONTENT}</dd>
- </dl>
-
- <!-- ENDIF -->
- <!-- END options -->
-
- </fieldset>
-<!-- ENDIF -->
-
-<!-- IF S_SHOW_DOWNLOAD -->
- <h1>{L_DL_CONFIG}</h1>
- <p>{L_DL_CONFIG_EXPLAIN}</p>
-
- <fieldset class="submit-buttons">
- <legend>{L_DL_CONFIG}</legend>
- {S_HIDDEN}
- <input class="button1" type="submit" id="dlconfig" name="dlconfig" value="{L_DL_DOWNLOAD}" />&nbsp;<input class="button1" type="submit" id="dldone" name="dldone" value="{L_DL_DONE}" />
- </fieldset>
-<!-- ENDIF -->
-
-<!-- IF L_SUBMIT -->
- <fieldset class="submit-buttons">
- <legend>{L_SUBMIT}</legend>
- {S_HIDDEN}
- <!-- IF L_SUBMIT --><input class="button1" type="submit" id="submit" onclick="this.className = 'button1 disabled';" name="submit" value="{L_SUBMIT}" /><!-- ENDIF -->
- </fieldset>
-<!-- ENDIF -->
-
-</form>
-
-<!-- INCLUDE install_footer.html -->
diff --git a/phpBB/adm/style/install_main.html b/phpBB/adm/style/install_main.html
deleted file mode 100644
index 73e73ad578..0000000000
--- a/phpBB/adm/style/install_main.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!-- INCLUDE install_header.html -->
-
- <h1>{TITLE}</h1>
- <p>{BODY}</p>
-
-<!-- INCLUDE install_footer.html -->
diff --git a/phpBB/adm/style/install_update.html b/phpBB/adm/style/install_update.html
deleted file mode 100644
index 898233f72d..0000000000
--- a/phpBB/adm/style/install_update.html
+++ /dev/null
@@ -1,491 +0,0 @@
-<!-- INCLUDE install_header.html -->
-
-<script type="text/javascript">
-// <![CDATA[
- function popup(url, width, height, name)
- {
- if (!name)
- {
- name = '_popup';
- }
-
- window.open(url.replace(/&amp;/g, '&'), name, 'height=' + height + ',resizable=yes,scrollbars=yes, width=' + width);
- return false;
- }
-
- function diff_popup(url)
- {
- popup(url, 950, 600, '_diff');
- return false;
- }
-// ]]>
-</script>
-
-<!-- IF S_ERROR -->
- <div class="errorbox" style="margin-top: 0;">
- <h3>{L_NOTICE}</h3>
- <p>{ERROR_MSG}</p>
- </div>
-<!-- ENDIF -->
-
-<!-- IF S_IN_PROGRESS -->
-
- <div class="successbox" style="margin-top: 0;">
- <h3>{L_IN_PROGRESS}</h3>
- <p>{L_IN_PROGRESS_EXPLAIN}</p>
- </div>
-
-<!-- ELSEIF S_INTRO -->
-
- <!-- IF S_WARNING -->
- <div class="successbox" style="margin-top: 0;">
- <h3>{L_NOTICE}</h3>
- <p>{WARNING_MSG}</p>
- </div>
- <!-- ENDIF -->
-
- <div class="errorbox" style="margin-top: 0;">
- <h3>{L_NOTICE}</h3>
- <p>{L_BACKUP_NOTICE}</p>
- </div>
-
- <form id="install_update" method="post" action="{U_ACTION}">
-
- <h1>{L_UPDATE_INSTALLATION}</h1>
- <p>{L_UPDATE_INSTALLATION_EXPLAIN}</p>
-
- <fieldset class="submit-buttons">
- <input class="button1" type="submit" name="submit" value="{L_NEXT_STEP}" />
- </fieldset>
-
- </form>
-
-<!-- ELSEIF S_UPLOAD_SUCCESS -->
-
- <form id="install_update" method="post" action="{U_ACTION}">
-
- <h1>{L_UPDATE_SUCCESS}</h1>
- <p>{L_UPDATE_SUCCESS_EXPLAIN}</p>
-
- <fieldset class="submit-buttons">
- <input class="button1" type="submit" name="check_again" value="{L_CONTINUE_UPDATE}" />
- </fieldset>
-
- </form>
-
-<!-- ENDIF -->
-
-<!-- IF S_VERSION_CHECK -->
-
- <h1>{L_VERSION_CHECK}</h1>
-
- <p>{L_VERSION_CHECK_EXPLAIN}</p>
-
- <!-- IF S_UP_TO_DATE -->
- <div class="successbox">
- <p>{L_VERSION_UP_TO_DATE}</p>
- </div>
- <!-- ELSE -->
- <div class="errorbox">
- <p>{L_VERSION_NOT_UP_TO_DATE}</p>
- </div>
- <!-- ENDIF -->
-
- <fieldset>
- <legend></legend>
- <dl>
- <dt><label>{L_CURRENT_VERSION}</label></dt>
- <dd><strong>{CURRENT_VERSION}</strong></dd>
- </dl>
- <dl>
- <dt><label>{L_LATEST_VERSION}</label></dt>
- <dd><strong>{LATEST_VERSION}</strong></dd>
- </dl>
- <!-- IF PACKAGE_VERSION and not S_UP_TO_DATE -->
- <dl>
- <dt><label>{L_PACKAGE_UPDATES_TO}</label></dt>
- <dd><strong>{PACKAGE_VERSION}</strong></dd>
- </dl>
- <!-- ENDIF -->
- </fieldset>
-
- <form id="install_update" method="post" action="{U_ACTION}">
-
- <fieldset class="submit-buttons">
- <p>{L_CHECK_FILES_EXPLAIN}</p>
- <input class="button1" type="submit" name="submit" value="{L_CHECK_FILES}" />
- </fieldset>
-
- </form>
-
-<!-- ELSEIF S_DB_UPDATE -->
-
- <!-- IF not S_DB_UPDATE_FINISHED -->
-
- <h1>{L_PERFORM_DATABASE_UPDATE}</h1>
-
- <p>
- {L_PERFORM_DATABASE_UPDATE_EXPLAIN}<br />
- </p>
-
- <br /><br />
-
- <form id="install_dbupdate" method="post" action="{U_DB_UPDATE_ACTION}">
-
- <fieldset class="submit-buttons">
- <a href="{U_DB_UPDATE}" class="button1">{L_RUN_DATABASE_SCRIPT}</a>
-
- <!-- input class="button1" type="submit" name="db_update" value="{L_CHECK_UPDATE_DATABASE}" / -->
- </fieldset>
-
- </form>
-
- <!-- ELSE -->
-
- <div class="successbox">
- <h3>{L_UPDATE_SUCCESS}</h3>
- <p>{L_EVERYTHING_UP_TO_DATE}</p>
- </div>
-
- <!-- ENDIF -->
-
-<!-- ELSEIF S_FILE_CHECK -->
-
- <!-- IF S_ALL_UP_TO_DATE -->
-
- <h1>{L_UPDATE_FILE_SUCCESS}</h1>
- <p>{L_ALL_FILES_UP_TO_DATE}</p>
-
- <p>{L_UPDATE_DATABASE_EXPLAIN}</p>
-
- <form id="install_dbupdate" method="post" action="{U_DB_UPDATE_ACTION}">
-
- <fieldset class="submit-buttons">
- <input class="button1" type="submit" name="db_update" value="{L_UPDATE_DATABASE}" />
- </fieldset>
-
- </form>
-
- <!-- ELSE -->
- <h1>{L_COLLECTED_INFORMATION}</h1>
-
- <p>{L_COLLECTED_INFORMATION_EXPLAIN}</p>
-
- <!-- IF S_NO_UPDATE_FILES -->
- <div class="errorbox">
- <h3>{L_NO_UPDATE_FILES}</h3>
-
- <p>{L_NO_UPDATE_FILES_EXPLAIN}</p><br />
-
- <strong>{NO_UPDATE_FILES}</strong>
-
- </div>
- <!-- ENDIF -->
-
- <form id="install_update" method="post" action="{U_UPDATE_ACTION}">
-
- <!-- IF .deleted -->
- <h2>{L_FILES_DELETED}</h2>
- <div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('deleted', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
- <p>{L_FILES_DELETED_EXPLAIN}</p>
-
- <fieldset id="deleted">
- <legend><img src="{T_IMAGE_PATH}icon_delete.gif" alt="{L_STATUS_DELETED}" /></legend>
- <!-- BEGIN deleted -->
- <dl>
- <dt style="width: 60%;"><strong><!-- IF deleted.DIR_PART -->{deleted.DIR_PART}<br /><!-- ENDIF -->{deleted.FILE_PART}</strong></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}: 60%;">
- <!-- IF not deleted.S_BINARY -->[<a href="{deleted.U_SHOW_DIFF}" onclick="diff_popup(this.href); return false;">{deleted.L_SHOW_DIFF}</a>]<!-- ELSE -->{L_BINARY_FILE}<!-- ENDIF -->
- </dd>
- </dl>
- <!-- END deleted -->
- </fieldset>
-
- <!-- ENDIF -->
-
- <!-- IF .conflict -->
- <h2>{L_FILES_CONFLICT}</h2>
- <div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('conflict', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
- <p>{L_FILES_CONFLICT_EXPLAIN}</p>
-
- <!-- BEGIN conflict -->
- <fieldset id="conflict">
- <legend><img src="{T_IMAGE_PATH}file_conflict.gif" alt="{L_STATUS_CONFLICT}" /></legend>
- <dl>
- <dt style="width: 60%;"><strong><!-- IF conflict.DIR_PART -->{conflict.DIR_PART}<br /><!-- ENDIF -->{conflict.FILE_PART}</strong>
- <!-- IF conflict.S_CUSTOM --><br /><span><em>{L_FILE_USED}{L_COLON} </em>{conflict.CUSTOM_ORIGINAL}</span><!-- ENDIF -->
- <!-- IF conflict.NUM_CONFLICTS --><br /><span>{L_NUM_CONFLICTS}{L_COLON} {conflict.NUM_CONFLICTS}</span><!-- ENDIF -->
- </dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">
- <!-- IF not conflict.S_BINARY -->[<a href="{conflict.U_SHOW_DIFF}">{L_DOWNLOAD_CONFLICTS}</a>]<br />{L_DOWNLOAD_CONFLICTS_EXPLAIN}
- <!-- ELSE -->{L_BINARY_FILE}<!-- ENDIF -->
- </dd>
- <!-- IF conflict.S_CUSTOM -->
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><label><input type="checkbox" name="no_update[]" value="{conflict.FILENAME}" class="radio" /> {L_DO_NOT_UPDATE}</label></dd>
- <!-- ENDIF -->
- </dl>
- <!-- IF conflict.S_BINARY -->
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="conflict[{conflict.FILENAME}]" value="1" checked="checked" /> {L_MERGE_NO_MERGE_NEW_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">&nbsp;</dd>
- </dl>
- <!-- ELSE -->
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="conflict[{conflict.FILENAME}]" value="3" checked="checked" /> {L_MERGE_NEW_FILE_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">[<a href="{conflict.U_VIEW_NEW_FILE}" onclick="diff_popup(this.href); return false;">{L_SHOW_DIFF_MODIFIED}</a>]</dd>
- </dl>
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="conflict[{conflict.FILENAME}]" value="4" /> {L_MERGE_MOD_FILE_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">[<a href="{conflict.U_VIEW_MOD_FILE}" onclick="diff_popup(this.href); return false;">{L_SHOW_DIFF_MODIFIED}</a>]</dd>
- </dl>
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="conflict[{conflict.FILENAME}]" value="1" /> {L_MERGE_NO_MERGE_NEW_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">[<a href="{conflict.U_VIEW_NO_MERGE_NEW}" onclick="diff_popup(this.href); return false;">{L_SHOW_DIFF_FINAL}</a>]</dd>
- </dl>
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="conflict[{conflict.FILENAME}]" value="2" /> {L_MERGE_NO_MERGE_MOD_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">[<a href="{conflict.U_VIEW_NO_MERGE_MOD}" onclick="diff_popup(this.href); return false;">{L_SHOW_DIFF_FINAL}</a>]</dd>
- </dl>
- <!-- ENDIF -->
- </fieldset>
- <!-- END conflict -->
-
- <!-- ENDIF -->
-
- <!-- IF .new_conflict -->
- <h2>{L_FILES_NEW_CONFLICT}</h2>
- <div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('new_conflict', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
- <p>{L_FILES_NEW_CONFLICT_EXPLAIN}</p>
-
- <fieldset id="new_conflict">
- <legend><img src="{T_IMAGE_PATH}file_new_conflict.gif" alt="{L_STATUS_NEW_CONFLICT}" /></legend>
- <!-- BEGIN new_conflict -->
- <dl>
- <dt style="width: 60%;"><strong><!-- IF new_conflict.DIR_PART -->{new_conflict.DIR_PART}<br /><!-- ENDIF -->{new_conflict.FILE_PART}</strong>
- <!-- IF new_conflict.S_CUSTOM --><br /><span><em>{L_FILE_USED}{L_COLON} </em>{new_conflict.CUSTOM_ORIGINAL}</span><!-- ENDIF -->
- </dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">
- <!-- IF not new_conflict.S_BINARY -->[<a href="{new_conflict.U_SHOW_DIFF}" onclick="diff_popup(this.href); return false;">{new_conflict.L_SHOW_DIFF}</a>]<!-- ELSE -->{L_BINARY_FILE}<!-- ENDIF -->
- </dd>
- <!-- IF new_conflict.S_CUSTOM -->
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><label><input type="checkbox" name="no_update[]" value="{new_conflict.FILENAME}" class="radio" /> {L_DO_NOT_UPDATE}</label></dd>
- <!-- ENDIF -->
- </dl>
- <!-- END new_conflict -->
- </fieldset>
-
- <!-- ENDIF -->
-
- <!-- IF .modified -->
- <h2>{L_FILES_MODIFIED}</h2>
- <div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('modified', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
- <p>{L_FILES_MODIFIED_EXPLAIN}</p>
-
- <!-- BEGIN modified -->
- <fieldset id="modified">
- <legend><img src="{T_IMAGE_PATH}file_modified.gif" alt="{L_STATUS_MODIFIED}" /></legend>
- <dl>
- <dt style="width: 60%;"><strong><!-- IF modified.DIR_PART -->{modified.DIR_PART}<br /><!-- ENDIF -->{modified.FILE_PART}</strong>
- <!-- IF modified.S_CUSTOM --><br /><span><em>{L_FILE_USED}{L_COLON} </em>{modified.CUSTOM_ORIGINAL}</span><!-- ENDIF -->
- </dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">&nbsp;</dd>
- <!-- IF modified.S_CUSTOM -->
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><label><input type="checkbox" name="no_update[]" value="{modified.FILENAME}" class="radio" /> {L_DO_NOT_UPDATE}</label></dd>
- <!-- ENDIF -->
- </dl>
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="modified[{modified.FILENAME}]" value="0" checked="checked" /> {L_MERGE_MODIFICATIONS_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><!-- IF not modified.S_BINARY -->[<a href="{modified.U_SHOW_DIFF}" onclick="diff_popup(this.href); return false;">{modified.L_SHOW_DIFF}</a>]<!-- ELSE -->{L_BINARY_FILE}<!-- ENDIF --></dd>
- </dl>
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="modified[{modified.FILENAME}]" value="1" /> {L_MERGE_NO_MERGE_NEW_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><!-- IF not modified.S_BINARY -->[<a href="{modified.U_VIEW_NO_MERGE_NEW}" onclick="diff_popup(this.href); return false;">{L_SHOW_DIFF_FINAL}</a>]<!-- ELSE -->&nbsp;<!-- ENDIF --></dd>
- </dl>
- <dl>
- <dt style="width: 60%"><label><input type="radio" class="radio" name="modified[{modified.FILENAME}]" value="2" /> {L_MERGE_NO_MERGE_MOD_OPTION}</label></dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><!-- IF not modified.S_BINARY -->[<a href="{modified.U_VIEW_NO_MERGE_MOD}" onclick="diff_popup(this.href); return false;">{L_SHOW_DIFF_FINAL}</a>]<!-- ELSE -->&nbsp;<!-- ENDIF --></dd>
- </dl>
- </fieldset>
- <!-- END modified -->
-
- <!-- ENDIF -->
-
- <!-- IF .new -->
- <h2>{L_FILES_NEW}</h2>
- <div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('new_files', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
- <p>{L_FILES_NEW_EXPLAIN}</p>
-
- <fieldset id="new_files" style="display: none;">
- <legend><img src="{T_IMAGE_PATH}file_new.gif" alt="{L_STATUS_NEW}" /></legend>
- <!-- BEGIN new -->
- <dl>
- <dt style="width: 60%;"><strong><!-- IF new.DIR_PART -->{new.DIR_PART}<br /><!-- ENDIF -->{new.FILE_PART}</strong>
- <!-- IF new.S_CUSTOM --><br /><span><em>{L_FILE_USED}{L_COLON} </em>{new.CUSTOM_ORIGINAL}</span><!-- ENDIF -->
- </dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;">
- <!-- IF not new.S_BINARY -->[<a href="{new.U_SHOW_DIFF}" onclick="diff_popup(this.href); return false;">{new.L_SHOW_DIFF}</a>]<!-- ELSE -->{L_BINARY_FILE}<!-- ENDIF -->
- </dd>
- <!-- IF new.S_CUSTOM -->
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><label><input type="checkbox" name="no_update[]" value="{new.FILENAME}" class="radio" /> {L_DO_NOT_UPDATE}</label></dd>
- <!-- ENDIF -->
- </dl>
- <!-- END new -->
- </fieldset>
-
- <!-- ENDIF -->
-
- <!-- IF .not_modified -->
- <h2>{L_FILES_NOT_MODIFIED}</h2>
- <div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('not_modified', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
- <p>{L_FILES_NOT_MODIFIED_EXPLAIN}</p>
-
- <fieldset id="not_modified" style="display: none;">
- <legend><img src="{T_IMAGE_PATH}file_not_modified.gif" alt="{L_STATUS_NOT_MODIFIED}" /></legend>
- <!-- BEGIN not_modified -->
- <dl>
- <dt style="width: 60%;"><strong><!-- IF not_modified.DIR_PART -->{not_modified.DIR_PART}<br /><!-- ENDIF -->{not_modified.FILE_PART}</strong>
- <!-- IF not_modified.S_CUSTOM --><br /><span><em>{L_FILE_USED}{L_COLON} </em>{not_modified.CUSTOM_ORIGINAL}</span><!-- ENDIF -->
- </dt>
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><!-- IF not not_modified.S_BINARY -->[<a href="{not_modified.U_SHOW_DIFF}" onclick="diff_popup(this.href); return false;">{not_modified.L_SHOW_DIFF}</a>]<!-- ELSE -->{L_BINARY_FILE}<!-- ENDIF --></dd>
- <!-- IF not_modified.S_CUSTOM -->
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 60%;"><label><input type="checkbox" name="no_update[]" value="{not_modified.FILENAME}" class="radio" /> {L_DO_NOT_UPDATE}</label></dd>
- <!-- ENDIF -->
- </dl>
- <!-- END not_modified -->
- </fieldset>
-
- <!-- ENDIF -->
-
- <!-- IF .up_to_date -->
- <h2>{L_FILES_UP_TO_DATE}</h2>
- <div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('up_to_date', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
- <p>{L_FILES_UP_TO_DATE_EXPLAIN}</p>
-
- <fieldset id="up_to_date" style="display: none;">
- <legend><img src="{T_IMAGE_PATH}file_up_to_date.gif" alt="{L_STATUS_UP_TO_DATE}" /></legend>
- <!-- BEGIN up_to_date -->
- <dl>
- <dd class="full" style="text-align: {S_CONTENT_FLOW_BEGIN};"><strong>{up_to_date.FILENAME}</strong></dd>
- </dl>
- <!-- END up_to_date -->
- </fieldset>
-
- <!-- ENDIF -->
-
- <br />
-
- <fieldset class="quick">
- <input class="button1" type="submit" name="check_again" value="{L_CHECK_FILES_AGAIN}" />
- </fieldset>
-
- <br />
-
- <h1>{L_UPDATE_METHOD}</h1>
-
- <p>{L_UPDATE_METHOD_EXPLAIN}</p>
-
- <fieldset class="submit-buttons">
- <input class="button1" type="submit" name="ftp_upload" value="{L_FTP_UPDATE_METHOD}" />&nbsp; &nbsp;<input class="button1" type="submit" name="download" value="{L_DOWNLOAD_UPDATE_METHOD_BUTTON}" />
- </fieldset>
-
- </form>
-
- <!-- ENDIF -->
-
-<!-- ELSEIF S_DOWNLOAD_FILES -->
-
- <h1>{L_DOWNLOAD_UPDATE_METHOD}</h1>
-
- <p>{L_DOWNLOAD_UPDATE_METHOD_EXPLAIN}</p>
-
- <form id="install_update" method="post" action="{U_ACTION}">
-
- <fieldset>
- <legend>{L_SELECT_DOWNLOAD_FORMAT}</legend>
- <dl>
- <dt><label for="use_method">{L_DOWNLOAD_AS}{L_COLON}</label></dt>
- <dd>{RADIO_BUTTONS}</dd>
- </dl>
- </fieldset>
-
- <fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}
- <input type="submit" class="button2" value="{L_CONTINUE_UPDATE}" name="check_again" />&nbsp; &nbsp;<input type="submit" class="button1" value="{L_DOWNLOAD}" name="download" />
- </fieldset>
-
- </form>
-
- <br /><br />
-
- <p>{L_MAPPING_FILE_STRUCTURE}</p>
-
- <table class="table1">
- <col class="row1" /><col class="row2" /><col class="row1" />
- <thead>
- <tr>
- <th style="width: 49%">{L_ARCHIVE_FILE}</th>
- <th style="width: 2%">&nbsp;</th>
- <th style="width: 49%">{L_DESTINATION}</th>
- </tr>
- </thead>
- <tbody>
- <!-- BEGIN location -->
- <tr>
- <td>{location.SOURCE}</td>
- <td><strong>&raquo;</strong></td>
- <td>{location.DESTINATION}</td>
- </tr>
- <!-- END location -->
- </tbody>
- </table>
-
-<!-- ELSEIF S_FTP_UPLOAD -->
-
- <h1>{L_SELECT_FTP_SETTINGS}</h1>
-
- <form id="install_update" method="post" action="{U_ACTION}">
-
- <!-- IF S_CONNECTION_SUCCESS -->
- <div class="successbox">
- <p>{L_CONNECTION_SUCCESS}</p>
- </div>
- <!-- ELSEIF S_CONNECTION_FAILED -->
- <div class="successbox">
- <p>{L_TRY_DOWNLOAD_METHOD}</p>
-
- <fieldset class="quick">
- <input class="button1" type="submit" name="download" value="{L_TRY_DOWNLOAD_METHOD_BUTTON}" />
- </fieldset>
- </div>
-
- <div class="errorbox">
- <p>{L_CONNECTION_FAILED}<br />{ERROR_MSG}</p>
- </div>
- <!-- ENDIF -->
-
- <fieldset>
- <legend>{L_FTP_SETTINGS}</legend>
- <dl>
- <dt><label>{L_UPLOAD_METHOD}{L_COLON}</label></dt>
- <dd><strong>{UPLOAD_METHOD}</strong></dd>
- </dl>
- <!-- BEGIN data -->
- <dl>
- <dt><label for="{data.DATA}">{data.NAME}{L_COLON}</label><br /><span>{data.EXPLAIN}</span></dt>
- <dd><input type="<!-- IF data.DATA == 'password' -->password<!-- ELSE -->text<!-- ENDIF -->" id="{data.DATA}" name="{data.DATA}" value="{data.DEFAULT}" /></dd>
- </dl>
- <!-- END data -->
- </fieldset>
-
- <fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}
- <input class="button2" type="submit" name="check_again" value="{L_BACK}" />
- <input class="button1" type="submit" name="test_connection" value="{L_TEST_CONNECTION}" />
- <input class="button1" type="submit" name="submit" value="{L_UPDATE_FILES}" />
- </fieldset>
-
- </form>
-
-<!-- ENDIF -->
-
-<!-- INCLUDE install_footer.html -->
diff --git a/phpBB/adm/style/install_update_diff.html b/phpBB/adm/style/install_update_diff.html
deleted file mode 100644
index 324dc50d05..0000000000
--- a/phpBB/adm/style/install_update_diff.html
+++ /dev/null
@@ -1,255 +0,0 @@
-<!DOCTYPE html>
-<html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">
-<head>
-<meta charset="utf-8">
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="viewport" content="width=device-width, initial-scale=1" />
-<!-- IF META -->{META}<!-- ENDIF -->
-<title>{PAGE_TITLE}</title>
-
-<link href="{T_TEMPLATE_PATH}/admin.css" rel="stylesheet" type="text/css" media="screen" />
-
-<script type="text/javascript">
-// <![CDATA[
-function resize_panel()
-{
- var block = document.getElementById('diff_content');
- var height;
-
- if (window.innerHeight)
- {
- height = window.innerHeight - 200;
- block.style.height = height + 'px';
- }
- else
- {
- //whatever IE needs to do this
- }
-}
-
-window.onresize = resize_panel;
-
-// ]]>
-</script>
-
-<style type="text/css">
-/* <![CDATA[ */
-
-#main, .rtl #main {
- font-size: 1em;
- line-height: 0.7em;
- margin: 0;
- padding: 0;
- width: 99%;
-}
-
-#diff_content {
- padding: 30px 10px 10px;
- overflow: hidden;
-}
-
-<!-- IF DIFF_MODE neq 'side_by_side' and DIFF_MODE neq 'raw' -->
-div#codepanel {
- width: 100%;
-}
-<!-- ELSE -->
-div#codepanel {
- background-color: #eee;
-}
-<!-- ENDIF -->
-
-<!-- IF DIFF_MODE neq 'unified' and DIFF_MODE neq 'side_by_side' -->
-div#diff_content pre {
- overflow: auto;
- height: 414px;
- width: 100% !important;
-}
-<!-- ENDIF -->
-
-<!-- IF not S_DIFF_NEW_FILE -->
-/**
-* Unified Diff
-*/
-.file {
- line-height: .7em;
- overflow: auto;
- height: 414px;
-}
-
-.diff {
- margin: 0;
-}
-
-.added {
- background-color: #dfd;
-}
-
-.removed {
- background-color: #fdd;
-}
-
-.info {
- color: #888;
-}
-
-.context {
- background-color: #eee;
-}
-
-/**
-* Inline Diff
-*/
-.ins {
- background-color: #dfd;
- text-decoration: underline;
-}
-
-.del {
- background-color: #fdd;
- text-decoration: line-through;
-}
-
-/**
-* Column Diff
-*/
-table.hrdiff {
- margin: 0 0 8px 5px;
- width: 100%;
- overflow: hidden;
- border-bottom: 1px solid #999;
- table-layout: fixed;
- background: transparent;
-}
-
-table.hrdiff th {
- text-align: left;
- width: 50%;
- color: #333;
- font-family: Verdana,Helvetica,sans-serif;
- font-size: 11px;
- border-bottom: 1px solid #999;
- border-right: 1px solid #999;
- background: #D9D9D9;
-}
-
-table.hrdiff thead th {
- font-weight: bold;
- font-size: 110%;
- padding: 2px;
-}
-
-table.hrdiff tr:first-child th {
- border-top: none;
-}
-
-table.hrdiff tbody th {
- font-size: 80%;
- border-top: 1px solid #999;
-}
-
-table.hrdiff tbody td {
- border-right: 1px solid #999;
-}
-
-table.hrdiff td pre {
- font-family: "Consolas", monospace;
- font-size: 1.1em;
- white-space: pre-wrap; /* css-3 */
- word-wrap: break-word; /* Internet Explorer 5.5+ */
-}
-
-table.hrdiff .unmodified {
- background: transparent;
-}
-
-table.hrdiff .added {
- background: #9f9;
-}
-
-table.hrdiff .added_empty {
- background: #cfc;
-}
-
-table.hrdiff .modified {
- background: #fd9;
-}
-
-table.hrdiff .removed {
- background: #f99;
-}
-
-table.hrdiff .removed_empty {
- background: #fcc;
-}
-
-table.hrdiff caption {
- caption-side: top;
- text-align: left;
- margin: 0 0 8px 5px;
- font-size: 90%;
- font-weight: bold;
- padding: 5px;
-}
-
-table.hrdiff caption span {
- height: 10px;
- width: 10px;
- line-height: 10px;
- letter-spacing: 10px;
- border: 1px solid #000;
- margin-left: 0.5em;
- vertical-align: baseline;
-}
-
-<!-- ENDIF -->
-
-/* ]]> */
-</style>
-
-</head>
-
-<!-- IF DIFF_MODE neq 'side_by_side' and DIFF_MODE neq 'raw' -->
-<body onload="resize_panel();">
-<!-- ELSE -->
-<body>
-<!-- ENDIF -->
-
-<div id="wrap">
- <div id="page-header">
-<!-- IF S_DIFF_NEW_FILE -->
-
- <h1>{L_VIEWING_FILE_CONTENTS}</h1>
-<!-- ELSE -->
- <h1>{L_VIEWING_FILE_DIFF}</h1>
-<!-- ENDIF -->
-<!-- IF not S_DIFF_NEW_FILE -->
- <p id="skip"><a href="#acp">{L_SKIP}</a></p>
- <form method="post" action="#">
- <fieldset class="quick">
- <label for="diff_mode">{L_SELECT_DIFF_MODE}{L_COLON}</label>
- <select name="diff_mode" id="diff_mode">{S_DIFF_MODE_OPTIONS}</select>
-
- <input class="button1" type="submit" id="submit" name="submit" value="{L_CHANGE}" />
- </fieldset>
- </form>
-<!-- ENDIF -->
-<!-- IF S_DIFF_CONFLICT_FILE -->
- <div style="float: {S_CONTENT_FLOW_BEGIN};"><strong>{L_NUM_CONFLICTS}{L_COLON} {NUM_CONFLICTS}</strong></div>
- <br style="clear: both;" />
-<!-- ENDIF -->
- </div>
-
- <div id="page-body">
- <div id="acp">
- <div id="codepanel">
- <div id="diff_content">
- <div id="main">
- {DIFF_CONTENT}
- </div>
- </div>
- </div>
- </div>
- </div>
-
-
-<!-- INCLUDE simple_footer.html -->
diff --git a/phpBB/adm/style/installer_convert.html b/phpBB/adm/style/installer_convert.html
new file mode 100644
index 0000000000..aa16542b6b
--- /dev/null
+++ b/phpBB/adm/style/installer_convert.html
@@ -0,0 +1,87 @@
+<!-- INCLUDE installer_header.html -->
+<!-- IF TITLE --><h1>{TITLE}</h1><!-- ENDIF -->
+<!-- IF S_ERROR_BOX -->
+<div class="errorbox">
+ <h3>{ERROR_TITLE}</h3>
+ <p>{ERROR_MSG}</p>
+</div>
+<!-- ENDIF -->
+<!-- IF .errors -->
+<div id="error-container">
+<!-- BEGIN errors -->
+ <strong>{errors.TITLE}</strong>
+ <!-- IF errors.DESCRIPTION --><p>{errors.DESCRIPTION}</p><!-- ENDIF -->
+<!-- END errors -->
+</div>
+<!-- ENDIF -->
+<!-- IF BODY --><p>{BODY}</p><!-- ENDIF -->
+<!-- IF CONTENT -->{CONTENT}<!-- ENDIF -->
+<!-- IF S_CONV_IN_PROGRESS -->
+<p class="centered-text"><a href="{U_ACTION}" class="button1<!-- IF S_REFRESH --> disabled<!-- ENDIF -->"<!-- IF S_REFRESH --> onclick="return false;"<!-- ENDIF -->>{L_SUBMIT}</a></p>
+<!-- ENDIF -->
+<!-- IF S_CONTINUE -->
+<div id="download-wrapper" class="download-box">
+ <p class="centered-text">
+ <a href="{U_NEW_ACTION}" class="button1">{L_CONVERT_NEW_CONVERSION}</a>
+ <a href="{U_CONTINUE_ACTION}" class="button1">{L_CONTINUE_OLD_CONVERSION}</a>
+ </p>
+</div>
+<!-- ENDIF -->
+<!-- IF S_LIST -->
+<table class="table1">
+ <caption>{L_AVAILABLE_CONVERTORS}</caption>
+ <col class="col1" /><col class="col2" /><col class="col1" /><col class="col2" />
+ <thead>
+ <tr>
+ <th>{L_SOFTWARE}</th>
+ <th>{L_VERSION}</th>
+ <th>{L_AUTHOR}</th>
+ <th>{L_CONVERT_OPTIONS}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- IF .convertors -->
+ <!-- BEGIN convertors -->
+ <tr>
+ <td>{convertors.SOFTWARE}</td>
+ <td>{convertors.VERSION}</td>
+ <td>{convertors.AUTHOR}</td>
+ <td><a href="{convertors.U_CONVERT}">{L_CONVERT}</a></td>
+ </tr>
+ <!-- END convertors -->
+ <!-- ELSE -->
+ <tr>
+ <td>{L_NO_CONVERTORS}</td>
+ <td>-</td>
+ <td>-</td>
+ <td>-</td>
+ </tr>
+ <!-- ENDIF -->
+ </tbody>
+</table>
+<!-- ENDIF -->
+<!-- IF .checks -->
+<fieldset>
+
+ <!-- BEGIN checks -->
+ <!-- IF checks.S_LEGEND -->
+ <!-- IF not checks.S_FIRST_ROW -->
+</fieldset>
+
+<fieldset>
+ <!-- ENDIF -->
+ <legend>{checks.LEGEND}</legend>
+ <!-- IF checks.LEGEND_EXPLAIN --><p>{checks.LEGEND_EXPLAIN}</p><!-- ENDIF -->
+ <!-- ELSE -->
+
+ <dl>
+ <dt><label>{checks.TITLE}{L_COLON}</label><!-- IF checks.S_EXPLAIN --><br /><span class="explain">{checks.TITLE_EXPLAIN}</span><!-- ENDIF --></dt>
+ <dd>{checks.RESULT}</dd>
+ </dl>
+ <!-- ENDIF -->
+ <!-- END checks -->
+
+</fieldset>
+<!-- ENDIF -->
+<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/installer.js -->
+<!-- INCLUDE installer_footer.html -->
diff --git a/phpBB/adm/style/installer_footer.html b/phpBB/adm/style/installer_footer.html
new file mode 100644
index 0000000000..8b3b04d8a5
--- /dev/null
+++ b/phpBB/adm/style/installer_footer.html
@@ -0,0 +1,32 @@
+ </div>
+ </div><!-- /#main -->
+ </div>
+ </div><!-- /#acp -->
+ </div>
+
+ <div id="page-footer">
+ <div class="copyright">
+ {% if S_COPYRIGHT_HTML %}
+ {{ CREDIT_LINE }}
+ {% endif %}
+ </div>
+ </div>
+</div>
+
+<script>
+<!--
+installLang = {
+ title: '{LA_TIMEOUT_DETECTED_TITLE}',
+ msg: '{LA_TIMEOUT_DETECTED_MESSAGE}'
+};
+//-->
+</script>
+
+<script src="{T_JQUERY_LINK}"></script>
+<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js">\x3C/script>');</script><!-- ENDIF -->
+<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
+<!-- INCLUDEJS admin.js -->
+{$SCRIPTS}
+
+</body>
+</html>
diff --git a/phpBB/adm/style/installer_form.html b/phpBB/adm/style/installer_form.html
new file mode 100644
index 0000000000..592d361d1e
--- /dev/null
+++ b/phpBB/adm/style/installer_form.html
@@ -0,0 +1,57 @@
+<!-- IF FORM_TITLE --><h1>{FORM_TITLE}</h1><!-- ENDIF -->
+<form id="<!-- IF FORM_ID -->{FORM_ID}<!-- ELSE -->install_install<!-- ENDIF -->" method="POST" action="{U_ACTION}">
+<!-- IF .options -->
+<!-- IF S_NOT_ONLY_BUTTON_FORM -->
+<fieldset>
+<!-- ENDIF -->
+
+ <!-- BEGIN options -->
+ <!-- IF options.S_LEGEND -->
+ <!-- IF not options.S_FIRST_ROW -->
+ </fieldset>
+ <!-- ENDIF -->
+ <fieldset>
+
+ <legend>{options.LEGEND}</legend>
+ <!-- ELSE -->
+ <dl>
+ <dt><label for="{options.KEY}">{options.TITLE}{L_COLON}</label><!-- IF options.S_EXPLAIN --><br /><span class="explain">{options.TITLE_EXPLAIN}</span><!-- ENDIF --></dt>
+ <dd>
+ <!-- IF options.TYPE == 'text' -->
+ <input type="text" name="{options.KEY}" value="{options.DEFAULT}" />
+ <!-- ENDIF -->
+ <!-- IF options.TYPE == 'email' -->
+ <input type="email" name="{options.KEY}" value="{options.DEFAULT}" />
+ <!-- ENDIF -->
+ <!-- IF options.TYPE == 'password' -->
+ <input type="password" name="{options.KEY}" />
+ <!-- ENDIF -->
+ <!-- IF options.TYPE == 'select' -->
+ <select name="{options.KEY}">
+ <!-- BEGIN options.OPTIONS -->
+ <option value="{options.OPTIONS.value}"<!-- IF options.OPTIONS.selected --> selected<!-- ENDIF -->>{options.OPTIONS.label}</option>
+ <!-- END options.OPTIONS -->
+ </select>
+ <!-- ENDIF -->
+ <!-- IF options.TYPE == 'radio' -->
+ <!-- BEGIN options.OPTIONS -->
+ <input type="radio" name="{options.KEY}" value="{options.OPTIONS.value}" <!-- IF options.OPTIONS.selected -->checked<!-- ENDIF --> /> {options.OPTIONS.label}
+ <!-- END options.OPTIONS -->
+ <!-- ENDIF -->
+ </dd>
+ </dl>
+ <!-- ENDIF-->
+ <!-- END options -->
+<!-- IF S_NOT_ONLY_BUTTON_FORM -->
+</fieldset>
+<!-- ENDIF -->
+<!-- ENDIF -->
+<!-- IF .submit_buttons -->
+<fieldset class="submit-buttons">
+ <legend>{L_SUBMIT}</legend>
+ <!-- BEGIN submit_buttons -->
+ <input class="<!-- IF not submit_buttons.IS_SECONDARY -->button1<!-- ELSE -->button2<!-- ENDIF --><!-- IF submit_buttons.DISABLED --> disabled<!-- ENDIF -->" type="submit" name="{submit_buttons.KEY}" value="{submit_buttons.TITLE}"<!-- IF submit_buttons.DISABLED --> disabled="disabled"<!-- ENDIF --> />
+ <!-- END submit_buttons -->
+</fieldset>
+<!-- ENDIF -->
+</form>
diff --git a/phpBB/adm/style/installer_header.html b/phpBB/adm/style/installer_header.html
new file mode 100644
index 0000000000..704db9e174
--- /dev/null
+++ b/phpBB/adm/style/installer_header.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <!-- IF META -->{META}<!-- ENDIF -->
+ <title>{PAGE_TITLE}</title>
+
+ <link href="{T_TEMPLATE_PATH}/admin.css" rel="stylesheet" type="text/css" media="screen" />
+</head>
+
+<body class="{S_CONTENT_DIRECTION} nojs">
+<div id="wrap">
+ <div id="page-header">
+ <h1>{L_INSTALL_PANEL}</h1>
+ <p id="skip"><a href="#acp">{L_SKIP}</a></p>
+ <!-- IF S_LANG_SELECT -->
+ <form method="post" action="#" id="language_selector">
+ <fieldset class="nobg">
+ <label for="language">{L_SELECT_LANG}{L_COLON}</label>
+ <select id="language" name="language">
+ <!-- BEGIN language_select_item -->
+ <option value="{language_select_item.VALUE}"<!-- IF language_select_item.SELECTED --> selected="selected"<!-- ENDIF -->>{language_select_item.NAME}</option>
+ <!-- END language_select_item -->
+ </select>
+ <input class="button1" type="submit" id="change_lang" name="change_lang" value="{L_CHANGE}" />
+ </fieldset>
+ </form>
+ <!-- ENDIF -->
+ </div>
+
+ <div id="page-body">
+ <div id="tabs">
+ <ul>
+ <!-- BEGIN t_block1 -->
+ <li class="tab<!-- IF t_block1.S_SELECTED --> activetab<!-- ENDIF -->"><a href="{t_block1.U_TITLE}">{t_block1.L_TITLE}</a></li>
+ <!-- END t_block1 -->
+ </ul>
+ </div>
+
+ <div id="acp">
+ <div id="content">
+ <div id="menu">
+ <div class="menu-block no-header">
+ <ul>
+ <!-- BEGIN l_block1 -->
+ <li<!-- IF l_block1.S_SELECTED --> id="activemenu"<!-- ENDIF -->><a href="{l_block1.U_TITLE}"><span>{l_block1.L_TITLE}</span></a></li>
+ <!-- END l_block1 -->
+ <!-- BEGIN l_block2 -->
+ <li<!-- IF l_block2.S_SELECTED --> id="activemenu"<!-- ENDIF -->><span<!-- IF l_block2.S_COMPLETE --> class="completed"<!-- ENDIF --> id="installer-stage-{l_block2.STAGE_NAME}">{l_block2.L_TITLE}</span></li>
+ <!-- END l_block2 -->
+ </ul>
+ </div>
+ </div>
+
+ <div id="main" class="install-body">
+ <div class="main">
diff --git a/phpBB/adm/style/installer_install.html b/phpBB/adm/style/installer_install.html
new file mode 100644
index 0000000000..53a91f2700
--- /dev/null
+++ b/phpBB/adm/style/installer_install.html
@@ -0,0 +1,13 @@
+<!-- INCLUDE installer_header.html -->
+<h1>{TITLE}</h1>
+<p>{CONTENT}</p>
+<!-- IF SHOW_INSTALL_START_FORM -->
+<form id="install_install" method="post" action="{U_ACTION}">
+ <fieldset class="submit-buttons">
+ <legend>{L_SUBMIT}</legend>
+ <input class="button1" name="install" type="submit" value="{L_INSTALL}" />
+ </fieldset>
+</form>
+<!-- ENDIF -->
+<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/installer.js -->
+<!-- INCLUDE installer_footer.html -->
diff --git a/phpBB/adm/style/installer_main.html b/phpBB/adm/style/installer_main.html
new file mode 100644
index 0000000000..f14fe4da70
--- /dev/null
+++ b/phpBB/adm/style/installer_main.html
@@ -0,0 +1,6 @@
+<!-- INCLUDE installer_header.html -->
+
+ <h1>{TITLE}</h1>
+ <p>{BODY}</p>
+
+<!-- INCLUDE installer_footer.html -->
diff --git a/phpBB/adm/style/installer_update.html b/phpBB/adm/style/installer_update.html
new file mode 100644
index 0000000000..48cc07f5d6
--- /dev/null
+++ b/phpBB/adm/style/installer_update.html
@@ -0,0 +1,13 @@
+<!-- INCLUDE installer_header.html -->
+<h1>{TITLE}</h1>
+<p>{CONTENT}</p>
+<!-- IF SHOW_INSTALL_START_FORM -->
+<form id="install_install" method="post" action="{U_ACTION}">
+ <fieldset class="submit-buttons">
+ <legend>{L_SUBMIT}</legend>
+ <input class="button1" name="update" type="submit" value="{L_UPDATE}" />
+ </fieldset>
+</form>
+<!-- ENDIF -->
+<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/installer.js -->
+<!-- INCLUDE installer_footer.html -->
diff --git a/phpBB/adm/style/installer_update_file_status.html b/phpBB/adm/style/installer_update_file_status.html
new file mode 100644
index 0000000000..a27bfa6a44
--- /dev/null
+++ b/phpBB/adm/style/installer_update_file_status.html
@@ -0,0 +1,80 @@
+<!-- IF .deleted -->
+<h2>{L_FILES_DELETED}</h2>
+<div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('deleted', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
+<p>{L_FILES_DELETED_EXPLAIN}</p>
+
+<fieldset id="deleted">
+ <legend><img src="{T_IMAGE_PATH}/icon_delete.gif" alt="{L_STATUS_DELETED}" /></legend>
+ <!-- BEGIN deleted -->
+ <dl>
+ <dt style="width: 100%;"><!-- IF deleted.DIR_PART -->{deleted.DIR_PART}<!-- ENDIF --><strong>{deleted.FILE_PART}</strong></dt>
+ </dl>
+ <!-- END deleted -->
+</fieldset>
+
+<!-- ENDIF -->
+
+<!-- IF .conflict -->
+<h2>{L_FILES_CONFLICT}</h2>
+<div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('conflict', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
+<p>{L_FILES_CONFLICT_EXPLAIN}</p>
+
+<fieldset id="conflict">
+ <legend><img src="{T_IMAGE_PATH}/file_conflict.gif" alt="{L_STATUS_CONFLICT}" /></legend>
+ <!-- BEGIN conflict -->
+ <dl>
+ <dt style="width: 100%;"><!-- IF conflict.DIR_PART -->{conflict.DIR_PART}<!-- ENDIF --><strong>{conflict.FILE_PART}</strong></dt>
+ </dl>
+ <!-- END conflict -->
+</fieldset>
+
+<!-- ENDIF -->
+
+<!-- IF .modified -->
+<h2>{L_FILES_MODIFIED}</h2>
+<div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('modified', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
+<p>{L_FILES_MODIFIED_EXPLAIN}</p>
+
+<fieldset id="modified">
+ <legend><img src="{T_IMAGE_PATH}/file_modified.gif" alt="{L_STATUS_MODIFIED}" /></legend>
+ <!-- BEGIN modified -->
+ <dl>
+ <dt style="width: 100%;"><!-- IF modified.DIR_PART -->{modified.DIR_PART}<!-- ENDIF --><strong>{modified.FILE_PART}</strong></dt>
+ </dl>
+ <!-- END modified -->
+</fieldset>
+
+<!-- ENDIF -->
+
+<!-- IF .new -->
+<h2>{L_FILES_NEW}</h2>
+<div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('new_files', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
+<p>{L_FILES_NEW_EXPLAIN}</p>
+
+<fieldset id="new_files" style="display: none;">
+ <legend><img src="{T_IMAGE_PATH}/file_new.gif" alt="{L_STATUS_NEW}" /></legend>
+ <!-- BEGIN new -->
+ <dl>
+ <dt style="width: 100%;"><!-- IF new.DIR_PART -->{new.DIR_PART}<!-- ENDIF --><strong>{new.FILE_PART}</strong>
+ </dt>
+ </dl>
+ <!-- END new -->
+</fieldset>
+
+<!-- ENDIF -->
+
+<!-- IF .not_modified -->
+<h2>{L_FILES_NOT_MODIFIED}</h2>
+<div style="float: {S_CONTENT_FLOW_END};">&raquo; <a href="#" onclick="phpbb.toggleDisplay('not_modified', 0); return false;">{L_TOGGLE_DISPLAY}</a></div>
+<p>{L_FILES_NOT_MODIFIED_EXPLAIN}</p>
+
+<fieldset id="not_modified" style="display: none;">
+ <legend><img src="{T_IMAGE_PATH}/file_not_modified.gif" alt="{L_STATUS_NOT_MODIFIED}" /></legend>
+ <!-- BEGIN not_modified -->
+ <dl>
+ <dt style="width: 100%;"><!-- IF not_modified.DIR_PART -->{not_modified.DIR_PART}<!-- ENDIF --><strong>{not_modified.FILE_PART}</strong></dt>
+ </dl>
+ <!-- END not_modified -->
+</fieldset>
+
+<!-- ENDIF -->
diff --git a/phpBB/adm/style/overall_footer.html b/phpBB/adm/style/overall_footer.html
index 8745286d64..3ab633e04b 100644
--- a/phpBB/adm/style/overall_footer.html
+++ b/phpBB/adm/style/overall_footer.html
@@ -33,9 +33,9 @@
</div>
</div>
-<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
-<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
-<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
+<script src="{T_JQUERY_LINK}"></script>
+<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
+<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
<!-- INCLUDEJS ajax.js -->
<!-- INCLUDEJS admin.js -->
diff --git a/phpBB/adm/style/overall_header.html b/phpBB/adm/style/overall_header.html
index bd8caf1443..fa361d6016 100644
--- a/phpBB/adm/style/overall_header.html
+++ b/phpBB/adm/style/overall_header.html
@@ -7,9 +7,10 @@
<!-- IF META -->{META}<!-- ENDIF -->
<title>{PAGE_TITLE}</title>
+<link href="{T_FONT_AWESOME_LINK}" rel="stylesheet">
<link href="style/admin.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen" />
-<script type="text/javascript">
+<script>
// <![CDATA[
var jump_page = '{LA_JUMP_PAGE}{L_COLON}';
var on_page = '{CURRENT_PAGE}';
@@ -50,7 +51,7 @@ function marklist(id, name, state)
}
var rb = parent.getElementsByTagName('input');
-
+
for (var r = 0; r < rb.length; r++)
{
if (rb[r].name.substr(0, name.length) == name && rb[r].disabled !== true)
@@ -104,7 +105,7 @@ function popup(url, width, height, name)
<p><a href="{U_ADM_INDEX}">{L_ADMIN_INDEX}</a> &bull; <a href="{U_INDEX}">{L_FORUM_INDEX}</a></p>
<p id="skip"><a href="#acp">{L_SKIP}</a></p>
</div>
-
+
<div id="page-body">
<div id="tabs">
<ul>
@@ -121,7 +122,7 @@ function popup(url, width, height, name)
<!-- DEFINE $LI_USED = 0 -->
<!-- BEGIN l_block1 -->
<!-- IF l_block1.S_SELECTED -->
-
+
<!-- BEGIN l_block2 -->
<!-- IF .l_block1.l_block2.l_block3 -->
<!-- IF $LI_USED --></ul></div><!-- ENDIF -->
@@ -130,13 +131,13 @@ function popup(url, width, height, name)
<ul>
<!-- DEFINE $LI_USED = 1 -->
<!-- ENDIF -->
-
+
<!-- BEGIN l_block3 -->
<li<!-- IF l_block1.l_block2.l_block3.S_SELECTED --> id="activemenu"<!-- ENDIF -->><a href="{l_block1.l_block2.l_block3.U_TITLE}"><span>{l_block1.l_block2.l_block3.L_TITLE}</span></a></li>
<!-- DEFINE $LI_USED = 1 -->
<!-- END l_block3 -->
<!-- END l_block2 -->
-
+
<!-- ENDIF -->
<!-- END l_block1 -->
<!-- IF $LI_USED -->
@@ -144,6 +145,13 @@ function popup(url, width, height, name)
</div>
<!-- ENDIF -->
</div>
-
+
<div id="main">
<div class="main">
+ {% if CONTAINER_EXCEPTION !== false %}
+ <div class="errorbox">
+ <p>{{ lang('CONTAINER_EXCEPTION') }}</p><br />
+ <p>{{ lang('EXCEPTION') }}{{ lang('COLON') }} {{ CONTAINER_EXCEPTION.getMessage() }}</p>
+ <pre>{{ CONTAINER_EXCEPTION.getTraceAsString() }}</pre>
+ </div>
+ {% endif %}
diff --git a/phpBB/adm/style/permission_mask.html b/phpBB/adm/style/permission_mask.html
index 7b5c071693..26aa5e098f 100644
--- a/phpBB/adm/style/permission_mask.html
+++ b/phpBB/adm/style/permission_mask.html
@@ -1,5 +1,5 @@
-<script type="text/javascript">
+<script>
// <![CDATA[
var active_pmask = '0';
var active_fmask = '0';
@@ -9,12 +9,14 @@
var role_options = new Array();
+ var no_role_assigned = "{LA_NO_ROLE_ASSIGNED}";
+
<!-- IF S_ROLE_JS_ARRAY -->
{S_ROLE_JS_ARRAY}
<!-- ENDIF -->
// ]]>
</script>
-<script type="text/javascript" src="style/permissions.js"></script>
+<script src="style/permissions.js"></script>
<!-- BEGIN p_mask -->
<div class="clearfix"></div>
@@ -39,11 +41,24 @@
</div>
<dl class="permissions-simple">
<dt style="width: 20%"><label for="role{p_mask.S_ROW_COUNT}{p_mask.f_mask.S_ROW_COUNT}">{L_ROLE}{L_COLON}</label></dt>
- <!-- IF p_mask.f_mask.S_ROLE_OPTIONS -->
- <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 20%"><select id="role{p_mask.S_ROW_COUNT}{p_mask.f_mask.S_ROW_COUNT}" name="role[{p_mask.f_mask.UG_ID}][{p_mask.f_mask.FORUM_ID}]" onchange="set_role_settings(this.options[selectedIndex].value, 'advanced{p_mask.S_ROW_COUNT}{p_mask.f_mask.S_ROW_COUNT}'); init_colours('{p_mask.S_ROW_COUNT}{p_mask.f_mask.S_ROW_COUNT}')">{p_mask.f_mask.S_ROLE_OPTIONS}</select></dd>
- <!-- ELSE -->
+ {% if p_mask.f_mask.role_options %}
+ <dd style="margin-{S_CONTENT_FLOW_BEGIN}{L_COLON} 20%">
+ <div class="dropdown-container dropdown-{S_CONTENT_FLOW_END} dropdown-button-control roles-options" data-alt-text="{LA_ROLE_DESCRIPTION}">
+ <select id="role{p_mask.S_ROW_COUNT}{p_mask.f_mask.S_ROW_COUNT}" name="role[{p_mask.f_mask.UG_ID}][{p_mask.f_mask.FORUM_ID}]">{p_mask.f_mask.S_ROLE_OPTIONS}</select>
+ <span title="Roles" class="button icon-button tools-icon dropdown-trigger dropdown-select">{L_NO_ROLE_ASSIGNED}</span>
+ <div class="dropdown hidden">
+ <ul class="dropdown-contents" id="role{p_mask.S_ROW_COUNT}{p_mask.f_mask.S_ROW_COUNT}" >
+ {% for role in p_mask.f_mask.role_options %}
+ <li data-id="{{ role.ID }}" data-target-id="advanced{p_mask.S_ROW_COUNT}{p_mask.f_mask.S_ROW_COUNT}" data-title="{{ role.TITLE }}"{% if role.SELECTED == true %} data-selected="{{ role.SELECTED }}"{% endif %}>{{ role.ROLE_NAME }}</li>
+ {% endfor %}
+ </ul>
+ </div>
+ <input type="hidden" data-name="role[{p_mask.f_mask.UG_ID}][{p_mask.f_mask.FORUM_ID}]"{% if p_mask.f_mask.S_ROLE_ID %}value="{{ p_mask.f_mask.S_ROLE_ID }}"{% endif %} />
+ </div>
+ </dd>
+ {% else %}
<dd>{L_NO_ROLE_AVAILABLE}</dd>
- <!-- ENDIF -->
+ {% endif %}
</dl>
<!-- ENDIF -->
diff --git a/phpBB/adm/style/permissions.js b/phpBB/adm/style/permissions.js
index 9178adab50..af8e21ad51 100644
--- a/phpBB/adm/style/permissions.js
+++ b/phpBB/adm/style/permissions.js
@@ -279,6 +279,10 @@ function reset_role(id) {
}
t.options[0].selected = true;
+
+ var parent = t.parentNode;
+ parent.querySelector('span.dropdown-trigger').innerText = no_role_assigned;
+ parent.querySelector('input[data-name^=role]').value = '0';
}
/**
diff --git a/phpBB/adm/style/progress_bar.html b/phpBB/adm/style/progress_bar.html
index 1822675c15..1e58257ff0 100644
--- a/phpBB/adm/style/progress_bar.html
+++ b/phpBB/adm/style/progress_bar.html
@@ -1,6 +1,6 @@
<!-- INCLUDE simple_header.html -->
-<script type="text/javascript">
+<script>
// <![CDATA[
/**
* Close previously opened popup
@@ -31,7 +31,7 @@
<p>{L_PROGRESS_EXPLAIN}</p>
</div>
-<script type="text/javascript">
+<script>
// <![CDATA[
close_popup();
// ]]>
diff --git a/phpBB/adm/style/simple_footer.html b/phpBB/adm/style/simple_footer.html
index 08ee0a739f..4b54b83373 100644
--- a/phpBB/adm/style/simple_footer.html
+++ b/phpBB/adm/style/simple_footer.html
@@ -16,9 +16,9 @@
</div>
-<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
-<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
-<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
+<script src="{T_JQUERY_LINK}"></script>
+<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
+<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
<!-- EVENT acp_simple_footer_after -->
{$SCRIPTS}
diff --git a/phpBB/adm/style/simple_header.html b/phpBB/adm/style/simple_header.html
index 439645a211..a8a32bf768 100644
--- a/phpBB/adm/style/simple_header.html
+++ b/phpBB/adm/style/simple_header.html
@@ -9,7 +9,7 @@
<link href="style/admin.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen" />
-<script type="text/javascript">
+<script>
// <![CDATA[
var jump_page = '{LA_JUMP_PAGE}{L_COLON}';
var on_page = '{CURRENT_PAGE}';
diff --git a/phpBB/adm/style/tooltip.js b/phpBB/adm/style/tooltip.js
index 3a89008706..7b7abb11e6 100644
--- a/phpBB/adm/style/tooltip.js
+++ b/phpBB/adm/style/tooltip.js
@@ -10,206 +10,231 @@ phpBB Development Team:
- further adjustements
*/
-var head_text, tooltip_mode;
+(function($) { // Avoid conflicts with other libraries
-/**
-* Enable tooltip replacements for links
-*/
-function enable_tooltips_link(id, headline, sub_id) {
- var links, i, hold;
-
- head_text = headline;
-
- if (!document.getElementById || !document.getElementsByTagName) {
- return;
- }
-
- hold = document.createElement('span');
- hold.id = '_tooltip_container';
- hold.setAttribute('id', '_tooltip_container');
- hold.style.position = 'absolute';
-
- document.getElementsByTagName('body')[0].appendChild(hold);
-
- if (id === null) {
- links = document.getElementsByTagName('a');
- } else {
- links = document.getElementById(id).getElementsByTagName('a');
- }
-
- for (i = 0; i < links.length; i++) {
- if (sub_id) {
- if (links[i].id.substr(0, sub_id.length) === sub_id) {
- prepare(links[i]);
- }
- } else {
- prepare(links[i]);
- }
- }
+'use strict';
- tooltip_mode = 'link';
-}
+var tooltips = [];
/**
-* Enable tooltip replacements for selects
+ * Enable tooltip replacements for selects
+ * @param {string} id ID tag of select
+ * @param {string} headline Text that should appear on top of tooltip
+ * @param {string} [subId] Sub ID that should only be using tooltips (optional)
*/
-function enable_tooltips_select(id, headline, sub_id) {
- var links, i, hold;
-
- head_text = headline;
-
- if (!document.getElementById || !document.getElementsByTagName) {
- return;
- }
+phpbb.enableTooltipsSelect = function (id, headline, subId) {
+ var $links, hold;
- hold = document.createElement('span');
- hold.id = '_tooltip_container';
- hold.setAttribute('id', '_tooltip_container');
- hold.style.position = 'absolute';
+ hold = $('<span />', {
+ id: '_tooltip_container',
+ css: {
+ position: 'absolute'
+ }
+ });
- document.getElementsByTagName('body')[0].appendChild(hold);
+ $('body').append(hold);
- if (id === null) {
- links = document.getElementsByTagName('option');
+ if (!id) {
+ $links = $('.roles-options li');
} else {
- links = document.getElementById(id).getElementsByTagName('option');
+ $links = $('.roles-options li', '#' + id);
}
- for (i = 0; i < links.length; i++) {
- if (sub_id) {
- if (links[i].parentNode.id.substr(0, sub_id.length) === sub_id) {
- prepare(links[i]);
+ $links.each(function () {
+ var $this = $(this);
+
+ if (subId) {
+ if ($this.parent().attr('id').substr(0, subId.length) === subId) {
+ phpbb.prepareTooltips($this, headline);
}
} else {
- prepare(links[i]);
+ phpbb.prepareTooltips($this, headline);
}
- }
-
- tooltip_mode = 'select';
-}
+ });
+};
/**
-* Prepare elements to replace
+ * Prepare elements to replace
+ *
+ * @param {jQuery} $element Element to prepare for tooltips
+ * @param {string} headText Text heading to display
*/
-function prepare(element) {
- var tooltip, text, desc, title;
+phpbb.prepareTooltips = function ($element, headText) {
+ var $tooltip, text, $desc, $title;
- text = element.getAttribute('title');
+ text = $element.attr('data-title');
if (text === null || text.length === 0) {
return;
}
- element.removeAttribute('title');
- tooltip = create_element('span', 'tooltip');
-
- title = create_element('span', 'top');
- title.appendChild(document.createTextNode(head_text));
- tooltip.appendChild(title);
-
- desc = create_element('span', 'bottom');
- desc.innerHTML = text;
- tooltip.appendChild(desc);
+ $title = $('<span />', {
+ class: 'top',
+ css: {
+ display: 'block'
+ }
+ })
+ .append(document.createTextNode(headText));
+
+ $desc = $('<span />', {
+ class: 'bottom',
+ html: text,
+ css: {
+ display: 'block'
+ }
+ });
- set_opacity(tooltip);
+ $tooltip = $('<span />', {
+ class: 'tooltip',
+ css: {
+ display: 'block'
+ }
+ })
+ .append($title)
+ .append($desc);
- element.tooltip = tooltip;
- element.onmouseover = show_tooltip;
- element.onmouseout = hide_tooltip;
-
- if (tooltip_mode === 'link') {
- element.onmousemove = locate;
- }
-}
+ tooltips[$element.attr('data-id')] = $tooltip;
+ $element.on('mouseover', phpbb.showTooltip);
+ $element.on('mouseout', phpbb.hideTooltip);
+};
/**
-* Show tooltip
+ * Show tooltip
+ *
+ * @param {object} $element Element passed by .on()
*/
-function show_tooltip(e) {
- document.getElementById('_tooltip_container').appendChild(this.tooltip);
- locate(this);
-}
+phpbb.showTooltip = function ($element) {
+ var $this = $($element.target);
+ $('#_tooltip_container').append(tooltips[$this.attr('data-id')]);
+ phpbb.positionTooltip($this);
+};
/**
-* Hide tooltip
+ * Hide tooltip
*/
-function hide_tooltip(e) {
+phpbb.hideTooltip = function () {
var d = document.getElementById('_tooltip_container');
if (d.childNodes.length > 0) {
d.removeChild(d.firstChild);
}
-}
+};
/**
-* Set opacity on tooltip element
+ * Correct positioning of tooltip container
+ *
+ * @param {jQuery} $element Tooltip element that should be positioned
*/
-function set_opacity(element) {
- element.style.filter = 'alpha(opacity:95)';
- element.style.KHTMLOpacity = '0.95';
- element.style.MozOpacity = '0.95';
- element.style.opacity = '0.95';
-}
+phpbb.positionTooltip = function ($element) {
+ var offset;
-/**
-* Create new element
-*/
-function create_element(tag, c) {
- var x = document.createElement(tag);
- x.className = c;
- x.style.display = 'block';
- return x;
-}
+ $element = $element.parent();
+ offset = $element.offset();
-/**
-* Correct positioning of tooltip container
-*/
-function locate(e) {
- var posx = 0;
- var posy = 0;
-
- e = e.parentNode;
-
- if (e.offsetParent) {
- for (posx = 0, posy = 0; e.offsetParent; e = e.offsetParent) {
- posx += e.offsetLeft;
- posy += e.offsetTop;
- }
+ if ($('body').hasClass('rtl')) {
+ $('#_tooltip_container').css({
+ top: offset.top + 30,
+ left: offset.left + 255
+ });
} else {
- posx = e.offsetLeft;
- posy = e.offsetTop;
+ $('#_tooltip_container').css({
+ top: offset.top + 30,
+ left: offset.left - 205
+ });
}
+};
- if (tooltip_mode === 'link') {
- document.getElementById('_tooltip_container').style.top=(posy+20) + 'px';
- document.getElementById('_tooltip_container').style.left=(posx-20) + 'px';
- } else {
- document.getElementById('_tooltip_container').style.top=(posy+30) + 'px';
- document.getElementById('_tooltip_container').style.left=(posx-205) + 'px';
- }
-
-/*
- if (e == null)
- {
- e = window.event;
- }
-
- if (e.pageX || e.pageY)
- {
- posx = e.pageX;
- posy = e.pageY;
- }
- else if (e.clientX || e.clientY)
- {
- if (document.documentElement.scrollTop)
- {
- posx = e.clientX+document.documentElement.scrollLeft;
- posy = e.clientY+document.documentElement.scrollTop;
+/**
+ * Prepare roles drop down select
+ */
+phpbb.prepareRolesDropdown = function () {
+ var $options = $('.roles-options li');
+
+ // Display span and hide select
+ $('.roles-options > span').css('display', 'block');
+ $('.roles-options > select').hide();
+ $('.roles-options > input[type=hidden]').each(function () {
+ var $this = $(this);
+
+ if ($this.attr('data-name') && !$this.attr('name')) {
+ $this.attr('name', $this.attr('data-name'));
}
- else
- {
- posx = e.clientX+document.body.scrollLeft;
- posy = e.clientY+document.body.scrollTop;
+ });
+
+ // Prepare highlighting of select options and settings update
+ $options.each(function () {
+ var $this = $(this);
+ var $rolesOptions = $this.closest('.roles-options');
+ var $span = $rolesOptions.children('span');
+
+ // Correctly show selected option
+ if (typeof $this.attr('data-selected') !== 'undefined') {
+ $rolesOptions
+ .children('span')
+ .text($this.text())
+ .attr('data-default', $this.text())
+ .attr('data-default-val', $this.attr('data-id'));
+
+ // Save default text of drop down if there is no default set yet
+ if (typeof $span.attr('data-default') === 'undefined') {
+ $span.attr('data-default', $span.text());
+ }
+
+ // Prepare resetting drop down on form reset
+ $this.closest('form').on('reset', function () {
+ $span.text($span.attr('data-default'));
+ $rolesOptions.children('input[type=hidden]')
+ .val($span.attr('data-default-val'));
+ });
}
- }
-*/
-}
+
+ $this.on('mouseover', function () {
+ var $this = $(this);
+ $options.removeClass('roles-highlight');
+ $this.addClass('roles-highlight');
+ }).on('click', function () {
+ var $this = $(this);
+ var $rolesOptions = $this.closest('.roles-options');
+
+ // Update settings
+ set_role_settings($this.attr('data-id'), $this.attr('data-target-id'));
+ init_colours($this.attr('data-target-id').replace('advanced', ''));
+
+ // Set selected setting
+ $rolesOptions.children('span')
+ .text($this.text());
+ $rolesOptions.children('input[type=hidden]')
+ .val($this.attr('data-id'));
+
+ // Trigger hiding of selection options
+ $('body').trigger('click');
+ });
+ });
+};
+
+// Run onload functions for RolesDropdown and tooltips
+$(function() {
+ // Enable tooltips
+ phpbb.enableTooltipsSelect('set-permissions', $('#set-permissions').attr('data-role-description'), 'role');
+
+ // Prepare dropdown
+ phpbb.prepareRolesDropdown();
+
+ // Reset role drop-down on modifying permissions in advanced tab
+ $('div.permissions-switch > a').on('click', function () {
+ $.each($('input[type=radio][name^="setting["]'), function () {
+ var $this = $(this);
+ $this.on('click', function () {
+ var $rolesOptions = $this.closest('fieldset.permissions').find('.roles-options'),
+ rolesSelect = $rolesOptions.find('select > option')[0];
+
+ // Set selected setting
+ $rolesOptions.children('span')
+ .text(rolesSelect.text);
+ $rolesOptions.children('input[type=hidden]')
+ .val(rolesSelect.value);
+ });
+ });
+ });
+});
+
+})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/app.php b/phpBB/app.php
index d9250adc75..4873fb10c3 100644
--- a/phpBB/app.php
+++ b/phpBB/app.php
@@ -21,14 +21,16 @@ define('IN_PHPBB', true);
$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
include($phpbb_root_path . 'common.' . $phpEx);
-include($phpbb_root_path . 'includes/functions_url_matcher.' . $phpEx);
// Start session management
$user->session_begin();
$auth->acl($user->data);
$user->setup('app');
+/* @var $http_kernel \Symfony\Component\HttpKernel\HttpKernel */
$http_kernel = $phpbb_container->get('http_kernel');
+
+/* @var $symfony_request \phpbb\symfony_request */
$symfony_request = $phpbb_container->get('symfony_request');
$response = $http_kernel->handle($symfony_request);
$response->send();
diff --git a/phpBB/assets/cookieconsent/cookieconsent.min.css b/phpBB/assets/cookieconsent/cookieconsent.min.css
new file mode 100644
index 0000000000..03c69fe82f
--- /dev/null
+++ b/phpBB/assets/cookieconsent/cookieconsent.min.css
@@ -0,0 +1,6 @@
+.cc-window{opacity:1;transition:opacity 1s ease}.cc-window.cc-invisible{opacity:0}.cc-animate.cc-revoke{transition:transform 1s ease}.cc-animate.cc-revoke.cc-top{transform:translateY(-2em)}.cc-animate.cc-revoke.cc-bottom{transform:translateY(2em)}.cc-animate.cc-revoke.cc-active.cc-bottom,.cc-animate.cc-revoke.cc-active.cc-top,.cc-revoke:hover{transform:translateY(0)}.cc-grower{max-height:0;overflow:hidden;transition:max-height 1s}
+.cc-link,.cc-revoke:hover{text-decoration:underline}.cc-revoke,.cc-window{position:fixed;overflow:hidden;box-sizing:border-box;font-family:Helvetica,Calibri,Arial,sans-serif;font-size:16px;line-height:1.5em;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;z-index:9999}.cc-window.cc-static{position:static}.cc-window.cc-floating{padding:2em;max-width:24em;-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner{padding:1em 1.8em;width:100%;-ms-flex-direction:row;flex-direction:row}.cc-revoke{padding:.5em}.cc-header{font-size:18px;font-weight:700}.cc-btn,.cc-close,.cc-link,.cc-revoke{cursor:pointer}.cc-link{opacity:.8;display:inline-block;padding:.2em}.cc-link:hover{opacity:1}.cc-link:active,.cc-link:visited{color:initial}.cc-btn{display:block;padding:.4em .8em;font-size:.9em;font-weight:700;border-width:2px;border-style:solid;text-align:center;white-space:nowrap}.cc-banner .cc-btn:last-child{min-width:140px}.cc-highlight .cc-btn:first-child{background-color:transparent;border-color:transparent}.cc-highlight .cc-btn:first-child:focus,.cc-highlight .cc-btn:first-child:hover{background-color:transparent;text-decoration:underline}.cc-close{display:block;position:absolute;top:.5em;right:.5em;font-size:1.6em;opacity:.9;line-height:.75}.cc-close:focus,.cc-close:hover{opacity:1}
+.cc-revoke.cc-top{top:0;left:3em;border-bottom-left-radius:.5em;border-bottom-right-radius:.5em}.cc-revoke.cc-bottom{bottom:0;left:3em;border-top-left-radius:.5em;border-top-right-radius:.5em}.cc-revoke.cc-left{left:3em;right:unset}.cc-revoke.cc-right{right:3em;left:unset}.cc-top{top:1em}.cc-left{left:1em}.cc-right{right:1em}.cc-bottom{bottom:1em}.cc-floating>.cc-link{margin-bottom:1em}.cc-floating .cc-message{display:block;margin-bottom:1em}.cc-window.cc-floating .cc-compliance{-ms-flex:1;flex:1}.cc-window.cc-banner{-ms-flex-align:center;align-items:center}.cc-banner.cc-top{left:0;right:0;top:0}.cc-banner.cc-bottom{left:0;right:0;bottom:0}.cc-banner .cc-message{-ms-flex:1;flex:1}.cc-compliance{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:justify;align-content:space-between}.cc-compliance>.cc-btn{-ms-flex:1;flex:1}.cc-btn+.cc-btn{margin-left:.5em}
+@media print{.cc-revoke,.cc-window{display:none}}@media screen and (max-width:900px){.cc-btn{white-space:normal}}@media screen and (max-width:414px) and (orientation:portrait),screen and (max-width:736px) and (orientation:landscape){.cc-window.cc-top{top:0}.cc-window.cc-bottom{bottom:0}.cc-window.cc-banner,.cc-window.cc-left,.cc-window.cc-right{left:0;right:0}.cc-window.cc-banner{-ms-flex-direction:column;flex-direction:column}.cc-window.cc-banner .cc-compliance{-ms-flex:1;flex:1}.cc-window.cc-floating{max-width:none}.cc-window .cc-message{margin-bottom:1em}.cc-window.cc-banner{-ms-flex-align:unset;align-items:unset}}
+.cc-floating.cc-theme-classic{padding:1.2em;border-radius:5px}.cc-floating.cc-type-info.cc-theme-classic .cc-compliance{text-align:center;display:inline;-ms-flex:none;flex:none}.cc-theme-classic .cc-btn{border-radius:5px}.cc-theme-classic .cc-btn:last-child{min-width:140px}.cc-floating.cc-type-info.cc-theme-classic .cc-btn{display:inline-block}
+.cc-theme-edgeless.cc-window{padding:0}.cc-floating.cc-theme-edgeless .cc-message{margin:2em 2em 1.5em}.cc-banner.cc-theme-edgeless .cc-btn{margin:0;padding:.8em 1.8em;height:100%}.cc-banner.cc-theme-edgeless .cc-message{margin-left:1em}.cc-floating.cc-theme-edgeless .cc-btn+.cc-btn{margin-left:0} \ No newline at end of file
diff --git a/phpBB/assets/cookieconsent/cookieconsent.min.js b/phpBB/assets/cookieconsent/cookieconsent.min.js
new file mode 100644
index 0000000000..8e44bdde90
--- /dev/null
+++ b/phpBB/assets/cookieconsent/cookieconsent.min.js
@@ -0,0 +1 @@
+!function(e){if(!e.hasInitialised){var t={escapeRegExp:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},hasClass:function(e,t){var i=" ";return 1===e.nodeType&&(i+e.className+i).replace(/[\n\t]/g,i).indexOf(i+t+i)>=0},addClass:function(e,t){e.className+=" "+t},removeClass:function(e,t){var i=new RegExp("\\b"+this.escapeRegExp(t)+"\\b");e.className=e.className.replace(i,"")},interpolateString:function(e,t){var i=/{{([a-z][a-z0-9\-_]*)}}/gi;return e.replace(i,function(e){return t(arguments[1])||""})},getCookie:function(e){var t="; "+document.cookie,i=t.split("; "+e+"=");return 2!=i.length?void 0:i.pop().split(";").shift()},setCookie:function(e,t,i,n,o){var s=new Date;s.setDate(s.getDate()+(i||365));var r=[e+"="+t,"expires="+s.toUTCString(),"path="+(o||"/")];n&&r.push("domain="+n),document.cookie=r.join(";")},deepExtend:function(e,t){for(var i in t)t.hasOwnProperty(i)&&(i in e&&this.isPlainObject(e[i])&&this.isPlainObject(t[i])?this.deepExtend(e[i],t[i]):e[i]=t[i]);return e},throttle:function(e,t){var i=!1;return function(){i||(e.apply(this,arguments),i=!0,setTimeout(function(){i=!1},t))}},hash:function(e){var t,i,n,o=0;if(0===e.length)return o;for(t=0,n=e.length;t<n;++t)i=e.charCodeAt(t),o=(o<<5)-o+i,o|=0;return o},normaliseHex:function(e){return"#"==e[0]&&(e=e.substr(1)),3==e.length&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),e},getContrast:function(e){e=this.normaliseHex(e);var t=parseInt(e.substr(0,2),16),i=parseInt(e.substr(2,2),16),n=parseInt(e.substr(4,2),16),o=(299*t+587*i+114*n)/1e3;return o>=128?"#000":"#fff"},getLuminance:function(e){var t=parseInt(this.normaliseHex(e),16),i=38,n=(t>>16)+i,o=(t>>8&255)+i,s=(255&t)+i,r=(16777216+65536*(n<255?n<1?0:n:255)+256*(o<255?o<1?0:o:255)+(s<255?s<1?0:s:255)).toString(16).slice(1);return"#"+r},isMobile:function(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},isPlainObject:function(e){return"object"==typeof e&&null!==e&&e.constructor==Object}};e.status={deny:"deny",allow:"allow",dismiss:"dismiss"},e.transitionEnd=function(){var e=document.createElement("div"),t={t:"transitionend",OT:"oTransitionEnd",msT:"MSTransitionEnd",MozT:"transitionend",WebkitT:"webkitTransitionEnd"};for(var i in t)if(t.hasOwnProperty(i)&&"undefined"!=typeof e.style[i+"ransition"])return t[i];return""}(),e.hasTransition=!!e.transitionEnd;var i=Object.keys(e.status).map(t.escapeRegExp);e.customStyles={},e.Popup=function(){function n(){this.initialise.apply(this,arguments)}function o(e){this.openingTimeout=null,t.removeClass(e,"cc-invisible")}function s(t){t.style.display="none",t.removeEventListener(e.transitionEnd,this.afterTransition),this.afterTransition=null}function r(){var t=this.options.onInitialise.bind(this);if(!window.navigator.cookieEnabled)return t(e.status.deny),!0;if(window.CookiesOK||window.navigator.CookiesOK)return t(e.status.allow),!0;var i=Object.keys(e.status),n=this.getStatus(),o=i.indexOf(n)>=0;return o&&t(n),o}function a(){var e=this.options.position.split("-"),t=[];return e.forEach(function(e){t.push("cc-"+e)}),t}function c(){var e=this.options,i="top"==e.position||"bottom"==e.position?"banner":"floating";t.isMobile()&&(i="floating");var n=["cc-"+i,"cc-type-"+e.type,"cc-theme-"+e.theme];e["static"]&&n.push("cc-static"),n.push.apply(n,a.call(this));p.call(this,this.options.palette);return this.customStyleSelector&&n.push(this.customStyleSelector),n}function l(){var e={},i=this.options;i.showLink||(i.elements.link="",i.elements.messagelink=i.elements.message),Object.keys(i.elements).forEach(function(n){e[n]=t.interpolateString(i.elements[n],function(e){var t=i.content[e];return e&&"string"==typeof t&&t.length?t:""})});var n=i.compliance[i.type];n||(n=i.compliance.info),e.compliance=t.interpolateString(n,function(t){return e[t]});var o=i.layouts[i.layout];return o||(o=i.layouts.basic),t.interpolateString(o,function(t){return e[t]})}function u(i){var n=this.options,o=document.createElement("div"),s=n.container&&1===n.container.nodeType?n.container:document.body;o.innerHTML=i;var r=o.children[0];return r.style.display="none",t.hasClass(r,"cc-window")&&e.hasTransition&&t.addClass(r,"cc-invisible"),this.onButtonClick=h.bind(this),r.addEventListener("click",this.onButtonClick),n.autoAttach&&(s.firstChild?s.insertBefore(r,s.firstChild):s.appendChild(r)),r}function h(n){var o=n.target;if(t.hasClass(o,"cc-btn")){var s=o.className.match(new RegExp("\\bcc-("+i.join("|")+")\\b")),r=s&&s[1]||!1;r&&(this.setStatus(r),this.close(!0))}t.hasClass(o,"cc-close")&&(this.setStatus(e.status.dismiss),this.close(!0)),t.hasClass(o,"cc-revoke")&&this.revokeChoice()}function p(e){var i=t.hash(JSON.stringify(e)),n="cc-color-override-"+i,o=t.isPlainObject(e);return this.customStyleSelector=o?n:null,o&&d(i,e,"."+n),o}function d(i,n,o){if(e.customStyles[i])return void++e.customStyles[i].references;var s={},r=n.popup,a=n.button,c=n.highlight;r&&(r.text=r.text?r.text:t.getContrast(r.background),r.link=r.link?r.link:r.text,s[o+".cc-window"]=["color: "+r.text,"background-color: "+r.background],s[o+".cc-revoke"]=["color: "+r.text,"background-color: "+r.background],s[o+" .cc-link,"+o+" .cc-link:active,"+o+" .cc-link:visited"]=["color: "+r.link],a&&(a.text=a.text?a.text:t.getContrast(a.background),a.border=a.border?a.border:"transparent",s[o+" .cc-btn"]=["color: "+a.text,"border-color: "+a.border,"background-color: "+a.background],"transparent"!=a.background&&(s[o+" .cc-btn:hover, "+o+" .cc-btn:focus"]=["background-color: "+v(a.background)]),c?(c.text=c.text?c.text:t.getContrast(c.background),c.border=c.border?c.border:"transparent",s[o+" .cc-highlight .cc-btn:first-child"]=["color: "+c.text,"border-color: "+c.border,"background-color: "+c.background]):s[o+" .cc-highlight .cc-btn:first-child"]=["color: "+r.text]));var l=document.createElement("style");document.head.appendChild(l),e.customStyles[i]={references:1,element:l.sheet};var u=-1;for(var h in s)s.hasOwnProperty(h)&&l.sheet.insertRule(h+"{"+s[h].join(";")+"}",++u)}function v(e){return e=t.normaliseHex(e),"000000"==e?"#222":t.getLuminance(e)}function f(i){if(t.isPlainObject(i)){var n=t.hash(JSON.stringify(i)),o=e.customStyles[n];if(o&&!--o.references){var s=o.element.ownerNode;s&&s.parentNode&&s.parentNode.removeChild(s),e.customStyles[n]=null}}}function m(e,t){for(var i=0,n=e.length;i<n;++i){var o=e[i];if(o instanceof RegExp&&o.test(t)||"string"==typeof o&&o.length&&o===t)return!0}return!1}function b(){var t=this.setStatus.bind(this),i=this.options.dismissOnTimeout;"number"==typeof i&&i>=0&&(this.dismissTimeout=window.setTimeout(function(){t(e.status.dismiss)},Math.floor(i)));var n=this.options.dismissOnScroll;if("number"==typeof n&&n>=0){var o=function(i){window.pageYOffset>Math.floor(n)&&(t(e.status.dismiss),window.removeEventListener("scroll",o),this.onWindowScroll=null)};this.onWindowScroll=o,window.addEventListener("scroll",o)}}function y(){if("info"!=this.options.type&&(this.options.revokable=!0),t.isMobile()&&(this.options.animateRevokable=!1),this.options.revokable){var e=a.call(this);this.options.animateRevokable&&e.push("cc-animate"),this.customStyleSelector&&e.push(this.customStyleSelector);var i=this.options.revokeBtn.replace("{{classes}}",e.join(" "));this.revokeBtn=u.call(this,i);var n=this.revokeBtn;if(this.options.animateRevokable){var o=t.throttle(function(e){var i=!1,o=20,s=window.innerHeight-20;t.hasClass(n,"cc-top")&&e.clientY<o&&(i=!0),t.hasClass(n,"cc-bottom")&&e.clientY>s&&(i=!0),i?t.hasClass(n,"cc-active")||t.addClass(n,"cc-active"):t.hasClass(n,"cc-active")&&t.removeClass(n,"cc-active")},200);this.onMouseMove=o,window.addEventListener("mousemove",o)}}}var g={enabled:!0,container:null,cookie:{name:"cookieconsent_status",path:"/",domain:"",expiryDays:365},onPopupOpen:function(){},onPopupClose:function(){},onInitialise:function(e){},onStatusChange:function(e,t){},onRevokeChoice:function(){},content:{header:"Cookies used on the website!",message:"This website uses cookies to ensure you get the best experience on our website.",dismiss:"Got it!",allow:"Allow cookies",deny:"Decline",link:"Learn more",href:"http://cookiesandyou.com",close:"&#x274c;"},elements:{header:'<span class="cc-header">{{header}}</span>&nbsp;',message:'<span id="cookieconsent:desc" class="cc-message">{{message}}</span>',messagelink:'<span id="cookieconsent:desc" class="cc-message">{{message}} <a aria-label="learn more about cookies" role=button tabindex="0" class="cc-link" href="{{href}}" target="_blank">{{link}}</a></span>',dismiss:'<a aria-label="dismiss cookie message" role=button tabindex="0" class="cc-btn cc-dismiss">{{dismiss}}</a>',allow:'<a aria-label="allow cookies" role=button tabindex="0" class="cc-btn cc-allow">{{allow}}</a>',deny:'<a aria-label="deny cookies" role=button tabindex="0" class="cc-btn cc-deny">{{deny}}</a>',link:'<a aria-label="learn more about cookies" role=button tabindex="0" class="cc-link" href="{{href}}" target="_blank">{{link}}</a>',close:'<span aria-label="dismiss cookie message" role=button tabindex="0" class="cc-close">{{close}}</span>'},window:'<div role="dialog" aria-live="polite" aria-label="cookieconsent" aria-describedby="cookieconsent:desc" class="cc-window {{classes}}"><!--googleoff: all-->{{children}}<!--googleon: all--></div>',revokeBtn:'<div class="cc-revoke {{classes}}">Cookie Policy</div>',compliance:{info:'<div class="cc-compliance">{{dismiss}}</div>',"opt-in":'<div class="cc-compliance cc-highlight">{{dismiss}}{{allow}}</div>',"opt-out":'<div class="cc-compliance cc-highlight">{{deny}}{{dismiss}}</div>'},type:"info",layouts:{basic:"{{messagelink}}{{compliance}}","basic-close":"{{messagelink}}{{compliance}}{{close}}","basic-header":"{{header}}{{message}}{{link}}{{compliance}}"},layout:"basic",position:"bottom",theme:"block","static":!1,palette:null,revokable:!1,animateRevokable:!0,showLink:!0,dismissOnScroll:!1,dismissOnTimeout:!1,autoOpen:!0,autoAttach:!0,whitelistPage:[],blacklistPage:[],overrideHTML:null};return n.prototype.initialise=function(e){this.options&&this.destroy(),t.deepExtend(this.options={},g),t.isPlainObject(e)&&t.deepExtend(this.options,e),r.call(this)&&(this.options.enabled=!1),m(this.options.blacklistPage,location.pathname)&&(this.options.enabled=!1),m(this.options.whitelistPage,location.pathname)&&(this.options.enabled=!0);var i=this.options.window.replace("{{classes}}",c.call(this).join(" ")).replace("{{children}}",l.call(this)),n=this.options.overrideHTML;if("string"==typeof n&&n.length&&(i=n),this.options["static"]){var o=u.call(this,'<div class="cc-grower">'+i+"</div>");o.style.display="",this.element=o.firstChild,this.element.style.display="none",t.addClass(this.element,"cc-invisible")}else this.element=u.call(this,i);b.call(this),y.call(this),this.options.autoOpen&&this.autoOpen()},n.prototype.destroy=function(){this.onButtonClick&&this.element&&(this.element.removeEventListener("click",this.onButtonClick),this.onButtonClick=null),this.dismissTimeout&&(clearTimeout(this.dismissTimeout),this.dismissTimeout=null),this.onWindowScroll&&(window.removeEventListener("scroll",this.onWindowScroll),this.onWindowScroll=null),this.onMouseMove&&(window.removeEventListener("mousemove",this.onMouseMove),this.onMouseMove=null),this.element&&this.element.parentNode&&this.element.parentNode.removeChild(this.element),this.element=null,this.revokeBtn&&this.revokeBtn.parentNode&&this.revokeBtn.parentNode.removeChild(this.revokeBtn),this.revokeBtn=null,f(this.options.palette),this.options=null},n.prototype.open=function(t){if(this.element)return this.isOpen()||(e.hasTransition?this.fadeIn():this.element.style.display="",this.options.revokable&&this.toggleRevokeButton(),this.options.onPopupOpen.call(this)),this},n.prototype.close=function(t){if(this.element)return this.isOpen()&&(e.hasTransition?this.fadeOut():this.element.style.display="none",t&&this.options.revokable&&this.toggleRevokeButton(!0),this.options.onPopupClose.call(this)),this},n.prototype.fadeIn=function(){var i=this.element;if(e.hasTransition&&i&&(this.afterTransition&&s.call(this,i),t.hasClass(i,"cc-invisible"))){if(i.style.display="",this.options["static"]){var n=this.element.clientHeight;this.element.parentNode.style.maxHeight=n+"px"}var r=20;this.openingTimeout=setTimeout(o.bind(this,i),r)}},n.prototype.fadeOut=function(){var i=this.element;e.hasTransition&&i&&(this.openingTimeout&&(clearTimeout(this.openingTimeout),o.bind(this,i)),t.hasClass(i,"cc-invisible")||(this.options["static"]&&(this.element.parentNode.style.maxHeight=""),this.afterTransition=s.bind(this,i),i.addEventListener(e.transitionEnd,this.afterTransition),t.addClass(i,"cc-invisible")))},n.prototype.isOpen=function(){return this.element&&""==this.element.style.display&&(!e.hasTransition||!t.hasClass(this.element,"cc-invisible"))},n.prototype.toggleRevokeButton=function(e){this.revokeBtn&&(this.revokeBtn.style.display=e?"":"none")},n.prototype.revokeChoice=function(e){this.options.enabled=!0,this.clearStatus(),this.options.onRevokeChoice.call(this),e||this.autoOpen()},n.prototype.hasAnswered=function(t){return Object.keys(e.status).indexOf(this.getStatus())>=0},n.prototype.hasConsented=function(t){var i=this.getStatus();return i==e.status.allow||i==e.status.dismiss},n.prototype.autoOpen=function(e){!this.hasAnswered()&&this.options.enabled&&this.open()},n.prototype.setStatus=function(i){var n=this.options.cookie,o=t.getCookie(n.name),s=Object.keys(e.status).indexOf(o)>=0;Object.keys(e.status).indexOf(i)>=0?(t.setCookie(n.name,i,n.expiryDays,n.domain,n.path),this.options.onStatusChange.call(this,i,s)):this.clearStatus()},n.prototype.getStatus=function(){return t.getCookie(this.options.cookie.name)},n.prototype.clearStatus=function(){var e=this.options.cookie;t.setCookie(e.name,"",-1,e.domain,e.path)},n}(),e.Location=function(){function e(e){t.deepExtend(this.options={},s),t.isPlainObject(e)&&t.deepExtend(this.options,e),this.currentServiceIndex=-1}function i(e,t,i){var n,o=document.createElement("script");o.type="text/"+(e.type||"javascript"),o.src=e.src||e,o.async=!1,o.onreadystatechange=o.onload=function(){var e=o.readyState;clearTimeout(n),t.done||e&&!/loaded|complete/.test(e)||(t.done=!0,t(),o.onreadystatechange=o.onload=null)},document.body.appendChild(o),n=setTimeout(function(){t.done=!0,t(),o.onreadystatechange=o.onload=null},i)}function n(e,t,i,n,o){var s=new(window.XMLHttpRequest||window.ActiveXObject)("MSXML2.XMLHTTP.3.0");if(s.open(n?"POST":"GET",e,1),s.setRequestHeader("X-Requested-With","XMLHttpRequest"),s.setRequestHeader("Content-type","application/x-www-form-urlencoded"),Array.isArray(o))for(var r=0,a=o.length;r<a;++r){var c=o[r].split(":",2);s.setRequestHeader(c[0].replace(/^\s+|\s+$/g,""),c[1].replace(/^\s+|\s+$/g,""))}"function"==typeof t&&(s.onreadystatechange=function(){s.readyState>3&&t(s)}),s.send(n)}function o(e){return new Error("Error ["+(e.code||"UNKNOWN")+"]: "+e.error)}var s={timeout:5e3,services:["freegeoip","ipinfo","maxmind"],serviceDefinitions:{freegeoip:function(){return{url:"//freegeoip.net/json/?callback={callback}",isScript:!0,callback:function(e,t){try{var i=JSON.parse(t);return i.error?o(i):{code:i.country_code}}catch(n){return o({error:"Invalid response ("+n+")"})}}}},ipinfo:function(){return{url:"//ipinfo.io",headers:["Accept: application/json"],callback:function(e,t){try{var i=JSON.parse(t);return i.error?o(i):{code:i.country}}catch(n){return o({error:"Invalid response ("+n+")"})}}}},ipinfodb:function(e){return{url:"//api.ipinfodb.com/v3/ip-country/?key={api_key}&format=json&callback={callback}",isScript:!0,callback:function(e,t){try{var i=JSON.parse(t);return"ERROR"==i.statusCode?o({error:i.statusMessage}):{code:i.countryCode}}catch(n){return o({error:"Invalid response ("+n+")"})}}}},maxmind:function(){return{url:"//js.maxmind.com/js/apis/geoip2/v2.1/geoip2.js",isScript:!0,callback:function(e){return window.geoip2?void geoip2.country(function(t){try{e({code:t.country.iso_code})}catch(i){e(o(i))}},function(t){e(o(t))}):void e(new Error("Unexpected response format. The downloaded script should have exported `geoip2` to the global scope"))}}}}};return e.prototype.getNextService=function(){var e;do e=this.getServiceByIdx(++this.currentServiceIndex);while(this.currentServiceIndex<this.options.services.length&&!e);return e},e.prototype.getServiceByIdx=function(e){var i=this.options.services[e];if("function"==typeof i){var n=i();return n.name&&t.deepExtend(n,this.options.serviceDefinitions[n.name](n)),n}return"string"==typeof i?this.options.serviceDefinitions[i]():t.isPlainObject(i)?this.options.serviceDefinitions[i.name](i):null},e.prototype.locate=function(e,t){var i=this.getNextService();return i?(this.callbackComplete=e,this.callbackError=t,void this.runService(i,this.runNextServiceOnError.bind(this))):void t(new Error("No services to run"))},e.prototype.setupUrl=function(e){var t=this.getCurrentServiceOpts();return e.url.replace(/\{(.*?)\}/g,function(i,n){if("callback"===n){var o="callback"+Date.now();return window[o]=function(t){e.__JSONP_DATA=JSON.stringify(t)},o}if(n in t.interpolateUrl)return t.interpolateUrl[n]})},e.prototype.runService=function(e,t){var o=this;if(e&&e.url&&e.callback){var s=e.isScript?i:n,r=this.setupUrl(e);s(r,function(i){var n=i?i.responseText:"";e.__JSONP_DATA&&(n=e.__JSONP_DATA,delete e.__JSONP_DATA),o.runServiceCallback.call(o,t,e,n)},this.options.timeout,e.data,e.headers)}},e.prototype.runServiceCallback=function(e,t,i){var n=this,o=function(t){s||n.onServiceResult.call(n,e,t)},s=t.callback(o,i);s&&this.onServiceResult.call(this,e,s)},e.prototype.onServiceResult=function(e,t){t instanceof Error||t&&t.error?e.call(this,t,null):e.call(this,null,t)},e.prototype.runNextServiceOnError=function(e,t){if(e){this.logError(e);var i=this.getNextService();i?this.runService(i,this.runNextServiceOnError.bind(this)):this.completeService.call(this,this.callbackError,new Error("All services failed"))}else this.completeService.call(this,this.callbackComplete,t)},e.prototype.getCurrentServiceOpts=function(){var e=this.options.services[this.currentServiceIndex];return"string"==typeof e?{name:e}:"function"==typeof e?e():t.isPlainObject(e)?e:{}},e.prototype.completeService=function(e,t){this.currentServiceIndex=-1,e&&e(t)},e.prototype.logError=function(e){var t=this.currentServiceIndex,i=this.getServiceByIdx(t);console.error("The service["+t+"] ("+i.url+") responded with the following error",e)},e}(),e.Law=function(){function e(e){this.initialise.apply(this,arguments)}var i={regionalLaw:!0,hasLaw:["AT","BE","BG","HR","CZ","CY","DK","EE","FI","FR","DE","EL","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","SK","SI","ES","SE","GB","UK"],revokable:["HR","CY","DK","EE","FR","DE","LV","LT","NL","PT","ES"],explicitAction:["HR","IT","ES"]};return e.prototype.initialise=function(e){t.deepExtend(this.options={},i),t.isPlainObject(e)&&t.deepExtend(this.options,e)},e.prototype.get=function(e){var t=this.options;return{hasLaw:t.hasLaw.indexOf(e)>=0,revokable:t.revokable.indexOf(e)>=0,explicitAction:t.explicitAction.indexOf(e)>=0}},e.prototype.applyLaw=function(e,t){var i=this.get(t);return i.hasLaw||(e.enabled=!1),this.options.regionalLaw&&(i.revokable&&(e.revokable=!0),i.explicitAction&&(e.dismissOnScroll=!1,e.dismissOnTimeout=!1)),e},e}(),e.initialise=function(t,i,n){var o=new e.Law(t.law);i||(i=function(){}),n||(n=function(){}),e.getCountryCode(t,function(n){delete t.law,delete t.location,n.code&&(t=o.applyLaw(t,n.code)),i(new e.Popup(t))},function(i){delete t.law,delete t.location,n(i,new e.Popup(t))})},e.getCountryCode=function(t,i,n){if(t.law&&t.law.countryCode)return void i({code:t.law.countryCode});if(t.location){var o=new e.Location(t.location);return void o.locate(function(e){i(e||{})},n)}i({})},e.utils=t,e.hasInitialised=!0,window.cookieconsent=e}}(window.cookieconsent||{}); \ No newline at end of file
diff --git a/phpBB/assets/css/font-awesome.min.css b/phpBB/assets/css/font-awesome.min.css
new file mode 100644
index 0000000000..540440ce89
--- /dev/null
+++ b/phpBB/assets/css/font-awesome.min.css
@@ -0,0 +1,4 @@
+/*!
+ * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}
diff --git a/phpBB/assets/fonts/FontAwesome.otf b/phpBB/assets/fonts/FontAwesome.otf
new file mode 100644
index 0000000000..401ec0f36e
--- /dev/null
+++ b/phpBB/assets/fonts/FontAwesome.otf
Binary files differ
diff --git a/phpBB/assets/fonts/fontawesome-webfont.eot b/phpBB/assets/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000000..e9f60ca953
--- /dev/null
+++ b/phpBB/assets/fonts/fontawesome-webfont.eot
Binary files differ
diff --git a/phpBB/assets/fonts/fontawesome-webfont.svg b/phpBB/assets/fonts/fontawesome-webfont.svg
new file mode 100644
index 0000000000..855c845e53
--- /dev/null
+++ b/phpBB/assets/fonts/fontawesome-webfont.svg
@@ -0,0 +1,2671 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg>
+<metadata>
+Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016
+ By ,,,
+Copyright Dave Gandy 2016. All rights reserved.
+</metadata>
+<defs>
+<font id="FontAwesome" horiz-adv-x="1536" >
+ <font-face
+ font-family="FontAwesome"
+ font-weight="400"
+ font-stretch="normal"
+ units-per-em="1792"
+ panose-1="0 0 0 0 0 0 0 0 0 0"
+ ascent="1536"
+ descent="-256"
+ bbox="-1.02083 -256.962 2304.6 1537.02"
+ underline-thickness="0"
+ underline-position="0"
+ unicode-range="U+0020-F500"
+ />
+<missing-glyph horiz-adv-x="896"
+d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" />
+ <glyph glyph-name=".notdef" horiz-adv-x="896"
+d="M224 112h448v1312h-448v-1312zM112 0v1536h672v-1536h-672z" />
+ <glyph glyph-name=".null" horiz-adv-x="0"
+ />
+ <glyph glyph-name="nonmarkingreturn" horiz-adv-x="597"
+ />
+ <glyph glyph-name="space" unicode=" " horiz-adv-x="448"
+ />
+ <glyph glyph-name="dieresis" unicode="&#xa8;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="copyright" unicode="&#xa9;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="registered" unicode="&#xae;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="acute" unicode="&#xb4;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="AE" unicode="&#xc6;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="Oslash" unicode="&#xd8;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="trademark" unicode="&#x2122;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="infinity" unicode="&#x221e;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="notequal" unicode="&#x2260;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="glass" unicode="&#xf000;" horiz-adv-x="1792"
+d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+ <glyph glyph-name="music" unicode="&#xf001;"
+d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89
+t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="search" unicode="&#xf002;" horiz-adv-x="1664"
+d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5
+t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+ <glyph glyph-name="envelope" unicode="&#xf003;" horiz-adv-x="1792"
+d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13
+t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 29.5q208 165 401 317q54 43 100.5 115.5t46.5 131.5z
+M1792 1120v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="heart" unicode="&#xf004;" horiz-adv-x="1792"
+d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600
+q-18 -18 -44 -18z" />
+ <glyph glyph-name="star" unicode="&#xf005;" horiz-adv-x="1664"
+d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455
+l502 -73q56 -9 56 -46z" />
+ <glyph glyph-name="star_empty" unicode="&#xf006;" horiz-adv-x="1664"
+d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500
+l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+ <glyph glyph-name="user" unicode="&#xf007;" horiz-adv-x="1280"
+d="M1280 137q0 -109 -62.5 -187t-150.5 -78h-854q-88 0 -150.5 78t-62.5 187q0 85 8.5 160.5t31.5 152t58.5 131t94 89t134.5 34.5q131 -128 313 -128t313 128q76 0 134.5 -34.5t94 -89t58.5 -131t31.5 -152t8.5 -160.5zM1024 1024q0 -159 -112.5 -271.5t-271.5 -112.5
+t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+ <glyph glyph-name="film" unicode="&#xf008;" horiz-adv-x="1920"
+d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128
+q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45
+t45 -19h128q26 0 45 19t19 45zM1792 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 704v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1792 320v128
+q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 704v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1792 1088v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19
+t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1920 1248v-1344q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1344q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="th_large" unicode="&#xf009;" horiz-adv-x="1664"
+d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38
+h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="th" unicode="&#xf00a;" horiz-adv-x="1792"
+d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320
+q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28
+h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192
+q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="th_list" unicode="&#xf00b;" horiz-adv-x="1792"
+d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960
+q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28
+h960q40 0 68 -28t28 -68zM1792 1312v-192q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="ok" unicode="&#xf00c;" horiz-adv-x="1792"
+d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+ <glyph glyph-name="remove" unicode="&#xf00d;" horiz-adv-x="1408"
+d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68
+t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+ <glyph glyph-name="zoom_in" unicode="&#xf00e;" horiz-adv-x="1664"
+d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224
+q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5
+t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+ <glyph glyph-name="zoom_out" unicode="&#xf010;" horiz-adv-x="1664"
+d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z
+M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z
+" />
+ <glyph glyph-name="off" unicode="&#xf011;"
+d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5
+t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0 52 38 90t90 38t90 -38t38 -90z" />
+ <glyph glyph-name="signal" unicode="&#xf012;" horiz-adv-x="1792"
+d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23
+v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1472q0 14 9 23t23 9h192q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="cog" unicode="&#xf013;"
+d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38
+q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5t-8 23.5v222q0 12 8 23t19 13
+l186 28q14 46 39 92q-40 57 -107 138q-10 12 -10 24q0 10 9 23q26 36 98.5 107.5t94.5 71.5q13 0 26 -10l138 -107q44 23 91 38q16 136 29 186q7 28 36 28h222q14 0 24.5 -8.5t11.5 -21.5l28 -184q49 -16 90 -37l142 107q9 9 24 9q13 0 25 -10q129 -119 165 -170q7 -8 7 -22
+q0 -12 -8 -23q-15 -21 -51 -66.5t-54 -70.5q26 -50 41 -98l183 -28q13 -2 21 -12.5t8 -23.5z" />
+ <glyph glyph-name="trash" unicode="&#xf014;" horiz-adv-x="1408"
+d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576
+q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832
+q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="home" unicode="&#xf015;" horiz-adv-x="1664"
+d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5
+l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+ <glyph glyph-name="file_alt" unicode="&#xf016;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+" />
+ <glyph glyph-name="time" unicode="&#xf017;"
+d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="road" unicode="&#xf018;" horiz-adv-x="1920"
+d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256
+q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t26 -33l417 -1044q26 -62 26 -116z" />
+ <glyph glyph-name="download_alt" unicode="&#xf019;" horiz-adv-x="1664"
+d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136
+q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q42 0 59 -39z" />
+ <glyph glyph-name="download" unicode="&#xf01a;"
+d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273
+t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="upload" unicode="&#xf01b;"
+d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198
+t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="inbox" unicode="&#xf01c;"
+d="M1023 576h316q-1 3 -2.5 8.5t-2.5 7.5l-212 496h-708l-212 -496q-1 -3 -2.5 -8.5t-2.5 -7.5h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552
+q25 -61 25 -123z" />
+ <glyph glyph-name="play_circle" unicode="&#xf01d;"
+d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="repeat" unicode="&#xf01e;"
+d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q15 0 25 -9
+l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+ <glyph glyph-name="refresh" unicode="&#xf021;"
+d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117
+q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 22.5v7q65 268 270 434.5t480 166.5
+q146 0 284 -55.5t245 -156.5l130 129q19 19 45 19t45 -19t19 -45z" />
+ <glyph glyph-name="list_alt" unicode="&#xf022;" horiz-adv-x="1792"
+d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5z
+M1536 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5t9.5 -22.5zM1536 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h960q13 0 22.5 -9.5
+t9.5 -22.5zM1664 160v832q0 13 -9.5 22.5t-22.5 9.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 1248v-1088q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1472q66 0 113 -47
+t47 -113z" />
+ <glyph glyph-name="lock" unicode="&#xf023;" horiz-adv-x="1152"
+d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="flag" unicode="&#xf024;" horiz-adv-x="1792"
+d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48
+t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="headphones" unicode="&#xf025;" horiz-adv-x="1664"
+d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78
+t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185 33l-20 49q-60 148 -60 314q0 151 67 291t179 242.5
+t266 163.5t320 61t320 -61t266 -163.5t179 -242.5t67 -291z" />
+ <glyph glyph-name="volume_off" unicode="&#xf026;" horiz-adv-x="768"
+d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+ <glyph glyph-name="volume_down" unicode="&#xf027;" horiz-adv-x="1152"
+d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36
+t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+ <glyph glyph-name="volume_up" unicode="&#xf028;" horiz-adv-x="1664"
+d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 36
+t12 56.5t-12 56.5t-29 36t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56 29 76 44q74 54 115.5 135.5t41.5 173.5t-41.5 173.5
+t-115.5 135.5q-20 15 -76 44q-39 20 -39 59q0 26 19 45t45 19q13 0 26 -5q140 -59 225 -188.5t85 -282.5zM1664 640q0 -230 -127 -422.5t-338 -283.5q-13 -5 -26 -5q-26 0 -45 19t-19 45q0 36 39 59q7 4 22.5 10.5t22.5 10.5q46 25 82 51q123 91 192 227t69 289t-69 289
+t-192 227q-36 26 -82 51q-7 4 -22.5 10.5t-22.5 10.5q-39 23 -39 59q0 26 19 45t45 19q13 0 26 -5q211 -91 338 -283.5t127 -422.5z" />
+ <glyph glyph-name="qrcode" unicode="&#xf029;" horiz-adv-x="1408"
+d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z
+M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+ <glyph glyph-name="barcode" unicode="&#xf02a;" horiz-adv-x="1792"
+d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z
+M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+ <glyph glyph-name="tag" unicode="&#xf02b;"
+d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5
+l715 -714q37 -39 37 -91z" />
+ <glyph glyph-name="tags" unicode="&#xf02c;" horiz-adv-x="1920"
+d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5
+l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l715 -714q37 -39 37 -91z" />
+ <glyph glyph-name="book" unicode="&#xf02d;" horiz-adv-x="1664"
+d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23
+q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 9h761q74 0 114 -56t18 -130l-274 -906
+q-36 -119 -71.5 -153.5t-128.5 -34.5h-869q-27 0 -38 -15q-11 -16 -1 -43q24 -70 144 -70h923q29 0 56 15.5t35 41.5l300 987q7 22 5 57q38 -15 59 -43zM575 1056q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5
+t-16.5 -22.5zM492 800q-4 -13 2 -22.5t20 -9.5h608q13 0 25.5 9.5t16.5 22.5l21 64q4 13 -2 22.5t-20 9.5h-608q-13 0 -25.5 -9.5t-16.5 -22.5z" />
+ <glyph glyph-name="bookmark" unicode="&#xf02e;" horiz-adv-x="1280"
+d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+ <glyph glyph-name="print" unicode="&#xf02f;" horiz-adv-x="1664"
+d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68
+v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+ <glyph glyph-name="camera" unicode="&#xf030;" horiz-adv-x="1920"
+d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136
+q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="font" unicode="&#xf031;" horiz-adv-x="1664"
+d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57
+q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -5 -0.5 -13.5t-0.5 -12.5q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-42 100l-450 2q-26 -58 -76.5 -195.5t-50.5 -162.5
+q0 -22 14 -37.5t43.5 -24.5t48.5 -13.5t57 -8.5t41 -4q1 -19 1 -58q0 -9 -2 -27q-58 0 -174.5 10t-174.5 10q-8 0 -26.5 -4t-21.5 -4q-80 -14 -188 -14z" />
+ <glyph glyph-name="bold" unicode="&#xf032;" horiz-adv-x="1408"
+d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142
+q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v30q0 982 -22 1025q-4 8 -22 14.5t-44.5 11t-49.5 7t-48.5 4.5
+t-30.5 3l-4 83q98 2 340 11.5t373 9.5q23 0 68 -0.5t68 -0.5q70 0 136.5 -13t128.5 -42t108 -71t74 -104.5t28 -137.5q0 -52 -16.5 -95.5t-39 -72t-64.5 -57.5t-73 -45t-84 -40q154 -35 256.5 -134t102.5 -248q0 -100 -35 -179.5t-93.5 -130.5t-138 -85.5t-163.5 -48.5
+t-176 -14q-44 0 -132 3t-132 3q-106 0 -307 -11t-231 -12z" />
+ <glyph glyph-name="italic" unicode="&#xf033;" horiz-adv-x="1024"
+d="M0 -126l17 85q22 7 61.5 16.5t72 19t59.5 23.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5
+q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q-138 2 -206 2q-51 0 -143 -9t-121 -11z" />
+ <glyph glyph-name="text_height" unicode="&#xf034;" horiz-adv-x="1792"
+d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2
+t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q-6 8 -12 12.5t-15.5 6t-13 2.5t-18 0.5t-16.5 -0.5
+q-17 0 -66.5 0.5t-74.5 0.5t-64 -2t-71 -6q-9 -81 -8 -136q0 -94 2 -388t2 -455q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27
+q19 42 19 383q0 101 -3 303t-3 303v117q0 2 0.5 15.5t0.5 25t-1 25.5t-3 24t-5 14q-11 12 -162 12q-33 0 -93 -12t-80 -26q-19 -13 -34 -72.5t-31.5 -111t-42.5 -53.5q-42 26 -56 44v383z" />
+ <glyph glyph-name="text_width" unicode="&#xf035;"
+d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1
+t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 52v9q17 27 61.5 43t98.5 29t78 27
+q7 16 11.5 74t6 145.5t1.5 155t-0.5 153.5t-0.5 89q0 7 -2.5 21.5t-2.5 22.5q0 7 0.5 44t1 73t0 76.5t-3 67.5t-6.5 32q-11 12 -162 12q-41 0 -163 -13.5t-138 -24.5q-19 -12 -34 -71.5t-31.5 -111.5t-42.5 -54q-42 26 -56 44v383zM1310 125q12 0 42 -19.5t57.5 -41.5
+t59.5 -49t36 -30q26 -21 26 -49t-26 -49q-4 -3 -36 -30t-59.5 -49t-57.5 -41.5t-42 -19.5q-13 0 -20.5 10.5t-10 28.5t-2.5 33.5t1.5 33t1.5 19.5h-1024q0 -2 1.5 -19.5t1.5 -33t-2.5 -33.5t-10 -28.5t-20.5 -10.5q-12 0 -42 19.5t-57.5 41.5t-59.5 49t-36 30q-26 21 -26 49
+t26 49q4 3 36 30t59.5 49t57.5 41.5t42 19.5q13 0 20.5 -10.5t10 -28.5t2.5 -33.5t-1.5 -33t-1.5 -19.5h1024q0 2 -1.5 19.5t-1.5 33t2.5 33.5t10 28.5t20.5 10.5z" />
+ <glyph glyph-name="align_left" unicode="&#xf036;" horiz-adv-x="1792"
+d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45
+t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="align_center" unicode="&#xf037;" horiz-adv-x="1792"
+d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19
+h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="align_right" unicode="&#xf038;" horiz-adv-x="1792"
+d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45
+t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="align_justify" unicode="&#xf039;" horiz-adv-x="1792"
+d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45
+t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="list" unicode="&#xf03a;" horiz-adv-x="1792"
+d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5
+t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344
+q13 0 22.5 -9.5t9.5 -22.5zM256 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5
+t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v192
+q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5z" />
+ <glyph glyph-name="indent_left" unicode="&#xf03b;" horiz-adv-x="1792"
+d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5
+t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088
+q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+ <glyph glyph-name="indent_right" unicode="&#xf03c;" horiz-adv-x="1792"
+d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5
+t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088
+q13 0 22.5 -9.5t9.5 -22.5zM1792 1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5t9.5 -22.5z" />
+ <glyph glyph-name="facetime_video" unicode="&#xf03d;" horiz-adv-x="1792"
+d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5
+q39 -17 39 -59z" />
+ <glyph glyph-name="picture" unicode="&#xf03e;" horiz-adv-x="1920"
+d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216
+q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="pencil" unicode="&#xf040;"
+d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38
+q53 0 91 -38l235 -234q37 -39 37 -91z" />
+ <glyph glyph-name="map_marker" unicode="&#xf041;" horiz-adv-x="1024"
+d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+ <glyph glyph-name="adjust" unicode="&#xf042;"
+d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="tint" unicode="&#xf043;" horiz-adv-x="1024"
+d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362
+q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+ <glyph glyph-name="edit" unicode="&#xf044;" horiz-adv-x="1792"
+d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832
+q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 1216l288 -288l-672 -672h-288v288zM1756 1084l-92 -92
+l-288 288l92 92q28 28 68 28t68 -28l152 -152q28 -28 28 -68t-28 -68z" />
+ <glyph glyph-name="share" unicode="&#xf045;" horiz-adv-x="1664"
+d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832
+q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34q-8 -2 -12 -2q-16 0 -26 13q-10 14 -21 31t-39.5 68.5t-49.5 99.5
+t-38.5 114t-17.5 122q0 49 3.5 91t14 90t28 88t47 81.5t68.5 74t94.5 61.5t124.5 48.5t159.5 30.5t196.5 11h160v192q0 42 39 59q13 5 25 5q26 0 45 -19l384 -384q19 -19 19 -45t-19 -45z" />
+ <glyph glyph-name="check" unicode="&#xf046;" horiz-adv-x="1664"
+d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832
+q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263 -263l647 647q24 24 57 24t57 -24l110 -110
+q24 -24 24 -57t-24 -57z" />
+ <glyph glyph-name="move" unicode="&#xf047;" horiz-adv-x="1792"
+d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45
+t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+ <glyph glyph-name="step_backward" unicode="&#xf048;" horiz-adv-x="1024"
+d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19z" />
+ <glyph glyph-name="fast_backward" unicode="&#xf049;" horiz-adv-x="1792"
+d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 10 13 19l710 710
+q19 19 32 13t13 -32v-710q4 10 13 19z" />
+ <glyph glyph-name="backward" unicode="&#xf04a;" horiz-adv-x="1664"
+d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q4 10 13 19z" />
+ <glyph glyph-name="play" unicode="&#xf04b;" horiz-adv-x="1408"
+d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+ <glyph glyph-name="pause" unicode="&#xf04c;"
+d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="stop" unicode="&#xf04d;"
+d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="forward" unicode="&#xf04e;" horiz-adv-x="1664"
+d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" />
+ <glyph glyph-name="fast_forward" unicode="&#xf050;" horiz-adv-x="1792"
+d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v710q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19l-710 -710
+q-19 -19 -32 -13t-13 32v710q-4 -10 -13 -19z" />
+ <glyph glyph-name="step_forward" unicode="&#xf051;" horiz-adv-x="1024"
+d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q9 -9 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-4 -10 -13 -19z" />
+ <glyph glyph-name="eject" unicode="&#xf052;" horiz-adv-x="1538"
+d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+ <glyph glyph-name="chevron_left" unicode="&#xf053;" horiz-adv-x="1280"
+d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
+ <glyph glyph-name="chevron_right" unicode="&#xf054;" horiz-adv-x="1280"
+d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
+ <glyph glyph-name="plus_sign" unicode="&#xf055;"
+d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5
+t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="minus_sign" unicode="&#xf056;"
+d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5
+t103 -385.5z" />
+ <glyph glyph-name="remove_sign" unicode="&#xf057;"
+d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19
+q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="ok_sign" unicode="&#xf058;"
+d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103
+t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="question_sign" unicode="&#xf059;"
+d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59
+q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5
+t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="info_sign" unicode="&#xf05a;"
+d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23
+t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="screenshot" unicode="&#xf05b;"
+d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109
+q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v143
+q-161 37 -278.5 154.5t-154.5 278.5h-143q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h143q37 161 154.5 278.5t278.5 154.5v143q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-143q161 -37 278.5 -154.5t154.5 -278.5h143q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="remove_circle" unicode="&#xf05c;"
+d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23
+l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5
+t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="ok_circle" unicode="&#xf05d;"
+d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198
+t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="ban_circle" unicode="&#xf05e;"
+d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61
+t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+ <glyph glyph-name="arrow_left" unicode="&#xf060;"
+d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5
+t32.5 -90.5z" />
+ <glyph glyph-name="arrow_right" unicode="&#xf061;"
+d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+ <glyph glyph-name="arrow_up" unicode="&#xf062;" horiz-adv-x="1664"
+d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651
+q37 -39 37 -91z" />
+ <glyph glyph-name="arrow_down" unicode="&#xf063;" horiz-adv-x="1664"
+d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+ <glyph glyph-name="share_alt" unicode="&#xf064;" horiz-adv-x="1792"
+d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22
+t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+ <glyph glyph-name="resize_full" unicode="&#xf065;"
+d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332
+q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="resize_small" unicode="&#xf066;"
+d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45
+t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+ <glyph glyph-name="plus" unicode="&#xf067;" horiz-adv-x="1408"
+d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="minus" unicode="&#xf068;" horiz-adv-x="1408"
+d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="asterisk" unicode="&#xf069;" horiz-adv-x="1664"
+d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154
+q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+ <glyph glyph-name="exclamation_sign" unicode="&#xf06a;"
+d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192
+q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+ <glyph glyph-name="gift" unicode="&#xf06b;"
+d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320
+q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 77 168 77q93 0 158.5 -65.5t65.5 -158.5
+t-65.5 -158.5t-158.5 -65.5h440q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="leaf" unicode="&#xf06c;" horiz-adv-x="1792"
+d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268
+q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-43 0 -63.5 17.5t-45.5 59.5q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 38t-16 44q-9 51 -9 104q0 115 43.5 220t119 184.5
+t170.5 139t204 95.5q55 18 145 25.5t179.5 9t178.5 6t163.5 24t113.5 56.5l29.5 29.5t29.5 28t27 20t36.5 16t43.5 4.5q39 0 70.5 -46t47.5 -112t24 -124t8 -96z" />
+ <glyph glyph-name="fire" unicode="&#xf06d;" horiz-adv-x="1408"
+d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1
+q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150.5t27.5 -184z" />
+ <glyph glyph-name="eye_open" unicode="&#xf06e;" horiz-adv-x="1792"
+d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5
+t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 368t499.5 139t499.5 -139t376.5 -368q20 -35 20 -69z" />
+ <glyph glyph-name="eye_close" unicode="&#xf070;" horiz-adv-x="1792"
+d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9
+q-106 -189 -316 -567t-315 -566l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 18 -6t31 -15.5t33 -18.5t31.5 -18.5t19.5 -11.5
+q16 -10 16 -27zM1344 704q0 -139 -79 -253.5t-209 -164.5l280 502q8 -45 8 -84zM1792 576q0 -35 -20 -69q-39 -64 -109 -145q-150 -172 -347.5 -267t-419.5 -95l74 132q212 18 392.5 137t301.5 307q-115 179 -282 294l63 112q95 -64 182.5 -153t144.5 -184q20 -34 20 -69z
+" />
+ <glyph glyph-name="warning_sign" unicode="&#xf071;" horiz-adv-x="1792"
+d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185
+q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+ <glyph glyph-name="plane" unicode="&#xf072;" horiz-adv-x="1408"
+d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9
+q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+ <glyph glyph-name="calendar" unicode="&#xf073;" horiz-adv-x="1664"
+d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z
+M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h288v288h-288v-288zM1280 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64
+q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47
+h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="random" unicode="&#xf074;" horiz-adv-x="1792"
+d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1
+t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5
+v192h-256q-48 0 -87 -15t-69 -45t-51 -61.5t-45 -77.5q-32 -62 -78 -171q-29 -66 -49.5 -111t-54 -105t-64 -100t-74 -83t-90 -68.5t-106.5 -42t-128 -16.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q48 0 87 15t69 45t51 61.5t45 77.5q32 62 78 171q29 66 49.5 111
+t54 105t64 100t74 83t90 68.5t106.5 42t128 16.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+ <glyph glyph-name="comment" unicode="&#xf075;" horiz-adv-x="1792"
+d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281
+q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+ <glyph glyph-name="magnet" unicode="&#xf076;"
+d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384
+q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="chevron_up" unicode="&#xf077;" horiz-adv-x="1792"
+d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
+ <glyph glyph-name="chevron_down" unicode="&#xf078;" horiz-adv-x="1792"
+d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
+ <glyph glyph-name="retweet" unicode="&#xf079;" horiz-adv-x="1920"
+d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -10 7 -21
+zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5 -8t3 -11.5t1 -11.5v-13v-11v-160v-416h192q26 0 45 -19t19 -45z
+" />
+ <glyph glyph-name="shopping_cart" unicode="&#xf07a;" horiz-adv-x="1664"
+d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45
+t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="folder_close" unicode="&#xf07b;" horiz-adv-x="1664"
+d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+ <glyph glyph-name="folder_open" unicode="&#xf07c;" horiz-adv-x="1920"
+d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5
+t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+ <glyph glyph-name="resize_vertical" unicode="&#xf07d;" horiz-adv-x="768"
+d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+ <glyph glyph-name="resize_horizontal" unicode="&#xf07e;" horiz-adv-x="1792"
+d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+ <glyph glyph-name="bar_chart" unicode="&#xf080;" horiz-adv-x="2048"
+d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
+ <glyph glyph-name="twitter_sign" unicode="&#xf081;"
+d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4
+q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5
+t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="facebook_sign" unicode="&#xf082;"
+d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960
+q0 119 84.5 203.5t203.5 84.5h960z" />
+ <glyph glyph-name="camera_retro" unicode="&#xf083;" horiz-adv-x="1792"
+d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5
+t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 -90.5t-90.5 -37.5h-1536q-53 0 -90.5 37.5t-37.5 90.5v1280
+q0 53 37.5 90.5t90.5 37.5h1536q53 0 90.5 -37.5t37.5 -90.5z" />
+ <glyph glyph-name="key" unicode="&#xf084;" horiz-adv-x="1792"
+d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26
+l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189 -131 -365l355 -355l96 96q-3 3 -26 24.5t-40 38.5t-33 36.5
+t-16 28.5q0 17 49 66t66 49q13 0 23 -10q6 -6 46 -44.5t82 -79.5t86.5 -86t73 -78t28.5 -41z" />
+ <glyph glyph-name="cogs" unicode="&#xf085;" horiz-adv-x="1920"
+d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5
+t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -11 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11 -108 -23 -155q-7 -24 -30 -24h-186q-11 0 -20 7.5t-10 17.5
+l-23 153q-34 10 -75 31l-118 -89q-7 -7 -20 -7q-11 0 -21 8q-144 133 -144 160q0 9 7 19q10 14 41 53t47 61q-23 44 -35 82l-152 24q-10 1 -17 9.5t-7 19.5v185q0 10 7 19.5t16 10.5l155 24q11 35 32 76q-34 48 -90 115q-7 11 -7 20q0 12 7 20q22 30 82 89t79 59q11 0 21 -7
+l115 -90q34 18 77 32q11 108 23 154q7 24 30 24h186q11 0 20 -7.5t10 -17.5l23 -153q34 -10 75 -31l118 89q8 7 20 7q11 0 21 -8q144 -133 144 -160q0 -8 -7 -19q-12 -16 -42 -54t-45 -60q23 -48 34 -82l152 -23q10 -2 17 -10.5t7 -19.5zM1920 198v-140q0 -16 -149 -31
+q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20
+t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31zM1920 1222v-140q0 -16 -149 -31q-12 -27 -30 -52q51 -113 51 -138q0 -4 -4 -7q-122 -71 -124 -71q-8 0 -46 47t-52 68
+q-20 -2 -30 -2t-30 2q-14 -21 -52 -68t-46 -47q-2 0 -124 71q-4 3 -4 7q0 25 51 138q-18 25 -30 52q-149 15 -149 31v140q0 16 149 31q13 29 30 52q-51 113 -51 138q0 4 4 7q4 2 35 20t59 34t30 16q8 0 46 -46.5t52 -67.5q20 2 30 2t30 -2q51 71 92 112l6 2q4 0 124 -70
+q4 -3 4 -7q0 -25 -51 -138q17 -23 30 -52q149 -15 149 -31z" />
+ <glyph glyph-name="comments" unicode="&#xf086;" horiz-adv-x="1792"
+d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224
+q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7
+q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230z" />
+ <glyph glyph-name="thumbs_up_alt" unicode="&#xf087;"
+d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5
+t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5q32 1 53.5 47t21.5 81zM1536 769
+q0 -89 -49 -163q9 -33 9 -69q0 -77 -38 -144q3 -21 3 -43q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5h-36h-93q-96 0 -189.5 22.5t-216.5 65.5q-116 40 -138 40h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h274q36 24 137 155q58 75 107 128
+q24 25 35.5 85.5t30.5 126.5t62 108q39 37 90 37q84 0 151 -32.5t102 -101.5t35 -186q0 -93 -48 -192h176q104 0 180 -76t76 -179z" />
+ <glyph glyph-name="thumbs_down_alt" unicode="&#xf088;"
+d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 31 18 69q0 37 -17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5
+t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h352q50 0 89 38.5t39 89.5z
+M1536 511q0 -103 -76 -179t-180 -76h-176q48 -99 48 -192q0 -118 -35 -186q-35 -69 -102 -101.5t-151 -32.5q-51 0 -90 37q-34 33 -54 82t-25.5 90.5t-17.5 84.5t-31 64q-48 50 -107 127q-101 131 -137 155h-274q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5
+h288q22 0 138 40q128 44 223 66t200 22h112q140 0 226.5 -79t85.5 -216v-5q60 -77 60 -178q0 -22 -3 -43q38 -67 38 -144q0 -36 -9 -69q49 -73 49 -163z" />
+ <glyph glyph-name="star_half" unicode="&#xf089;" horiz-adv-x="896"
+d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+ <glyph glyph-name="heart_empty" unicode="&#xf08a;" horiz-adv-x="1792"
+d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559
+q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5
+q224 0 351 -124t127 -344z" />
+ <glyph glyph-name="signout" unicode="&#xf08b;" horiz-adv-x="1664"
+d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704
+q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45z" />
+ <glyph glyph-name="linkedin_sign" unicode="&#xf08c;"
+d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5
+q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="pushpin" unicode="&#xf08d;" horiz-adv-x="1152"
+d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38
+t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+ <glyph glyph-name="external_link" unicode="&#xf08e;" horiz-adv-x="1792"
+d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320
+q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="signin" unicode="&#xf090;"
+d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5
+q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="trophy" unicode="&#xf091;" horiz-adv-x="1664"
+d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91
+t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 44.5t-173 97.5t-112 130t-41.5 143v128q0 40 28 68t68 28h288v96
+q0 66 47 113t113 47h576q66 0 113 -47t47 -113v-96h288q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="github_sign" unicode="&#xf092;"
+d="M519 336q4 6 -3 13q-9 7 -14 2q-4 -6 3 -13q9 -7 14 -2zM491 377q-5 7 -12 4q-6 -4 0 -12q7 -8 12 -5q6 4 0 13zM450 417q2 4 -5 8q-7 2 -8 -2q-3 -5 4 -8q8 -2 9 2zM471 394q2 1 1.5 4.5t-3.5 5.5q-6 7 -10 3t1 -11q6 -6 11 -2zM557 319q2 7 -9 11q-9 3 -13 -4
+q-2 -7 9 -11q9 -3 13 4zM599 316q0 8 -12 8q-10 0 -10 -8t11 -8t11 8zM638 323q-2 7 -13 5t-9 -9q2 -8 12 -6t10 10zM1280 640q0 212 -150 362t-362 150t-362 -150t-150 -362q0 -167 98 -300.5t252 -185.5q18 -3 26.5 5t8.5 20q0 52 -1 95q-6 -1 -15.5 -2.5t-35.5 -2t-48 4
+t-43.5 20t-29.5 41.5q-23 59 -57 74q-2 1 -4.5 3.5l-8 8t-7 9.5t4 7.5t19.5 3.5q6 0 15 -2t30 -15.5t33 -35.5q16 -28 37.5 -42t43.5 -14t38 3.5t30 9.5q7 47 33 69q-49 6 -86 18.5t-73 39t-55.5 76t-19.5 119.5q0 79 53 137q-24 62 5 136q19 6 54.5 -7.5t60.5 -29.5l26 -16
+q58 17 128 17t128 -17q11 7 28.5 18t55.5 26t57 9q29 -74 5 -136q53 -58 53 -137q0 -57 -14 -100.5t-35.5 -70t-53.5 -44.5t-62.5 -26t-68.5 -12q35 -31 35 -95q0 -40 -0.5 -89t-0.5 -51q0 -12 8.5 -20t26.5 -5q154 52 252 185.5t98 300.5zM1536 1120v-960
+q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="upload_alt" unicode="&#xf093;" horiz-adv-x="1664"
+d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92
+t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 -19l448 -448q31 -30 14 -69z" />
+ <glyph glyph-name="lemon" unicode="&#xf094;"
+d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5
+q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t-281 -180.5q-124 -44 -326 -44
+q-57 0 -170 14.5t-169 14.5q-24 0 -72.5 -14.5t-73.5 -14.5q-73 0 -123.5 55.5t-50.5 128.5q0 24 11 68t11 67q0 40 -12.5 120.5t-12.5 121.5q0 111 18 217.5t54.5 209.5t100.5 194t150 156q78 59 232 120q194 78 316 78q60 0 175.5 -24t173.5 -24q19 0 57 5t58 5
+q81 0 118 -50.5t37 -134.5q0 -23 -5 -68t-5 -68q0 -13 2 -25t3.5 -16.5t7.5 -20.5t8 -20q16 -40 25 -118.5t9 -136.5z" />
+ <glyph glyph-name="phone" unicode="&#xf095;" horiz-adv-x="1408"
+d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -53 3.5t-57.5 12.5t-47 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-127 79 -264 216t-216 264q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47t-12.5 57.5t-3.5 53q0 92 51 186
+q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5 -20.5t14 -24t11.5 -19q76 -137 174 -235t235 -174q2 -1 19 -11.5t24 -14
+t20.5 -8.5t22.5 -5q18 0 46 28.5t53 62t55 62t50 28.5q14 0 28.5 -7t35.5 -21.5t25 -17.5q25 -15 53.5 -31t63.5 -35t54 -30q70 -35 76 -53q3 -7 3 -21z" />
+ <glyph glyph-name="check_empty" unicode="&#xf096;" horiz-adv-x="1408"
+d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832
+q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="bookmark_empty" unicode="&#xf097;" horiz-adv-x="1280"
+d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289
+q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+ <glyph glyph-name="phone_sign" unicode="&#xf098;"
+d="M1280 343q0 11 -2 16t-18 16.5t-40.5 25t-47.5 26.5t-45.5 25t-28.5 15q-5 3 -19 13t-25 15t-21 5q-15 0 -36.5 -20.5t-39.5 -45t-38.5 -45t-33.5 -20.5q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170 126.5t-127 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5
+t-3.5 16.5q0 13 20.5 33.5t45 38.5t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216.5 -320.5
+t320.5 -216.5q6 -2 30 -11t33 -12.5t29.5 -10t33 -9t30.5 -5t34 -2.5q57 0 130.5 34t94.5 80q22 53 22 101zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z
+" />
+ <glyph glyph-name="twitter" unicode="&#xf099;" horiz-adv-x="1664"
+d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41
+q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+ <glyph glyph-name="facebook" unicode="&#xf09a;" horiz-adv-x="1024"
+d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
+ <glyph glyph-name="github" unicode="&#xf09b;"
+d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -40 7t-13 30q0 3 0.5 76.5t0.5 134.5q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 119 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24
+q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-85 13.5q-45 -113 -8 -204q-79 -87 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-39 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5
+t-5 -11.5t9 -14t13 -12l7 -5q22 -10 43.5 -38t31.5 -51l10 -23q13 -38 44 -61.5t67 -30t69.5 -7t55.5 3.5l23 4q0 -38 0.5 -88.5t0.5 -54.5q0 -18 -13 -30t-40 -7q-232 77 -378.5 277.5t-146.5 451.5q0 209 103 385.5t279.5 279.5t385.5 103zM291 305q3 7 -7 12
+q-10 3 -13 -2q-3 -7 7 -12q9 -6 13 2zM322 271q7 5 -2 16q-10 9 -16 3q-7 -5 2 -16q10 -10 16 -3zM352 226q9 7 0 19q-8 13 -17 6q-9 -5 0 -18t17 -7zM394 184q8 8 -4 19q-12 12 -20 3q-9 -8 4 -19q12 -12 20 -3zM451 159q3 11 -13 16q-15 4 -19 -7t13 -15q15 -6 19 6z
+M514 154q0 13 -17 11q-16 0 -16 -11q0 -13 17 -11q16 0 16 11zM572 164q-2 11 -18 9q-16 -3 -14 -15t18 -8t14 14z" />
+ <glyph glyph-name="unlock" unicode="&#xf09c;" horiz-adv-x="1664"
+d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5
+t316.5 -131.5t131.5 -316.5z" />
+ <glyph glyph-name="credit_card" unicode="&#xf09d;" horiz-adv-x="1920"
+d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608
+q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+ <glyph glyph-name="rss" unicode="&#xf09e;" horiz-adv-x="1408"
+d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5
+t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5v143q0 28 20 46q18 18 44 18h3q262 -13 501.5 -120t425.5 -294
+q187 -186 294 -425.5t120 -501.5z" />
+ <glyph glyph-name="hdd" unicode="&#xf0a0;"
+d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5
+h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v320q0 25 16 75
+l197 606q17 53 63 86t101 33h782q55 0 101 -33t63 -86l197 -606q16 -50 16 -75z" />
+ <glyph glyph-name="bullhorn" unicode="&#xf0a1;" horiz-adv-x="1792"
+d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5
+t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+ <glyph glyph-name="bell" unicode="&#xf0a2;" horiz-adv-x="1792"
+d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z
+M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5
+t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+ <glyph glyph-name="certificate" unicode="&#xf0a3;"
+d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70
+l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 -188l186 53q41 12 70 -19q31 -29 19 -70
+l-53 -186l188 -48q40 -10 52 -51q10 -42 -20 -70z" />
+ <glyph glyph-name="hand_right" unicode="&#xf0a4;" horiz-adv-x="1792"
+d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106
+q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-180.5 -76h-169q-4 -62 -37 -119q3 -21 3 -43
+q0 -101 -60 -178q1 -139 -85 -219.5t-227 -80.5q-133 0 -322 69q-164 59 -223 59h-288q-53 0 -90.5 37.5t-37.5 90.5v640q0 53 37.5 90.5t90.5 37.5h288q10 0 21.5 4.5t23.5 14t22.5 18t24 22.5t20.5 21.5t19 21.5t14 17q65 74 100 129q13 21 33 62t37 72t40.5 63t55 49.5
+t69.5 17.5q125 0 206.5 -67t81.5 -189q0 -68 -22 -128h374q104 0 180 -76t76 -179z" />
+ <glyph glyph-name="hand_left" unicode="&#xf0a5;" horiz-adv-x="1792"
+d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-8 9 -12 14q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576q-50 0 -89 -38.5
+t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32zM1664 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45z
+M1792 768v-640q0 -53 -37.5 -90.5t-90.5 -37.5h-288q-59 0 -223 -59q-190 -69 -317 -69q-142 0 -230 77.5t-87 217.5l1 5q-61 76 -61 178q0 22 3 43q-33 57 -37 119h-169q-105 0 -180.5 76t-75.5 181q0 103 76 179t180 76h374q-22 60 -22 128q0 122 81.5 189t206.5 67
+q38 0 69.5 -17.5t55 -49.5t40.5 -63t37 -72t33 -62q35 -55 100 -129q2 -3 14 -17t19 -21.5t20.5 -21.5t24 -22.5t22.5 -18t23.5 -14t21.5 -4.5h288q53 0 90.5 -37.5t37.5 -90.5z" />
+ <glyph glyph-name="hand_up" unicode="&#xf0a6;"
+d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576
+q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 -59 -223v-288q0 -53 -37.5 -90.5
+t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v288q0 10 -4.5 21.5t-14 23.5t-18 22.5t-22.5 24t-21.5 20.5t-21.5 19t-17 14q-74 65 -129 100q-21 13 -62 33t-72 37t-63 40.5t-49.5 55t-17.5 69.5q0 125 67 206.5t189 81.5q68 0 128 -22v374q0 104 76 180t179 76
+q105 0 181 -75.5t76 -180.5v-169q62 -4 119 -37q21 3 43 3q101 0 178 -60q139 1 219.5 -85t80.5 -227z" />
+ <glyph glyph-name="hand_down" unicode="&#xf0a7;"
+d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33
+t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 580
+q0 -142 -77.5 -230t-217.5 -87l-5 1q-76 -61 -178 -61q-22 0 -43 3q-54 -30 -119 -37v-169q0 -105 -76 -180.5t-181 -75.5q-103 0 -179 76t-76 180v374q-54 -22 -128 -22q-121 0 -188.5 81.5t-67.5 206.5q0 38 17.5 69.5t49.5 55t63 40.5t72 37t62 33q55 35 129 100
+q3 2 17 14t21.5 19t21.5 20.5t22.5 24t18 22.5t14 23.5t4.5 21.5v288q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-288q0 -59 59 -223q69 -190 69 -317z" />
+ <glyph glyph-name="circle_arrow_left" unicode="&#xf0a8;"
+d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="circle_arrow_right" unicode="&#xf0a9;"
+d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="circle_arrow_up" unicode="&#xf0aa;"
+d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="circle_arrow_down" unicode="&#xf0ab;"
+d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="globe" unicode="&#xf0ac;"
+d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11
+q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 11t-9.5 10q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5q-3 2 -6 1.5t-4.5 -1t-4.5 -3t-5 -3.5
+q-3 -2 -8.5 -3t-8.5 -2q15 5 -1 11q-10 4 -16 3q9 4 7.5 12t-8.5 14h5q-1 4 -8.5 8.5t-17.5 8.5t-13 6q-8 5 -34 9.5t-33 0.5q-5 -6 -4.5 -10.5t4 -14t3.5 -12.5q1 -6 -5.5 -13t-6.5 -12q0 -7 14 -15.5t10 -21.5q-3 -8 -16 -16t-16 -12q-5 -8 -1.5 -18.5t10.5 -16.5
+q2 -2 1.5 -4t-3.5 -4.5t-5.5 -4t-6.5 -3.5l-3 -2q-11 -5 -20.5 6t-13.5 26q-7 25 -16 30q-23 8 -29 -1q-5 13 -41 26q-25 9 -58 4q6 1 0 15q-7 15 -19 12q3 6 4 17.5t1 13.5q3 13 12 23q1 1 7 8.5t9.5 13.5t0.5 6q35 -4 50 11q5 5 11.5 17t10.5 17q9 6 14 5.5t14.5 -5.5
+t14.5 -5q14 -1 15.5 11t-7.5 20q12 -1 3 17q-4 7 -8 9q-12 4 -27 -5q-8 -4 2 -8q-1 1 -9.5 -10.5t-16.5 -17.5t-16 5q-1 1 -5.5 13.5t-9.5 13.5q-8 0 -16 -15q3 8 -11 15t-24 8q19 12 -8 27q-7 4 -20.5 5t-19.5 -4q-5 -7 -5.5 -11.5t5 -8t10.5 -5.5t11.5 -4t8.5 -3
+q14 -10 8 -14q-2 -1 -8.5 -3.5t-11.5 -4.5t-6 -4q-3 -4 0 -14t-2 -14q-5 5 -9 17.5t-7 16.5q7 -9 -25 -6l-10 1q-4 0 -16 -2t-20.5 -1t-13.5 8q-4 8 0 20q1 4 4 2q-4 3 -11 9.5t-10 8.5q-46 -15 -94 -41q6 -1 12 1q5 2 13 6.5t10 5.5q34 14 42 7l5 5q14 -16 20 -25
+q-7 4 -30 1q-20 -6 -22 -12q7 -12 5 -18q-4 3 -11.5 10t-14.5 11t-15 5q-16 0 -22 -1q-146 -80 -235 -222q7 -7 12 -8q4 -1 5 -9t2.5 -11t11.5 3q9 -8 3 -19q1 1 44 -27q19 -17 21 -21q3 -11 -10 -18q-1 2 -9 9t-9 4q-3 -5 0.5 -18.5t10.5 -12.5q-7 0 -9.5 -16t-2.5 -35.5
+t-1 -23.5l2 -1q-3 -12 5.5 -34.5t21.5 -19.5q-13 -3 20 -43q6 -8 8 -9q3 -2 12 -7.5t15 -10t10 -10.5q4 -5 10 -22.5t14 -23.5q-2 -6 9.5 -20t10.5 -23q-1 0 -2.5 -1t-2.5 -1q3 -7 15.5 -14t15.5 -13q1 -3 2 -10t3 -11t8 -2q2 20 -24 62q-15 25 -17 29q-3 5 -5.5 15.5
+t-4.5 14.5q2 0 6 -1.5t8.5 -3.5t7.5 -4t2 -3q-3 -7 2 -17.5t12 -18.5t17 -19t12 -13q6 -6 14 -19.5t0 -13.5q9 0 20 -10.5t17 -19.5q5 -8 8 -26t5 -24q2 -7 8.5 -13.5t12.5 -9.5l16 -8t13 -7q5 -2 18.5 -10.5t21.5 -11.5q10 -4 16 -4t14.5 2.5t13.5 3.5q15 2 29 -15t21 -21
+q36 -19 55 -11q-2 -1 0.5 -7.5t8 -15.5t9 -14.5t5.5 -8.5q5 -6 18 -15t18 -15q6 4 7 9q-3 -8 7 -20t18 -10q14 3 14 32q-31 -15 -49 18q0 1 -2.5 5.5t-4 8.5t-2.5 8.5t0 7.5t5 3q9 0 10 3.5t-2 12.5t-4 13q-1 8 -11 20t-12 15q-5 -9 -16 -8t-16 9q0 -1 -1.5 -5.5t-1.5 -6.5
+q-13 0 -15 1q1 3 2.5 17.5t3.5 22.5q1 4 5.5 12t7.5 14.5t4 12.5t-4.5 9.5t-17.5 2.5q-19 -1 -26 -20q-1 -3 -3 -10.5t-5 -11.5t-9 -7q-7 -3 -24 -2t-24 5q-13 8 -22.5 29t-9.5 37q0 10 2.5 26.5t3 25t-5.5 24.5q3 2 9 9.5t10 10.5q2 1 4.5 1.5t4.5 0t4 1.5t3 6q-1 1 -4 3
+q-3 3 -4 3q7 -3 28.5 1.5t27.5 -1.5q15 -11 22 2q0 1 -2.5 9.5t-0.5 13.5q5 -27 29 -9q3 -3 15.5 -5t17.5 -5q3 -2 7 -5.5t5.5 -4.5t5 0.5t8.5 6.5q10 -14 12 -24q11 -40 19 -44q7 -3 11 -2t4.5 9.5t0 14t-1.5 12.5l-1 8v18l-1 8q-15 3 -18.5 12t1.5 18.5t15 18.5q1 1 8 3.5
+t15.5 6.5t12.5 8q21 19 15 35q7 0 11 9q-1 0 -5 3t-7.5 5t-4.5 2q9 5 2 16q5 3 7.5 11t7.5 10q9 -12 21 -2q8 8 1 16q5 7 20.5 10.5t18.5 9.5q7 -2 8 2t1 12t3 12q4 5 15 9t13 5l17 11q3 4 0 4q18 -2 31 11q10 11 -6 20q3 6 -3 9.5t-15 5.5q3 1 11.5 0.5t10.5 1.5
+q15 10 -7 16q-17 5 -43 -12zM879 10q206 36 351 189q-3 3 -12.5 4.5t-12.5 3.5q-18 7 -24 8q1 7 -2.5 13t-8 9t-12.5 8t-11 7q-2 2 -7 6t-7 5.5t-7.5 4.5t-8.5 2t-10 -1l-3 -1q-3 -1 -5.5 -2.5t-5.5 -3t-4 -3t0 -2.5q-21 17 -36 22q-5 1 -11 5.5t-10.5 7t-10 1.5t-11.5 -7
+q-5 -5 -6 -15t-2 -13q-7 5 0 17.5t2 18.5q-3 6 -10.5 4.5t-12 -4.5t-11.5 -8.5t-9 -6.5t-8.5 -5.5t-8.5 -7.5q-3 -4 -6 -12t-5 -11q-2 4 -11.5 6.5t-9.5 5.5q2 -10 4 -35t5 -38q7 -31 -12 -48q-27 -25 -29 -40q-4 -22 12 -26q0 -7 -8 -20.5t-7 -21.5q0 -6 2 -16z" />
+ <glyph glyph-name="wrench" unicode="&#xf0ad;" horiz-adv-x="1664"
+d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5
+t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+ <glyph glyph-name="tasks" unicode="&#xf0ae;" horiz-adv-x="1792"
+d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19
+t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="filter" unicode="&#xf0b0;" horiz-adv-x="1408"
+d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+ <glyph glyph-name="briefcase" unicode="&#xf0b1;" horiz-adv-x="1792"
+d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68
+t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="fullscreen" unicode="&#xf0b2;"
+d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144
+l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0 -42 -39 -59q-13 -5 -25 -5q-26 0 -45 19z
+" />
+ <glyph glyph-name="group" unicode="&#xf0c0;" horiz-adv-x="1920"
+d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5
+t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75
+t75 -181zM1344 896q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5zM1920 671q0 -78 -56 -118.5t-138 -40.5h-134q-103 123 -265 128q81 117 81 256q0 29 -5 66q66 -23 133 -23q59 0 119 21.5t97.5 42.5
+t43.5 21q124 0 124 -353zM1792 1280q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181z" />
+ <glyph glyph-name="link" unicode="&#xf0c1;" horiz-adv-x="1664"
+d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26
+l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3.5 27.5q0 40 28 68t68 28q15 0 27.5 -3.5t25.5 -13t19 -15
+t21.5 -21.5t18.5 -19q33 31 33 73zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-206 207q-83 83 -83 203q0 123 88 209l-88 88q-86 -88 -208 -88q-120 0 -204 84l-208 208q-84 84 -84 204t85 203l147 146q83 83 203 83q121 0 204 -85l206 -207
+q83 -83 83 -203q0 -123 -88 -209l88 -88q86 88 208 88q120 0 204 -84l208 -208q84 -84 84 -204z" />
+ <glyph glyph-name="cloud" unicode="&#xf0c2;" horiz-adv-x="1920"
+d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z
+" />
+ <glyph glyph-name="beaker" unicode="&#xf0c3;" horiz-adv-x="1664"
+d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+ <glyph glyph-name="cut" unicode="&#xf0c4;" horiz-adv-x="1792"
+d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84
+q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 79 222 79q145 0 277 -84q83 -52 132 -123t56 -148
+q4 -48 -10 -97q4 -1 12 -5l110 -66l690 387q14 8 31 8q16 0 29 -7l128 -64q30 -16 35 -51q3 -36 -25 -56zM579 836q46 42 21 108t-106 117q-92 59 -192 59q-74 0 -113 -36q-46 -42 -21 -108t106 -117q92 -59 192 -59q74 0 113 36zM494 91q81 51 106 117t-21 108
+q-39 36 -113 36q-100 0 -192 -59q-81 -51 -106 -117t21 -108q39 -36 113 -36q100 0 192 59zM672 704l96 -58v11q0 36 33 56l14 8l-79 47l-26 -26q-3 -3 -10 -11t-12 -12q-2 -2 -4 -3.5t-3 -2.5zM896 480l96 -32l736 576l-128 64l-768 -431v-113l-160 -96l9 -8q2 -2 7 -6
+q4 -4 11 -12t11 -12l26 -26zM1600 64l128 64l-520 408l-177 -138q-2 -3 -13 -7z" />
+ <glyph glyph-name="copy" unicode="&#xf0c5;" horiz-adv-x="1792"
+d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299
+h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+ <glyph glyph-name="paper_clip" unicode="&#xf0c6;" horiz-adv-x="1408"
+d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181
+l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0 82 57 139t139 57q88 0 149 -63l581 -581q100 -98 100 -235
+z" />
+ <glyph glyph-name="save" unicode="&#xf0c7;"
+d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5
+h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 -28 48 -76t20 -88z" />
+ <glyph glyph-name="sign_blank" unicode="&#xf0c8;"
+d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="reorder" unicode="&#xf0c9;"
+d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45
+t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="ul" unicode="&#xf0ca;" horiz-adv-x="1792"
+d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5
+t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z
+M1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+ <glyph glyph-name="ol" unicode="&#xf0cb;" horiz-adv-x="1792"
+d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362
+q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t-35.5 -52.5h127v60h105zM1792 224v-192q0 -13 -9.5 -22.5
+t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1123v-99h-335v99h107q0 41 0.5 121.5t0.5 121.5v12h-2q-8 -17 -50 -54l-71 76l136 127h106v-404h108zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216
+q-13 0 -22.5 9.5t-9.5 22.5v192q0 14 9 23t23 9h1216q13 0 22.5 -9.5t9.5 -22.5zM1792 1248v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5z" />
+ <glyph glyph-name="strikethrough" unicode="&#xf0cc;" horiz-adv-x="1792"
+d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 98 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6
+l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -56 -71 -104q-37 -35 -109 -81q-80 -48 -153 -66q-80 -21 -203 -21q-114 0 -195 23
+l-140 40q-57 16 -72 28q-8 8 -8 22v13q0 108 -2 156q-1 30 0 68l2 37v44l102 2q15 -34 30 -71t22.5 -56t12.5 -27q35 -57 80 -94q43 -36 105 -57q59 -22 132 -22q64 0 139 27q77 26 122 86q47 61 47 129q0 84 -81 157q-34 29 -137 71z" />
+ <glyph glyph-name="underline" unicode="&#xf0cd;"
+d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47
+q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -13q-73 -11 -79 -17q-15 -15 -15 -41
+q0 -7 1.5 -27t1.5 -31q8 -19 22 -396q6 -195 -15 -304q-15 -76 -41 -122q-38 -65 -112 -123q-75 -57 -182 -89q-109 -33 -255 -33q-167 0 -284 46q-119 47 -179 122q-61 76 -83 195q-16 80 -16 237v333q0 188 -17 213q-25 36 -147 39zM1536 -96v64q0 14 -9 23t-23 9h-1472
+q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h1472q14 0 23 9t9 23z" />
+ <glyph glyph-name="table" unicode="&#xf0ce;" horiz-adv-x="1664"
+d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23
+v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 160v192
+q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192
+q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1536 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1664 1248v-1088q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1344q66 0 113 -47t47 -113
+z" />
+ <glyph glyph-name="magic" unicode="&#xf0d0;" horiz-adv-x="1664"
+d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276
+l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+ <glyph glyph-name="truck" unicode="&#xf0d1;" horiz-adv-x="1792"
+d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5
+t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5 18.5t-4 26.5q0 26 19 45t45 19v320q0 8 -0.5 35t0 38
+t2.5 34.5t6.5 37t14 30.5t22.5 30l198 198q19 19 50.5 32t58.5 13h160v192q0 26 19 45t45 19h1024q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="pinterest" unicode="&#xf0d2;"
+d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134
+q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11.5 75.5q0 50 -27 83t-77 33
+q-62 0 -105 -57t-43 -142q0 -73 25 -122l-99 -418q-17 -70 -13 -177q-206 91 -333 281t-127 423q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="pinterest_sign" unicode="&#xf0d3;"
+d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5
+t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 -97 43.5t-23 103.5q8 34 26.5 92.5
+t29.5 102t11 74.5q0 49 -26.5 81.5t-75.5 32.5q-61 0 -103.5 -56.5t-42.5 -139.5q0 -72 24 -121l-98 -414q-24 -100 -7 -254h-183q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960z" />
+ <glyph glyph-name="google_plus_sign" unicode="&#xf0d4;"
+d="M917 631q0 26 -6 64h-362v-132h217q-3 -24 -16.5 -50t-37.5 -53t-66.5 -44.5t-96.5 -17.5q-99 0 -169 71t-70 171t70 171t169 71q92 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585
+h109v110h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="google_plus" unicode="&#xf0d5;" horiz-adv-x="2304"
+d="M1437 623q0 -208 -87 -370.5t-248 -254t-369 -91.5q-149 0 -285 58t-234 156t-156 234t-58 285t58 285t156 234t234 156t285 58q286 0 491 -192l-199 -191q-117 113 -292 113q-123 0 -227.5 -62t-165.5 -168.5t-61 -232.5t61 -232.5t165.5 -168.5t227.5 -62
+q83 0 152.5 23t114.5 57.5t78.5 78.5t49 83t21.5 74h-416v252h692q12 -63 12 -122zM2304 745v-210h-209v-209h-210v209h-209v210h209v209h210v-209h209z" />
+ <glyph glyph-name="money" unicode="&#xf0d6;" horiz-adv-x="1920"
+d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384
+v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45 19h1792q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="caret_down" unicode="&#xf0d7;" horiz-adv-x="1024"
+d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="caret_up" unicode="&#xf0d8;" horiz-adv-x="1024"
+d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+ <glyph glyph-name="caret_left" unicode="&#xf0d9;" horiz-adv-x="640"
+d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+ <glyph glyph-name="caret_right" unicode="&#xf0da;" horiz-adv-x="640"
+d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+ <glyph glyph-name="columns" unicode="&#xf0db;" horiz-adv-x="1664"
+d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="sort" unicode="&#xf0dc;" horiz-adv-x="1024"
+d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+ <glyph glyph-name="sort_down" unicode="&#xf0dd;" horiz-adv-x="1024"
+d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="sort_up" unicode="&#xf0de;" horiz-adv-x="1024"
+d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+ <glyph glyph-name="envelope_alt" unicode="&#xf0e0;" horiz-adv-x="1792"
+d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123
+q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t118.5 52h1472q65 0 112.5 -47t47.5 -113z" />
+ <glyph glyph-name="linkedin" unicode="&#xf0e1;"
+d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329
+q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+ <glyph glyph-name="undo" unicode="&#xf0e2;"
+d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5
+t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298z" />
+ <glyph glyph-name="legal" unicode="&#xf0e3;" horiz-adv-x="1792"
+d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5
+t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 -12.5q-14 14 -14 34t14 34l348 348q14 14 34 14t34 -14
+q-2 2 -12.5 12t-12.5 13t-10 11.5t-10 13.5t-6 13.5t-5.5 16.5t-1.5 18q0 38 28 68q3 3 16.5 18t19 20.5t18.5 16.5t22 15.5t22 9t26 4.5q40 0 68 -28l408 -408q28 -28 28 -68q0 -13 -4.5 -26t-9 -22t-15.5 -22t-16.5 -18.5t-20.5 -19t-18 -16.5q-30 -28 -68 -28
+q-10 0 -18 1.5t-16.5 5.5t-13.5 6t-13.5 10t-11.5 10t-13 12.5t-12 12.5q14 -14 14 -34t-14 -34l-126 -126l256 -256q43 43 96 43q52 0 91 -37l363 -363q37 -39 37 -91z" />
+ <glyph glyph-name="dashboard" unicode="&#xf0e4;" horiz-adv-x="1792"
+d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5
+t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 1024q0 53 -37.5 90.5
+t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1472 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 384q0 -261 -141 -483q-19 -29 -54 -29h-1402q-35 0 -54 29
+q-141 221 -141 483q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="comment_alt" unicode="&#xf0e5;" horiz-adv-x="1792"
+d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640
+q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 174 120 321.5
+t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+ <glyph glyph-name="comments_alt" unicode="&#xf0e6;" horiz-adv-x="1792"
+d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257
+t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224q0 139 94 257t256.5 186.5
+t353.5 68.5zM1526 111q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 -5t2 -6t0.5 -6.5t-1 -6.5q-3 -14 -13 -22t-22 -7q-50 7 -86 16q-154 40 -278 128q-90 -16 -176 -16q-271 0 -472 132q58 -4 88 -4q161 0 309 45t264 129
+q125 92 192 212t67 254q0 77 -23 152q129 -71 204 -178t75 -230q0 -120 -71 -224.5t-195 -176.5z" />
+ <glyph glyph-name="bolt" unicode="&#xf0e7;" horiz-adv-x="896"
+d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+ <glyph glyph-name="sitemap" unicode="&#xf0e8;" horiz-adv-x="1792"
+d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320
+q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h512q52 0 90 -38t38 -90v-192h96q40 0 68 -28t28 -68
+z" />
+ <glyph glyph-name="umbrella" unicode="&#xf0e9;" horiz-adv-x="1664"
+d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97
+q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 28q-43 60 -103 97t-128 37q-58 0 -102 -23t-93 -69
+q-12 -10 -23 -10q-13 0 -22.5 9.5t-9.5 22.5q0 5 1 7q45 183 172.5 319.5t298 204.5t360.5 68q140 0 274.5 -40t246.5 -113.5t194.5 -187t115.5 -251.5q1 -2 1 -7zM896 1408v-98q-42 2 -64 2t-64 -2v98q0 26 19 45t45 19t45 -19t19 -45z" />
+ <glyph glyph-name="paste" unicode="&#xf0ea;" horiz-adv-x="1792"
+d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28
+h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+ <glyph glyph-name="light_bulb" unicode="&#xf0eb;" horiz-adv-x="1024"
+d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134
+q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q0 -37 -25 -64q25 -27 25 -64q0 -52 -45 -81q13 -23 13 -47
+q0 -46 -31.5 -71t-77.5 -25q-20 -44 -60 -70t-87 -26t-87 26t-60 70q-46 0 -77.5 25t-31.5 71q0 24 13 47q-45 29 -45 81q0 37 25 64q-25 27 -25 64q0 54 47 82q-4 50 -34 107.5t-59.5 95.5t-74.5 87q-103 113 -103 268q0 99 44.5 184.5t117 142t164 89t186.5 32.5
+t186.5 -32.5t164 -89t117 -142t44.5 -184.5z" />
+ <glyph glyph-name="exchange" unicode="&#xf0ec;" horiz-adv-x="1792"
+d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9
+q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+ <glyph glyph-name="cloud_download" unicode="&#xf0ed;" horiz-adv-x="1920"
+d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088
+q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+ <glyph glyph-name="cloud_upload" unicode="&#xf0ee;" horiz-adv-x="1920"
+d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088
+q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+ <glyph glyph-name="user_md" unicode="&#xf0f0;" horiz-adv-x="1408"
+d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56
+t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 38 90t90 38t90 -38t38 -90v-89q-32 -29 -32 -71q0 -40 28 -68
+t68 -28t68 28t28 68q0 42 -32 71v89q0 68 -34.5 127.5t-93.5 93.5q0 10 0.5 42.5t0 48t-2.5 41.5t-7 47t-13 40q68 -15 120 -60.5t81 -103t47.5 -132.5t24 -138t5.5 -131zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5
+t271.5 -112.5t112.5 -271.5z" />
+ <glyph glyph-name="stethoscope" unicode="&#xf0f1;" horiz-adv-x="1408"
+d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48
+t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 -48q10 2 16 2q26 0 45 -19t19 -45v-512q0 -144 -110 -252
+t-274 -128v-132q0 -106 94 -181t226 -75t226 75t94 181v395q-57 21 -92.5 70t-35.5 111q0 80 56 136t136 56t136 -56t56 -136z" />
+ <glyph glyph-name="suitcase" unicode="&#xf0f2;" horiz-adv-x="1792"
+d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66
+t66 -158z" />
+ <glyph glyph-name="bell_alt" unicode="&#xf0f3;" horiz-adv-x="1792"
+d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5
+t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+ <glyph glyph-name="coffee" unicode="&#xf0f4;" horiz-adv-x="1920"
+d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45
+t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+ <glyph glyph-name="food" unicode="&#xf0f5;" horiz-adv-x="1408"
+d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45
+t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="file_text_alt" unicode="&#xf0f6;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704
+q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704z" />
+ <glyph glyph-name="building" unicode="&#xf0f7;" horiz-adv-x="1408"
+d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M640 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M640 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 992v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M896 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 1248v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M896 -128h384v1536h-1152v-1536h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM1408 1472v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="hospital" unicode="&#xf0f8;" horiz-adv-x="1408"
+d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M1152 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM896 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M640 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M896 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1152 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z
+M896 -128h384v1152h-256v-32q0 -40 -28 -68t-68 -28h-448q-40 0 -68 28t-28 68v32h-256v-1152h384v224q0 13 9.5 22.5t22.5 9.5h320q13 0 22.5 -9.5t9.5 -22.5v-224zM896 1056v320q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-96h-128v96q0 13 -9.5 22.5
+t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5v96h128v-96q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1408 1088v-1280q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1280q0 26 19 45t45 19h320
+v288q0 40 28 68t68 28h448q40 0 68 -28t28 -68v-288h320q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="ambulance" unicode="&#xf0f9;" horiz-adv-x="1920"
+d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5
+t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM1920 1344v-1152
+q0 -26 -19 -45t-45 -19h-192q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-128q-26 0 -45 19t-19 45t19 45t45 19v416q0 26 13 58t32 51l198 198q19 19 51 32t58 13h160v320q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="medkit" unicode="&#xf0fa;" horiz-adv-x="1792"
+d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32
+q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 158 -66t66 -158z" />
+ <glyph glyph-name="fighter_jet" unicode="&#xf0fb;" horiz-adv-x="1920"
+d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96
+q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q128 -28 200 -52t80 -34z" />
+ <glyph glyph-name="beer" unicode="&#xf0fc;" horiz-adv-x="1664"
+d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+ <glyph glyph-name="h_sign" unicode="&#xf0fd;"
+d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960
+q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="f0fe" unicode="&#xf0fe;"
+d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960
+q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="double_angle_left" unicode="&#xf100;" horiz-adv-x="1024"
+d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23
+t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+ <glyph glyph-name="double_angle_right" unicode="&#xf101;" horiz-adv-x="1024"
+d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23
+l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+ <glyph glyph-name="double_angle_up" unicode="&#xf102;" horiz-adv-x="1152"
+d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393
+q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+ <glyph glyph-name="double_angle_down" unicode="&#xf103;" horiz-adv-x="1152"
+d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23
+t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+ <glyph glyph-name="angle_left" unicode="&#xf104;" horiz-adv-x="640"
+d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+ <glyph glyph-name="angle_right" unicode="&#xf105;" horiz-adv-x="640"
+d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+ <glyph glyph-name="angle_up" unicode="&#xf106;" horiz-adv-x="1152"
+d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+ <glyph glyph-name="angle_down" unicode="&#xf107;" horiz-adv-x="1152"
+d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+ <glyph glyph-name="desktop" unicode="&#xf108;" horiz-adv-x="1920"
+d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19
+t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="laptop" unicode="&#xf109;" horiz-adv-x="1920"
+d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z
+M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+ <glyph glyph-name="tablet" unicode="&#xf10a;" horiz-adv-x="1152"
+d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832
+q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="mobile_phone" unicode="&#xf10b;" horiz-adv-x="768"
+d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136
+q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="circle_blank" unicode="&#xf10c;"
+d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103
+t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="quote_left" unicode="&#xf10d;" horiz-adv-x="1664"
+d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z
+M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z" />
+ <glyph glyph-name="quote_right" unicode="&#xf10e;" horiz-adv-x="1664"
+d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216
+v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136z" />
+ <glyph glyph-name="spinner" unicode="&#xf110;" horiz-adv-x="1792"
+d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5
+t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-113 -47t-113 47t-47 113t47 113t113 47t113 -47t47 -113z
+M1728 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1088 1344q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1618 1138q0 -93 -66 -158.5t-158 -65.5q-93 0 -158.5 65.5t-65.5 158.5
+q0 92 65.5 158t158.5 66q92 0 158 -66t66 -158z" />
+ <glyph glyph-name="circle" unicode="&#xf111;"
+d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="reply" unicode="&#xf112;" horiz-adv-x="1792"
+d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19
+l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+ <glyph glyph-name="github_alt" unicode="&#xf113;" horiz-adv-x="1664"
+d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320
+q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM1664 496q0 -207 -61 -331q-38 -77 -105.5 -133t-141 -86
+t-170 -47.5t-171.5 -22t-167 -4.5q-78 0 -142 3t-147.5 12.5t-152.5 30t-137 51.5t-121 81t-86 115q-62 123 -62 331q0 237 136 396q-27 82 -27 170q0 116 51 218q108 0 190 -39.5t189 -123.5q147 35 309 35q148 0 280 -32q105 82 187 121t189 39q51 -102 51 -218
+q0 -87 -27 -168q136 -160 136 -398z" />
+ <glyph glyph-name="folder_close_alt" unicode="&#xf114;" horiz-adv-x="1664"
+d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320
+q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+ <glyph glyph-name="folder_open_alt" unicode="&#xf115;" horiz-adv-x="1920"
+d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68
+v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158v-160h192q54 0 99 -24.5t67 -70.5q15 -32 15 -68z
+" />
+ <glyph glyph-name="expand_alt" unicode="&#xf116;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="collapse_alt" unicode="&#xf117;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="smile" unicode="&#xf118;"
+d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5
+t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5
+t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="frown" unicode="&#xf119;"
+d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5
+t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204
+t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="meh" unicode="&#xf11a;"
+d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5
+t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="gamepad" unicode="&#xf11b;" horiz-adv-x="1920"
+d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5
+t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -150q-192 0 -338 128h-220q-146 -128 -338 -128q-212 0 -362 150
+t-150 362t150 362t362 150h896q212 0 362 -150t150 -362z" />
+ <glyph glyph-name="keyboard" unicode="&#xf11c;" horiz-adv-x="1920"
+d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16
+h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1024 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16
+h96q16 0 16 -16zM896 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1280 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1152 880v-96
+q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1664 880v-352q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h112v240q0 16 16 16h96q16 0 16 -16zM1792 128v896h-1664v-896
+h1664zM1920 1024v-896q0 -53 -37.5 -90.5t-90.5 -37.5h-1664q-53 0 -90.5 37.5t-37.5 90.5v896q0 53 37.5 90.5t90.5 37.5h1664q53 0 90.5 -37.5t37.5 -90.5z" />
+ <glyph glyph-name="flag_alt" unicode="&#xf11d;" horiz-adv-x="1792"
+d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9
+h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102
+q-15 -9 -33 -9q-16 0 -32 8q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+ <glyph glyph-name="flag_checkered" unicode="&#xf11e;" horiz-adv-x="1792"
+d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2
+q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v1266
+q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -99 48t-91 29t-114 14q-102 0 -235.5 -44t-228.5 -102q-15 -9 -33 -9q-16 0 -32 8
+q-32 19 -32 56v742q0 35 31 55q35 21 78.5 42.5t114 52t152.5 49.5t155 19q112 0 209 -31t209 -86q38 -19 89 -19q122 0 310 112q22 12 31 17q31 16 62 -2q31 -20 31 -55z" />
+ <glyph glyph-name="terminal" unicode="&#xf120;" horiz-adv-x="1664"
+d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9
+t9 -23z" />
+ <glyph glyph-name="code" unicode="&#xf121;" horiz-adv-x="1920"
+d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5
+l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23z" />
+ <glyph glyph-name="reply_all" unicode="&#xf122;" horiz-adv-x="1792"
+d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1
+q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 -173 169 -509z" />
+ <glyph glyph-name="star_half_empty" unicode="&#xf123;" horiz-adv-x="1664"
+d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5
+l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+ <glyph glyph-name="location_arrow" unicode="&#xf124;" horiz-adv-x="1408"
+d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+ <glyph glyph-name="crop" unicode="&#xf125;" horiz-adv-x="1664"
+d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23
+v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="code_fork" unicode="&#xf126;" horiz-adv-x="1024"
+d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5
+q-2 -287 -226 -414q-67 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136q0 -52 -26 -96.5t-70 -69.5v-497
+q54 26 154 57q55 17 87.5 29.5t70.5 31t59 39.5t40.5 51t28 69.5t8.5 91.5q-44 25 -70 69.5t-26 96.5q0 80 56 136t136 56t136 -56t56 -136z" />
+ <glyph glyph-name="unlink" unicode="&#xf127;" horiz-adv-x="1664"
+d="M439 265l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320
+q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239q35 -21 56 -42l336 -336q84 -86 84 -204zM1031 1044l-239 -18
+l-273 274q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l274 -274l-18 -240q-35 21 -56 42l-336 336q-84 86 -84 204q0 120 85 203l147 146q83 83 203 83q121 0 204 -85l334 -335q21 -21 42 -56zM1664 960q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9
+t-9 23t9 23t23 9h320q14 0 23 -9t9 -23zM1120 1504v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM1527 1353l-256 -256q-11 -9 -23 -9t-23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+ <glyph glyph-name="question" unicode="&#xf128;" horiz-adv-x="1024"
+d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5
+t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 161 -31t146 -83t106 -127.5t41 -158.5z" />
+ <glyph glyph-name="_279" unicode="&#xf129;" horiz-adv-x="640"
+d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192
+q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="exclamation" unicode="&#xf12a;" horiz-adv-x="640"
+d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+ <glyph glyph-name="superscript" unicode="&#xf12b;"
+d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z
+M1534 846v-206h-514l-3 27q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t-82 -50.5
+t-65.5 -51.5t-30.5 -63h232v80h126z" />
+ <glyph glyph-name="subscript" unicode="&#xf12c;"
+d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3q-1 -3 -2.5 -6.5t-3.5 -8t-3 -6.5q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109z
+M1536 -50v-206h-514l-4 27q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t-87 -63t-41 -73
+h232v80h126z" />
+ <glyph glyph-name="_283" unicode="&#xf12d;" horiz-adv-x="1920"
+d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+ <glyph glyph-name="puzzle_piece" unicode="&#xf12e;" horiz-adv-x="1664"
+d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5
+t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t34 -5t21.5 -3.5q150 -24 245 -24q80 0 117 35q46 44 46 89
+q0 22 -15 50.5t-33.5 53t-33.5 64.5t-15 83q0 82 59 127.5t144 45.5q80 0 134 -44.5t54 -123.5q0 -41 -17.5 -77.5t-38 -59t-38 -56.5t-17.5 -71q0 -57 42 -83.5t103 -26.5q64 0 180 15t163 17v-2q-1 -2 -3.5 -17.5t-5 -34t-3.5 -21.5q-24 -150 -24 -245q0 -80 35 -117
+q44 -46 89 -46q22 0 50.5 15t53 33.5t64.5 33.5t83 15q82 0 127.5 -59t45.5 -143z" />
+ <glyph glyph-name="microphone" unicode="&#xf130;" horiz-adv-x="1152"
+d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5
+t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+ <glyph glyph-name="microphone_off" unicode="&#xf131;" horiz-adv-x="1408"
+d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128
+q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l1234 1234q10 10 23 10t23 -10l82 -82q10 -10 10 -23
+t-10 -23zM1005 1325l-621 -621v512q0 132 94 226t226 94q102 0 184.5 -59t116.5 -152z" />
+ <glyph glyph-name="shield" unicode="&#xf132;" horiz-adv-x="1280"
+d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150
+t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="calendar_empty" unicode="&#xf133;" horiz-adv-x="1664"
+d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280
+q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="fire_extinguisher" unicode="&#xf134;" horiz-adv-x="1408"
+d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800
+q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-25 42 -25 86q0 66 47 113t113 47t113 -47t47 -113
+q0 -33 -14 -64h302q0 11 7 20t18 11l448 96q3 1 7 1q12 0 20 -7q12 -9 12 -25z" />
+ <glyph glyph-name="rocket" unicode="&#xf135;" horiz-adv-x="1664"
+d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1
+q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+ <glyph glyph-name="maxcdn" unicode="&#xf136;" horiz-adv-x="1792"
+d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+ <glyph glyph-name="chevron_sign_left" unicode="&#xf137;"
+d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5
+t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="chevron_sign_right" unicode="&#xf138;"
+d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5
+t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="chevron_sign_up" unicode="&#xf139;"
+d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5
+t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="chevron_sign_down" unicode="&#xf13a;"
+d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5
+t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="html5" unicode="&#xf13b;" horiz-adv-x="1408"
+d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+ <glyph glyph-name="css3" unicode="&#xf13c;" horiz-adv-x="1792"
+d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+ <glyph glyph-name="anchor" unicode="&#xf13d;" horiz-adv-x="1792"
+d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352
+q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 -181q0 -70 -35 -128.5t-93 -92.5v-163h192q26 0 45 -19
+t19 -45v-128q0 -26 -19 -45t-45 -19h-192v-647q149 20 271.5 82.5t189.5 153.5l-100 100q-15 16 -7 35q8 20 30 20h352q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="unlock_alt" unicode="&#xf13e;" horiz-adv-x="1152"
+d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181
+v-320h736z" />
+ <glyph glyph-name="bullseye" unicode="&#xf140;"
+d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150
+t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5zM1536 640
+q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="ellipsis_horizontal" unicode="&#xf141;" horiz-adv-x="1408"
+d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192
+q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="ellipsis_vertical" unicode="&#xf142;" horiz-adv-x="384"
+d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192
+q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+ <glyph glyph-name="_303" unicode="&#xf143;"
+d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 233 -176.5 396.5t-396.5 176.5q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128
+q13 0 23 10t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23zM1536 1120v-960
+q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="play_sign" unicode="&#xf144;"
+d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56
+q16 -8 32 -8q17 0 32 9z" />
+ <glyph glyph-name="ticket" unicode="&#xf145;" horiz-adv-x="1792"
+d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136
+t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+ <glyph glyph-name="minus_sign_alt" unicode="&#xf146;"
+d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5
+t84.5 -203.5z" />
+ <glyph glyph-name="check_minus" unicode="&#xf147;" horiz-adv-x="1408"
+d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5
+t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="level_up" unicode="&#xf148;" horiz-adv-x="1024"
+d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+ <glyph glyph-name="level_down" unicode="&#xf149;" horiz-adv-x="1024"
+d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+ <glyph glyph-name="check_sign" unicode="&#xf14a;"
+d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5
+t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="edit_sign" unicode="&#xf14b;"
+d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120
+v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_312" unicode="&#xf14c;"
+d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960
+q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="share_sign" unicode="&#xf14d;"
+d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q11 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5
+t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="compass" unicode="&#xf14e;"
+d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103
+t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="collapse" unicode="&#xf150;"
+d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120
+v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="collapse_top" unicode="&#xf151;"
+d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960
+q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_317" unicode="&#xf152;"
+d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5
+t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="eur" unicode="&#xf153;" horiz-adv-x="1024"
+d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9
+t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126 0 -226 -64t-150 -176h468q16 0 25 -12q10 -12 7 -26
+l-24 -114q-5 -26 -32 -26h-488q-3 -37 0 -105h459q15 0 25 -12q9 -12 6 -27l-24 -112q-2 -11 -11 -18.5t-20 -7.5h-387q48 -117 149.5 -185.5t228.5 -68.5q18 0 36 1.5t33.5 3.5t29.5 4.5t24.5 5t18.5 4.5l12 3l5 2q13 5 26 -2q12 -7 15 -21z" />
+ <glyph glyph-name="gbp" unicode="&#xf154;" horiz-adv-x="1024"
+d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7
+q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+ <glyph glyph-name="usd" unicode="&#xf155;" horiz-adv-x="1024"
+d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43
+t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5 9.5h135q14 0 23 -9t9 -23v-176q57 -6 110.5 -23t87 -33.5
+t63.5 -37.5t39 -29t15 -14q17 -18 5 -38l-81 -146q-8 -15 -23 -16q-14 -3 -27 7q-3 3 -14.5 12t-39 26.5t-58.5 32t-74.5 26t-85.5 11.5q-95 0 -155 -43t-60 -111q0 -26 8.5 -48t29.5 -41.5t39.5 -33t56 -31t60.5 -27t70 -27.5q53 -20 81 -31.5t76 -35t75.5 -42.5t62 -50
+t53 -63.5t31.5 -76.5t13 -94z" />
+ <glyph glyph-name="inr" unicode="&#xf156;" horiz-adv-x="898"
+d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102
+q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="jpy" unicode="&#xf157;" horiz-adv-x="1027"
+d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61
+l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q0 -13 -9.5 -22.5t-22.5 -9.5z" />
+ <glyph glyph-name="rub" unicode="&#xf158;" horiz-adv-x="1280"
+d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128
+q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+ <glyph glyph-name="krw" unicode="&#xf159;" horiz-adv-x="1792"
+d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23
+t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h109l-89 344q-5 15 5 28
+q10 12 26 12h137q26 0 31 -24l90 -360h359l97 360q7 24 31 24h126q24 0 31 -24l98 -360h365l93 360q5 24 31 24h137q16 0 26 -12q10 -13 5 -28l-91 -344h111q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-145l-34 -128h179q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="btc" unicode="&#xf15a;" horiz-adv-x="1280"
+d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164
+l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0.5t48 -0.5t53 1.5t58.5 4t57 8.5t55.5 14t47.5 21t39.5 30
+t24.5 40t9.5 51zM881 827q0 33 -12.5 58.5t-30.5 42t-48 28t-55 16.5t-61.5 8t-58 2.5t-54 -1t-39.5 -0.5v-307q5 0 34.5 -0.5t46.5 0t50 2t55 5.5t51.5 11t48.5 18.5t37 27t27 38.5t9 51z" />
+ <glyph glyph-name="file" unicode="&#xf15b;"
+d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
+ <glyph glyph-name="file_text" unicode="&#xf15c;"
+d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704
+q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
+ <glyph glyph-name="sort_by_alphabet" unicode="&#xf15d;" horiz-adv-x="1664"
+d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23
+v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162
+l230 -662h70z" />
+ <glyph glyph-name="_329" unicode="&#xf15e;" horiz-adv-x="1664"
+d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150
+v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -10v-3l14 3q9 1 30 1h248
+v119h121z" />
+ <glyph glyph-name="sort_by_attributes" unicode="&#xf160;" horiz-adv-x="1792"
+d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832
+q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1216 1504v-192q0 -14 -9 -23t-23 -9h-256
+q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="sort_by_attributes_alt" unicode="&#xf161;" horiz-adv-x="1792"
+d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192
+q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1792 1504v-192q0 -14 -9 -23t-23 -9h-832
+q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="sort_by_order" unicode="&#xf162;"
+d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23
+zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5
+t82 -252.5zM1456 882v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165z" />
+ <glyph glyph-name="sort_by_order_alt" unicode="&#xf163;"
+d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9
+t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13
+q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 172.5q0 105 72 178t181 73q123 0 205 -94.5t82 -252.5z" />
+ <glyph glyph-name="_334" unicode="&#xf164;" horiz-adv-x="1664"
+d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76
+q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24 2 76 59t101 121q68 87 101 120q18 18 31 48t17.5 48.5
+t13.5 60.5q7 39 12.5 61t19.5 52t34 50q19 19 45 19q46 0 82.5 -10.5t60 -26t40 -40.5t24 -45t12 -50t5 -45t0.5 -39q0 -38 -9.5 -76t-19 -60t-27.5 -56q-3 -6 -10 -18t-11 -22t-8 -24h277q78 0 135 -57t57 -135z" />
+ <glyph glyph-name="_335" unicode="&#xf165;" horiz-adv-x="1664"
+d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135
+t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 -13.5 60.5t-17.5 48.5t-31 48q-33 33 -101 120q-49 64 -101 121
+t-76 59q-25 2 -43 20.5t-18 43.5v641q0 26 19 44.5t45 19.5q35 1 158 44q77 26 120.5 39.5t121.5 29t144 15.5h17h76h36q133 -2 197 -78q58 -69 49 -181q39 -37 54 -94q17 -61 0 -117q46 -61 43 -137q0 -32 -15 -76z" />
+ <glyph glyph-name="youtube_sign" unicode="&#xf166;"
+d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 17 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15
+q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86v129q0 59 20 86q29 38 80 38t78 -38
+q21 -29 21 -86v-76h-133v-65q0 -51 34 -51q24 0 30 26q0 1 0.5 7t0.5 16.5v21.5h68zM785 1079v-156q0 -51 -32 -51t-32 51v156q0 52 32 52t32 -52zM1318 366q0 177 -19 260q-10 44 -43 73.5t-76 34.5q-136 15 -412 15q-275 0 -411 -15q-44 -5 -76.5 -34.5t-42.5 -73.5
+q-20 -87 -20 -260q0 -176 20 -260q10 -43 42.5 -73t75.5 -35q137 -15 412 -15t412 15q43 5 75.5 35t42.5 73q20 84 20 260zM563 1017l90 296h-75l-51 -195l-53 195h-78q7 -23 23 -69l24 -69q35 -103 46 -158v-201h74v201zM852 936v130q0 58 -21 87q-29 38 -78 38
+q-51 0 -78 -38q-21 -29 -21 -87v-130q0 -58 21 -87q27 -38 78 -38q49 0 78 38q21 27 21 87zM1033 816h67v370h-67v-283q-22 -31 -42 -31q-15 0 -16 16q-1 2 -1 26v272h-67v-293q0 -37 6 -55q11 -27 43 -27q36 0 77 45v-40zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5
+h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="youtube" unicode="&#xf167;"
+d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73
+q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39 51 -106 51q-68 0 -107 -51
+q-28 -37 -28 -116v-173q0 -79 29 -116q39 -51 108 -51q72 0 108 53q18 27 21 54q2 9 2 58zM790 1011v210q0 69 -43 69t-43 -69v-210q0 -70 43 -70t43 70zM1509 260q0 -234 -26 -350q-14 -59 -58 -99t-102 -46q-184 -21 -555 -21t-555 21q-58 6 -102.5 46t-57.5 99
+q-26 112 -26 350q0 234 26 350q14 59 58 99t103 47q183 20 554 20t555 -20q58 -7 102.5 -47t57.5 -99q26 -112 26 -350zM511 1536h102l-121 -399v-271h-100v271q-14 74 -61 212q-37 103 -65 187h106l71 -263zM881 1203v-175q0 -81 -28 -118q-38 -51 -106 -51q-67 0 -105 51
+q-28 38 -28 118v175q0 80 28 117q38 51 105 51q68 0 106 -51q28 -37 28 -117zM1216 1365v-499h-91v55q-53 -62 -103 -62q-46 0 -59 37q-8 24 -8 75v394h91v-367q0 -33 1 -35q3 -22 21 -22q27 0 57 43v381h91z" />
+ <glyph glyph-name="xing" unicode="&#xf168;" horiz-adv-x="1408"
+d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942
+q25 45 64 45h241q22 0 31 -15z" />
+ <glyph glyph-name="xing_sign" unicode="&#xf169;"
+d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1
+l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="youtube_play" unicode="&#xf16a;" horiz-adv-x="1792"
+d="M711 408l484 250l-484 253v-503zM896 1270q168 0 324.5 -4.5t229.5 -9.5l73 -4q1 0 17 -1.5t23 -3t23.5 -4.5t28.5 -8t28 -13t31 -19.5t29 -26.5q6 -6 15.5 -18.5t29 -58.5t26.5 -101q8 -64 12.5 -136.5t5.5 -113.5v-40v-136q1 -145 -18 -290q-7 -55 -25 -99.5t-32 -61.5
+l-14 -17q-14 -15 -29 -26.5t-31 -19t-28 -12.5t-28.5 -8t-24 -4.5t-23 -3t-16.5 -1.5q-251 -19 -627 -19q-207 2 -359.5 6.5t-200.5 7.5l-49 4l-36 4q-36 5 -54.5 10t-51 21t-56.5 41q-6 6 -15.5 18.5t-29 58.5t-26.5 101q-8 64 -12.5 136.5t-5.5 113.5v40v136
+q-1 145 18 290q7 55 25 99.5t32 61.5l14 17q14 15 29 26.5t31 19.5t28 13t28.5 8t23.5 4.5t23 3t17 1.5q251 18 627 18z" />
+ <glyph glyph-name="dropbox" unicode="&#xf16b;" horiz-adv-x="1792"
+d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+ <glyph glyph-name="stackexchange" unicode="&#xf16c;"
+d="M1289 -96h-1118v480h-160v-640h1438v640h-160v-480zM347 428l33 157l783 -165l-33 -156zM450 802l67 146l725 -339l-67 -145zM651 1158l102 123l614 -513l-102 -123zM1048 1536l477 -641l-128 -96l-477 641zM330 65v159h800v-159h-800z" />
+ <glyph glyph-name="instagram" unicode="&#xf16d;"
+d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1162 640q0 -164 -115 -279t-279 -115t-279 115t-115 279t115 279t279 115t279 -115t115 -279zM1270 1050q0 -38 -27 -65t-65 -27t-65 27t-27 65t27 65t65 27t65 -27t27 -65zM768 1270
+q-7 0 -76.5 0.5t-105.5 0t-96.5 -3t-103 -10t-71.5 -18.5q-50 -20 -88 -58t-58 -88q-11 -29 -18.5 -71.5t-10 -103t-3 -96.5t0 -105.5t0.5 -76.5t-0.5 -76.5t0 -105.5t3 -96.5t10 -103t18.5 -71.5q20 -50 58 -88t88 -58q29 -11 71.5 -18.5t103 -10t96.5 -3t105.5 0t76.5 0.5
+t76.5 -0.5t105.5 0t96.5 3t103 10t71.5 18.5q50 20 88 58t58 88q11 29 18.5 71.5t10 103t3 96.5t0 105.5t-0.5 76.5t0.5 76.5t0 105.5t-3 96.5t-10 103t-18.5 71.5q-20 50 -58 88t-88 58q-29 11 -71.5 18.5t-103 10t-96.5 3t-105.5 0t-76.5 -0.5zM1536 640q0 -229 -5 -317
+q-10 -208 -124 -322t-322 -124q-88 -5 -317 -5t-317 5q-208 10 -322 124t-124 322q-5 88 -5 317t5 317q10 208 124 322t322 124q88 5 317 5t317 -5q208 -10 322 -124t124 -322q5 -88 5 -317z" />
+ <glyph glyph-name="flickr" unicode="&#xf16e;"
+d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150
+t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+ <glyph glyph-name="adn" unicode="&#xf170;"
+d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="f171" unicode="&#xf171;" horiz-adv-x="1408"
+d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22
+t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q-86 -48 -189.5 -71.5t-202 -22t-201.5 18.5q-46 8 -81.5 18
+t-76.5 27t-73 43.5t-52 61.5q-25 96 -57 292l6 16l18 9q223 -148 506.5 -148t507.5 148q21 -6 24 -23t-5 -45t-8 -37zM1403 1166q-26 -167 -111 -655q-5 -30 -27 -56t-43.5 -40t-54.5 -31q-252 -126 -610 -88q-248 27 -394 139q-15 12 -25.5 26.5t-17 35t-9 34t-6 39.5
+t-5.5 35q-9 50 -26.5 150t-28 161.5t-23.5 147.5t-22 158q3 26 17.5 48.5t31.5 37.5t45 30t46 22.5t48 18.5q125 46 313 64q379 37 676 -50q155 -46 215 -122q16 -20 16.5 -51t-5.5 -54z" />
+ <glyph glyph-name="bitbucket_sign" unicode="&#xf172;"
+d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5
+t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 428 53q34 19 49 51.5t22.5 85.5t12.5 71z
+M1272 1020q9 53 -8 75q-43 55 -155 88q-216 63 -487 36q-132 -12 -226 -46q-38 -15 -59.5 -25t-47 -34t-29.5 -54q8 -68 19 -138t29 -171t24 -137q1 -5 5 -31t7 -36t12 -27t22 -28q105 -80 284 -100q259 -28 440 63q24 13 39.5 23t31 29t19.5 40q48 267 80 473zM1536 1120
+v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="tumblr" unicode="&#xf173;" horiz-adv-x="1024"
+d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14
+q78 2 134 29z" />
+ <glyph glyph-name="tumblr_sign" unicode="&#xf174;"
+d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z
+M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="long_arrow_down" unicode="&#xf175;" horiz-adv-x="768"
+d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+ <glyph glyph-name="long_arrow_up" unicode="&#xf176;" horiz-adv-x="768"
+d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+ <glyph glyph-name="long_arrow_left" unicode="&#xf177;" horiz-adv-x="1792"
+d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="long_arrow_right" unicode="&#xf178;" horiz-adv-x="1792"
+d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+ <glyph glyph-name="apple" unicode="&#xf179;" horiz-adv-x="1408"
+d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q113 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65
+q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11q0 -4 0.5 -10t0.5 -10z" />
+ <glyph glyph-name="windows" unicode="&#xf17a;" horiz-adv-x="1664"
+d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+ <glyph glyph-name="android" unicode="&#xf17b;" horiz-adv-x="1408"
+d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30
+t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78 32t-32 78v666h918zM931 1255q107 -55 171 -153.5t64 -215.5
+h-925q0 117 64 215.5t172 153.5l-71 131q-7 13 5 20q13 6 20 -6l72 -132q95 42 201 42t201 -42l72 132q7 12 20 6q12 -7 5 -20zM1408 767v-430q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73v430q0 43 30 72.5t72 29.5q43 0 73 -29.5t30 -72.5z" />
+ <glyph glyph-name="linux" unicode="&#xf17c;"
+d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-10 -11 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z
+M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69t-19.5 45.5t-15.5 24.5t-13 15t-7.5 7
+q-14 62 -31 103t-29.5 56t-23.5 33t-15 40q-4 21 6 53.5t4.5 49.5t-44.5 25q-15 3 -44.5 18t-35.5 16q-8 1 -11 26t8 51t36 27q37 3 51 -30t4 -58q-11 -19 -2 -26.5t30 -0.5q13 4 13 36v37q-5 30 -13.5 50t-21 30.5t-23.5 15t-27 7.5q-107 -8 -89 -134q0 -15 -1 -15
+q-9 9 -29.5 10.5t-33 -0.5t-15.5 5q1 57 -16 90t-45 34q-27 1 -41.5 -27.5t-16.5 -59.5q-1 -15 3.5 -37t13 -37.5t15.5 -13.5q10 3 16 14q4 9 -7 8q-7 0 -15.5 14.5t-9.5 33.5q-1 22 9 37t34 14q17 0 27 -21t9.5 -39t-1.5 -22q-22 -15 -31 -29q-8 -12 -27.5 -23.5
+t-20.5 -12.5q-13 -14 -15.5 -27t7.5 -18q14 -8 25 -19.5t16 -19t18.5 -13t35.5 -6.5q47 -2 102 15q2 1 23 7t34.5 10.5t29.5 13t21 17.5q9 14 20 8q5 -3 6.5 -8.5t-3 -12t-16.5 -9.5q-20 -6 -56.5 -21.5t-45.5 -19.5q-44 -19 -70 -23q-25 -5 -79 2q-10 2 -9 -2t17 -19
+q25 -23 67 -22q17 1 36 7t36 14t33.5 17.5t30 17t24.5 12t17.5 2.5t8.5 -11q0 -2 -1 -4.5t-4 -5t-6 -4.5t-8.5 -5t-9 -4.5t-10 -5t-9.5 -4.5q-28 -14 -67.5 -44t-66.5 -43t-49 -1q-21 11 -63 73q-22 31 -25 22q-1 -3 -1 -10q0 -25 -15 -56.5t-29.5 -55.5t-21 -58t11.5 -63
+q-23 -6 -62.5 -90t-47.5 -141q-2 -18 -1.5 -69t-5.5 -59q-8 -24 -29 -3q-32 31 -36 94q-2 28 4 56q4 19 -1 18q-2 -1 -4 -5q-36 -65 10 -166q5 -12 25 -28t24 -20q20 -23 104 -90.5t93 -76.5q16 -15 17.5 -38t-14 -43t-45.5 -23q8 -15 29 -44.5t28 -54t7 -70.5q46 24 7 92
+q-4 8 -10.5 16t-9.5 12t-2 6q3 5 13 9.5t20 -2.5q46 -52 166 -36q133 15 177 87q23 38 34 30q12 -6 10 -52q-1 -25 -23 -92q-9 -23 -6 -37.5t24 -15.5q3 19 14.5 77t13.5 90q2 21 -6.5 73.5t-7.5 97t23 70.5q15 18 51 18q1 37 34.5 53t72.5 10.5t60 -22.5zM626 1152
+q3 17 -2.5 30t-11.5 15q-9 2 -9 -7q2 -5 5 -6q10 0 7 -15q-3 -20 8 -20q3 0 3 3zM1045 955q-2 8 -6.5 11.5t-13 5t-14.5 5.5q-5 3 -9.5 8t-7 8t-5.5 6.5t-4 4t-4 -1.5q-14 -16 7 -43.5t39 -31.5q9 -1 14.5 8t3.5 20zM867 1168q0 11 -5 19.5t-11 12.5t-9 3q-6 0 -8 -2t0 -4
+t5 -3q14 -4 18 -31q0 -3 8 2q2 2 2 3zM921 1401q0 2 -2.5 5t-9 7t-9.5 6q-15 15 -24 15q-9 -1 -11.5 -7.5t-1 -13t-0.5 -12.5q-1 -4 -6 -10.5t-6 -9t3 -8.5q4 -3 8 0t11 9t15 9q1 1 9 1t15 2t9 7zM1486 60q20 -12 31 -24.5t12 -24t-2.5 -22.5t-15.5 -22t-23.5 -19.5
+t-30 -18.5t-31.5 -16.5t-32 -15.5t-27 -13q-38 -19 -85.5 -56t-75.5 -64q-17 -16 -68 -19.5t-89 14.5q-18 9 -29.5 23.5t-16.5 25.5t-22 19.5t-47 9.5q-44 1 -130 1q-19 0 -57 -1.5t-58 -2.5q-44 -1 -79.5 -15t-53.5 -30t-43.5 -28.5t-53.5 -11.5q-29 1 -111 31t-146 43
+q-19 4 -51 9.5t-50 9t-39.5 9.5t-33.5 14.5t-17 19.5q-10 23 7 66.5t18 54.5q1 16 -4 40t-10 42.5t-4.5 36.5t10.5 27q14 12 57 14t60 12q30 18 42 35t12 51q21 -73 -32 -106q-32 -20 -83 -15q-34 3 -43 -10q-13 -15 5 -57q2 -6 8 -18t8.5 -18t4.5 -17t1 -22q0 -15 -17 -49
+t-14 -48q3 -17 37 -26q20 -6 84.5 -18.5t99.5 -20.5q24 -6 74 -22t82.5 -23t55.5 -4q43 6 64.5 28t23 48t-7.5 58.5t-19 52t-20 36.5q-121 190 -169 242q-68 74 -113 40q-11 -9 -15 15q-3 16 -2 38q1 29 10 52t24 47t22 42q8 21 26.5 72t29.5 78t30 61t39 54
+q110 143 124 195q-12 112 -16 310q-2 90 24 151.5t106 104.5q39 21 104 21q53 1 106 -13.5t89 -41.5q57 -42 91.5 -121.5t29.5 -147.5q-5 -95 30 -214q34 -113 133 -218q55 -59 99.5 -163t59.5 -191q8 -49 5 -84.5t-12 -55.5t-20 -22q-10 -2 -23.5 -19t-27 -35.5
+t-40.5 -33.5t-61 -14q-18 1 -31.5 5t-22.5 13.5t-13.5 15.5t-11.5 20.5t-9 19.5q-22 37 -41 30t-28 -49t7 -97q20 -70 1 -195q-10 -65 18 -100.5t73 -33t85 35.5q59 49 89.5 66.5t103.5 42.5q53 18 77 36.5t18.5 34.5t-25 28.5t-51.5 23.5q-33 11 -49.5 48t-15 72.5
+t15.5 47.5q1 -31 8 -56.5t14.5 -40.5t20.5 -28.5t21 -19t21.5 -13t16.5 -9.5z" />
+ <glyph glyph-name="dribble" unicode="&#xf17d;"
+d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81
+t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q-185 164 -433 164q-76 0 -155 -19
+q131 -170 246 -382q69 26 130 60.5t96.5 61.5t65.5 57t37.5 40.5zM1424 647q-3 232 -149 410l-1 -1q-9 -12 -19 -24.5t-43.5 -44.5t-71 -60.5t-100 -65t-131.5 -64.5q25 -53 44 -95q2 -5 6.5 -17t7.5 -17q36 5 74.5 7t73.5 2t69 -1.5t64 -4t56.5 -5.5t48 -6.5t36.5 -6
+t25 -4.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="skype" unicode="&#xf17e;"
+d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5
+t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 -92 122 -157.5t291 -65.5
+q73 0 140 18.5t122.5 53.5t88.5 93.5t33 131.5zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5q-130 0 -234 80q-77 -16 -150 -16q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5q0 73 16 150q-80 104 -80 234q0 159 112.5 271.5t271.5 112.5q130 0 234 -80
+q77 16 150 16q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -73 -16 -150q80 -104 80 -234z" />
+ <glyph glyph-name="foursquare" unicode="&#xf180;" horiz-adv-x="1280"
+d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z
+M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 55 38 102.5t120 47.5h888q95 0 127 -53t10 -159zM1227 1324
+l-158 -790q4 17 35 173.5t69.5 350t53.5 266.5z" />
+ <glyph glyph-name="trello" unicode="&#xf181;"
+d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408
+q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="female" unicode="&#xf182;" horiz-adv-x="1280"
+d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43
+q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+ <glyph glyph-name="male" unicode="&#xf183;" horiz-adv-x="1024"
+d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z
+M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+ <glyph glyph-name="gittip" unicode="&#xf184;"
+d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103
+t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="sun" unicode="&#xf185;" horiz-adv-x="1792"
+d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4
+l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 29 4l292 -94l180 248q9 12 26 12t26 -12l180 -248l292 94
+q14 6 29 -4q13 -10 13 -26v-306l292 -96q16 -5 20 -20q5 -16 -4 -29l-180 -248l180 -248q9 -12 4 -29z" />
+ <glyph glyph-name="_366" unicode="&#xf186;"
+d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61
+t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+ <glyph glyph-name="archive" unicode="&#xf187;" horiz-adv-x="1792"
+d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536
+q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="bug" unicode="&#xf188;" horiz-adv-x="1664"
+d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207
+q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 -19t19 -45t-19 -45l-173 -173v-294h224q26 0 45 -19
+t19 -45zM1152 1152h-640q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5z" />
+ <glyph glyph-name="vk" unicode="&#xf189;" horiz-adv-x="1920"
+d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-40 -51 -55 -72t-30.5 -49.5t-12 -42t13 -34.5t32.5 -43t57 -53q4 -2 5 -4q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58
+t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91t-106 151t-122.5 211t-130.5 272q-6 16 -6 27t3 16l4 6
+q15 19 57 19l274 2q12 -2 23 -6.5t16 -8.5l5 -3q16 -11 24 -32q20 -50 46 -103.5t41 -81.5l16 -29q29 -60 56 -104t48.5 -68.5t41.5 -38.5t34 -14t27 5q2 1 5 5t12 22t13.5 47t9.5 81t0 125q-2 40 -9 73t-14 46l-6 12q-25 34 -85 43q-13 2 5 24q16 19 38 30q53 26 239 24
+q82 -1 135 -13q20 -5 33.5 -13.5t20.5 -24t10.5 -32t3.5 -45.5t-1 -55t-2.5 -70.5t-1.5 -82.5q0 -11 -1 -42t-0.5 -48t3.5 -40.5t11.5 -39t22.5 -24.5q8 -2 17 -4t26 11t38 34.5t52 67t68 107.5q60 104 107 225q4 10 10 17.5t11 10.5l4 3l5 2.5t13 3t20 0.5l288 2
+q39 5 64 -2.5t31 -16.5z" />
+ <glyph glyph-name="weibo" unicode="&#xf18a;" horiz-adv-x="1792"
+d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12
+q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 369.5 141.5t132.5 264.5zM1563 422
+q0 -68 -37 -139.5t-109 -137t-168.5 -117.5t-226 -83t-270.5 -31t-275 33.5t-240.5 93t-171.5 151t-65 199.5q0 115 69.5 245t197.5 258q169 169 341.5 236t246.5 -7q65 -64 20 -209q-4 -14 -1 -20t10 -7t14.5 0.5t13.5 3.5l6 2q139 59 246 59t153 -61q45 -63 0 -178
+q-2 -13 -4.5 -20t4.5 -12.5t12 -7.5t17 -6q57 -18 103 -47t80 -81.5t34 -116.5zM1489 1046q42 -47 54.5 -108.5t-6.5 -117.5q-8 -23 -29.5 -34t-44.5 -4q-23 8 -34 29.5t-4 44.5q20 63 -24 111t-107 35q-24 -5 -45 8t-25 37q-5 24 8 44.5t37 25.5q60 13 119 -5.5t101 -65.5z
+M1670 1209q87 -96 112.5 -222.5t-13.5 -241.5q-9 -27 -34 -40t-52 -4t-40 34t-5 52q28 82 10 172t-80 158q-62 69 -148 95.5t-173 8.5q-28 -6 -52 9.5t-30 43.5t9.5 51.5t43.5 29.5q123 26 244 -11.5t208 -134.5z" />
+ <glyph glyph-name="renren" unicode="&#xf18b;"
+d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495
+q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+ <glyph glyph-name="_372" unicode="&#xf18c;" horiz-adv-x="1408"
+d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5
+t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70 28 133.5 36.5t112.5 -1t92 -30t73.5 -50t56 -61t42 -63t27.5 -56
+t16 -39.5l4 -16q12 122 12 195q-8 6 -21.5 16t-49 44.5t-63.5 71.5t-54 93t-33 112.5t12 127t70 138.5q73 -25 127.5 -61.5t84.5 -76.5t48 -85t20.5 -89t-0.5 -85.5t-13 -76.5t-19 -62t-17 -42l-7 -15q1 -4 1 -50t-1 -72q3 7 10 18.5t30.5 43t50.5 58t71 55.5t91.5 44.5
+t112 14.5t132.5 -24q-2 -78 -21.5 -141.5t-50 -104.5t-69.5 -71.5t-81.5 -45.5t-84.5 -24t-80 -9.5t-67.5 1t-46.5 4.5l-17 3q-23 -147 -73 -283q6 7 18 18.5t49.5 41t77.5 52.5t99.5 42t117.5 20t129 -23.5t137 -77.5z" />
+ <glyph glyph-name="stack_exchange" unicode="&#xf18d;" horiz-adv-x="1280"
+d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z
+" />
+ <glyph glyph-name="_374" unicode="&#xf18e;"
+d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198
+t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="arrow_circle_alt_left" unicode="&#xf190;"
+d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198
+t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_376" unicode="&#xf191;"
+d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z
+M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="dot_circle_alt" unicode="&#xf192;"
+d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5
+t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_378" unicode="&#xf193;" horiz-adv-x="1664"
+d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128
+q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 17 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455q40 0 57 -35l228 -455z" />
+ <glyph glyph-name="vimeo_square" unicode="&#xf194;"
+d="M1292 898q10 216 -161 222q-231 8 -312 -261q44 19 82 19q85 0 74 -96q-4 -57 -74 -167t-105 -110q-43 0 -82 169q-13 54 -45 255q-30 189 -160 177q-59 -7 -164 -100l-81 -72l-81 -72l52 -67q76 52 87 52q57 0 107 -179q15 -55 45 -164.5t45 -164.5q68 -179 164 -179
+q157 0 383 294q220 283 226 444zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_380" unicode="&#xf195;" horiz-adv-x="1152"
+d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160
+q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="plus_square_o" unicode="&#xf196;" horiz-adv-x="1408"
+d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832
+q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_382" unicode="&#xf197;" horiz-adv-x="2176"
+d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40
+t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-288 -288q-26 -26 -70.5 -45t-89.5 -19h-96l-93 464h29
+q157 0 273 64zM352 816h-29l93 464h96q46 0 90 -19t70 -45l288 -288q4 -4 11 -10.5t30.5 -23t48.5 -29t61.5 -23t72.5 -10.5l456 -80h-1015q-116 64 -273 64z" />
+ <glyph glyph-name="_383" unicode="&#xf198;" horiz-adv-x="1664"
+d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9
+q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 -72l54 -160l310 105l-54 160q-8 24 -8 47q0 59 42.5 102
+t101.5 43q47 0 85.5 -27.5t53.5 -71.5l53 -161l162 55q21 6 43 6q60 0 102.5 -39.5t42.5 -98.5q0 -45 -30 -81.5t-74 -51.5l-157 -54l105 -316l164 56q24 8 46 8zM725 498l310 105l-105 315l-310 -107z" />
+ <glyph glyph-name="_384" unicode="&#xf199;"
+d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69
+q-47 32 -142 92.5t-142 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 17 -11.5t21 -14t21 -13t23.5 -13
+t21.5 -9.5t22.5 -7.5t20.5 -2.5t20.5 2.5t22.5 7.5t21.5 9.5t23.5 13t21 13t21 14t17 11.5l267 174q35 23 66.5 62.5t31.5 73.5z" />
+ <glyph glyph-name="_385" unicode="&#xf19a;" horiz-adv-x="1792"
+d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5
+t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5t-37 -95.5q0 -12 2 -24t4 -21.5t8 -23t9 -21t12 -22.5t12.5 -21
+t14.5 -24t14 -23q63 -107 63 -212zM909 573l237 -647q1 -6 5 -11q-126 -44 -255 -44q-112 0 -217 32zM1570 1009q95 -174 95 -369q0 -209 -104 -385.5t-279 -278.5l235 678q59 169 59 276q0 42 -6 79zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286
+t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 -215q173 0 331.5 68t273 182.5t182.5 273t68 331.5t-68 331.5t-182.5 273t-273 182.5t-331.5 68t-331.5 -68t-273 -182.5t-182.5 -273t-68 -331.5t68 -331.5t182.5 -273
+t273 -182.5t331.5 -68z" />
+ <glyph glyph-name="_386" unicode="&#xf19b;" horiz-adv-x="1792"
+d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
+ <glyph glyph-name="_387" unicode="&#xf19c;" horiz-adv-x="2048"
+d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64
+q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
+ <glyph glyph-name="_388" unicode="&#xf19d;" horiz-adv-x="2304"
+d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433
+q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
+ <glyph glyph-name="_389" unicode="&#xf19e;"
+d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q44 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0
+q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
+ <glyph glyph-name="uniF1A0" unicode="&#xf1a0;"
+d="M768 750h725q12 -67 12 -128q0 -217 -91 -387.5t-259.5 -266.5t-386.5 -96q-157 0 -299 60.5t-245 163.5t-163.5 245t-60.5 299t60.5 299t163.5 245t245 163.5t299 60.5q300 0 515 -201l-209 -201q-123 119 -306 119q-129 0 -238.5 -65t-173.5 -176.5t-64 -243.5
+t64 -243.5t173.5 -176.5t238.5 -65q87 0 160 24t120 60t82 82t51.5 87t22.5 78h-436v264z" />
+ <glyph glyph-name="f1a1" unicode="&#xf1a1;" horiz-adv-x="1792"
+d="M1095 369q16 -16 0 -31q-62 -62 -199 -62t-199 62q-16 15 0 31q6 6 15 6t15 -6q48 -49 169 -49q120 0 169 49q6 6 15 6t15 -6zM788 550q0 -37 -26 -63t-63 -26t-63.5 26t-26.5 63q0 38 26.5 64t63.5 26t63 -26.5t26 -63.5zM1183 550q0 -37 -26.5 -63t-63.5 -26t-63 26
+t-26 63t26 63.5t63 26.5t63.5 -26t26.5 -64zM1434 670q0 49 -35 84t-85 35t-86 -36q-130 90 -311 96l63 283l200 -45q0 -37 26 -63t63 -26t63.5 26.5t26.5 63.5t-26.5 63.5t-63.5 26.5q-54 0 -80 -50l-221 49q-19 5 -25 -16l-69 -312q-180 -7 -309 -97q-35 37 -87 37
+q-50 0 -85 -35t-35 -84q0 -35 18.5 -64t49.5 -44q-6 -27 -6 -56q0 -142 140 -243t337 -101q198 0 338 101t140 243q0 32 -7 57q30 15 48 43.5t18 63.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191
+t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="_392" unicode="&#xf1a2;"
+d="M939 407q13 -13 0 -26q-53 -53 -171 -53t-171 53q-13 13 0 26q5 6 13 6t13 -6q42 -42 145 -42t145 42q5 6 13 6t13 -6zM676 563q0 -31 -23 -54t-54 -23t-54 23t-23 54q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1014 563q0 -31 -23 -54t-54 -23t-54 23t-23 54
+q0 32 22.5 54.5t54.5 22.5t54.5 -22.5t22.5 -54.5zM1229 666q0 42 -30 72t-73 30q-42 0 -73 -31q-113 78 -267 82l54 243l171 -39q1 -32 23.5 -54t53.5 -22q32 0 54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5q-48 0 -69 -43l-189 42q-17 5 -21 -13l-60 -268q-154 -6 -265 -83
+q-30 32 -74 32q-43 0 -73 -30t-30 -72q0 -30 16 -55t42 -38q-5 -25 -5 -48q0 -122 120 -208.5t289 -86.5q170 0 290 86.5t120 208.5q0 25 -6 49q25 13 40.5 37.5t15.5 54.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960
+q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_393" unicode="&#xf1a3;"
+d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150
+v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103
+t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="f1a4" unicode="&#xf1a4;" horiz-adv-x="1920"
+d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328
+v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
+ <glyph glyph-name="_395" unicode="&#xf1a5;"
+d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5
+t84.5 -203.5z" />
+ <glyph glyph-name="_396" unicode="&#xf1a6;" horiz-adv-x="2048"
+d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123
+v-369h123z" />
+ <glyph glyph-name="_397" unicode="&#xf1a7;"
+d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101
+v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960
+q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_398" unicode="&#xf1a8;" horiz-adv-x="2038"
+d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14
+q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5 41.5t57 59t26.5 51.5q-24 2 -43 -24
+q-36 -53 -111.5 -99.5t-136.5 -46.5q-25 0 -75.5 63t-106.5 139.5t-84 96.5q-6 4 -27 30q-482 -112 -513 -112q-16 0 -28 11t-12 27q0 15 8.5 26.5t22.5 14.5l486 106q-8 14 -8 25t5.5 17.5t16 11.5t20 7t23 4.5t18.5 4.5q4 1 15.5 7.5t17.5 6.5q15 0 28 -16t20 -33
+q163 37 172 37q17 0 29.5 -11t12.5 -28q0 -15 -8.5 -26t-23.5 -14l-182 -40l-1 -16q-1 -26 81.5 -117.5t104.5 -91.5q47 0 119 80t72 129q0 36 -23.5 53t-51 18.5t-51 11.5t-23.5 34q0 16 10 34l-68 19q43 44 43 117q0 26 -5 58q82 16 144 16q44 0 71.5 -1.5t48.5 -8.5
+t31 -13.5t20.5 -24.5t15.5 -33.5t17 -47.5t24 -60l50 25q-3 -40 -23 -60t-42.5 -21t-40 -6.5t-16.5 -20.5zM1282 842q-5 5 -13.5 15.5t-12 14.5t-10.5 11.5t-10 10.5l-8 8t-8.5 7.5t-8 5t-8.5 4.5q-7 3 -14.5 5t-20.5 2.5t-22 0.5h-32.5h-37.5q-126 0 -217 -43
+q16 30 36 46.5t54 29.5t65.5 36t46 36.5t50 55t43.5 50.5q12 -9 28 -31.5t32 -36.5t38 -13l12 1v-76l22 -1q247 95 371 190q28 21 50 39t42.5 37.5t33 31t29.5 34t24 31t24.5 37t23 38t27 47.5t29.5 53l7 9q-2 -53 -43 -139q-79 -165 -205 -264t-306 -142q-14 -3 -42 -7.5
+t-50 -9.5t-39 -14q3 -19 24.5 -46t21.5 -34q0 -11 -26 -30zM1061 -79q39 26 131.5 47.5t146.5 21.5q9 0 22.5 -15.5t28 -42.5t26 -50t24 -51t14.5 -33q-121 -45 -244 -45q-61 0 -125 11zM822 568l48 12l109 -177l-73 -48zM1323 51q3 -15 3 -16q0 -7 -17.5 -14.5t-46 -13
+t-54 -9.5t-53.5 -7.5t-32 -4.5l-7 43q21 2 60.5 8.5t72 10t60.5 3.5h14zM866 679l-96 -20l-6 17q10 1 32.5 7t34.5 6q19 0 35 -10zM1061 45h31l10 -83l-41 -12v95zM1950 1535v1v-1zM1950 1535l-1 -5l-2 -2l1 3zM1950 1535l1 1z" />
+ <glyph glyph-name="_399" unicode="&#xf1a9;"
+d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10
+q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 36.5t-52.5 14
+q-33 0 -97 -41.5t-129 -83.5t-101 -42q-27 -1 -63.5 19t-76 49t-83.5 58t-100 49t-111 19q-115 -1 -197 -78.5t-84 -178.5q-2 -112 74 -164q29 -20 62.5 -28.5t103.5 -8.5q57 0 132 32.5t134 71t120 70.5t93 31q26 -1 65 -31.5t71.5 -67t68 -67.5t55.5 -32q35 -3 58.5 14
+t55.5 63q28 41 42.5 101t14.5 106zM1536 506q0 -164 -62 -304.5t-166 -236t-242.5 -149.5t-290.5 -54t-293 57.5t-247.5 157t-170.5 241.5t-64 302q0 89 19.5 172.5t49 145.5t70.5 118.5t78.5 94t78.5 69.5t64.5 46.5t42.5 24.5q14 8 51 26.5t54.5 28.5t48 30t60.5 44
+q36 28 58 72.5t30 125.5q129 -155 186 -193q44 -29 130 -68t129 -66q21 -13 39 -25t60.5 -46.5t76 -70.5t75 -95t69 -122t47 -148.5t19.5 -177.5z" />
+ <glyph glyph-name="_400" unicode="&#xf1aa;"
+d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z
+M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 133.5 -49t69.5 -123q84 20 169.5 -3.5
+t149.5 -87.5zM1536 78q0 -85 -60 -145.5t-145 -60.5q-74 0 -131 47t-71 118q-86 -28 -179.5 -6t-161.5 90l-11 12l151 152l12 -12q37 -37 89 -37t89 37t37 89t-37 89l-30 30l-152 152l-160 160l152 152l160 -160l152 -152l29 -30q64 -64 87.5 -150.5t2.5 -171.5
+q76 -11 126.5 -68.5t50.5 -134.5zM1534 1202q0 -77 -51 -135t-127 -69q26 -85 3 -176.5t-90 -158.5l-12 -12l-151 152l12 12q37 37 37 89t-37 89t-89 37t-89 -37l-30 -30l-152 -152l-160 -160l-152 152l161 160l152 152l29 30q67 67 159 89.5t178 -3.5q11 75 68.5 126
+t135.5 51q85 0 145 -60.5t60 -145.5z" />
+ <glyph glyph-name="f1ab" unicode="&#xf1ab;"
+d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5
+q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q-25 -50 -77 -131l64 -28
+q12 -6 74.5 -32t67.5 -28q4 -1 10.5 -25.5t4.5 -30.5zM449 944q3 -15 -4 -28q-12 -23 -50 -38q-30 -12 -60 -12q-26 3 -49 26q-14 15 -18 41l1 3q3 -3 19.5 -5t26.5 0t58 16q36 12 55 14q17 0 21 -17zM1147 815l63 -227l-139 42zM39 15l694 232v1032l-694 -233v-1031z
+M1280 332l102 -31l-181 657l-100 31l-216 -536l102 -31l45 110l211 -65zM777 1294l573 -184v380zM1088 -29l158 -13l-54 -160l-40 66q-130 -83 -276 -108q-58 -12 -91 -12h-84q-79 0 -199.5 39t-183.5 85q-8 7 -8 16q0 8 5 13.5t13 5.5q4 0 18 -7.5t30.5 -16.5t20.5 -11
+q73 -37 159.5 -61.5t157.5 -24.5q95 0 167 14.5t157 50.5q15 7 30.5 15.5t34 19t28.5 16.5zM1536 1050v-1079l-774 246q-14 -6 -375 -127.5t-368 -121.5q-13 0 -18 13q0 1 -1 3v1078q3 9 4 10q5 6 20 11q107 36 149 50v384l558 -198q2 0 160.5 55t316 108.5t161.5 53.5
+q20 0 20 -21v-418z" />
+ <glyph glyph-name="_402" unicode="&#xf1ac;" horiz-adv-x="1792"
+d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48
+l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 512v128q0 14 -9 23
+t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1184 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128
+q14 0 23 9t9 23zM1184 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 256v128q0 14 -9 23t-23 9h-128
+q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1440 512v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM1536 896v256h-160q-40 0 -68 28t-28 68v160h-640v-512h896z" />
+ <glyph glyph-name="_403" unicode="&#xf1ad;"
+d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9
+t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 160v64
+q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64
+q14 0 23 9t9 23zM384 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM384 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 -96v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9
+t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM896 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 928v64
+q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM896 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 160v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64
+q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 928v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9
+t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1152 1184v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23z" />
+ <glyph glyph-name="_404" unicode="&#xf1ae;" horiz-adv-x="1280"
+d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68q29 28 68.5 28t67.5 -28l228 -228h368l228 228q28 28 68 28t68 -28q28 -29 28 -68.5t-28 -67.5zM864 1152
+q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+ <glyph glyph-name="uniF1B1" unicode="&#xf1b0;" horiz-adv-x="1664"
+d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5
+q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 86 56 191.5t139.5 192.5t187.5 146t193 59zM1071 819
+q-61 0 -105 39t-63 92.5t-19 113.5q0 74 30 151.5t91.5 135t138.5 57.5q61 0 105 -39t63 -92.5t19 -113.5q0 -73 -30 -151t-92 -135.5t-138 -57.5zM1503 923q77 0 119 -59.5t42 -139.5q0 -74 -35 -152t-100.5 -133.5t-141.5 -55.5q-77 0 -119 59t-42 139q0 74 35 152.5
+t100.5 134t141.5 55.5z" />
+ <glyph glyph-name="_406" unicode="&#xf1b1;" horiz-adv-x="768"
+d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
+ <glyph glyph-name="_407" unicode="&#xf1b2;" horiz-adv-x="1792"
+d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z
+" />
+ <glyph glyph-name="_408" unicode="&#xf1b3;" horiz-adv-x="2304"
+d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67
+t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-4 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l448 192q23 10 50 10t50 -10l448 -192q35 -16 56.5 -48t21.5 -70
+v-400l434 -186q36 -16 57 -48t21 -70z" />
+ <glyph glyph-name="_409" unicode="&#xf1b4;" horiz-adv-x="2048"
+d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658
+q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96.5t31.5 -154q0 -181 -172 -263q114 -32 172 -115t58 -204
+q0 -75 -24.5 -136.5t-66 -103.5t-98.5 -71t-121 -42t-134 -13h-611v1260z" />
+ <glyph glyph-name="_410" unicode="&#xf1b5;"
+d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5
+t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 -210 -86t-82 -216q0 -135 79 -217
+t213 -82q205 0 267 191h-138q-11 -34 -47.5 -54t-75.5 -20zM1126 722q113 0 124 -122h-254q4 56 39 89t91 33zM964 988h319v-77h-319v77z" />
+ <glyph glyph-name="_411" unicode="&#xf1b6;" horiz-adv-x="1792"
+d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5
+q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -322t-321.5 -133l-437 -319q-12 -129 -109 -218t-229 -89
+q-121 0 -214 76t-118 192l-230 92v429l389 -157q79 48 173 48q13 0 35 -2l284 407q2 187 135.5 319t320.5 132q188 0 321.5 -133.5t133.5 -321.5z" />
+ <glyph glyph-name="_412" unicode="&#xf1b7;"
+d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5
+q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 255.5t-255.5 105.5
+q-148 0 -253 -104.5t-107 -252.5l-225 -322q-9 1 -28 1q-75 0 -137 -37l-297 119v468q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5zM1289 887q0 -100 -71 -170.5t-171 -70.5t-170.5 70.5t-70.5 170.5t70.5 171t170.5 71q101 0 171.5 -70.5t70.5 -171.5z
+" />
+ <glyph glyph-name="_413" unicode="&#xf1b8;" horiz-adv-x="1792"
+d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188
+l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 60 45t80 10q24 -2 48.5 -12t42 -21t41.5 -33t36 -34.5
+t36 -39.5t32 -35zM1550 1053l212 -363q18 -37 12.5 -76t-27.5 -74q-13 -20 -33 -37t-38 -28t-48.5 -22t-47 -16t-51.5 -14t-46 -12q-34 72 -265 436l313 195zM1407 1279l142 83l-220 -373l-419 20l151 86q-34 89 -75 166t-75.5 123.5t-64.5 80t-47 46.5l-17 13l405 -1
+q31 3 58 -10.5t39 -28.5l11 -15q39 -61 112 -190z" />
+ <glyph glyph-name="_414" unicode="&#xf1b9;" horiz-adv-x="2048"
+d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384
+q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5t179 63.5h768q98 0 179 -63.5t104 -157.5
+l105 -419h28q93 0 158.5 -65.5t65.5 -158.5z" />
+ <glyph glyph-name="_415" unicode="&#xf1ba;" horiz-adv-x="2048"
+d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5
+t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5z
+M1728 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47z" />
+ <glyph glyph-name="_416" unicode="&#xf1bb;"
+d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384
+q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
+ <glyph glyph-name="_417" unicode="&#xf1bc;"
+d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64
+q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t51.5 -21q11 0 40 8q133 37 307 37
+q159 0 309.5 -34t253.5 -95q21 -12 40 -12q29 0 50.5 20.5t21.5 51.5zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_418" unicode="&#xf1bd;" horiz-adv-x="1024"
+d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" />
+ <glyph glyph-name="_419" unicode="&#xf1be;" horiz-adv-x="2304"
+d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11
+q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l-25 -237q0 -11 -11 -11q-10 0 -12 11l-21 237l21 245
+q2 12 12 12q11 0 11 -12zM307 657l23 -252l-23 -244q-2 -13 -14 -13q-13 0 -13 13l-21 244l21 252q0 13 13 13q12 0 14 -13zM401 639l21 -234l-21 -246q-2 -16 -16 -16q-6 0 -10.5 4.5t-4.5 11.5l-20 246l20 234q0 6 4.5 10.5t10.5 4.5q14 0 16 -15zM784 164zM495 785
+l21 -380l-21 -246q0 -7 -5 -12.5t-12 -5.5q-16 0 -18 18l-18 246l18 380q2 18 18 18q7 0 12 -5.5t5 -12.5zM589 871l19 -468l-19 -244q0 -8 -5.5 -13.5t-13.5 -5.5q-18 0 -20 19l-16 244l16 468q2 19 20 19q8 0 13.5 -5.5t5.5 -13.5zM687 911l18 -506l-18 -242
+q-2 -21 -22 -21q-19 0 -21 21l-16 242l16 506q0 9 6.5 15.5t14.5 6.5q9 0 15 -6.5t7 -15.5zM1079 169v0v0v0zM881 915l15 -510l-15 -239q0 -10 -7.5 -17.5t-17.5 -7.5t-17 7t-8 18l-14 239l14 510q0 11 7.5 18t17.5 7t17.5 -7t7.5 -18zM980 896l14 -492l-14 -236
+q0 -11 -8 -19t-19 -8t-19 8t-9 19l-12 236l12 492q1 12 9 20t19 8t18.5 -8t8.5 -20zM1192 404l-14 -231v0q0 -13 -9 -22t-22 -9t-22 9t-10 22l-6 114l-6 117l12 636v3q2 15 12 24q9 7 20 7q8 0 15 -5q14 -8 16 -26zM2304 423q0 -117 -83 -199.5t-200 -82.5h-786
+q-13 2 -22 11t-9 22v899q0 23 28 33q85 34 181 34q195 0 338 -131.5t160 -323.5q53 22 110 22q117 0 200 -83t83 -201z" />
+ <glyph glyph-name="uniF1C0" unicode="&#xf1c0;"
+d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127
+t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5
+t-103 128v128q0 69 103 128t280 93.5t385 34.5z" />
+ <glyph glyph-name="uniF1C1" unicode="&#xf1c1;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t132 96.5q14 9 23 -6q2 -2 2 -4q52 85 107 197
+q68 136 104 262q-24 82 -30.5 159.5t6.5 127.5q11 40 42 40h21h1q23 0 35 -15q18 -21 9 -68q-2 -6 -4 -8q1 -3 1 -8v-30q-2 -123 -14 -192q55 -164 146 -238zM318 54q52 24 137 158q-51 -40 -87.5 -84t-49.5 -74zM716 974q-15 -42 -2 -132q1 7 7 44q0 3 7 43q1 4 4 8
+q-1 1 -1 2q-1 2 -1 3q-1 22 -13 36q0 -1 -1 -2v-2zM592 313q135 54 284 81q-2 1 -13 9.5t-16 13.5q-76 67 -127 176q-27 -86 -83 -197q-30 -56 -45 -83zM1238 329q-24 24 -140 24q76 -28 124 -28q14 0 18 1q0 1 -2 3z" />
+ <glyph glyph-name="_422" unicode="&#xf1c2;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4q0 3 -0.5 6.5t-1.5 8t-1 6.5q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 -9 -4.5 -24.5
+t-3.5 -21.5l-4 -21h-4l-2 21q-2 26 -7 46l-99 438h90v107h-300z" />
+ <glyph glyph-name="_423" unicode="&#xf1c3;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q-1 4 -5 10q-6 11 -17 23l-106 159h76v107
+h-290v-107h68l189 -272l-194 -283h-68z" />
+ <glyph glyph-name="_424" unicode="&#xf1c4;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
+ <glyph glyph-name="_425" unicode="&#xf1c5;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
+ <glyph glyph-name="_426" unicode="&#xf1c6;"
+d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400
+v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137.5q0 25 8 52q21 63 120 396v128h128v-128h79
+q22 0 39 -13t23 -34zM640 128q53 0 90.5 19t37.5 45t-37.5 45t-90.5 19t-90.5 -19t-37.5 -45t37.5 -45t90.5 -19z" />
+ <glyph glyph-name="_427" unicode="&#xf1c7;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -17 -23.5 -43.5t14.5 -47.5
+q100 -123 100 -282t-100 -282q-17 -21 -14.5 -47.5t23.5 -42.5q18 -15 40 -15zM826 145q27 0 47 20q87 93 87 219t-87 219q-18 19 -45 20t-46 -17t-20 -44.5t18 -46.5q52 -57 52 -131t-52 -131q-19 -20 -18 -46.5t20 -44.5q20 -17 44 -17z" />
+ <glyph glyph-name="_428" unicode="&#xf1c8;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
+ <glyph glyph-name="_429" unicode="&#xf1c9;"
+d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z
+M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6.5l-51 38q-11 8 -12.5 21t6.5 24l182 243
+l-182 243q-8 11 -6.5 24t12.5 21l51 38q11 8 24 6.5t21 -12.5zM662 6q-13 2 -20.5 13t-5.5 24l138 831q2 13 13 20.5t24 5.5l63 -10q13 -2 20.5 -13t5.5 -24l-138 -831q-2 -13 -13 -20.5t-24 -5.5z" />
+ <glyph glyph-name="_430" unicode="&#xf1ca;"
+d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406
+q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 105 -293.5t267 -107.5q62 0 121 14z" />
+ <glyph glyph-name="_431" unicode="&#xf1cb;" horiz-adv-x="1792"
+d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546
+q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
+ <glyph glyph-name="_432" unicode="&#xf1cc;" horiz-adv-x="2048"
+d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94
+q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44 0 84.5 -21t73 -55t65 -75t69 -82t77 -75t97 -55
+t121.5 -21q121 0 204.5 71.5t83.5 190.5q0 121 -84 192t-207 71q-143 0 -241 -97l93 -108q66 64 142 64q52 0 92 -33t40 -84q0 -57 -37 -91.5t-94 -34.5q-43 0 -82.5 21t-72 55t-65.5 75t-69.5 82t-77.5 75t-96.5 55t-118.5 21q-122 0 -207 -70.5t-85 -189.5z" />
+ <glyph glyph-name="_433" unicode="&#xf1cd;" horiz-adv-x="1792"
+d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194
+q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5
+t271.5 -112.5zM1380 473l194 -194q90 171 90 361t-90 361l-194 -194q28 -82 28 -167t-28 -167z" />
+ <glyph glyph-name="_434" unicode="&#xf1ce;" horiz-adv-x="1792"
+d="M1760 640q0 -176 -68.5 -336t-184 -275.5t-275.5 -184t-336 -68.5t-336 68.5t-275.5 184t-184 275.5t-68.5 336q0 213 97 398.5t265 305.5t374 151v-228q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5
+t136.5 204t51 248.5q0 230 -145.5 406t-366.5 221v228q206 -31 374 -151t265 -305.5t97 -398.5z" />
+ <glyph glyph-name="uniF1D0" unicode="&#xf1d0;" horiz-adv-x="1792"
+d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41
+t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115q-44 -14 -85 -50t-60 -65l-19 -29q-31 -56 -48 -133.5t-7 -170
+t57 -156.5q33 -45 77.5 -60.5t85 -5.5t76 26.5t57.5 33.5l21 16q60 53 96.5 115t48.5 121.5t10 121.5t-18 118t-37 107.5t-45.5 93t-45 72t-34.5 47.5l-13 17q-14 13 -7 13l10 -3q40 -29 62.5 -46t62 -50t64 -58t58.5 -65t55.5 -77t45.5 -88t38 -103t23.5 -117t10.5 -136
+q3 -259 -108 -465t-312 -321t-456 -115q-185 0 -351 74t-283.5 198t-184 293t-60.5 353z" />
+ <glyph glyph-name="uniF1D1" unicode="&#xf1d1;" horiz-adv-x="1792"
+d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251
+l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241q-52 -10 -98 -10t-98 10l48 241q-90 18 -147 85l-185 -162
+q-67 77 -98 169l232 80q-14 42 -14 85t14 85l-233 80q33 93 99 169l185 -162q59 68 147 86l-48 240q44 10 98 10t98 -10l-48 -240q88 -18 147 -86l185 162q66 -76 99 -169zM874 1448v-66q-65 -2 -121 -13l17 -86q-220 -42 -368 -211l-65 56q-38 -42 -73 -98l-57 33
+q106 172 282 275.5t385 109.5zM1705 640q0 -205 -98 -385l-57 33q27 52 49 112l-83 28q36 103 36 212q0 112 -35 212l82 28q-19 56 -49 112l57 33q98 -180 98 -385zM1585 1063l-57 -33q-35 56 -73 98l-65 -56q-148 169 -368 211l17 86q-56 11 -121 13v66q209 -6 385 -109.5
+t282 -275.5zM1748 640q0 173 -67.5 331t-181.5 272t-272 181.5t-331 67.5t-331 -67.5t-272 -181.5t-181.5 -272t-67.5 -331t67.5 -331t181.5 -272t272 -181.5t331 -67.5t331 67.5t272 181.5t181.5 272t67.5 331zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71
+t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="uniF1D2" unicode="&#xf1d2;"
+d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85
+q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387q0 46 2 69h-137q3 -23 3 -71v-392
+q0 -50 -3 -75zM1280 366v121q-30 -21 -68 -21q-53 0 -53 82v225h52q9 0 26.5 -1t26.5 -1v117h-105q0 82 3 102h-140q4 -24 4 -55v-47h-60v-117q36 3 37 3q3 0 11 -0.5t12 -0.5v-2h-2v-217q0 -37 2.5 -64t11.5 -56.5t24.5 -48.5t43.5 -31t66 -12q64 0 108 24zM924 1072
+q0 36 -24 63.5t-60 27.5t-60.5 -27t-24.5 -64q0 -36 25 -62.5t60 -26.5t59.5 27t24.5 62zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_438" unicode="&#xf1d3;" horiz-adv-x="1792"
+d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58
+q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 108.5t-47.5 165.5q0 139 95 231.5t235 92.5q96 0 178 -47
+q98 0 218 47zM1123 220h-222q4 45 4 134v609q0 94 -4 128h222q-4 -33 -4 -124v-613q0 -89 4 -134zM1724 442v-196q-71 -39 -174 -39q-62 0 -107 20t-70 50t-39.5 78t-18.5 92t-4 103v351h2v4q-7 0 -19 1t-18 1q-21 0 -59 -6v190h96v76q0 54 -6 89h227q-6 -41 -6 -165h171
+v-190q-15 0 -43.5 2t-42.5 2h-85v-365q0 -131 87 -131q61 0 109 33zM1148 1389q0 -58 -39 -101.5t-96 -43.5q-58 0 -98 43.5t-40 101.5q0 59 39.5 103t98.5 44q58 0 96.5 -44.5t38.5 -102.5z" />
+ <glyph glyph-name="_439" unicode="&#xf1d4;"
+d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="uniF1D5" unicode="&#xf1d5;" horiz-adv-x="1280"
+d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5
+t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186t-102 153t-153 102t-186 38t-186 -38t-153 -102t-102 -153
+t-38 -186q0 -114 52 -218q10 -20 3.5 -40t-25.5 -30t-39.5 -3t-30.5 26q-64 123 -64 265q0 119 46.5 227t124.5 186t186 124t226 46q158 0 292.5 -78t212.5 -212.5t78 -292.5z" />
+ <glyph glyph-name="uniF1D6" unicode="&#xf1d6;" horiz-adv-x="1792"
+d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5
+q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 -4 -16t-7 -18q-64 -97 -302 -97q-53 0 -110.5 9t-98 20
+t-104.5 30q-15 5 -23 7q-14 4 -46 4.5t-40 1.5q-41 -45 -127.5 -65t-168.5 -20q-35 0 -69 1.5t-93 9t-101 20.5t-74.5 40t-32.5 64q0 40 10 59.5t41 48.5q11 2 40.5 13t49.5 12q4 0 14 2q2 2 2 4l-2 3q-48 11 -108 105.5t-73 156.5l-5 3q-4 0 -12 -20q-18 -41 -54.5 -74.5
+t-77.5 -37.5h-1q-4 0 -6 4.5t-5 5.5q-23 54 -23 100q0 275 252 466z" />
+ <glyph glyph-name="uniF1D7" unicode="&#xf1d7;" horiz-adv-x="2048"
+d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25
+q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -70 4q-169 0 -311 -77t-223.5 -208.5t-81.5 -287.5
+q0 -78 23 -152q-35 -3 -68 -3q-26 0 -50 1.5t-55 6.5t-44.5 7t-54.5 10.5t-50 10.5l-253 -127l72 218q-290 203 -290 490q0 169 97.5 311t264 223.5t363.5 81.5q176 0 332.5 -66t262 -182.5t136.5 -260.5zM2048 404q0 -117 -68.5 -223.5t-185.5 -193.5l55 -181l-199 109
+q-150 -37 -218 -37q-169 0 -311 70.5t-223.5 191.5t-81.5 264t81.5 264t223.5 191.5t311 70.5q161 0 303 -70.5t227.5 -192t85.5 -263.5z" />
+ <glyph glyph-name="_443" unicode="&#xf1d8;" horiz-adv-x="1792"
+d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
+ <glyph glyph-name="_444" unicode="&#xf1d9;" horiz-adv-x="1792"
+d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137
+l863 639l-478 -797z" />
+ <glyph glyph-name="_445" unicode="&#xf1da;"
+d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5
+t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 -298zM896 928v-448q0 -14 -9 -23
+t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="_446" unicode="&#xf1db;"
+d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103
+t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_447" unicode="&#xf1dc;" horiz-adv-x="1792"
+d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15
+t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5t-3.5 42t-6.5 36.5t-11 31.5t-16 18q-15 10 -45 12t-53 2
+t-41 14t-18 45q0 26 12 48t36 22q46 0 138.5 -3.5t138.5 -3.5q42 0 126.5 3.5t126.5 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17 -43.5t-38.5 -14.5t-49.5 -4t-43 -13q-35 -21 -35 -160l1 -320q0 -21 1 -32q13 -3 39 -3h699q25 0 38 3q1 11 1 32l1 320q0 139 -35 160
+q-18 11 -58.5 12.5t-66 13t-25.5 49.5q0 26 12.5 48t37.5 22q44 0 132 -3.5t132 -3.5q43 0 129 3.5t129 3.5q25 0 37.5 -22t12.5 -48q0 -30 -17.5 -44t-40 -14.5t-51.5 -3t-44 -12.5q-35 -23 -35 -161l1 -943q0 -119 34 -140q16 -10 46 -13.5t53.5 -4.5t41.5 -15.5t18 -44.5
+q0 -26 -12 -48t-36 -22z" />
+ <glyph glyph-name="_448" unicode="&#xf1dd;" horiz-adv-x="1280"
+d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179
+q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
+ <glyph glyph-name="_449" unicode="&#xf1de;"
+d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256
+q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1152v-128h-864v128h864z" />
+ <glyph glyph-name="uniF1E0" unicode="&#xf1e0;"
+d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5
+t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
+ <glyph glyph-name="_451" unicode="&#xf1e1;"
+d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5
+t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_452" unicode="&#xf1e2;" horiz-adv-x="1792"
+d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5
+t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q-13 0 -23 10l-91 90q-9 10 -9 23t9 23q10 9 23 9t23 -9l90 -91
+q10 -9 10 -22.5t-10 -22.5zM1751 1129q-11 -9 -23 -9t-23 9l-90 91q-10 9 -10 22.5t10 22.5q9 10 22.5 10t22.5 -10l91 -90q9 -10 9 -23t-9 -23zM1792 1312q0 -14 -9 -23t-23 -9h-96q-14 0 -23 9t-9 23t9 23t23 9h96q14 0 23 -9t9 -23zM1600 1504v-96q0 -14 -9 -23t-23 -9
+t-23 9t-9 23v96q0 14 9 23t23 9t23 -9t9 -23zM1751 1449l-91 -90q-10 -10 -22 -10q-13 0 -23 10q-10 9 -10 22.5t10 22.5l90 91q10 9 23 9t23 -9q9 -10 9 -23t-9 -23z" />
+ <glyph glyph-name="_453" unicode="&#xf1e3;" horiz-adv-x="1792"
+d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323
+l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l139 298l326 40z" />
+ <glyph glyph-name="_454" unicode="&#xf1e4;" horiz-adv-x="1792"
+d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23
+v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t-46 -19h-383zM1216 224v-192q0 -14 -9 -23t-23 -9h-192
+q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1600 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23
+zM1408 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1016v-13h-514v10q0 104 -382 102q-382 -1 -382 -102v-10h-514v13q0 17 8.5 43t34 64t65.5 75.5t110.5 76t160 67.5t224 47.5t293.5 18.5t293 -18.5t224 -47.5
+t160.5 -67.5t110.5 -76t65.5 -75.5t34 -64t8.5 -43zM1792 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 962v-129q0 -27 -19 -46t-46 -19h-384q-27 0 -46 19t-19 46v129h514z" />
+ <glyph glyph-name="_455" unicode="&#xf1e5;" horiz-adv-x="1792"
+d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z
+M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="_456" unicode="&#xf1e6;" horiz-adv-x="1792"
+d="M1755 1083q37 -38 37 -90.5t-37 -90.5l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234
+l401 400q38 37 91 37t90 -37z" />
+ <glyph glyph-name="_457" unicode="&#xf1e7;" horiz-adv-x="1792"
+d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5
+t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1t53 1t54.5 4.5t61 8.5t62 13.5t67 19.5t67.5 27t72 34.5z
+M1763 621q-121 -149 -372 -252q84 -285 -23 -465q-66 -113 -183 -148q-104 -32 -182 15q-86 51 -82 164l-1 326v1q-8 2 -24.5 6t-23.5 5l-1 -338q4 -114 -83 -164q-79 -47 -183 -15q-117 36 -182 150q-105 180 -22 463q-251 103 -372 252q-25 37 -4 63t60 -1q4 -2 11.5 -7
+t10.5 -8v694q0 72 47 123t114 51h1257q67 0 114 -51t47 -123v-694l21 15q39 27 60 1t-4 -63z" />
+ <glyph glyph-name="_458" unicode="&#xf1e8;" horiz-adv-x="1792"
+d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
+ <glyph glyph-name="_459" unicode="&#xf1e9;"
+d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36
+q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q71 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 -1 119 -40q203 -66 242 -79.5
+t47 -20.5q28 -22 22 -61zM778 803q5 -102 -54 -122q-58 -17 -114 71l-378 598q-8 35 19 62q41 43 207.5 89.5t224.5 31.5q40 -10 49 -45q3 -18 22 -305.5t24 -379.5zM1440 695q3 -39 -26 -59q-15 -10 -329 -86q-67 -15 -91 -23l1 2q-23 -6 -46 4t-37 32q-30 47 0 87
+q1 1 75 102q125 171 150 204t34 39q28 19 65 2q48 -23 123 -133.5t81 -167.5v-3z" />
+ <glyph glyph-name="_460" unicode="&#xf1ea;" horiz-adv-x="2048"
+d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19
+t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
+ <glyph glyph-name="_461" unicode="&#xf1eb;" horiz-adv-x="2048"
+d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121
+q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73t380 -73t320 -205q10 -10 10 -22q0 -18 -75 -93t-92 -75z
+M1838 827q-11 0 -22 9q-179 157 -371.5 236.5t-420.5 79.5t-420.5 -79.5t-371.5 -236.5q-11 -9 -22 -9q-17 0 -92.5 75t-75.5 93q0 13 10 23q187 186 445 288t527 102t527 -102t445 -288q10 -10 10 -23q0 -18 -75.5 -93t-92.5 -75z" />
+ <glyph glyph-name="_462" unicode="&#xf1ec;" horiz-adv-x="1792"
+d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5
+t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5
+t37.5 90.5zM384 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 768q0 53 -37.5 90.5t-90.5 37.5
+t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1536 0v384q0 52 -38 90t-90 38t-90 -38t-38 -90v-384q0 -52 38 -90t90 -38t90 38t38 90zM1152 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z
+M1536 1088v256q0 26 -19 45t-45 19h-1280q-26 0 -45 -19t-19 -45v-256q0 -26 19 -45t45 -19h1280q26 0 45 19t19 45zM1536 768q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1408v-1536q0 -52 -38 -90t-90 -38
+h-1408q-52 0 -90 38t-38 90v1536q0 52 38 90t90 38h1408q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_463" unicode="&#xf1ed;"
+d="M1519 890q18 -84 -4 -204q-87 -444 -565 -444h-44q-25 0 -44 -16.5t-24 -42.5l-4 -19l-55 -346l-2 -15q-5 -26 -24.5 -42.5t-44.5 -16.5h-251q-21 0 -33 15t-9 36q9 56 26.5 168t26.5 168t27 167.5t27 167.5q5 37 43 37h131q133 -2 236 21q175 39 287 144q102 95 155 246
+q24 70 35 133q1 6 2.5 7.5t3.5 1t6 -3.5q79 -59 98 -162zM1347 1172q0 -107 -46 -236q-80 -233 -302 -315q-113 -40 -252 -42q0 -1 -90 -1l-90 1q-100 0 -118 -96q-2 -8 -85 -530q-1 -10 -12 -10h-295q-22 0 -36.5 16.5t-11.5 38.5l232 1471q5 29 27.5 48t51.5 19h598
+q34 0 97.5 -13t111.5 -32q107 -41 163.5 -123t56.5 -196z" />
+ <glyph glyph-name="_464" unicode="&#xf1ee;" horiz-adv-x="1792"
+d="M441 864q33 0 52 -26q266 -364 362 -774h-446q-127 441 -367 749q-12 16 -3 33.5t29 17.5h373zM1000 507q-49 -199 -125 -393q-79 310 -256 594q40 221 44 449q211 -340 337 -650zM1099 1216q235 -324 384.5 -698.5t184.5 -773.5h-451q-41 665 -553 1472h435zM1792 640
+q0 -424 -101 -812q-67 560 -359 1083q-25 301 -106 584q-4 16 5.5 28.5t25.5 12.5h359q21 0 38.5 -13t22.5 -33q115 -409 115 -850z" />
+ <glyph glyph-name="uniF1F0" unicode="&#xf1f0;" horiz-adv-x="2304"
+d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27
+q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24.5 38.5t70.5 16.5q70 1 124 -24l15 -8zM2042 960h-128
+q-65 0 -87 -54l-246 -588h174l35 96h212q5 -22 20 -96h154zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_466" unicode="&#xf1f1;" horiz-adv-x="2304"
+d="M1119 1195q-128 85 -281 85q-103 0 -197.5 -40.5t-162.5 -108.5t-108.5 -162t-40.5 -197q0 -104 40.5 -198t108.5 -162t162 -108.5t198 -40.5q153 0 281 85q-131 107 -178 265.5t0.5 316.5t177.5 265zM1152 1171q-126 -99 -172 -249.5t-0.5 -300.5t172.5 -249
+q127 99 172.5 249t-0.5 300.5t-172 249.5zM1185 1195q130 -107 177.5 -265.5t0.5 -317t-178 -264.5q128 -85 281 -85q104 0 198 40.5t162 108.5t108.5 162t40.5 198q0 103 -40.5 197t-108.5 162t-162.5 108.5t-197.5 40.5q-153 0 -281 -85zM1926 473h7v3h-17v-3h7v-17h3v17z
+M1955 456h4v20h-5l-6 -13l-6 13h-5v-20h3v15l6 -13h4l5 13v-15zM1947 16v-2h-2h-3v3h3h2v-1zM1947 7h3l-4 5h2l1 1q1 1 1 3t-1 3l-1 1h-3h-6v-13h3v5h1zM685 75q0 19 11 31t30 12q18 0 29 -12.5t11 -30.5q0 -19 -11 -31t-29 -12q-19 0 -30 12t-11 31zM1158 119q30 0 35 -32
+h-70q5 32 35 32zM1514 75q0 19 11 31t29 12t29.5 -12.5t11.5 -30.5q0 -19 -11 -31t-30 -12q-18 0 -29 12t-11 31zM1786 75q0 18 11.5 30.5t29.5 12.5t29.5 -12.5t11.5 -30.5q0 -19 -11.5 -31t-29.5 -12t-29.5 12.5t-11.5 30.5zM1944 3q-2 0 -4 1q-1 0 -3 2t-2 3q-1 2 -1 4
+q0 3 1 4q0 2 2 4l1 1q2 0 2 1q2 1 4 1q3 0 4 -1l4 -2l2 -4v-1q1 -2 1 -3l-1 -1v-3t-1 -1l-1 -2q-2 -2 -4 -2q-1 -1 -4 -1zM599 7h30v85q0 24 -14.5 38.5t-39.5 15.5q-32 0 -47 -24q-14 24 -45 24q-24 0 -39 -20v16h-30v-135h30v75q0 36 33 36q30 0 30 -36v-75h29v75
+q0 36 33 36q30 0 30 -36v-75zM765 7h29v68v67h-29v-16q-17 20 -43 20q-29 0 -48 -20t-19 -51t19 -51t48 -20q28 0 43 20v-17zM943 48q0 34 -47 40l-14 2q-23 4 -23 14q0 15 25 15q23 0 43 -11l12 24q-22 14 -55 14q-26 0 -41 -12t-15 -32q0 -33 47 -39l13 -2q24 -4 24 -14
+q0 -17 -31 -17q-25 0 -45 14l-13 -23q25 -17 58 -17q29 0 45.5 12t16.5 32zM1073 14l-8 25q-13 -7 -26 -7q-19 0 -19 22v61h48v27h-48v41h-30v-41h-28v-27h28v-61q0 -50 47 -50q21 0 36 10zM1159 146q-29 0 -48 -20t-19 -51q0 -32 19.5 -51.5t49.5 -19.5q33 0 55 19l-14 22
+q-18 -15 -39 -15q-34 0 -41 33h101v12q0 32 -18 51.5t-46 19.5zM1318 146q-23 0 -35 -20v16h-30v-135h30v76q0 35 29 35q10 0 18 -4l9 28q-9 4 -21 4zM1348 75q0 -31 19.5 -51t52.5 -20q29 0 48 16l-14 24q-18 -13 -35 -12q-18 0 -29.5 12t-11.5 31t11.5 31t29.5 12
+q19 0 35 -12l14 24q-20 16 -48 16q-33 0 -52.5 -20t-19.5 -51zM1593 7h30v68v67h-30v-16q-15 20 -42 20q-29 0 -48.5 -20t-19.5 -51t19.5 -51t48.5 -20q28 0 42 20v-17zM1726 146q-23 0 -35 -20v16h-29v-135h29v76q0 35 29 35q10 0 18 -4l9 28q-8 4 -21 4zM1866 7h29v68v122
+h-29v-71q-15 20 -43 20t-47.5 -20.5t-19.5 -50.5t19.5 -50.5t47.5 -20.5q29 0 43 20v-17zM1944 27l-2 -1h-3q-2 -1 -4 -3q-3 -1 -3 -4q-1 -2 -1 -6q0 -3 1 -5q0 -2 3 -4q2 -2 4 -3t5 -1q4 0 6 1q0 1 2 2l2 1q1 1 3 4q1 2 1 5q0 4 -1 6q-1 1 -3 4q0 1 -2 2l-2 1q-1 0 -3 0.5
+t-3 0.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_467" unicode="&#xf1f2;" horiz-adv-x="2304"
+d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42
+q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0 -71 44l-42 -40q44 -64 115 -64q51 0 83 30.5t32 79.5zM1008 604
+v77q-37 -37 -78 -37q-49 0 -80.5 32.5t-31.5 82.5q0 48 31.5 81.5t77.5 33.5q43 0 81 -38v77q-40 20 -80 20q-74 0 -125.5 -50.5t-51.5 -123.5t51 -123.5t125 -50.5q42 0 81 19zM2240 0v527q-65 -40 -144.5 -84t-237.5 -117t-329.5 -137.5t-417.5 -134.5t-504 -118h1569
+q26 0 45 19t19 45zM1389 757q0 75 -53 128t-128 53t-128 -53t-53 -128t53 -128t128 -53t128 53t53 128zM1541 584l144 342h-71l-90 -224l-89 224h-71l142 -342h35zM1714 593h184v56h-119v90h115v56h-115v74h119v57h-184v-333zM2105 593h80l-105 140q76 16 76 94q0 47 -31 73
+t-87 26h-97v-333h65v133h9zM2304 1274v-1268q0 -56 -38.5 -95t-93.5 -39h-2040q-55 0 -93.5 39t-38.5 95v1268q0 56 38.5 95t93.5 39h2040q55 0 93.5 -39t38.5 -95z" />
+ <glyph glyph-name="f1f3" unicode="&#xf1f3;" horiz-adv-x="2304"
+d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z
+M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1t-32.5 0.5t-29.5 0.5v-91h-126l-80 90l-83 -90h-256v271h260
+l80 -89l82 89h207q109 0 109 -89zM964 794v-56h-217v271h217v-57h-152v-49h148v-55h-148v-54h152zM2304 235v-229q0 -55 -38.5 -94.5t-93.5 -39.5h-2040q-55 0 -93.5 39.5t-38.5 94.5v678h111l25 61h55l25 -61h218v46l19 -46h113l20 47v-47h541v99l10 1q10 0 10 -14v-86h279
+v23q23 -12 55 -18t52.5 -6.5t63 0.5t51.5 1l25 61h56l25 -61h227v58l34 -58h182v378h-180v-44l-25 44h-185v-44l-23 44h-249q-69 0 -109 -22v22h-172v-22q-24 22 -73 22h-628l-43 -97l-43 97h-198v-44l-22 44h-169l-78 -179v391q0 55 38.5 94.5t93.5 39.5h2040
+q55 0 93.5 -39.5t38.5 -94.5v-678h-120q-51 0 -81 -22v22h-177q-55 0 -78 -22v22h-316v-22q-31 22 -87 22h-209v-22q-23 22 -91 22h-234l-54 -58l-50 58h-349v-378h343l55 59l52 -59h211v89h21q59 0 90 13v-102h174v99h8q8 0 10 -2t2 -10v-87h529q57 0 88 24v-24h168
+q60 0 95 17zM1546 469q0 -23 -12 -43t-34 -29q25 -9 34 -26t9 -46v-54h-65v45q0 33 -12 43.5t-46 10.5h-69v-99h-65v271h154q48 0 77 -15t29 -58zM1269 936q0 -24 -12.5 -44t-33.5 -29q26 -9 34.5 -25.5t8.5 -46.5v-53h-65q0 9 0.5 26.5t0 25t-3 18.5t-8.5 16t-17.5 8.5
+t-29.5 3.5h-70v-98h-64v271l153 -1q49 0 78 -14.5t29 -57.5zM1798 327v-56h-216v271h216v-56h-151v-49h148v-55h-148v-54zM1372 1009v-271h-66v271h66zM2065 357q0 -86 -102 -86h-126v58h126q34 0 34 25q0 16 -17 21t-41.5 5t-49.5 3.5t-42 22.5t-17 55q0 39 26 60t66 21
+h130v-57h-119q-36 0 -36 -25q0 -16 17.5 -20.5t42 -4t49 -2.5t42 -21.5t17.5 -54.5zM2304 407v-101q-24 -35 -88 -35h-125v58h125q33 0 33 25q0 13 -12.5 19t-31 5.5t-40 2t-40 8t-31 24t-12.5 48.5q0 39 26.5 60t66.5 21h129v-57h-118q-36 0 -36 -25q0 -20 29 -22t68.5 -5
+t56.5 -26zM2139 1008v-270h-92l-122 203v-203h-132l-26 60h-134l-25 -60h-75q-129 0 -129 133q0 138 133 138h63v-59q-7 0 -28 1t-28.5 0.5t-23 -2t-21.5 -6.5t-14.5 -13.5t-11.5 -23t-3 -33.5q0 -38 13.5 -58t49.5 -20h29l92 213h97l109 -256v256h99l114 -188v188h66z" />
+ <glyph glyph-name="_469" unicode="&#xf1f4;" horiz-adv-x="2304"
+d="M745 630q0 -37 -25.5 -61.5t-62.5 -24.5q-29 0 -46.5 16t-17.5 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM1530 779q0 -42 -22 -57t-66 -15l-32 -1l17 107q2 11 13 11h18q22 0 35 -2t25 -12.5t12 -30.5zM1881 630q0 -36 -25.5 -61t-61.5 -25q-29 0 -47 16
+t-18 44q0 37 25 62.5t62 25.5q28 0 46.5 -16.5t18.5 -45.5zM513 801q0 59 -38.5 85.5t-100.5 26.5h-160q-19 0 -21 -19l-65 -408q-1 -6 3 -11t10 -5h76q20 0 22 19l18 110q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM822 489l41 261q1 6 -3 11t-10 5h-76
+q-14 0 -17 -33q-27 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q28 0 58 12t48 32q-4 -12 -4 -21q0 -16 13 -16h69q19 0 22 19zM1269 752q0 5 -4 9.5t-9 4.5h-77q-11 0 -18 -10l-106 -156l-44 150q-5 16 -22 16h-75q-5 0 -9 -4.5t-4 -9.5q0 -2 19.5 -59
+t42 -123t23.5 -70q-82 -112 -82 -120q0 -13 13 -13h77q11 0 18 10l255 368q2 2 2 7zM1649 801q0 59 -38.5 85.5t-100.5 26.5h-159q-20 0 -22 -19l-65 -408q-1 -6 3 -11t10 -5h82q12 0 16 13l18 116q1 8 7 13t15 6.5t17 1.5t19 -1t14 -1q86 0 135 48.5t49 134.5zM1958 489
+l41 261q1 6 -3 11t-10 5h-76q-14 0 -17 -33q-26 40 -95 40q-72 0 -122.5 -54t-50.5 -127q0 -59 34.5 -94t92.5 -35q29 0 59 12t47 32q0 -1 -2 -9t-2 -12q0 -16 13 -16h69q19 0 22 19zM2176 898v1q0 14 -13 14h-74q-11 0 -13 -11l-65 -416l-1 -2q0 -5 4 -9.5t10 -4.5h66
+q19 0 21 19zM392 764q-5 -35 -26 -46t-60 -11l-33 -1l17 107q2 11 13 11h19q40 0 58 -11.5t12 -48.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_470" unicode="&#xf1f5;" horiz-adv-x="2304"
+d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109
+q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 -8l-17 -103h62v-219q0 -84 44 -120q38 -30 111 -30q32 0 79 11v118
+q-32 -7 -44 -7q-42 0 -42 50v197h77zM1087 724v139q-15 3 -28 3q-32 0 -55.5 -16t-33.5 -46l-10 56h-131v-471h150v306q26 31 82 31q16 0 26 -2zM1124 389h150v471h-150v-471zM1746 638q0 122 -45 179q-40 52 -111 52q-64 0 -117 -56l-8 47h-132v-645l150 25v151
+q36 -11 68 -11q83 0 134 56q61 65 61 202zM1278 986q0 33 -23 56t-56 23t-56 -23t-23 -56t23 -56.5t56 -23.5t56 23.5t23 56.5zM2176 629q0 113 -48 176q-50 64 -144 64q-96 0 -151.5 -66t-55.5 -180q0 -128 63 -188q55 -55 161 -55q101 0 160 40l-16 103q-57 -31 -128 -31
+q-43 0 -63 19q-23 19 -28 66h248q2 14 2 52zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_471" unicode="&#xf1f6;" horiz-adv-x="2048"
+d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5
+l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5
+l418 363q10 8 23.5 7t21.5 -11z" />
+ <glyph glyph-name="_472" unicode="&#xf1f7;" horiz-adv-x="2048"
+d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128
+q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161
+q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q124 -18 219 -82.5t148 -157.5l418 363q10 8 23.5 7t21.5 -11z" />
+ <glyph glyph-name="_473" unicode="&#xf1f8;" horiz-adv-x="1408"
+d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704
+q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v952h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h309l70 167
+q15 37 54 63t79 26h320q40 0 79 -26t54 -63l70 -167h309q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="_474" unicode="&#xf1f9;"
+d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5
+t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5
+t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_475" unicode="&#xf1fa;"
+d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53
+q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0 -39 12.5 -52t44.5 -13q28 1 57 5.5t73 24
+t77 50t57 89.5t24 137q0 292 -174 466t-466 174q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51q228 0 405 144q11 9 24 8t21 -12l41 -49q8 -12 7 -24q-2 -13 -12 -22q-102 -83 -227.5 -128t-258.5 -45q-156 0 -298 61
+t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q344 0 556 -212t212 -556z" />
+ <glyph glyph-name="_476" unicode="&#xf1fb;" horiz-adv-x="1792"
+d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10
+t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
+ <glyph glyph-name="f1fc" unicode="&#xf1fc;" horiz-adv-x="1792"
+d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5
+t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
+ <glyph glyph-name="_478" unicode="&#xf1fd;" horiz-adv-x="1792"
+d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11q24 0 44 -7t31 -15t33 -27q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5
+t47 37.5q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-24 0 -44 7t-31 15t-33 27q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-31 -15t-44 -7q-35 0 -56.5 11t-51.5 38q-29 25 -47 38
+t-58 27t-86 14q-45 0 -85 -14.5t-58 -27t-48 -37.5q-21 -19 -32.5 -27t-31 -15t-43.5 -7q-35 0 -56.5 11t-51.5 38q-28 24 -47 37.5t-59 27.5t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-30 -27 -51.5 -38t-56.5 -11v192q0 80 56 136t136 56h64v448h256v-448h256v448h256v-448
+h256v448h256v-448h64q80 0 136 -56t56 -136zM512 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1024 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5
+q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150zM1536 1312q0 -77 -36 -118.5t-92 -41.5q-53 0 -90.5 37.5t-37.5 90.5q0 29 9.5 51t23.5 34t31 28t31 31.5t23.5 44.5t9.5 67q38 0 83 -74t45 -150z" />
+ <glyph glyph-name="_479" unicode="&#xf1fe;" horiz-adv-x="2048"
+d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
+ <glyph glyph-name="_480" unicode="&#xf200;" horiz-adv-x="1792"
+d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_481" unicode="&#xf201;" horiz-adv-x="2048"
+d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9
+t9 -23z" />
+ <glyph glyph-name="_482" unicode="&#xf202;" horiz-adv-x="1792"
+d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20
+q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43.5 206t116 176.5t172 121.5t204.5 46q87 0 159 -19t123.5 -50
+t95 -80t72.5 -99t58.5 -117t50.5 -124.5t50 -130.5t55 -127q96 -200 233 -200q81 0 138.5 48.5t57.5 128.5q0 42 -19 72t-50.5 46t-72.5 31.5t-84.5 27t-87.5 34t-81 52t-65 82t-39 122.5q-3 16 -3 33q0 110 87.5 192t198.5 78q78 -3 120.5 -14.5t90.5 -53.5h-1
+q12 -11 23 -24.5t26 -36t19 -27.5l-129 -99q-26 49 -54 70v1q-23 21 -97 21q-49 0 -84 -33t-35 -83z" />
+ <glyph glyph-name="_483" unicode="&#xf203;"
+d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73
+q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t133.5 -147.5t196 -56.5q186 0 279 110
+q20 27 31 51l-60 109q-42 -80 -99 -116t-146 -36q-115 0 -191 87t-76 204q0 105 82 189t186 84q112 0 170 -53.5t104 -172.5q8 -21 25.5 -68.5t28.5 -76.5t31.5 -74.5t38.5 -74t45.5 -62.5t55.5 -53.5t66 -33t80 -13.5q107 0 183 69.5t76 174.5zM1536 1120v-960
+q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_484" unicode="&#xf204;" horiz-adv-x="2048"
+d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5
+t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5
+t-136.5 204t-51 248.5t51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5z" />
+ <glyph glyph-name="_485" unicode="&#xf205;" horiz-adv-x="2048"
+d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5
+t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+ <glyph glyph-name="_486" unicode="&#xf206;" horiz-adv-x="2304"
+d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94
+q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 97 39.5 183.5t109.5 149.5l-65 98l-353 -469
+q-18 -26 -51 -26h-197q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q114 0 215 -55l137 183h-224q-26 0 -45 19t-19 45t19 45t45 19h384v-128h435l-85 128h-222q-26 0 -45 19t-19 45t19 45t45 19h256q33 0 53 -28l267 -400
+q91 44 192 44q185 0 316.5 -131.5t131.5 -316.5z" />
+ <glyph glyph-name="_487" unicode="&#xf207;"
+d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5
+h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5
+t-37.5 90.5v128h-768v-128q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5v128h-128v603q0 112 25 223l103 454q9 78 97.5 137t230 89t312.5 30t312.5 -30t230 -89t97.5 -137l105 -454q23 -102 23 -223z" />
+ <glyph glyph-name="_488" unicode="&#xf208;" horiz-adv-x="2048"
+d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327
+q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5 -319.5t-175.5 -263t-262.5 -176t-319.5 -65.5
+q-246 0 -448.5 133t-301.5 350h-189q-36 0 -61 25t-25 61q0 35 25 60t61 25h132q-17 85 -17 170q0 167 65.5 319.5t175.5 263t262.5 176t320.5 65.5q245 0 447.5 -133t301.5 -350h188q36 0 61 -25t25 -61z" />
+ <glyph glyph-name="_489" unicode="&#xf209;" horiz-adv-x="1280"
+d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q17 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119
+t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169 152 427q0 43 -1 67t-11.5 62t-30.5 56q-56 49 -211.5 75.5
+t-270.5 26.5q-37 0 -49 -11q-12 -5 -12 -35q0 -34 21.5 -60t55.5 -40t77.5 -23.5t87.5 -11.5t85 -4t70 0h23q24 0 40 -19q15 -19 19 -55q-28 -28 -96 -54q-61 -22 -93 -46q-64 -46 -108.5 -114t-44.5 -137q0 -31 18.5 -88.5t18.5 -87.5l-3 -12q-4 -12 -4 -14
+q-137 10 -146 216q-8 -2 -41 -2q2 -7 2 -21q0 -53 -40.5 -89.5t-94.5 -36.5q-82 0 -166.5 78t-84.5 159q0 34 33 67q52 -64 60 -76q77 -104 133 -104q12 0 26.5 8.5t14.5 20.5q0 34 -87.5 145t-116.5 111q-43 0 -70 -44.5t-27 -90.5zM11 264q0 101 42.5 163t136.5 88
+q-28 74 -28 104q0 62 61 123t122 61q29 0 70 -15q-163 462 -163 567q0 80 41 130.5t119 50.5q131 0 325 -581q6 -17 8 -23q6 16 29 79.5t43.5 118.5t54 127.5t64.5 123t70.5 86.5t76.5 36q71 0 112 -49t41 -122q0 -108 -159 -550q61 -15 100.5 -46t58.5 -78t26 -93.5
+t7 -110.5q0 -150 -47 -280t-132 -225t-211 -150t-278 -55q-111 0 -223 42q-149 57 -258 191.5t-109 286.5z" />
+ <glyph glyph-name="_490" unicode="&#xf20a;" horiz-adv-x="2048"
+d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206
+q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65.5 -18q49 0 76.5 38t33.5 101zM1856 647q0 207 -15.5 307
+t-60.5 161q-6 8 -13.5 14t-21.5 15t-16 11q-86 63 -697 63q-625 0 -710 -63q-5 -4 -17.5 -11.5t-21 -14t-14.5 -14.5q-45 -60 -60 -159.5t-15 -308.5q0 -208 15 -307.5t60 -160.5q6 -8 15 -15t20.5 -14t17.5 -12q44 -33 239.5 -49t470.5 -16q610 0 697 65q5 4 17 11t20.5 14
+t13.5 16q46 60 61 159t15 309zM2048 1408v-1536h-2048v1536h2048z" />
+ <glyph glyph-name="_491" unicode="&#xf20b;"
+d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5
+t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="_492" unicode="&#xf20c;"
+d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55
+q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -86 -32.5t-33 -85.5v-410
+q0 -21 22 -21h55q21 0 21 21v180q31 -42 94 -42h191q53 0 86 32.5t33 85.5zM1536 1176v-1072q0 -96 -68 -164t-164 -68h-1072q-96 0 -164 68t-68 164v1072q0 96 68 164t164 68h1072q96 0 164 -68t68 -164z" />
+ <glyph glyph-name="_493" unicode="&#xf20d;"
+d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" />
+ <glyph glyph-name="_494" unicode="&#xf20e;" horiz-adv-x="2048"
+d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335
+q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t43 -21h398q18 21 44 21q23 0 40 -16.5t17 -40.5
+q0 -6 -4 -18l207 -358q23 -1 39 -17.5t16 -38.5q0 -13 -7 -27l187 -324q19 -4 31.5 -19.5t12.5 -35.5zM1063 -158h389l-342 354h-143l-342 -354h360q18 16 39 16t39 -16zM112 654q1 -4 1 -13q0 -10 -2 -15l208 -360l15 -6l188 199v347l-187 194q-13 -8 -29 -10zM986 1438
+h-388l190 -200l554 200h-280q-16 -16 -38 -16t-38 16zM1689 226q1 6 5 11l-64 68l-17 -79h76zM1583 226l22 105l-252 266l-296 -307l63 -64h463zM1495 -142l16 28l65 310h-427l333 -343q8 4 13 5zM578 -158h5l342 354h-373v-335l4 -6q14 -5 22 -13zM552 226h402l64 66
+l-309 321l-157 -166v-221zM359 226h163v189l-168 -177q4 -8 5 -12zM358 1051q0 -1 0.5 -2t0.5 -2q0 -16 -8 -29l171 -177v269zM552 1121v-311l153 -157l297 314l-223 236zM556 1425l-4 -8v-264l205 74l-191 201q-6 -2 -10 -3zM1447 1438h-16l-621 -224l213 -225zM1023 946
+l-297 -315l311 -319l296 307zM688 634l-136 141v-284zM1038 270l-42 -44h85zM1374 618l238 -251l132 624l-3 5l-1 1zM1718 1018q-8 13 -8 29v2l-216 376q-5 1 -13 5l-437 -463l310 -327zM522 1142v223l-163 -282zM522 196h-163l163 -283v283zM1607 196l-48 -227l130 227h-82
+zM1729 266l207 361q-2 10 -2 14q0 1 3 16l-171 296l-129 -612l77 -82q5 3 15 7z" />
+ <glyph glyph-name="f210" unicode="&#xf210;"
+d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" />
+ <glyph glyph-name="_496" unicode="&#xf211;"
+d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384
+q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" />
+ <glyph glyph-name="f212" unicode="&#xf212;" horiz-adv-x="2048"
+d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021
+q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-176 0 -336 -66l-114 -941q124 51 228.5 76t221.5 25
+q209 0 374 -102q172 107 374 102z" />
+ <glyph glyph-name="_498" unicode="&#xf213;" horiz-adv-x="2048"
+d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101
+q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 -284t-284 -118h-1244q-166 0 -284 118t-118 284
+q0 116 63 214.5t168 148.5q-10 34 -10 73q0 113 80.5 193.5t193.5 80.5q102 0 180 -67q45 183 194 300t338 117q149 0 275 -73.5t199.5 -199.5t73.5 -275q0 -66 -14 -122q135 -33 221 -142.5t86 -247.5z" />
+ <glyph glyph-name="_499" unicode="&#xf214;"
+d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34
+l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l105 47l15 -34l-105 -46zM259 1389v-36h-114
+v36h114zM421 1389v-36h-115v36h115zM583 1389v-36h-115v36h115zM744 1389v-36h-114v36h114zM906 1389v-36h-114v36h114zM1068 1389v-36h-115v36h115zM1230 1389v-36h-115v36h115zM1391 1389v-36h-114v36h114zM181 1049v-79h-37v115h115v-36h-78zM421 1085v-36h-115v36h115z
+M583 1085v-36h-115v36h115zM744 1085v-36h-114v36h114zM906 1085v-36h-114v36h114zM1068 1085v-36h-115v36h115zM1230 1085v-36h-115v36h115zM1355 970v79h-78v36h115v-115h-37zM1355 822v115h37v-115h-37zM1355 674v115h37v-115h-37zM1355 526v115h37v-115h-37zM1355 378
+v115h37v-115h-37zM1355 230v115h37v-115h-37zM760 265q-129 0 -221 91.5t-92 221.5q0 129 92 221t221 92q130 0 221.5 -92t91.5 -221q0 -130 -91.5 -221.5t-221.5 -91.5zM595 646q0 -36 19.5 -56.5t49.5 -25t64 -7t64 -2t49.5 -9t19.5 -30.5q0 -49 -112 -49q-97 0 -123 51
+h-3l-31 -63q67 -42 162 -42q29 0 56.5 5t55.5 16t45.5 33t17.5 53q0 46 -27.5 69.5t-67.5 27t-79.5 3t-67 5t-27.5 25.5q0 21 20.5 33t40.5 15t41 3q34 0 70.5 -11t51.5 -34h3l30 58q-3 1 -21 8.5t-22.5 9t-19.5 7t-22 7t-20 4.5t-24 4t-23 1q-29 0 -56.5 -5t-54 -16.5
+t-43 -34t-16.5 -53.5z" />
+ <glyph glyph-name="_500" unicode="&#xf215;" horiz-adv-x="2048"
+d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832
+q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" />
+ <glyph glyph-name="_501" unicode="&#xf216;" horiz-adv-x="2048"
+d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126t-103.5 132.5t-108.5 126.5t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5
+t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 -113t151.5 -153t139 -167.5t133.5 -153.5t149.5 -113
+t172.5 -43.5q102 0 168.5 61.5t66.5 162.5q0 95 -64.5 159t-159.5 64q-30 0 -81.5 -18.5t-68.5 -18.5q-20 0 -35.5 15t-15.5 35q0 18 8.5 57t8.5 59q0 159 -107.5 263t-266.5 104q-58 0 -111.5 -18.5t-84 -40.5t-55.5 -40.5t-33 -18.5q-15 0 -25.5 10.5t-10.5 25.5
+q0 19 25 46q59 67 147 103.5t182 36.5q191 0 318 -125.5t127 -315.5q0 -37 -4 -66q57 15 115 15z" />
+ <glyph glyph-name="_502" unicode="&#xf217;" horiz-adv-x="1664"
+d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5
+t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920
+q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="_503" unicode="&#xf218;" horiz-adv-x="1664"
+d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5
+t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 -7 4.5 -21.5t6 -26.5t2.5 -22q0 -16 -24 -64h920
+q26 0 45 -19t19 -45t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 14 11 39.5t29.5 59.5t20.5 38l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t20 -15.5t13 -24.5t7.5 -26.5t5.5 -29.5t4.5 -25.5h1201q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="_504" unicode="&#xf219;" horiz-adv-x="2048"
+d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20
+l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" />
+ <glyph glyph-name="_505" unicode="&#xf21a;" horiz-adv-x="2048"
+d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83
+q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83
+q19 19 45 19t45 -19l83 -83zM237 19q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -82l83 82q19 19 45 19t45 -19l83 -82l64 64v293l-210 314q-17 26 -7 56.5t40 40.5l177 58v299h128v128h256v128h256v-128h256v-128h128v-299l177 -58q30 -10 40 -40.5t-7 -56.5l-210 -314
+v-293l19 18q19 19 45 19t45 -19l83 -82l83 82q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83
+q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83zM640 1152v-128l384 128l384 -128v128h-128v128h-512v-128h-128z" />
+ <glyph glyph-name="_506" unicode="&#xf21b;"
+d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14
+t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 20.5t7.5 20.5q2 7 7.5 10.5t7.5 6.5
+q2 9 4 27zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 61 4.5 118t19 125.5t37.5 123.5t63.5 103.5t93.5 74.5l-90 220h214q-22 64 -22 128q0 12 2 32q-194 40 -194 96q0 57 210 99q17 62 51.5 134t70.5 114q32 37 76 37q30 0 84 -31t84 -31t84 31
+t84 31q44 0 76 -37q36 -42 70.5 -114t51.5 -134q210 -42 210 -99q0 -56 -194 -96q7 -81 -20 -160h214l-82 -225q63 -33 107.5 -96.5t65.5 -143.5t29 -151.5t8 -148.5z" />
+ <glyph glyph-name="_507" unicode="&#xf21c;" horiz-adv-x="2304"
+d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5
+t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5t-14 52.5q4 23 23 38t43 15h253q33 0 53 -28l70 -105
+l114 114q19 19 46 19h101q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-179l115 -172q131 63 275 36q143 -26 244 -134.5t118 -253.5zM448 128q115 0 203 72.5t111 183.5h-314q-35 0 -55 31q-18 32 -1 63l147 277q-47 13 -91 13q-132 0 -226 -94t-94 -226t94 -226
+t226 -94zM1856 128q132 0 226 94t94 226t-94 226t-226 94q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94z" />
+ <glyph glyph-name="_508" unicode="&#xf21d;"
+d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12
+q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 -44.5t91 -66.5t33 -88.5zM1024 896v-384
+q0 -26 -19 -45t-45 -19h-64v-384q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v384h-64q-26 0 -45 19t-19 45v384q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5zM928 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5
+t158.5 -65.5t65.5 -158.5z" />
+ <glyph glyph-name="_509" unicode="&#xf21e;" horiz-adv-x="1792"
+d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221
+q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124
+t127 -344z" />
+ <glyph glyph-name="venus" unicode="&#xf221;" horiz-adv-x="1280"
+d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292
+q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" />
+ <glyph glyph-name="_511" unicode="&#xf222;"
+d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-382 -383q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5
+q203 0 359 -126l382 382h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_512" unicode="&#xf223;" horiz-adv-x="1280"
+d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5
+t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -273zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5
+t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_513" unicode="&#xf224;"
+d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64
+q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 131.5t131.5 316.5t-131.5 316.5
+t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_514" unicode="&#xf225;" horiz-adv-x="1792"
+d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64
+q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l-111 112v-134q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9
+t-9 23v288q0 26 19 45t45 19h288q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-133l106 -107l86 94q9 10 22 10.5t23 -7.5l48 -44q10 -8 10.5 -21.5t-8.5 -23.5l-90 -99l57 -56q158 126 359 126t359 -126l255 254h-134q-14 0 -23 9t-9 23v64zM832 256q185 0 316.5 131.5
+t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_515" unicode="&#xf226;" horiz-adv-x="1792"
+d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23
+t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM576 512q115 0 218 57q-154 165 -154 391
+q0 224 154 391q-103 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 128v260q-137 15 -256 94q-119 -79 -256 -94v-260h512zM1216 512q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5q-115 0 -218 -57q154 -167 154 -391
+q0 -226 -154 -391q103 -57 218 -57z" />
+ <glyph glyph-name="_516" unicode="&#xf227;" horiz-adv-x="1920"
+d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230
+q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -74 93 -169q182 -9 328 -124l255 254h-134q-14 0 -23 9
+t-9 23v64zM1024 704q0 20 -4 58q-162 -25 -271 -150t-109 -292q0 -20 4 -58q162 25 271 150t109 292zM128 704q0 -168 111 -294t276 -149q-3 29 -3 59q0 210 135 369.5t338 196.5q-53 120 -163.5 193t-245.5 73q-185 0 -316.5 -131.5t-131.5 -316.5zM1088 -128
+q185 0 316.5 131.5t131.5 316.5q0 168 -111 294t-276 149q3 -28 3 -59q0 -210 -135 -369.5t-338 -196.5q53 -120 163.5 -193t245.5 -73z" />
+ <glyph glyph-name="_517" unicode="&#xf228;" horiz-adv-x="2048"
+d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23
+t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q146 97 320 97q201 0 359 -126l255 254h-134q-14 0 -23 9
+t-9 23v64zM896 391q128 131 128 313t-128 313q-128 -131 -128 -313t128 -313zM128 704q0 -185 131.5 -316.5t316.5 -131.5q117 0 218 57q-154 167 -154 391t154 391q-101 57 -218 57q-185 0 -316.5 -131.5t-131.5 -316.5zM1216 256q185 0 316.5 131.5t131.5 316.5
+t-131.5 316.5t-316.5 131.5q-117 0 -218 -57q154 -167 154 -391t-154 -391q101 -57 218 -57z" />
+ <glyph glyph-name="_518" unicode="&#xf229;"
+d="M1472 1408q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-213 -214l140 -140q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-140 141l-78 -79q126 -156 126 -359q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5
+t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5q203 0 359 -126l78 78l-172 172q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l172 -172l213 213h-261q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h416zM576 0q185 0 316.5 131.5t131.5 316.5t-131.5 316.5
+t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_519" unicode="&#xf22a;" horiz-adv-x="1280"
+d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22
+t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5
+t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_520" unicode="&#xf22b;" horiz-adv-x="2048"
+d="M1901 621q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-132q-24 -217 -187.5 -364.5t-384.5 -147.5q-167 0 -306 87t-212 236t-54 319q15 133 88 245.5
+t188 182t249 80.5q155 12 292 -52.5t224 -186t103 -271.5h132v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 -10zM576 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5
+t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_521" unicode="&#xf22c;" horiz-adv-x="1280"
+d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5
+t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+ <glyph glyph-name="_522" unicode="&#xf22d;" horiz-adv-x="1280"
+d="M1024 576q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1152 576q0 -117 -45.5 -223.5t-123 -184t-184 -123t-223.5 -45.5t-223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123
+t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5z" />
+ <glyph glyph-name="_523" unicode="&#xf22e;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="_524" unicode="&#xf22f;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="_525" unicode="&#xf230;"
+d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" />
+ <glyph glyph-name="_526" unicode="&#xf231;" horiz-adv-x="1280"
+d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5
+l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 95t38 110.5t20 111t6.5 99.5q0 173 -109.5 269.5t-285.5 96.5
+q-200 0 -334 -129.5t-134 -328.5q0 -44 12.5 -85t27 -65t27 -45.5t12.5 -30.5q0 -28 -15 -73t-37 -45q-2 0 -17 3q-51 15 -90.5 56t-61 94.5t-32.5 108t-11 106.5z" />
+ <glyph glyph-name="_527" unicode="&#xf232;"
+d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5
+t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 -200.5t-50 -243.5q0 -203 120 -368l-79 -233
+l242 77q158 -104 345 -104zM782 1414q153 0 292.5 -60t240.5 -161t161 -240.5t60 -292.5t-60 -292.5t-161 -240.5t-240.5 -161t-292.5 -60q-195 0 -365 94l-417 -134l136 405q-108 178 -108 389q0 153 60 292.5t161 240.5t240.5 161t292.5 60z" />
+ <glyph glyph-name="_528" unicode="&#xf233;" horiz-adv-x="1792"
+d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216
+q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" />
+ <glyph glyph-name="_529" unicode="&#xf234;" horiz-adv-x="2048"
+d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5
+t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h-874q-121 0 -194 69t-73 190q0 53 3.5 103.5t14 109t26.5 108.5
+t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q79 -61 154.5 -91.5t164.5 -30.5t164.5 30.5t154.5 91.5q20 17 39 17q132 0 217 -96h-223q-52 0 -90 -38t-38 -90v-192z" />
+ <glyph glyph-name="_530" unicode="&#xf235;" horiz-adv-x="2048"
+d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136
+q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91q0 -53 37 -90l83 -83q-21 -3 -44 -3h-874q-121 0 -194 69
+t-73 190q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q19 0 39 -17q154 -122 319 -122t319 122q20 17 39 17q28 0 57 -6q-28 -27 -41 -50t-13 -56q0 -54 37 -91z" />
+ <glyph glyph-name="_531" unicode="&#xf236;" horiz-adv-x="2048"
+d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704
+q-26 0 -45 -19t-19 -45v-384h1152z" />
+ <glyph glyph-name="_532" unicode="&#xf237;"
+d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" />
+ <glyph glyph-name="_533" unicode="&#xf238;"
+d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56
+t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" />
+ <glyph glyph-name="_534" unicode="&#xf239;"
+d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47
+t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" />
+ <glyph glyph-name="_535" unicode="&#xf23a;" horiz-adv-x="1792"
+d="M597 1115v-1173q0 -25 -12.5 -42.5t-36.5 -17.5q-17 0 -33 8l-465 233q-21 10 -35.5 33.5t-14.5 46.5v1140q0 20 10 34t29 14q14 0 44 -15l511 -256q3 -3 3 -5zM661 1014l534 -866l-534 266v600zM1792 996v-1054q0 -25 -14 -40.5t-38 -15.5t-47 13l-441 220zM1789 1116
+q0 -3 -256.5 -419.5t-300.5 -487.5l-390 634l324 527q17 28 52 28q14 0 26 -6l541 -270q4 -2 4 -6z" />
+ <glyph glyph-name="_536" unicode="&#xf23b;"
+d="M809 532l266 499h-112l-157 -312q-24 -48 -44 -92l-42 92l-155 312h-120l263 -493v-324h101v318zM1536 1408v-1536h-1536v1536h1536z" />
+ <glyph glyph-name="_537" unicode="&#xf23c;" horiz-adv-x="2296"
+d="M478 -139q-8 -16 -27 -34.5t-37 -25.5q-25 -9 -51.5 3.5t-28.5 31.5q-1 22 40 55t68 38q23 4 34 -21.5t2 -46.5zM1819 -139q7 -16 26 -34.5t38 -25.5q25 -9 51.5 3.5t27.5 31.5q2 22 -39.5 55t-68.5 38q-22 4 -33 -21.5t-2 -46.5zM1867 -30q13 -27 56.5 -59.5t77.5 -41.5
+q45 -13 82 4.5t37 50.5q0 46 -67.5 100.5t-115.5 59.5q-40 5 -63.5 -37.5t-6.5 -76.5zM428 -30q-13 -27 -56 -59.5t-77 -41.5q-45 -13 -82 4.5t-37 50.5q0 46 67.5 100.5t115.5 59.5q40 5 63 -37.5t6 -76.5zM1158 1094h1q-41 0 -76 -15q27 -8 44 -30.5t17 -49.5
+q0 -35 -27 -60t-65 -25q-52 0 -80 43q-5 -23 -5 -42q0 -74 56 -126.5t135 -52.5q80 0 136 52.5t56 126.5t-56 126.5t-136 52.5zM1462 1312q-99 109 -220.5 131.5t-245.5 -44.5q27 60 82.5 96.5t118 39.5t121.5 -17t99.5 -74.5t44.5 -131.5zM2212 73q8 -11 -11 -42
+q7 -23 7 -40q1 -56 -44.5 -112.5t-109.5 -91.5t-118 -37q-48 -2 -92 21.5t-66 65.5q-687 -25 -1259 0q-23 -41 -66.5 -65t-92.5 -22q-86 3 -179.5 80.5t-92.5 160.5q2 22 7 40q-19 31 -11 42q6 10 31 1q14 22 41 51q-7 29 2 38q11 10 39 -4q29 20 59 34q0 29 13 37
+q23 12 51 -16q35 5 61 -2q18 -4 38 -19v73q-11 0 -18 2q-53 10 -97 44.5t-55 87.5q-9 38 0 81q15 62 93 95q2 17 19 35.5t36 23.5t33 -7.5t19 -30.5h13q46 -5 60 -23q3 -3 5 -7q10 1 30.5 3.5t30.5 3.5q-15 11 -30 17q-23 40 -91 43q0 6 1 10q-62 2 -118.5 18.5t-84.5 47.5
+q-32 36 -42.5 92t-2.5 112q16 126 90 179q23 16 52 4.5t32 -40.5q0 -1 1.5 -14t2.5 -21t3 -20t5.5 -19t8.5 -10q27 -14 76 -12q48 46 98 74q-40 4 -162 -14l47 46q61 58 163 111q145 73 282 86q-20 8 -41 15.5t-47 14t-42.5 10.5t-47.5 11t-43 10q595 126 904 -139
+q98 -84 158 -222q85 -10 121 9h1q5 3 8.5 10t5.5 19t3 19.5t3 21.5l1 14q3 28 32 40t52 -5q73 -52 91 -178q7 -57 -3.5 -113t-42.5 -91q-28 -32 -83.5 -48.5t-115.5 -18.5v-10q-71 -2 -95 -43q-14 -5 -31 -17q11 -1 32 -3.5t30 -3.5q1 5 5 8q16 18 60 23h13q5 18 19 30t33 8
+t36 -23t19 -36q79 -32 93 -95q9 -40 1 -81q-12 -53 -56 -88t-97 -44q-10 -2 -17 -2q0 -49 -1 -73q20 15 38 19q26 7 61 2q28 28 51 16q14 -9 14 -37q33 -16 59 -34q27 13 38 4q10 -10 2 -38q28 -30 41 -51q23 8 31 -1zM1937 1025q0 -29 -9 -54q82 -32 112 -132
+q4 37 -9.5 98.5t-41.5 90.5q-20 19 -36 17t-16 -20zM1859 925q35 -42 47.5 -108.5t-0.5 -124.5q67 13 97 45q13 14 18 28q-3 64 -31 114.5t-79 66.5q-15 -15 -52 -21zM1822 921q-30 0 -44 1q42 -115 53 -239q21 0 43 3q16 68 1 135t-53 100zM258 839q30 100 112 132
+q-9 25 -9 54q0 18 -16.5 20t-35.5 -17q-28 -29 -41.5 -90.5t-9.5 -98.5zM294 737q29 -31 97 -45q-13 58 -0.5 124.5t47.5 108.5v0q-37 6 -52 21q-51 -16 -78.5 -66t-31.5 -115q9 -17 18 -28zM471 683q14 124 73 235q-19 -4 -55 -18l-45 -19v1q-46 -89 -20 -196q25 -3 47 -3z
+M1434 644q8 -38 16.5 -108.5t11.5 -89.5q3 -18 9.5 -21.5t23.5 4.5q40 20 62 85.5t23 125.5q-24 2 -146 4zM1152 1285q-116 0 -199 -82.5t-83 -198.5q0 -117 83 -199.5t199 -82.5t199 82.5t83 199.5q0 116 -83 198.5t-199 82.5zM1380 646q-105 2 -211 0v1q-1 -27 2.5 -86
+t13.5 -66q29 -14 93.5 -14.5t95.5 10.5q9 3 11 39t-0.5 69.5t-4.5 46.5zM1112 447q8 4 9.5 48t-0.5 88t-4 63v1q-212 -3 -214 -3q-4 -20 -7 -62t0 -83t14 -46q34 -15 101 -16t101 10zM718 636q-16 -59 4.5 -118.5t77.5 -84.5q15 -8 24 -5t12 21q3 16 8 90t10 103
+q-69 -2 -136 -6zM591 510q3 -23 -34 -36q132 -141 271.5 -240t305.5 -154q172 49 310.5 146t293.5 250q-33 13 -30 34q0 2 0.5 3.5t1.5 3t1 2.5v1v-1q-17 2 -50 5.5t-48 4.5q-26 -90 -82 -132q-51 -38 -82 1q-5 6 -9 14q-7 13 -17 62q-2 -5 -5 -9t-7.5 -7t-8 -5.5t-9.5 -4
+l-10 -2.5t-12 -2l-12 -1.5t-13.5 -1t-13.5 -0.5q-106 -9 -163 11q-4 -17 -10 -26.5t-21 -15t-23 -7t-36 -3.5q-6 -1 -9 -1q-179 -17 -203 40q-2 -63 -56 -54q-47 8 -91 54q-12 13 -20 26q-17 29 -26 65q-58 -6 -87 -10q1 -2 4 -10zM507 -118q3 14 3 30q-17 71 -51 130
+t-73 70q-41 12 -101.5 -14.5t-104.5 -80t-39 -107.5q35 -53 100 -93t119 -42q51 -2 94 28t53 79zM510 53q23 -63 27 -119q195 113 392 174q-98 52 -180.5 120t-179.5 165q-6 -4 -29 -13q0 -1 -1 -4t-1 -5q31 -18 22 -37q-12 -23 -56 -34q-10 -13 -29 -24h-1q-2 -83 1 -150
+q19 -34 35 -73zM579 -113q532 -21 1145 0q-254 147 -428 196q-76 -35 -156 -57q-8 -3 -16 0q-65 21 -129 49q-208 -60 -416 -188h-1v-1q1 0 1 1zM1763 -67q4 54 28 120q14 38 33 71l-1 -1q3 77 3 153q-15 8 -30 25q-42 9 -56 33q-9 20 22 38q-2 4 -2 9q-16 4 -28 12
+q-204 -190 -383 -284q198 -59 414 -176zM2155 -90q5 54 -39 107.5t-104 80t-102 14.5q-38 -11 -72.5 -70.5t-51.5 -129.5q0 -16 3 -30q10 -49 53 -79t94 -28q54 2 119 42t100 93z" />
+ <glyph glyph-name="_538" unicode="&#xf23d;" horiz-adv-x="2304"
+d="M1524 -25q0 -68 -48 -116t-116 -48t-116.5 48t-48.5 116t48.5 116.5t116.5 48.5t116 -48.5t48 -116.5zM775 -25q0 -68 -48.5 -116t-116.5 -48t-116 48t-48 116t48 116.5t116 48.5t116.5 -48.5t48.5 -116.5zM0 1469q57 -60 110.5 -104.5t121 -82t136 -63t166 -45.5
+t200 -31.5t250 -18.5t304 -9.5t372.5 -2.5q139 0 244.5 -5t181 -16.5t124 -27.5t71 -39.5t24 -51.5t-19.5 -64t-56.5 -76.5t-89.5 -91t-116 -104.5t-139 -119q-185 -157 -286 -247q29 51 76.5 109t94 105.5t94.5 98.5t83 91.5t54 80.5t13 70t-45.5 55.5t-116.5 41t-204 23.5
+t-304 5q-168 -2 -314 6t-256 23t-204.5 41t-159.5 51.5t-122.5 62.5t-91.5 66.5t-68 71.5t-50.5 69.5t-40 68t-36.5 59.5z" />
+ <glyph glyph-name="_539" unicode="&#xf23e;" horiz-adv-x="1792"
+d="M896 1472q-169 0 -323 -66t-265.5 -177.5t-177.5 -265.5t-66 -323t66 -323t177.5 -265.5t265.5 -177.5t323 -66t323 66t265.5 177.5t177.5 265.5t66 323t-66 323t-177.5 265.5t-265.5 177.5t-323 66zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348
+t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM496 704q16 0 16 -16v-480q0 -16 -16 -16h-32q-16 0 -16 16v480q0 16 16 16h32zM896 640q53 0 90.5 -37.5t37.5 -90.5q0 -35 -17.5 -64t-46.5 -46v-114q0 -14 -9 -23
+t-23 -9h-64q-14 0 -23 9t-9 23v114q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5zM896 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM544 928v-96
+q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 93 65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5v-96q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v96q0 146 -103 249t-249 103t-249 -103t-103 -249zM1408 192v512q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-512
+q0 -26 19 -45t45 -19h896q26 0 45 19t19 45z" />
+ <glyph glyph-name="_540" unicode="&#xf240;" horiz-adv-x="2304"
+d="M1920 1024v-768h-1664v768h1664zM2048 448h128v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288zM2304 832v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113
+v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160q53 0 90.5 -37.5t37.5 -90.5z" />
+ <glyph glyph-name="_541" unicode="&#xf241;" horiz-adv-x="2304"
+d="M256 256v768h1280v-768h-1280zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9
+h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+ <glyph glyph-name="_542" unicode="&#xf242;" horiz-adv-x="2304"
+d="M256 256v768h896v-768h-896zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9
+h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+ <glyph glyph-name="_543" unicode="&#xf243;" horiz-adv-x="2304"
+d="M256 256v768h512v-768h-512zM2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9
+h-1856q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+ <glyph glyph-name="_544" unicode="&#xf244;" horiz-adv-x="2304"
+d="M2176 960q53 0 90.5 -37.5t37.5 -90.5v-384q0 -53 -37.5 -90.5t-90.5 -37.5v-160q0 -66 -47 -113t-113 -47h-1856q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1856q66 0 113 -47t47 -113v-160zM2176 448v384h-128v288q0 14 -9 23t-23 9h-1856q-14 0 -23 -9t-9 -23
+v-960q0 -14 9 -23t23 -9h1856q14 0 23 9t9 23v288h128z" />
+ <glyph glyph-name="_545" unicode="&#xf245;" horiz-adv-x="1280"
+d="M1133 493q31 -30 14 -69q-17 -40 -59 -40h-382l201 -476q10 -25 0 -49t-34 -35l-177 -75q-25 -10 -49 0t-35 34l-191 452l-312 -312q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v1504q0 42 40 59q12 5 24 5q27 0 45 -19z" />
+ <glyph glyph-name="_546" unicode="&#xf246;" horiz-adv-x="1024"
+d="M832 1408q-320 0 -320 -224v-416h128v-128h-128v-544q0 -224 320 -224h64v-128h-64q-272 0 -384 146q-112 -146 -384 -146h-64v128h64q320 0 320 224v544h-128v128h128v416q0 224 -320 224h-64v128h64q272 0 384 -146q112 146 384 146h64v-128h-64z" />
+ <glyph glyph-name="_547" unicode="&#xf247;" horiz-adv-x="2048"
+d="M2048 1152h-128v-1024h128v-384h-384v128h-1280v-128h-384v384h128v1024h-128v384h384v-128h1280v128h384v-384zM1792 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 -128v128h-128v-128h128zM1664 0v128h128v1024h-128v128h-1280v-128h-128v-1024h128v-128
+h1280zM1920 -128v128h-128v-128h128zM1280 896h384v-768h-896v256h-384v768h896v-256zM512 512h640v512h-640v-512zM1536 256v512h-256v-384h-384v-128h640z" />
+ <glyph glyph-name="_548" unicode="&#xf248;" horiz-adv-x="2304"
+d="M2304 768h-128v-640h128v-384h-384v128h-896v-128h-384v384h128v128h-384v-128h-384v384h128v640h-128v384h384v-128h896v128h384v-384h-128v-128h384v128h384v-384zM2048 1024v-128h128v128h-128zM1408 1408v-128h128v128h-128zM128 1408v-128h128v128h-128zM256 256
+v128h-128v-128h128zM1536 384h-128v-128h128v128zM384 384h896v128h128v640h-128v128h-896v-128h-128v-640h128v-128zM896 -128v128h-128v-128h128zM2176 -128v128h-128v-128h128zM2048 128v640h-128v128h-384v-384h128v-384h-384v128h-384v-128h128v-128h896v128h128z" />
+ <glyph glyph-name="_549" unicode="&#xf249;"
+d="M1024 288v-416h-928q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68v-928h-416q-40 0 -68 -28t-28 -68zM1152 256h381q-15 -82 -65 -132l-184 -184q-50 -50 -132 -65v381z" />
+ <glyph glyph-name="_550" unicode="&#xf24a;"
+d="M1400 256h-248v-248q29 10 41 22l185 185q12 12 22 41zM1120 384h288v896h-1280v-1280h896v288q0 40 28 68t68 28zM1536 1312v-1024q0 -40 -20 -88t-48 -76l-184 -184q-28 -28 -76 -48t-88 -20h-1024q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1344q40 0 68 -28t28 -68
+z" />
+ <glyph glyph-name="_551" unicode="&#xf24b;" horiz-adv-x="2304"
+d="M1951 538q0 -26 -15.5 -44.5t-38.5 -23.5q-8 -2 -18 -2h-153v140h153q10 0 18 -2q23 -5 38.5 -23.5t15.5 -44.5zM1933 751q0 -25 -15 -42t-38 -21q-3 -1 -15 -1h-139v129h139q3 0 8.5 -0.5t6.5 -0.5q23 -4 38 -21.5t15 -42.5zM728 587v308h-228v-308q0 -58 -38 -94.5
+t-105 -36.5q-108 0 -229 59v-112q53 -15 121 -23t109 -9l42 -1q328 0 328 217zM1442 403v113q-99 -52 -200 -59q-108 -8 -169 41t-61 142t61 142t169 41q101 -7 200 -58v112q-48 12 -100 19.5t-80 9.5l-28 2q-127 6 -218.5 -14t-140.5 -60t-71 -88t-22 -106t22 -106t71 -88
+t140.5 -60t218.5 -14q101 4 208 31zM2176 518q0 54 -43 88.5t-109 39.5v3q57 8 89 41.5t32 79.5q0 55 -41 88t-107 36q-3 0 -12 0.5t-14 0.5h-455v-510h491q74 0 121.5 36.5t47.5 96.5zM2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90
+t90 38h2048q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_552" unicode="&#xf24c;" horiz-adv-x="2304"
+d="M858 295v693q-106 -41 -172 -135.5t-66 -211.5t66 -211.5t172 -134.5zM1362 641q0 117 -66 211.5t-172 135.5v-694q106 41 172 135.5t66 211.5zM1577 641q0 -159 -78.5 -294t-213.5 -213.5t-294 -78.5q-119 0 -227.5 46.5t-187 125t-125 187t-46.5 227.5q0 159 78.5 294
+t213.5 213.5t294 78.5t294 -78.5t213.5 -213.5t78.5 -294zM1960 634q0 139 -55.5 261.5t-147.5 205.5t-213.5 131t-252.5 48h-301q-176 0 -323.5 -81t-235 -230t-87.5 -335q0 -171 87 -317.5t236 -231.5t323 -85h301q129 0 251.5 50.5t214.5 135t147.5 202.5t55.5 246z
+M2304 1280v-1280q0 -52 -38 -90t-90 -38h-2048q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h2048q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_553" unicode="&#xf24d;" horiz-adv-x="1792"
+d="M1664 -96v1088q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5zM1792 992v-1088q0 -66 -47 -113t-113 -47h-1088q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113
+zM1408 1376v-160h-128v160q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5v-1088q0 -13 9.5 -22.5t22.5 -9.5h160v-128h-160q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1088q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="_554" unicode="&#xf24e;" horiz-adv-x="2304"
+d="M1728 1088l-384 -704h768zM448 1088l-384 -704h768zM1269 1280q-14 -40 -45.5 -71.5t-71.5 -45.5v-1291h608q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1344q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h608v1291q-40 14 -71.5 45.5t-45.5 71.5h-491q-14 0 -23 9t-9 23v64
+q0 14 9 23t23 9h491q21 57 70 92.5t111 35.5t111 -35.5t70 -92.5h491q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-491zM1088 1264q33 0 56.5 23.5t23.5 56.5t-23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5zM2176 384q0 -73 -46.5 -131t-117.5 -91
+t-144.5 -49.5t-139.5 -16.5t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81zM896 384q0 -73 -46.5 -131t-117.5 -91t-144.5 -49.5t-139.5 -16.5
+t-139.5 16.5t-144.5 49.5t-117.5 91t-46.5 131q0 11 35 81t92 174.5t107 195.5t102 184t56 100q18 33 56 33t56 -33q4 -7 56 -100t102 -184t107 -195.5t92 -174.5t35 -81z" />
+ <glyph glyph-name="_555" unicode="&#xf250;"
+d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9
+t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-77 -29 -149 -92.5
+t-129.5 -152.5t-92.5 -210t-35 -253h1024q0 132 -35 253t-92.5 210t-129.5 152.5t-149 92.5q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" />
+ <glyph glyph-name="_556" unicode="&#xf251;"
+d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9
+t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -66 9 -128h1006q9 61 9 128zM1280 -128q0 130 -34 249.5t-90.5 208t-126.5 152t-146 94.5h-230q-76 -31 -146 -94.5t-126.5 -152t-90.5 -208t-34 -249.5h1024z" />
+ <glyph glyph-name="_557" unicode="&#xf252;"
+d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9
+t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM1280 1408h-1024q0 -206 85 -384h854q85 178 85 384zM1223 192q-54 141 -145.5 241.5t-194.5 142.5h-230q-103 -42 -194.5 -142.5t-145.5 -241.5h910z" />
+ <glyph glyph-name="_558" unicode="&#xf253;"
+d="M1408 1408q0 -261 -106.5 -461.5t-266.5 -306.5q160 -106 266.5 -306.5t106.5 -461.5h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96q0 261 106.5 461.5t266.5 306.5q-160 106 -266.5 306.5t-106.5 461.5h-96q-14 0 -23 9
+t-9 23v64q0 14 9 23t23 9h1472q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96zM874 700q77 29 149 92.5t129.5 152.5t92.5 210t35 253h-1024q0 -132 35 -253t92.5 -210t129.5 -152.5t149 -92.5q19 -7 30.5 -23.5t11.5 -36.5t-11.5 -36.5t-30.5 -23.5q-137 -51 -244 -196
+h700q-107 145 -244 196q-19 7 -30.5 23.5t-11.5 36.5t11.5 36.5t30.5 23.5z" />
+ <glyph glyph-name="_559" unicode="&#xf254;"
+d="M1504 -64q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472zM130 0q3 55 16 107t30 95t46 87t53.5 76t64.5 69.5t66 60t70.5 55t66.5 47.5t65 43q-43 28 -65 43t-66.5 47.5t-70.5 55t-66 60t-64.5 69.5t-53.5 76t-46 87
+t-30 95t-16 107h1276q-3 -55 -16 -107t-30 -95t-46 -87t-53.5 -76t-64.5 -69.5t-66 -60t-70.5 -55t-66.5 -47.5t-65 -43q43 -28 65 -43t66.5 -47.5t70.5 -55t66 -60t64.5 -69.5t53.5 -76t46 -87t30 -95t16 -107h-1276zM1504 1536q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9
+h-1472q-14 0 -23 9t-9 23v128q0 14 9 23t23 9h1472z" />
+ <glyph glyph-name="_560" unicode="&#xf255;"
+d="M768 1152q-53 0 -90.5 -37.5t-37.5 -90.5v-128h-32v93q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-429l-32 30v172q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-224q0 -47 35 -82l310 -296q39 -39 39 -102q0 -26 19 -45t45 -19h640q26 0 45 19t19 45v25
+q0 41 10 77l108 436q10 36 10 77v246q0 48 -32 81.5t-80 33.5q-46 0 -79 -33t-33 -79v-32h-32v125q0 40 -25 72.5t-64 40.5q-14 2 -23 2q-46 0 -79 -33t-33 -79v-128h-32v122q0 51 -32.5 89.5t-82.5 43.5q-5 1 -13 1zM768 1280q84 0 149 -50q57 34 123 34q59 0 111 -27
+t86 -76q27 7 59 7q100 0 170 -71.5t70 -171.5v-246q0 -51 -13 -108l-109 -436q-6 -24 -6 -71q0 -80 -56 -136t-136 -56h-640q-84 0 -138 58.5t-54 142.5l-308 296q-76 73 -76 175v224q0 99 70.5 169.5t169.5 70.5q11 0 16 -1q6 95 75.5 160t164.5 65q52 0 98 -21
+q72 69 174 69z" />
+ <glyph glyph-name="_561" unicode="&#xf256;" horiz-adv-x="1792"
+d="M880 1408q-46 0 -79 -33t-33 -79v-656h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528v-256l-154 205q-38 51 -102 51q-53 0 -90.5 -37.5t-37.5 -90.5q0 -43 26 -77l384 -512q38 -51 102 -51h688q34 0 61 22t34 56l76 405q5 32 5 59v498q0 46 -33 79t-79 33t-79 -33
+t-33 -79v-272h-32v528q0 46 -33 79t-79 33t-79 -33t-33 -79v-528h-32v656q0 46 -33 79t-79 33zM880 1536q68 0 125.5 -35.5t88.5 -96.5q19 4 42 4q99 0 169.5 -70.5t70.5 -169.5v-17q105 6 180.5 -64t75.5 -175v-498q0 -40 -8 -83l-76 -404q-14 -79 -76.5 -131t-143.5 -52
+h-688q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 106 75 181t181 75q78 0 128 -34v434q0 99 70.5 169.5t169.5 70.5q23 0 42 -4q31 61 88.5 96.5t125.5 35.5z" />
+ <glyph glyph-name="_562" unicode="&#xf257;" horiz-adv-x="1792"
+d="M1073 -128h-177q-163 0 -226 141q-23 49 -23 102v5q-62 30 -98.5 88.5t-36.5 127.5q0 38 5 48h-261q-106 0 -181 75t-75 181t75 181t181 75h113l-44 17q-74 28 -119.5 93.5t-45.5 145.5q0 106 75 181t181 75q46 0 91 -17l628 -239h401q106 0 181 -75t75 -181v-668
+q0 -88 -54 -157.5t-140 -90.5l-339 -85q-92 -23 -186 -23zM1024 583l-155 -71l-163 -74q-30 -14 -48 -41.5t-18 -60.5q0 -46 33 -79t79 -33q26 0 46 10l338 154q-49 10 -80.5 50t-31.5 90v55zM1344 272q0 46 -33 79t-79 33q-26 0 -46 -10l-290 -132q-28 -13 -37 -17
+t-30.5 -17t-29.5 -23.5t-16 -29t-8 -40.5q0 -50 31.5 -82t81.5 -32q20 0 38 9l352 160q30 14 48 41.5t18 60.5zM1112 1024l-650 248q-24 8 -46 8q-53 0 -90.5 -37.5t-37.5 -90.5q0 -40 22.5 -73t59.5 -47l526 -200v-64h-640q-53 0 -90.5 -37.5t-37.5 -90.5t37.5 -90.5
+t90.5 -37.5h535l233 106v198q0 63 46 106l111 102h-69zM1073 0q82 0 155 19l339 85q43 11 70 45.5t27 78.5v668q0 53 -37.5 90.5t-90.5 37.5h-308l-136 -126q-36 -33 -36 -82v-296q0 -46 33 -77t79 -31t79 35t33 81v208h32v-208q0 -70 -57 -114q52 -8 86.5 -48.5t34.5 -93.5
+q0 -42 -23 -78t-61 -53l-310 -141h91z" />
+ <glyph glyph-name="_563" unicode="&#xf258;" horiz-adv-x="2048"
+d="M1151 1536q61 0 116 -28t91 -77l572 -781q118 -159 118 -359v-355q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v177l-286 143h-546q-80 0 -136 56t-56 136v32q0 119 84.5 203.5t203.5 84.5h420l42 128h-686q-100 0 -173.5 67.5t-81.5 166.5q-65 79 -65 182v32
+q0 80 56 136t136 56h959zM1920 -64v355q0 157 -93 284l-573 781q-39 52 -103 52h-959q-26 0 -45 -19t-19 -45q0 -32 1.5 -49.5t9.5 -40.5t25 -43q10 31 35.5 50t56.5 19h832v-32h-832q-26 0 -45 -19t-19 -45q0 -44 3 -58q8 -44 44 -73t81 -29h640h91q40 0 68 -28t28 -68
+q0 -15 -5 -30l-64 -192q-10 -29 -35 -47.5t-56 -18.5h-443q-66 0 -113 -47t-47 -113v-32q0 -26 19 -45t45 -19h561q16 0 29 -7l317 -158q24 -13 38.5 -36t14.5 -50v-197q0 -26 19 -45t45 -19h384q26 0 45 19t19 45z" />
+ <glyph glyph-name="_564" unicode="&#xf259;" horiz-adv-x="2048"
+d="M459 -256q-77 0 -137.5 47.5t-79.5 122.5l-101 401q-13 57 -13 108q0 45 -5 67l-116 477q-7 27 -7 57q0 93 62 161t155 78q17 85 82.5 139t152.5 54q83 0 148 -51.5t85 -132.5l83 -348l103 428q20 81 85 132.5t148 51.5q89 0 155.5 -57.5t80.5 -144.5q92 -10 152 -79
+t60 -162q0 -24 -7 -59l-123 -512q10 7 37.5 28.5t38.5 29.5t35 23t41 20.5t41.5 11t49.5 5.5q105 0 180 -74t75 -179q0 -62 -28.5 -118t-78.5 -94l-507 -380q-68 -51 -153 -51h-694zM1104 1408q-38 0 -68.5 -24t-39.5 -62l-164 -682h-127l-145 602q-9 38 -39.5 62t-68.5 24
+q-48 0 -80 -33t-32 -80q0 -15 3 -28l132 -547h-26l-99 408q-9 37 -40 62.5t-69 25.5q-47 0 -80 -33t-33 -79q0 -14 3 -26l116 -478q7 -28 9 -86t10 -88l100 -401q8 -32 34 -52.5t59 -20.5h694q42 0 76 26l507 379q56 43 56 110q0 52 -37.5 88.5t-89.5 36.5q-43 0 -77 -26
+l-307 -230v227q0 4 32 138t68 282t39 161q4 18 4 29q0 47 -32 81t-79 34q-39 0 -69.5 -24t-39.5 -62l-116 -482h-26l150 624q3 14 3 28q0 48 -31.5 82t-79.5 34z" />
+ <glyph glyph-name="_565" unicode="&#xf25a;" horiz-adv-x="1792"
+d="M640 1408q-53 0 -90.5 -37.5t-37.5 -90.5v-512v-384l-151 202q-41 54 -107 54q-52 0 -89 -38t-37 -90q0 -43 26 -77l384 -512q38 -51 102 -51h718q22 0 39.5 13.5t22.5 34.5l92 368q24 96 24 194v217q0 41 -28 71t-68 30t-68 -28t-28 -68h-32v61q0 48 -32 81.5t-80 33.5
+q-46 0 -79 -33t-33 -79v-64h-32v90q0 55 -37 94.5t-91 39.5q-53 0 -90.5 -37.5t-37.5 -90.5v-96h-32v570q0 55 -37 94.5t-91 39.5zM640 1536q107 0 181.5 -77.5t74.5 -184.5v-220q22 2 32 2q99 0 173 -69q47 21 99 21q113 0 184 -87q27 7 56 7q94 0 159 -67.5t65 -161.5
+v-217q0 -116 -28 -225l-92 -368q-16 -64 -68 -104.5t-118 -40.5h-718q-60 0 -114.5 27.5t-90.5 74.5l-384 512q-51 68 -51 154q0 105 74.5 180.5t179.5 75.5q71 0 130 -35v547q0 106 75 181t181 75zM768 128v384h-32v-384h32zM1024 128v384h-32v-384h32zM1280 128v384h-32
+v-384h32z" />
+ <glyph glyph-name="_566" unicode="&#xf25b;"
+d="M1288 889q60 0 107 -23q141 -63 141 -226v-177q0 -94 -23 -186l-85 -339q-21 -86 -90.5 -140t-157.5 -54h-668q-106 0 -181 75t-75 181v401l-239 628q-17 45 -17 91q0 106 75 181t181 75q80 0 145.5 -45.5t93.5 -119.5l17 -44v113q0 106 75 181t181 75t181 -75t75 -181
+v-261q27 5 48 5q69 0 127.5 -36.5t88.5 -98.5zM1072 896q-33 0 -60.5 -18t-41.5 -48l-74 -163l-71 -155h55q50 0 90 -31.5t50 -80.5l154 338q10 20 10 46q0 46 -33 79t-79 33zM1293 761q-22 0 -40.5 -8t-29 -16t-23.5 -29.5t-17 -30.5t-17 -37l-132 -290q-10 -20 -10 -46
+q0 -46 33 -79t79 -33q33 0 60.5 18t41.5 48l160 352q9 18 9 38q0 50 -32 81.5t-82 31.5zM128 1120q0 -22 8 -46l248 -650v-69l102 111q43 46 106 46h198l106 233v535q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5v-640h-64l-200 526q-14 37 -47 59.5t-73 22.5
+q-53 0 -90.5 -37.5t-37.5 -90.5zM1180 -128q44 0 78.5 27t45.5 70l85 339q19 73 19 155v91l-141 -310q-17 -38 -53 -61t-78 -23q-53 0 -93.5 34.5t-48.5 86.5q-44 -57 -114 -57h-208v32h208q46 0 81 33t35 79t-31 79t-77 33h-296q-49 0 -82 -36l-126 -136v-308
+q0 -53 37.5 -90.5t90.5 -37.5h668z" />
+ <glyph glyph-name="_567" unicode="&#xf25c;" horiz-adv-x="1973"
+d="M857 992v-117q0 -13 -9.5 -22t-22.5 -9h-298v-812q0 -13 -9 -22.5t-22 -9.5h-135q-13 0 -22.5 9t-9.5 23v812h-297q-13 0 -22.5 9t-9.5 22v117q0 14 9 23t23 9h793q13 0 22.5 -9.5t9.5 -22.5zM1895 995l77 -961q1 -13 -8 -24q-10 -10 -23 -10h-134q-12 0 -21 8.5
+t-10 20.5l-46 588l-189 -425q-8 -19 -29 -19h-120q-20 0 -29 19l-188 427l-45 -590q-1 -12 -10 -20.5t-21 -8.5h-135q-13 0 -23 10q-9 10 -9 24l78 961q1 12 10 20.5t21 8.5h142q20 0 29 -19l220 -520q10 -24 20 -51q3 7 9.5 24.5t10.5 26.5l221 520q9 19 29 19h141
+q13 0 22 -8.5t10 -20.5z" />
+ <glyph glyph-name="_568" unicode="&#xf25d;" horiz-adv-x="1792"
+d="M1042 833q0 88 -60 121q-33 18 -117 18h-123v-281h162q66 0 102 37t36 105zM1094 548l205 -373q8 -17 -1 -31q-8 -16 -27 -16h-152q-20 0 -28 17l-194 365h-155v-350q0 -14 -9 -23t-23 -9h-134q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h294q128 0 190 -24q85 -31 134 -109
+t49 -180q0 -92 -42.5 -165.5t-115.5 -109.5q6 -10 9 -16zM896 1376q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM1792 640
+q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="_569" unicode="&#xf25e;" horiz-adv-x="1792"
+d="M605 303q153 0 257 104q14 18 3 36l-45 82q-6 13 -24 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78
+q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-148 0 -246 -96.5t-98 -240.5q0 -146 97 -241.5t247 -95.5zM1235 303q153 0 257 104q14 18 4 36l-45 82q-8 14 -25 17q-16 2 -27 -11l-4 -3q-4 -4 -11.5 -10t-17.5 -13.5t-23.5 -14.5t-28.5 -13t-33.5 -9.5
+t-37.5 -3.5q-76 0 -125 50t-49 127q0 76 48 125.5t122 49.5q37 0 71.5 -14t50.5 -28l16 -14q11 -11 26 -10q16 2 24 14l53 78q13 20 -2 39q-3 4 -11 12t-30 23.5t-48.5 28t-67.5 22.5t-86 10q-147 0 -245.5 -96.5t-98.5 -240.5q0 -146 97 -241.5t247 -95.5zM896 1376
+q-150 0 -286 -58.5t-234.5 -157t-157 -234.5t-58.5 -286t58.5 -286t157 -234.5t234.5 -157t286 -58.5t286 58.5t234.5 157t157 234.5t58.5 286t-58.5 286t-157 234.5t-234.5 157t-286 58.5zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191
+t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71z" />
+ <glyph glyph-name="f260" unicode="&#xf260;" horiz-adv-x="2048"
+d="M736 736l384 -384l-384 -384l-672 672l672 672l168 -168l-96 -96l-72 72l-480 -480l480 -480l193 193l-289 287zM1312 1312l672 -672l-672 -672l-168 168l96 96l72 -72l480 480l-480 480l-193 -193l289 -287l-96 -96l-384 384z" />
+ <glyph glyph-name="f261" unicode="&#xf261;" horiz-adv-x="1792"
+d="M717 182l271 271l-279 279l-88 -88l192 -191l-96 -96l-279 279l279 279l40 -40l87 87l-127 128l-454 -454zM1075 190l454 454l-454 454l-271 -271l279 -279l88 88l-192 191l96 96l279 -279l-279 -279l-40 40l-87 -88zM1792 640q0 -182 -71 -348t-191 -286t-286 -191
+t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="_572" unicode="&#xf262;" horiz-adv-x="2304"
+d="M651 539q0 -39 -27.5 -66.5t-65.5 -27.5q-39 0 -66.5 27.5t-27.5 66.5q0 38 27.5 65.5t66.5 27.5q38 0 65.5 -27.5t27.5 -65.5zM1805 540q0 -39 -27.5 -66.5t-66.5 -27.5t-66.5 27.5t-27.5 66.5t27.5 66t66.5 27t66.5 -27t27.5 -66zM765 539q0 79 -56.5 136t-136.5 57
+t-136.5 -56.5t-56.5 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM1918 540q0 80 -56.5 136.5t-136.5 56.5q-79 0 -136 -56.5t-57 -136.5t56.5 -136.5t136.5 -56.5t136.5 56.5t56.5 136.5zM850 539q0 -116 -81.5 -197.5t-196.5 -81.5q-116 0 -197.5 82t-81.5 197
+t82 196.5t197 81.5t196.5 -81.5t81.5 -196.5zM2004 540q0 -115 -81.5 -196.5t-197.5 -81.5q-115 0 -196.5 81.5t-81.5 196.5t81.5 196.5t196.5 81.5q116 0 197.5 -81.5t81.5 -196.5zM1040 537q0 191 -135.5 326.5t-326.5 135.5q-125 0 -231 -62t-168 -168.5t-62 -231.5
+t62 -231.5t168 -168.5t231 -62q191 0 326.5 135.5t135.5 326.5zM1708 1110q-254 111 -556 111q-319 0 -573 -110q117 0 223 -45.5t182.5 -122.5t122 -183t45.5 -223q0 115 43.5 219.5t118 180.5t177.5 123t217 50zM2187 537q0 191 -135 326.5t-326 135.5t-326.5 -135.5
+t-135.5 -326.5t135.5 -326.5t326.5 -135.5t326 135.5t135 326.5zM1921 1103h383q-44 -51 -75 -114.5t-40 -114.5q110 -151 110 -337q0 -156 -77 -288t-209 -208.5t-287 -76.5q-133 0 -249 56t-196 155q-47 -56 -129 -179q-11 22 -53.5 82.5t-74.5 97.5
+q-80 -99 -196.5 -155.5t-249.5 -56.5q-155 0 -287 76.5t-209 208.5t-77 288q0 186 110 337q-9 51 -40 114.5t-75 114.5h365q149 100 355 156.5t432 56.5q224 0 421 -56t348 -157z" />
+ <glyph glyph-name="f263" unicode="&#xf263;" horiz-adv-x="1280"
+d="M640 629q-188 0 -321 133t-133 320q0 188 133 321t321 133t321 -133t133 -321q0 -187 -133 -320t-321 -133zM640 1306q-92 0 -157.5 -65.5t-65.5 -158.5q0 -92 65.5 -157.5t157.5 -65.5t157.5 65.5t65.5 157.5q0 93 -65.5 158.5t-157.5 65.5zM1163 574q13 -27 15 -49.5
+t-4.5 -40.5t-26.5 -38.5t-42.5 -37t-61.5 -41.5q-115 -73 -315 -94l73 -72l267 -267q30 -31 30 -74t-30 -73l-12 -13q-31 -30 -74 -30t-74 30q-67 68 -267 268l-267 -268q-31 -30 -74 -30t-73 30l-12 13q-31 30 -31 73t31 74l267 267l72 72q-203 21 -317 94
+q-39 25 -61.5 41.5t-42.5 37t-26.5 38.5t-4.5 40.5t15 49.5q10 20 28 35t42 22t56 -2t65 -35q5 -4 15 -11t43 -24.5t69 -30.5t92 -24t113 -11q91 0 174 25.5t120 50.5l38 25q33 26 65 35t56 2t42 -22t28 -35z" />
+ <glyph glyph-name="_574" unicode="&#xf264;"
+d="M927 956q0 -66 -46.5 -112.5t-112.5 -46.5t-112.5 46.5t-46.5 112.5t46.5 112.5t112.5 46.5t112.5 -46.5t46.5 -112.5zM1141 593q-10 20 -28 32t-47.5 9.5t-60.5 -27.5q-10 -8 -29 -20t-81 -32t-127 -20t-124 18t-86 36l-27 18q-31 25 -60.5 27.5t-47.5 -9.5t-28 -32
+q-22 -45 -2 -74.5t87 -73.5q83 -53 226 -67l-51 -52q-142 -142 -191 -190q-22 -22 -22 -52.5t22 -52.5l9 -9q22 -22 52.5 -22t52.5 22l191 191q114 -115 191 -191q22 -22 52.5 -22t52.5 22l9 9q22 22 22 52.5t-22 52.5l-191 190l-52 52q141 14 225 67q67 44 87 73.5t-2 74.5
+zM1092 956q0 134 -95 229t-229 95t-229 -95t-95 -229t95 -229t229 -95t229 95t95 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="_575" unicode="&#xf265;" horiz-adv-x="1720"
+d="M1565 1408q65 0 110 -45.5t45 -110.5v-519q0 -176 -68 -336t-182.5 -275t-274 -182.5t-334.5 -67.5q-176 0 -335.5 67.5t-274.5 182.5t-183 275t-68 336v519q0 64 46 110t110 46h1409zM861 344q47 0 82 33l404 388q37 35 37 85q0 49 -34.5 83.5t-83.5 34.5q-47 0 -82 -33
+l-323 -310l-323 310q-35 33 -81 33q-49 0 -83.5 -34.5t-34.5 -83.5q0 -51 36 -85l405 -388q33 -33 81 -33z" />
+ <glyph glyph-name="_576" unicode="&#xf266;" horiz-adv-x="2304"
+d="M1494 -103l-295 695q-25 -49 -158.5 -305.5t-198.5 -389.5q-1 -1 -27.5 -0.5t-26.5 1.5q-82 193 -255.5 587t-259.5 596q-21 50 -66.5 107.5t-103.5 100.5t-102 43q0 5 -0.5 24t-0.5 27h583v-50q-39 -2 -79.5 -16t-66.5 -43t-10 -64q26 -59 216.5 -499t235.5 -540
+q31 61 140 266.5t131 247.5q-19 39 -126 281t-136 295q-38 69 -201 71v50l513 -1v-47q-60 -2 -93.5 -25t-12.5 -69q33 -70 87 -189.5t86 -187.5q110 214 173 363q24 55 -10 79.5t-129 26.5q1 7 1 25v24q64 0 170.5 0.5t180 1t92.5 0.5v-49q-62 -2 -119 -33t-90 -81
+l-213 -442q13 -33 127.5 -290t121.5 -274l441 1017q-14 38 -49.5 62.5t-65 31.5t-55.5 8v50l460 -4l1 -2l-1 -44q-139 -4 -201 -145q-526 -1216 -559 -1291h-49z" />
+ <glyph glyph-name="_577" unicode="&#xf267;" horiz-adv-x="1792"
+d="M949 643q0 -26 -16.5 -45t-41.5 -19q-26 0 -45 16.5t-19 41.5q0 26 17 45t42 19t44 -16.5t19 -41.5zM964 585l350 581q-9 -8 -67.5 -62.5t-125.5 -116.5t-136.5 -127t-117 -110.5t-50.5 -51.5l-349 -580q7 7 67 62t126 116.5t136 127t117 111t50 50.5zM1611 640
+q0 -201 -104 -371q-3 2 -17 11t-26.5 16.5t-16.5 7.5q-13 0 -13 -13q0 -10 59 -44q-74 -112 -184.5 -190.5t-241.5 -110.5l-16 67q-1 10 -15 10q-5 0 -8 -5.5t-2 -9.5l16 -68q-72 -15 -146 -15q-199 0 -372 105q1 2 13 20.5t21.5 33.5t9.5 19q0 13 -13 13q-6 0 -17 -14.5
+t-22.5 -34.5t-13.5 -23q-113 75 -192 187.5t-110 244.5l69 15q10 3 10 15q0 5 -5.5 8t-10.5 2l-68 -15q-14 72 -14 139q0 206 109 379q2 -1 18.5 -12t30 -19t17.5 -8q13 0 13 12q0 6 -12.5 15.5t-32.5 21.5l-20 12q77 112 189 189t244 107l15 -67q2 -10 15 -10q5 0 8 5.5
+t2 10.5l-15 66q71 13 134 13q204 0 379 -109q-39 -56 -39 -65q0 -13 12 -13q11 0 48 64q111 -75 187.5 -186t107.5 -241l-56 -12q-10 -2 -10 -16q0 -5 5.5 -8t9.5 -2l57 13q14 -72 14 -140zM1696 640q0 163 -63.5 311t-170.5 255t-255 170.5t-311 63.5t-311 -63.5
+t-255 -170.5t-170.5 -255t-63.5 -311t63.5 -311t170.5 -255t255 -170.5t311 -63.5t311 63.5t255 170.5t170.5 255t63.5 311zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191
+t191 -286t71 -348z" />
+ <glyph glyph-name="_578" unicode="&#xf268;" horiz-adv-x="1792"
+d="M893 1536q240 2 451 -120q232 -134 352 -372l-742 39q-160 9 -294 -74.5t-185 -229.5l-276 424q128 159 311 245.5t383 87.5zM146 1131l337 -663q72 -143 211 -217t293 -45l-230 -451q-212 33 -385 157.5t-272.5 316t-99.5 411.5q0 267 146 491zM1732 962
+q58 -150 59.5 -310.5t-48.5 -306t-153 -272t-246 -209.5q-230 -133 -498 -119l405 623q88 131 82.5 290.5t-106.5 277.5zM896 942q125 0 213.5 -88.5t88.5 -213.5t-88.5 -213.5t-213.5 -88.5t-213.5 88.5t-88.5 213.5t88.5 213.5t213.5 88.5z" />
+ <glyph glyph-name="_579" unicode="&#xf269;" horiz-adv-x="1792"
+d="M903 -256q-283 0 -504.5 150.5t-329.5 398.5q-58 131 -67 301t26 332.5t111 312t179 242.5l-11 -281q11 14 68 15.5t70 -15.5q42 81 160.5 138t234.5 59q-54 -45 -119.5 -148.5t-58.5 -163.5q25 -8 62.5 -13.5t63 -7.5t68 -4t50.5 -3q15 -5 9.5 -45.5t-30.5 -75.5
+q-5 -7 -16.5 -18.5t-56.5 -35.5t-101 -34l15 -189l-139 67q-18 -43 -7.5 -81.5t36 -66.5t65.5 -41.5t81 -6.5q51 9 98 34.5t83.5 45t73.5 17.5q61 -4 89.5 -33t19.5 -65q-1 -2 -2.5 -5.5t-8.5 -12.5t-18 -15.5t-31.5 -10.5t-46.5 -1q-60 -95 -144.5 -135.5t-209.5 -29.5
+q74 -61 162.5 -82.5t168.5 -6t154.5 52t128 87.5t80.5 104q43 91 39 192.5t-37.5 188.5t-78.5 125q87 -38 137 -79.5t77 -112.5q15 170 -57.5 343t-209.5 284q265 -77 412 -279.5t151 -517.5q2 -127 -40.5 -255t-123.5 -238t-189 -196t-247.5 -135.5t-288.5 -49.5z" />
+ <glyph glyph-name="_580" unicode="&#xf26a;" horiz-adv-x="1792"
+d="M1493 1308q-165 110 -359 110q-155 0 -293 -73t-240 -200q-75 -93 -119.5 -218t-48.5 -266v-42q4 -141 48.5 -266t119.5 -218q102 -127 240 -200t293 -73q194 0 359 110q-121 -108 -274.5 -168t-322.5 -60q-29 0 -43 1q-175 8 -333 82t-272 193t-181 281t-67 339
+q0 182 71 348t191 286t286 191t348 71h3q168 -1 320.5 -60.5t273.5 -167.5zM1792 640q0 -192 -77 -362.5t-213 -296.5q-104 -63 -222 -63q-137 0 -255 84q154 56 253.5 233t99.5 405q0 227 -99 404t-253 234q119 83 254 83q119 0 226 -65q135 -125 210.5 -295t75.5 -361z
+" />
+ <glyph glyph-name="_581" unicode="&#xf26b;" horiz-adv-x="1792"
+d="M1792 599q0 -56 -7 -104h-1151q0 -146 109.5 -244.5t257.5 -98.5q99 0 185.5 46.5t136.5 130.5h423q-56 -159 -170.5 -281t-267.5 -188.5t-321 -66.5q-187 0 -356 83q-228 -116 -394 -116q-237 0 -237 263q0 115 45 275q17 60 109 229q199 360 475 606
+q-184 -79 -427 -354q63 274 283.5 449.5t501.5 175.5q30 0 45 -1q255 117 433 117q64 0 116 -13t94.5 -40.5t66.5 -76.5t24 -115q0 -116 -75 -286q101 -182 101 -390zM1722 1239q0 83 -53 132t-137 49q-108 0 -254 -70q121 -47 222.5 -131.5t170.5 -195.5q51 135 51 216z
+M128 2q0 -86 48.5 -132.5t134.5 -46.5q115 0 266 83q-122 72 -213.5 183t-137.5 245q-98 -205 -98 -332zM632 715h728q-5 142 -113 237t-251 95q-144 0 -251.5 -95t-112.5 -237z" />
+ <glyph glyph-name="_582" unicode="&#xf26c;" horiz-adv-x="2048"
+d="M1792 288v960q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1248v-960q0 -66 -47 -113t-113 -47h-736v-128h352q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23
+v64q0 14 9 23t23 9h352v128h-736q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="_583" unicode="&#xf26d;" horiz-adv-x="1792"
+d="M138 1408h197q-70 -64 -126 -149q-36 -56 -59 -115t-30 -125.5t-8.5 -120t10.5 -132t21 -126t28 -136.5q4 -19 6 -28q51 -238 81 -329q57 -171 152 -275h-272q-48 0 -82 34t-34 82v1304q0 48 34 82t82 34zM1346 1408h308q48 0 82 -34t34 -82v-1304q0 -48 -34 -82t-82 -34
+h-178q212 210 196 565l-469 -101q-2 -45 -12 -82t-31 -72t-59.5 -59.5t-93.5 -36.5q-123 -26 -199 40q-32 27 -53 61t-51.5 129t-64.5 258q-35 163 -45.5 263t-5.5 139t23 77q20 41 62.5 73t102.5 45q45 12 83.5 6.5t67 -17t54 -35t43 -48t34.5 -56.5l468 100
+q-68 175 -180 287z" />
+ <glyph glyph-name="_584" unicode="&#xf26e;"
+d="M1401 -11l-6 -6q-113 -113 -259 -175q-154 -64 -317 -64q-165 0 -317 64q-148 63 -259 175q-113 112 -175 258q-42 103 -54 189q-4 28 48 36q51 8 56 -20q1 -1 1 -4q18 -90 46 -159q50 -124 152 -226q98 -98 226 -152q132 -56 276 -56q143 0 276 56q128 55 225 152l6 6
+q10 10 25 6q12 -3 33 -22q36 -37 17 -58zM929 604l-66 -66l63 -63q21 -21 -7 -49q-17 -17 -32 -17q-10 0 -19 10l-62 61l-66 -66q-5 -5 -15 -5q-15 0 -31 16l-2 2q-18 15 -18 29q0 7 8 17l66 65l-66 66q-16 16 14 45q18 18 31 18q6 0 13 -5l65 -66l65 65q18 17 48 -13
+q27 -27 11 -44zM1400 547q0 -118 -46 -228q-45 -105 -126 -186q-80 -80 -187 -126t-228 -46t-228 46t-187 126q-82 82 -125 186q-15 33 -15 40h-1q-9 27 43 44q50 16 60 -12q37 -99 97 -167h1v339v2q3 136 102 232q105 103 253 103q147 0 251 -103t104 -249
+q0 -147 -104.5 -251t-250.5 -104q-58 0 -112 16q-28 11 -13 61q16 51 44 43l14 -3q14 -3 33 -6t30 -3q104 0 176 71.5t72 174.5q0 101 -72 171q-71 71 -175 71q-107 0 -178 -80q-64 -72 -64 -160v-413q110 -67 242 -67q96 0 185 36.5t156 103.5t103.5 155t36.5 183
+q0 198 -141 339q-140 140 -339 140q-200 0 -340 -140q-53 -53 -77 -87l-2 -2q-8 -11 -13 -15.5t-21.5 -9.5t-38.5 3q-21 5 -36.5 16.5t-15.5 26.5v680q0 15 10.5 26.5t27.5 11.5h877q30 0 30 -55t-30 -55h-811v-483h1q40 42 102 84t108 61q109 46 231 46q121 0 228 -46
+t187 -126q81 -81 126 -186q46 -112 46 -229zM1369 1128q9 -8 9 -18t-5.5 -18t-16.5 -21q-26 -26 -39 -26q-9 0 -16 7q-106 91 -207 133q-128 56 -276 56q-133 0 -262 -49q-27 -10 -45 37q-9 25 -8 38q3 16 16 20q130 57 299 57q164 0 316 -64q137 -58 235 -152z" />
+ <glyph glyph-name="_585" unicode="&#xf270;" horiz-adv-x="1792"
+d="M1551 60q15 6 26 3t11 -17.5t-15 -33.5q-13 -16 -44 -43.5t-95.5 -68t-141 -74t-188 -58t-229.5 -24.5q-119 0 -238 31t-209 76.5t-172.5 104t-132.5 105t-84 87.5q-8 9 -10 16.5t1 12t8 7t11.5 2t11.5 -4.5q192 -117 300 -166q389 -176 799 -90q190 40 391 135z
+M1758 175q11 -16 2.5 -69.5t-28.5 -102.5q-34 -83 -85 -124q-17 -14 -26 -9t0 24q21 45 44.5 121.5t6.5 98.5q-5 7 -15.5 11.5t-27 6t-29.5 2.5t-35 0t-31.5 -2t-31 -3t-22.5 -2q-6 -1 -13 -1.5t-11 -1t-8.5 -1t-7 -0.5h-5.5h-4.5t-3 0.5t-2 1.5l-1.5 3q-6 16 47 40t103 30
+q46 7 108 1t76 -24zM1364 618q0 -31 13.5 -64t32 -58t37.5 -46t33 -32l13 -11l-227 -224q-40 37 -79 75.5t-58 58.5l-19 20q-11 11 -25 33q-38 -59 -97.5 -102.5t-127.5 -63.5t-140 -23t-137.5 21t-117.5 65.5t-83 113t-31 162.5q0 84 28 154t72 116.5t106.5 83t122.5 57
+t130 34.5t119.5 18.5t99.5 6.5v127q0 65 -21 97q-34 53 -121 53q-6 0 -16.5 -1t-40.5 -12t-56 -29.5t-56 -59.5t-48 -96l-294 27q0 60 22 119t67 113t108 95t151.5 65.5t190.5 24.5q100 0 181 -25t129.5 -61.5t81 -83t45 -86t12.5 -73.5v-589zM692 597q0 -86 70 -133
+q66 -44 139 -22q84 25 114 123q14 45 14 101v162q-59 -2 -111 -12t-106.5 -33.5t-87 -71t-32.5 -114.5z" />
+ <glyph glyph-name="_586" unicode="&#xf271;" horiz-adv-x="1792"
+d="M1536 1280q52 0 90 -38t38 -90v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128zM1152 1376v-288q0 -14 9 -23t23 -9
+h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM384 1376v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM1536 -128v1024h-1408v-1024h1408zM896 448h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224
+v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224z" />
+ <glyph glyph-name="_587" unicode="&#xf272;" horiz-adv-x="1792"
+d="M1152 416v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23
+t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47
+t47 -113v-96h128q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_588" unicode="&#xf273;" horiz-adv-x="1792"
+d="M1111 151l-46 -46q-9 -9 -22 -9t-23 9l-188 189l-188 -189q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22t9 23l189 188l-189 188q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l188 -188l188 188q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23l-188 -188l188 -188q9 -10 9 -23t-9 -22z
+M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280
+q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_589" unicode="&#xf274;" horiz-adv-x="1792"
+d="M1303 572l-512 -512q-10 -9 -23 -9t-23 9l-288 288q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l220 -220l444 444q10 9 23 9t22 -9l46 -46q9 -9 9 -22t-9 -23zM128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23
+t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47
+t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+ <glyph glyph-name="_590" unicode="&#xf275;" horiz-adv-x="1792"
+d="M448 1536q26 0 45 -19t19 -45v-891l536 429q17 14 40 14q26 0 45 -19t19 -45v-379l536 429q17 14 40 14q26 0 45 -19t19 -45v-1152q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h384z" />
+ <glyph glyph-name="_591" unicode="&#xf276;" horiz-adv-x="1024"
+d="M512 448q66 0 128 15v-655q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v655q62 -15 128 -15zM512 1536q212 0 362 -150t150 -362t-150 -362t-362 -150t-362 150t-150 362t150 362t362 150zM512 1312q14 0 23 9t9 23t-9 23t-23 9q-146 0 -249 -103t-103 -249
+q0 -14 9 -23t23 -9t23 9t9 23q0 119 84.5 203.5t203.5 84.5z" />
+ <glyph glyph-name="_592" unicode="&#xf277;" horiz-adv-x="1792"
+d="M1745 1239q10 -10 10 -23t-10 -23l-141 -141q-28 -28 -68 -28h-1344q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h576v64q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-64h512q40 0 68 -28zM768 320h256v-512q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v512zM1600 768
+q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-1344q-40 0 -68 28l-141 141q-10 10 -10 23t10 23l141 141q28 28 68 28h512v192h256v-192h576z" />
+ <glyph glyph-name="_593" unicode="&#xf278;" horiz-adv-x="2048"
+d="M2020 1525q28 -20 28 -53v-1408q0 -20 -11 -36t-29 -23l-640 -256q-24 -11 -48 0l-616 246l-616 -246q-10 -5 -24 -5q-19 0 -36 11q-28 20 -28 53v1408q0 20 11 36t29 23l640 256q24 11 48 0l616 -246l616 246q32 13 60 -6zM736 1390v-1270l576 -230v1270zM128 1173
+v-1270l544 217v1270zM1920 107v1270l-544 -217v-1270z" />
+ <glyph glyph-name="_594" unicode="&#xf279;" horiz-adv-x="1792"
+d="M512 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472q0 20 17 28l480 256q7 4 15 4zM1760 1536q13 0 22.5 -9.5t9.5 -22.5v-1472q0 -20 -17 -28l-480 -256q-7 -4 -15 -4q-13 0 -22.5 9.5t-9.5 22.5v1472
+q0 20 17 28l480 256q7 4 15 4zM640 1536q8 0 14 -3l512 -256q18 -10 18 -29v-1472q0 -13 -9.5 -22.5t-22.5 -9.5q-8 0 -14 3l-512 256q-18 10 -18 29v1472q0 13 9.5 22.5t22.5 9.5z" />
+ <glyph glyph-name="_595" unicode="&#xf27a;" horiz-adv-x="1792"
+d="M640 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 640q0 53 -37.5 90.5t-90.5 37.5
+t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-110 0 -211 18q-173 -173 -435 -229q-52 -10 -86 -13q-12 -1 -22 6t-13 18q-4 15 20 37q5 5 23.5 21.5t25.5 23.5t23.5 25.5t24 31.5t20.5 37
+t20 48t14.5 57.5t12.5 72.5q-146 90 -229.5 216.5t-83.5 269.5q0 174 120 321.5t326 233t450 85.5t450 -85.5t326 -233t120 -321.5z" />
+ <glyph glyph-name="_596" unicode="&#xf27b;" horiz-adv-x="1792"
+d="M640 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 640q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 -53 -37.5 -90.5t-90.5 -37.5
+t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5
+t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51
+t27 59t26 76q-157 89 -247.5 220t-90.5 281q0 130 71 248.5t191 204.5t286 136.5t348 50.5t348 -50.5t286 -136.5t191 -204.5t71 -248.5z" />
+ <glyph glyph-name="_597" unicode="&#xf27c;" horiz-adv-x="1024"
+d="M512 345l512 295v-591l-512 -296v592zM0 640v-591l512 296zM512 1527v-591l-512 -296v591zM512 936l512 295v-591z" />
+ <glyph glyph-name="_598" unicode="&#xf27d;" horiz-adv-x="1792"
+d="M1709 1018q-10 -236 -332 -651q-333 -431 -562 -431q-142 0 -240 263q-44 160 -132 482q-72 262 -157 262q-18 0 -127 -76l-77 98q24 21 108 96.5t130 115.5q156 138 241 146q95 9 153 -55.5t81 -203.5q44 -287 66 -373q55 -249 120 -249q51 0 154 161q101 161 109 246
+q13 139 -109 139q-57 0 -121 -26q120 393 459 382q251 -8 236 -326z" />
+ <glyph glyph-name="f27e" unicode="&#xf27e;"
+d="M0 1408h1536v-1536h-1536v1536zM1085 293l-221 631l221 297h-634l221 -297l-221 -631l317 -304z" />
+ <glyph glyph-name="uniF280" unicode="&#xf280;"
+d="M0 1408h1536v-1536h-1536v1536zM908 1088l-12 -33l75 -83l-31 -114l25 -25l107 57l107 -57l25 25l-31 114l75 83l-12 33h-95l-53 96h-32l-53 -96h-95zM641 925q32 0 44.5 -16t11.5 -63l174 21q0 55 -17.5 92.5t-50.5 56t-69 25.5t-85 7q-133 0 -199 -57.5t-66 -182.5v-72
+h-96v-128h76q20 0 20 -8v-382q0 -14 -5 -20t-18 -7l-73 -7v-88h448v86l-149 14q-6 1 -8.5 1.5t-3.5 2.5t-0.5 4t1 7t0.5 10v387h191l38 128h-231q-6 0 -2 6t4 9v80q0 27 1.5 40.5t7.5 28t19.5 20t36.5 5.5zM1248 96v86l-54 9q-7 1 -9.5 2.5t-2.5 3t1 7.5t1 12v520h-275
+l-23 -101l83 -22q23 -7 23 -27v-370q0 -14 -6 -18.5t-20 -6.5l-70 -9v-86h352z" />
+ <glyph glyph-name="uniF281" unicode="&#xf281;" horiz-adv-x="1792"
+d="M1792 690q0 -58 -29.5 -105.5t-79.5 -72.5q12 -46 12 -96q0 -155 -106.5 -287t-290.5 -208.5t-400 -76.5t-399.5 76.5t-290 208.5t-106.5 287q0 47 11 94q-51 25 -82 73.5t-31 106.5q0 82 58 140.5t141 58.5q85 0 145 -63q218 152 515 162l116 521q3 13 15 21t26 5
+l369 -81q18 37 54 59.5t79 22.5q62 0 106 -43.5t44 -105.5t-44 -106t-106 -44t-105.5 43.5t-43.5 105.5l-334 74l-104 -472q300 -9 519 -160q58 61 143 61q83 0 141 -58.5t58 -140.5zM418 491q0 -62 43.5 -106t105.5 -44t106 44t44 106t-44 105.5t-106 43.5q-61 0 -105 -44
+t-44 -105zM1228 136q11 11 11 26t-11 26q-10 10 -25 10t-26 -10q-41 -42 -121 -62t-160 -20t-160 20t-121 62q-11 10 -26 10t-25 -10q-11 -10 -11 -25.5t11 -26.5q43 -43 118.5 -68t122.5 -29.5t91 -4.5t91 4.5t122.5 29.5t118.5 68zM1225 341q62 0 105.5 44t43.5 106
+q0 61 -44 105t-105 44q-62 0 -106 -43.5t-44 -105.5t44 -106t106 -44z" />
+ <glyph glyph-name="_602" unicode="&#xf282;" horiz-adv-x="1792"
+d="M69 741h1q16 126 58.5 241.5t115 217t167.5 176t223.5 117.5t276.5 43q231 0 414 -105.5t294 -303.5q104 -187 104 -442v-188h-1125q1 -111 53.5 -192.5t136.5 -122.5t189.5 -57t213 -3t208 46.5t173.5 84.5v-377q-92 -55 -229.5 -92t-312.5 -38t-316 53
+q-189 73 -311.5 249t-124.5 372q-3 242 111 412t325 268q-48 -60 -78 -125.5t-46 -159.5h635q8 77 -8 140t-47 101.5t-70.5 66.5t-80.5 41t-75 20.5t-56 8.5l-22 1q-135 -5 -259.5 -44.5t-223.5 -104.5t-176 -140.5t-138 -163.5z" />
+ <glyph glyph-name="_603" unicode="&#xf283;" horiz-adv-x="2304"
+d="M0 32v608h2304v-608q0 -66 -47 -113t-113 -47h-1984q-66 0 -113 47t-47 113zM640 256v-128h384v128h-384zM256 256v-128h256v128h-256zM2144 1408q66 0 113 -47t47 -113v-224h-2304v224q0 66 47 113t113 47h1984z" />
+ <glyph glyph-name="_604" unicode="&#xf284;" horiz-adv-x="1792"
+d="M1584 246l-218 111q-74 -120 -196.5 -189t-263.5 -69q-147 0 -271 72t-196 196t-72 270q0 110 42.5 209.5t115 172t172 115t209.5 42.5q131 0 247.5 -60.5t192.5 -168.5l215 125q-110 169 -286.5 265t-378.5 96q-161 0 -308 -63t-253 -169t-169 -253t-63 -308t63 -308
+t169 -253t253 -169t308 -63q213 0 397.5 107t290.5 292zM1030 643l693 -352q-116 -253 -334.5 -400t-492.5 -147q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71q260 0 470.5 -133.5t335.5 -366.5zM1543 640h-39v-160h-96v352h136q32 0 54.5 -20
+t28.5 -48t1 -56t-27.5 -48t-57.5 -20z" />
+ <glyph glyph-name="uniF285" unicode="&#xf285;" horiz-adv-x="1792"
+d="M1427 827l-614 386l92 151h855zM405 562l-184 116v858l1183 -743zM1424 697l147 -95v-858l-532 335zM1387 718l-500 -802h-855l356 571z" />
+ <glyph glyph-name="uniF286" unicode="&#xf286;" horiz-adv-x="1792"
+d="M640 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1152 528v224q0 16 -16 16h-96q-16 0 -16 -16v-224q0 -16 16 -16h96q16 0 16 16zM1664 496v-752h-640v320q0 80 -56 136t-136 56t-136 -56t-56 -136v-320h-640v752q0 16 16 16h96
+q16 0 16 -16v-112h128v624q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 6 2.5 9.5t8.5 5t9.5 2t11.5 0t9 -0.5v391q-32 15 -32 50q0 23 16.5 39t38.5 16t38.5 -16t16.5 -39q0 -35 -32 -50v-17q45 10 83 10q21 0 59.5 -7.5t54.5 -7.5
+q17 0 47 7.5t37 7.5q16 0 16 -16v-210q0 -15 -35 -21.5t-62 -6.5q-18 0 -54.5 7.5t-55.5 7.5q-40 0 -90 -12v-133q1 0 9 0.5t11.5 0t9.5 -2t8.5 -5t2.5 -9.5v-112h128v112q0 16 16 16h96q16 0 16 -16v-112h128v112q0 16 16 16h96q16 0 16 -16v-624h128v112q0 16 16 16h96
+q16 0 16 -16z" />
+ <glyph glyph-name="_607" unicode="&#xf287;" horiz-adv-x="2304"
+d="M2288 731q16 -8 16 -27t-16 -27l-320 -192q-8 -5 -16 -5q-9 0 -16 4q-16 10 -16 28v128h-858q37 -58 83 -165q16 -37 24.5 -55t24 -49t27 -47t27 -34t31.5 -26t33 -8h96v96q0 14 9 23t23 9h320q14 0 23 -9t9 -23v-320q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v96h-96
+q-32 0 -61 10t-51 23.5t-45 40.5t-37 46t-33.5 57t-28.5 57.5t-28 60.5q-23 53 -37 81.5t-36 65t-44.5 53.5t-46.5 17h-360q-22 -84 -91 -138t-157 -54q-106 0 -181 75t-75 181t75 181t181 75q88 0 157 -54t91 -138h104q24 0 46.5 17t44.5 53.5t36 65t37 81.5q19 41 28 60.5
+t28.5 57.5t33.5 57t37 46t45 40.5t51 23.5t61 10h107q21 57 70 92.5t111 35.5q80 0 136 -56t56 -136t-56 -136t-136 -56q-62 0 -111 35.5t-70 92.5h-107q-17 0 -33 -8t-31.5 -26t-27 -34t-27 -47t-24 -49t-24.5 -55q-46 -107 -83 -165h1114v128q0 18 16 28t32 -1z" />
+ <glyph glyph-name="_608" unicode="&#xf288;" horiz-adv-x="1792"
+d="M1150 774q0 -56 -39.5 -95t-95.5 -39h-253v269h253q56 0 95.5 -39.5t39.5 -95.5zM1329 774q0 130 -91.5 222t-222.5 92h-433v-896h180v269h253q130 0 222 91.5t92 221.5zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348
+t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="_609" unicode="&#xf289;" horiz-adv-x="2304"
+d="M1645 438q0 59 -34 106.5t-87 68.5q-7 -45 -23 -92q-7 -24 -27.5 -38t-44.5 -14q-12 0 -24 3q-31 10 -45 38.5t-4 58.5q23 71 23 143q0 123 -61 227.5t-166 165.5t-228 61q-134 0 -247 -73t-167 -194q108 -28 188 -106q22 -23 22 -55t-22 -54t-54 -22t-55 22
+q-75 75 -180 75q-106 0 -181 -74.5t-75 -180.5t75 -180.5t181 -74.5h1046q79 0 134.5 55.5t55.5 133.5zM1798 438q0 -142 -100.5 -242t-242.5 -100h-1046q-169 0 -289 119.5t-120 288.5q0 153 100 267t249 136q62 184 221 298t354 114q235 0 408.5 -158.5t196.5 -389.5
+q116 -25 192.5 -118.5t76.5 -214.5zM2048 438q0 -175 -97 -319q-23 -33 -64 -33q-24 0 -43 13q-26 17 -32 48.5t12 57.5q71 104 71 233t-71 233q-18 26 -12 57t32 49t57.5 11.5t49.5 -32.5q97 -142 97 -318zM2304 438q0 -244 -134 -443q-23 -34 -64 -34q-23 0 -42 13
+q-26 18 -32.5 49t11.5 57q108 164 108 358q0 195 -108 357q-18 26 -11.5 57.5t32.5 48.5q26 18 57 12t49 -33q134 -198 134 -442z" />
+ <glyph glyph-name="_610" unicode="&#xf28a;"
+d="M1500 -13q0 -89 -63 -152.5t-153 -63.5t-153.5 63.5t-63.5 152.5q0 90 63.5 153.5t153.5 63.5t153 -63.5t63 -153.5zM1267 268q-115 -15 -192.5 -102.5t-77.5 -205.5q0 -74 33 -138q-146 -78 -379 -78q-109 0 -201 21t-153.5 54.5t-110.5 76.5t-76 85t-44.5 83
+t-23.5 66.5t-6 39.5q0 19 4.5 42.5t18.5 56t36.5 58t64 43.5t94.5 18t94 -17.5t63 -41t35.5 -53t17.5 -49t4 -33.5q0 -34 -23 -81q28 -27 82 -42t93 -17l40 -1q115 0 190 51t75 133q0 26 -9 48.5t-31.5 44.5t-49.5 41t-74 44t-93.5 47.5t-119.5 56.5q-28 13 -43 20
+q-116 55 -187 100t-122.5 102t-72 125.5t-20.5 162.5q0 78 20.5 150t66 137.5t112.5 114t166.5 77t221.5 28.5q120 0 220 -26t164.5 -67t109.5 -94t64 -105.5t19 -103.5q0 -46 -15 -82.5t-36.5 -58t-48.5 -36t-49 -19.5t-39 -5h-8h-32t-39 5t-44 14t-41 28t-37 46t-24 70.5
+t-10 97.5q-15 16 -59 25.5t-81 10.5l-37 1q-68 0 -117.5 -31t-70.5 -70t-21 -76q0 -24 5 -43t24 -46t53 -51t97 -53.5t150 -58.5q76 -25 138.5 -53.5t109 -55.5t83 -59t60.5 -59.5t41 -62.5t26.5 -62t14.5 -63.5t6 -62t1 -62.5z" />
+ <glyph glyph-name="_611" unicode="&#xf28b;"
+d="M704 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1152 352v576q0 14 -9 23t-23 9h-256q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h256q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103
+t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_612" unicode="&#xf28c;"
+d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273
+t73 -273t198 -198t273 -73zM864 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-192z" />
+ <glyph glyph-name="_613" unicode="&#xf28d;"
+d="M1088 352v576q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-576q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5
+t103 -385.5z" />
+ <glyph glyph-name="_614" unicode="&#xf28e;"
+d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM768 96q148 0 273 73t198 198t73 273t-73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273
+t73 -273t198 -198t273 -73zM480 320q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h576q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-576z" />
+ <glyph glyph-name="_615" unicode="&#xf290;" horiz-adv-x="1792"
+d="M1757 128l35 -313q3 -28 -16 -50q-19 -21 -48 -21h-1664q-29 0 -48 21q-19 22 -16 50l35 313h1722zM1664 967l86 -775h-1708l86 775q3 24 21 40.5t43 16.5h256v-128q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v128h384v-128q0 -53 37.5 -90.5t90.5 -37.5
+t90.5 37.5t37.5 90.5v128h256q25 0 43 -16.5t21 -40.5zM1280 1152v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-256q0 -26 -19 -45t-45 -19t-45 19t-19 45v256q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+ <glyph glyph-name="_616" unicode="&#xf291;" horiz-adv-x="2048"
+d="M1920 768q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5h-15l-115 -662q-8 -46 -44 -76t-82 -30h-1280q-46 0 -82 30t-44 76l-115 662h-15q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5h1792zM485 -32q26 2 43.5 22.5t15.5 46.5l-32 416q-2 26 -22.5 43.5
+t-46.5 15.5t-43.5 -22.5t-15.5 -46.5l32 -416q2 -25 20.5 -42t43.5 -17h5zM896 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1280 32v416q0 26 -19 45t-45 19t-45 -19t-19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45zM1632 27l32 416
+q2 26 -15.5 46.5t-43.5 22.5t-46.5 -15.5t-22.5 -43.5l-32 -416q-2 -26 15.5 -46.5t43.5 -22.5h5q25 0 43.5 17t20.5 42zM476 1244l-93 -412h-132l101 441q19 88 89 143.5t160 55.5h167q0 26 19 45t45 19h384q26 0 45 -19t19 -45h167q90 0 160 -55.5t89 -143.5l101 -441
+h-132l-93 412q-11 44 -45.5 72t-79.5 28h-167q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45h-167q-45 0 -79.5 -28t-45.5 -72z" />
+ <glyph glyph-name="_617" unicode="&#xf292;" horiz-adv-x="1792"
+d="M991 512l64 256h-254l-64 -256h254zM1759 1016l-56 -224q-7 -24 -31 -24h-327l-64 -256h311q15 0 25 -12q10 -14 6 -28l-56 -224q-5 -24 -31 -24h-327l-81 -328q-7 -24 -31 -24h-224q-16 0 -26 12q-9 12 -6 28l78 312h-254l-81 -328q-7 -24 -31 -24h-225q-15 0 -25 12
+q-9 12 -6 28l78 312h-311q-15 0 -25 12q-9 12 -6 28l56 224q7 24 31 24h327l64 256h-311q-15 0 -25 12q-10 14 -6 28l56 224q5 24 31 24h327l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h254l81 328q7 24 32 24h224q15 0 25 -12q9 -12 6 -28l-78 -312h311
+q15 0 25 -12q9 -12 6 -28z" />
+ <glyph glyph-name="_618" unicode="&#xf293;"
+d="M841 483l148 -148l-149 -149zM840 1094l149 -149l-148 -148zM710 -130l464 464l-306 306l306 306l-464 464v-611l-255 255l-93 -93l320 -321l-320 -321l93 -93l255 255v-611zM1429 640q0 -209 -32 -365.5t-87.5 -257t-140.5 -162.5t-181.5 -86.5t-219.5 -24.5
+t-219.5 24.5t-181.5 86.5t-140.5 162.5t-87.5 257t-32 365.5t32 365.5t87.5 257t140.5 162.5t181.5 86.5t219.5 24.5t219.5 -24.5t181.5 -86.5t140.5 -162.5t87.5 -257t32 -365.5z" />
+ <glyph glyph-name="_619" unicode="&#xf294;" horiz-adv-x="1024"
+d="M596 113l173 172l-173 172v-344zM596 823l173 172l-173 172v-344zM628 640l356 -356l-539 -540v711l-297 -296l-108 108l372 373l-372 373l108 108l297 -296v711l539 -540z" />
+ <glyph glyph-name="_620" unicode="&#xf295;"
+d="M1280 256q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM512 1024q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1536 256q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5
+t112.5 -271.5zM1440 1344q0 -20 -13 -38l-1056 -1408q-19 -26 -51 -26h-160q-26 0 -45 19t-19 45q0 20 13 38l1056 1408q19 26 51 26h160q26 0 45 -19t19 -45zM768 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5
+t271.5 -112.5t112.5 -271.5z" />
+ <glyph glyph-name="_621" unicode="&#xf296;" horiz-adv-x="1792"
+d="M104 830l792 -1015l-868 630q-18 13 -25 34.5t0 42.5l101 308v0zM566 830h660l-330 -1015v0zM368 1442l198 -612h-462l198 612q8 23 33 23t33 -23zM1688 830l101 -308q7 -21 0 -42.5t-25 -34.5l-868 -630l792 1015v0zM1688 830h-462l198 612q8 23 33 23t33 -23z" />
+ <glyph glyph-name="_622" unicode="&#xf297;" horiz-adv-x="1792"
+d="M384 704h160v224h-160v-224zM1221 372v92q-104 -36 -243 -38q-135 -1 -259.5 46.5t-220.5 122.5l1 -96q88 -80 212 -128.5t272 -47.5q129 0 238 49zM640 704h640v224h-640v-224zM1792 736q0 -187 -99 -352q89 -102 89 -229q0 -157 -129.5 -268t-313.5 -111
+q-122 0 -225 52.5t-161 140.5q-19 -1 -57 -1t-57 1q-58 -88 -161 -140.5t-225 -52.5q-184 0 -313.5 111t-129.5 268q0 127 89 229q-99 165 -99 352q0 209 120 385.5t326.5 279.5t449.5 103t449.5 -103t326.5 -279.5t120 -385.5z" />
+ <glyph glyph-name="_623" unicode="&#xf298;"
+d="M515 625v-128h-252v128h252zM515 880v-127h-252v127h252zM1273 369v-128h-341v128h341zM1273 625v-128h-672v128h672zM1273 880v-127h-672v127h672zM1408 20v1240q0 8 -6 14t-14 6h-32l-378 -256l-210 171l-210 -171l-378 256h-32q-8 0 -14 -6t-6 -14v-1240q0 -8 6 -14
+t14 -6h1240q8 0 14 6t6 14zM553 1130l185 150h-406zM983 1130l221 150h-406zM1536 1260v-1240q0 -62 -43 -105t-105 -43h-1240q-62 0 -105 43t-43 105v1240q0 62 43 105t105 43h1240q62 0 105 -43t43 -105z" />
+ <glyph glyph-name="_624" unicode="&#xf299;" horiz-adv-x="1792"
+d="M896 720q-104 196 -160 278q-139 202 -347 318q-34 19 -70 36q-89 40 -94 32t34 -38l39 -31q62 -43 112.5 -93.5t94.5 -116.5t70.5 -113t70.5 -131q9 -17 13 -25q44 -84 84 -153t98 -154t115.5 -150t131 -123.5t148.5 -90.5q153 -66 154 -60q1 3 -49 37q-53 36 -81 57
+q-77 58 -179 211t-185 310zM549 177q-76 60 -132.5 125t-98 143.5t-71 154.5t-58.5 186t-52 209t-60.5 252t-76.5 289q273 0 497.5 -36t379 -92t271 -144.5t185.5 -172.5t110 -198.5t56 -199.5t12.5 -198.5t-9.5 -173t-20 -143.5t-13 -107l323 -327h-104l-281 285
+q-22 -2 -91.5 -14t-121.5 -19t-138 -6t-160.5 17t-167.5 59t-179 111z" />
+ <glyph glyph-name="_625" unicode="&#xf29a;" horiz-adv-x="1792"
+d="M1374 879q-6 26 -28.5 39.5t-48.5 7.5q-261 -62 -401 -62t-401 62q-26 6 -48.5 -7.5t-28.5 -39.5t7.5 -48.5t39.5 -28.5q194 -46 303 -58q-2 -158 -15.5 -269t-26.5 -155.5t-41 -115.5l-9 -21q-10 -25 1 -49t36 -34q9 -4 23 -4q44 0 60 41l8 20q54 139 71 259h42
+q17 -120 71 -259l8 -20q16 -41 60 -41q14 0 23 4q25 10 36 34t1 49l-9 21q-28 71 -41 115.5t-26.5 155.5t-15.5 269q109 12 303 58q26 6 39.5 28.5t7.5 48.5zM1024 1024q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5z
+M1600 640q0 -143 -55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5zM896 1408q-156 0 -298 -61t-245 -164t-164 -245t-61 -298t61 -298
+t164 -245t245 -164t298 -61t298 61t245 164t164 245t61 298t-61 298t-164 245t-245 164t-298 61zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="_626" unicode="&#xf29b;"
+d="M1438 723q34 -35 29 -82l-44 -551q-4 -42 -34.5 -70t-71.5 -28q-6 0 -9 1q-44 3 -72.5 36.5t-25.5 77.5l35 429l-143 -8q55 -113 55 -240q0 -216 -148 -372l-137 137q91 101 91 235q0 145 -102.5 248t-247.5 103q-134 0 -236 -92l-137 138q120 114 284 141l264 300
+l-149 87l-181 -161q-33 -30 -77 -27.5t-73 35.5t-26.5 77t34.5 73l239 213q26 23 60 26.5t64 -14.5l488 -283q36 -21 48 -68q17 -67 -26 -117l-205 -232l371 20q49 3 83 -32zM1240 1180q-74 0 -126 52t-52 126t52 126t126 52t126.5 -52t52.5 -126t-52.5 -126t-126.5 -52z
+M613 -62q106 0 196 61l139 -139q-146 -116 -335 -116q-148 0 -273.5 73t-198.5 198t-73 273q0 188 116 336l139 -139q-60 -88 -60 -197q0 -145 102.5 -247.5t247.5 -102.5z" />
+ <glyph glyph-name="_627" unicode="&#xf29c;"
+d="M880 336v-160q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v160q0 14 9 23t23 9h160q14 0 23 -9t9 -23zM1136 832q0 -50 -15 -90t-45.5 -69t-52 -44t-59.5 -36q-32 -18 -46.5 -28t-26 -24t-11.5 -29v-32q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v68q0 35 10.5 64.5
+t24 47.5t39 35.5t41 25.5t44.5 21q53 25 75 43t22 49q0 42 -43.5 71.5t-95.5 29.5q-56 0 -95 -27q-29 -20 -80 -83q-9 -12 -25 -12q-11 0 -19 6l-108 82q-10 7 -12 20t5 23q122 192 349 192q129 0 238.5 -89.5t109.5 -214.5zM768 1280q-130 0 -248.5 -51t-204 -136.5
+t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5
+t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="_628" unicode="&#xf29d;" horiz-adv-x="1408"
+d="M366 1225q-64 0 -110 45.5t-46 110.5q0 64 46 109.5t110 45.5t109.5 -45.5t45.5 -109.5q0 -65 -45.5 -110.5t-109.5 -45.5zM917 583q0 -50 -30 -67.5t-63.5 -6.5t-47.5 34l-367 438q-7 12 -14 15.5t-11 1.5l-3 -3q-7 -8 4 -21l122 -139l1 -354l-161 -457
+q-67 -192 -92 -234q-15 -26 -28 -32q-50 -26 -103 -1q-29 13 -41.5 43t-9.5 57q2 17 197 618l5 416l-85 -164l35 -222q4 -24 -1 -42t-14 -27.5t-19 -16t-17 -7.5l-7 -2q-19 -3 -34.5 3t-24 16t-14 22t-7.5 19.5t-2 9.5l-46 299l211 381q23 34 113 34q75 0 107 -40l424 -521
+q7 -5 14 -17l3 -3l-1 -1q7 -13 7 -29zM514 433q43 -113 88.5 -225t69.5 -168l24 -55q36 -93 42 -125q11 -70 -36 -97q-35 -22 -66 -16t-51 22t-29 35h-1q-6 16 -8 25l-124 351zM1338 -159q31 -49 31 -57q0 -5 -3 -7q-9 -5 -14.5 0.5t-15.5 26t-16 30.5q-114 172 -423 661
+q3 -1 7 1t7 4l3 2q11 9 11 17z" />
+ <glyph glyph-name="_629" unicode="&#xf29e;" horiz-adv-x="2304"
+d="M504 542h171l-1 265zM1530 641q0 87 -50.5 140t-146.5 53h-54v-388h52q91 0 145 57t54 138zM956 1018l1 -756q0 -14 -9.5 -24t-23.5 -10h-216q-14 0 -23.5 10t-9.5 24v62h-291l-55 -81q-10 -15 -28 -15h-267q-21 0 -30.5 18t3.5 35l556 757q9 14 27 14h332q14 0 24 -10
+t10 -24zM1783 641q0 -193 -125.5 -303t-324.5 -110h-270q-14 0 -24 10t-10 24v756q0 14 10 24t24 10h268q200 0 326 -109t126 -302zM1939 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5
+t-7.5 60t-20 91.5t-41 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2123 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-45 -108t-74 -102.5h-51q38 45 66.5 104.5t41.5 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5
+h43q41 -47 72 -107t45.5 -111.5t23 -96t10.5 -70.5zM2304 640q0 -11 -0.5 -29t-8 -71.5t-21.5 -102t-44.5 -108t-73.5 -102.5h-51q38 45 66 104.5t41 112t21 98t9 72.5l1 27q0 8 -0.5 22.5t-7.5 60t-19.5 91.5t-40.5 111.5t-66 124.5h43q41 -47 72 -107t45.5 -111.5t23 -96
+t9.5 -70.5z" />
+ <glyph glyph-name="uniF2A0" unicode="&#xf2a0;" horiz-adv-x="1408"
+d="M617 -153q0 11 -13 58t-31 107t-20 69q-1 4 -5 26.5t-8.5 36t-13.5 21.5q-15 14 -51 14q-23 0 -70 -5.5t-71 -5.5q-34 0 -47 11q-6 5 -11 15.5t-7.5 20t-6.5 24t-5 18.5q-37 128 -37 255t37 255q1 4 5 18.5t6.5 24t7.5 20t11 15.5q13 11 47 11q24 0 71 -5.5t70 -5.5
+q36 0 51 14q9 8 13.5 21.5t8.5 36t5 26.5q2 9 20 69t31 107t13 58q0 22 -43.5 52.5t-75.5 42.5q-20 8 -45 8q-34 0 -98 -18q-57 -17 -96.5 -40.5t-71 -66t-46 -70t-45.5 -94.5q-6 -12 -9 -19q-49 -107 -68 -216t-19 -244t19 -244t68 -216q56 -122 83 -161q63 -91 179 -127
+l6 -2q64 -18 98 -18q25 0 45 8q32 12 75.5 42.5t43.5 52.5zM776 760q-26 0 -45 19t-19 45.5t19 45.5q37 37 37 90q0 52 -37 91q-19 19 -19 45t19 45t45 19t45 -19q75 -75 75 -181t-75 -181q-21 -19 -45 -19zM957 579q-27 0 -45 19q-19 19 -19 45t19 45q112 114 112 272
+t-112 272q-19 19 -19 45t19 45t45 19t45 -19q150 -150 150 -362t-150 -362q-18 -19 -45 -19zM1138 398q-27 0 -45 19q-19 19 -19 45t19 45q90 91 138.5 208t48.5 245t-48.5 245t-138.5 208q-19 19 -19 45t19 45t45 19t45 -19q109 -109 167 -249t58 -294t-58 -294t-167 -249
+q-18 -19 -45 -19z" />
+ <glyph glyph-name="uniF2A1" unicode="&#xf2a1;" horiz-adv-x="2176"
+d="M192 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM704 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 352
+q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 352q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1472 864q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 864
+q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM1984 1376q-66 0 -113 -47t-47 -113t47 -113t113 -47t113 47t47 113t-47 113t-113 47zM384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 192q0 -80 -56 -136
+t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 1216q0 -80 -56 -136t-136 -56
+t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 192q0 -80 -56 -136t-136 -56t-136 56
+t-56 136t56 136t136 56t136 -56t56 -136zM1664 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM2176 704q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136
+t56 136t136 56t136 -56t56 -136zM2176 1216q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z" />
+ <glyph glyph-name="uniF2A2" unicode="&#xf2a2;" horiz-adv-x="1792"
+d="M128 -192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM320 0q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM365 365l256 -256l-90 -90l-256 256zM704 384q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45z
+M1411 704q0 -59 -11.5 -108.5t-37.5 -93.5t-44 -67.5t-53 -64.5q-31 -35 -45.5 -54t-33.5 -50t-26.5 -64t-7.5 -74q0 -159 -112.5 -271.5t-271.5 -112.5q-26 0 -45 19t-19 45t19 45t45 19q106 0 181 75t75 181q0 57 11.5 105.5t37 91t43.5 66.5t52 63q40 46 59.5 72
+t37.5 74.5t18 103.5q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM896 576q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45
+t45 19t45 -19t19 -45zM1184 704q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 93 -65.5 158.5t-158.5 65.5q-92 0 -158 -65.5t-66 -158.5q0 -26 -19 -45t-45 -19t-45 19t-19 45q0 146 103 249t249 103t249 -103t103 -249zM1578 993q10 -25 -1 -49t-36 -34q-9 -4 -23 -4
+q-19 0 -35.5 11t-23.5 30q-68 178 -224 295q-21 16 -25 42t12 47q17 21 43 25t47 -12q183 -137 266 -351zM1788 1074q9 -25 -1.5 -49t-35.5 -34q-11 -4 -23 -4q-44 0 -60 41q-92 238 -297 393q-22 16 -25.5 42t12.5 47q16 22 42 25.5t47 -12.5q235 -175 341 -449z" />
+ <glyph glyph-name="uniF2A3" unicode="&#xf2a3;" horiz-adv-x="2304"
+d="M1032 576q-59 2 -84 55q-17 34 -48 53.5t-68 19.5q-53 0 -90.5 -37.5t-37.5 -90.5q0 -56 36 -89l10 -8q34 -31 82 -31q37 0 68 19.5t48 53.5q25 53 84 55zM1600 704q0 56 -36 89l-10 8q-34 31 -82 31q-37 0 -68 -19.5t-48 -53.5q-25 -53 -84 -55q59 -2 84 -55
+q17 -34 48 -53.5t68 -19.5q53 0 90.5 37.5t37.5 90.5zM1174 925q-17 -35 -55 -48t-73 4q-62 31 -134 31q-51 0 -99 -17q3 0 9.5 0.5t9.5 0.5q92 0 170.5 -50t118.5 -133q17 -36 3.5 -73.5t-49.5 -54.5q-18 -9 -39 -9q21 0 39 -9q36 -17 49.5 -54.5t-3.5 -73.5
+q-40 -83 -118.5 -133t-170.5 -50h-6q-16 2 -44 4l-290 27l-239 -120q-14 -7 -29 -7q-40 0 -57 35l-160 320q-11 23 -4 47.5t29 37.5l209 119l148 267q17 155 91.5 291.5t195.5 236.5q31 25 70.5 21.5t64.5 -34.5t21.5 -70t-34.5 -65q-70 -59 -117 -128q123 84 267 101
+q40 5 71.5 -19t35.5 -64q5 -40 -19 -71.5t-64 -35.5q-84 -10 -159 -55q46 10 99 10q115 0 218 -50q36 -18 49 -55.5t-5 -73.5zM2137 1085l160 -320q11 -23 4 -47.5t-29 -37.5l-209 -119l-148 -267q-17 -155 -91.5 -291.5t-195.5 -236.5q-26 -22 -61 -22q-45 0 -74 35
+q-25 31 -21.5 70t34.5 65q70 59 117 128q-123 -84 -267 -101q-4 -1 -12 -1q-36 0 -63.5 24t-31.5 60q-5 40 19 71.5t64 35.5q84 10 159 55q-46 -10 -99 -10q-115 0 -218 50q-36 18 -49 55.5t5 73.5q17 35 55 48t73 -4q62 -31 134 -31q51 0 99 17q-3 0 -9.5 -0.5t-9.5 -0.5
+q-92 0 -170.5 50t-118.5 133q-17 36 -3.5 73.5t49.5 54.5q18 9 39 9q-21 0 -39 9q-36 17 -49.5 54.5t3.5 73.5q40 83 118.5 133t170.5 50h6h1q14 -2 42 -4l291 -27l239 120q14 7 29 7q40 0 57 -35z" />
+ <glyph glyph-name="uniF2A4" unicode="&#xf2a4;" horiz-adv-x="1792"
+d="M1056 704q0 -26 19 -45t45 -19t45 19t19 45q0 146 -103 249t-249 103t-249 -103t-103 -249q0 -26 19 -45t45 -19t45 19t19 45q0 93 66 158.5t158 65.5t158 -65.5t66 -158.5zM835 1280q-117 0 -223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5q0 -26 19 -45t45 -19t45 19
+t19 45q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -55 -18 -103.5t-37.5 -74.5t-59.5 -72q-34 -39 -52 -63t-43.5 -66.5t-37 -91t-11.5 -105.5q0 -106 -75 -181t-181 -75q-26 0 -45 -19t-19 -45t19 -45t45 -19q159 0 271.5 112.5t112.5 271.5q0 41 7.5 74
+t26.5 64t33.5 50t45.5 54q35 41 53 64.5t44 67.5t37.5 93.5t11.5 108.5q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5zM591 561l226 -226l-579 -579q-12 -12 -29 -12t-29 12l-168 168q-12 12 -12 29t12 29zM1612 1524l168 -168q12 -12 12 -29t-12 -30l-233 -233
+l-26 -25l-71 -71q-66 153 -195 258l91 91l207 207q13 12 30 12t29 -12z" />
+ <glyph glyph-name="uniF2A5" unicode="&#xf2a5;"
+d="M866 1021q0 -27 -13 -94q-11 -50 -31.5 -150t-30.5 -150q-2 -11 -4.5 -12.5t-13.5 -2.5q-20 -2 -31 -2q-58 0 -84 49.5t-26 113.5q0 88 35 174t103 124q28 14 51 14q28 0 36.5 -16.5t8.5 -47.5zM1352 597q0 14 -39 75.5t-52 66.5q-21 8 -34 8q-91 0 -226 -77l-2 2
+q3 22 27.5 135t24.5 178q0 233 -242 233q-24 0 -68 -6q-94 -17 -168.5 -89.5t-111.5 -166.5t-37 -189q0 -146 80.5 -225t227.5 -79q25 0 25 -3t-1 -5q-4 -34 -26 -117q-14 -52 -51.5 -101t-82.5 -49q-42 0 -42 47q0 24 10.5 47.5t25 39.5t29.5 28.5t26 20t11 8.5q0 3 -7 10
+q-24 22 -58.5 36.5t-65.5 14.5q-35 0 -63.5 -34t-41 -75t-12.5 -75q0 -88 51.5 -142t138.5 -54q82 0 155 53t117.5 126t65.5 153q6 22 15.5 66.5t14.5 66.5q3 12 14 18q118 60 227 60q48 0 127 -18q1 -1 4 -1q5 0 9.5 4.5t4.5 8.5zM1536 1120v-960q0 -119 -84.5 -203.5
+t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="uniF2A6" unicode="&#xf2a6;" horiz-adv-x="1535"
+d="M744 1231q0 24 -2 38.5t-8.5 30t-21 23t-37.5 7.5q-39 0 -78 -23q-105 -58 -159 -190.5t-54 -269.5q0 -44 8.5 -85.5t26.5 -80.5t52.5 -62.5t81.5 -23.5q4 0 18 -0.5t20 0t16 3t15 8.5t7 16q16 77 48 231.5t48 231.5q19 91 19 146zM1498 575q0 -7 -7.5 -13.5t-15.5 -6.5
+l-6 1q-22 3 -62 11t-72 12.5t-63 4.5q-167 0 -351 -93q-15 -8 -21 -27q-10 -36 -24.5 -105.5t-22.5 -100.5q-23 -91 -70 -179.5t-112.5 -164.5t-154.5 -123t-185 -47q-135 0 -214.5 83.5t-79.5 219.5q0 53 19.5 117t63 116.5t97.5 52.5q38 0 120 -33.5t83 -61.5
+q0 -1 -16.5 -12.5t-39.5 -31t-46 -44.5t-39 -61t-16 -74q0 -33 16.5 -53t48.5 -20q45 0 85 31.5t66.5 78t48 105.5t32.5 107t16 90v9q0 2 -3.5 3.5t-8.5 1.5h-10t-10 -0.5t-6 -0.5q-227 0 -352 122.5t-125 348.5q0 108 34.5 221t96 210t156 167.5t204.5 89.5q52 9 106 9
+q374 0 374 -360q0 -98 -38 -273t-43 -211l3 -3q101 57 182.5 88t167.5 31q22 0 53 -13q19 -7 80 -102.5t61 -116.5z" />
+ <glyph glyph-name="uniF2A7" unicode="&#xf2a7;" horiz-adv-x="1664"
+d="M831 863q32 0 59 -18l222 -148q61 -40 110 -97l146 -170q40 -46 29 -106l-72 -413q-6 -32 -29.5 -53.5t-55.5 -25.5l-527 -56l-352 -32h-9q-39 0 -67.5 28t-28.5 68q0 37 27 64t65 32l260 32h-448q-41 0 -69.5 30t-26.5 71q2 39 32 65t69 26l442 1l-521 64q-41 5 -66 37
+t-19 73q6 35 34.5 57.5t65.5 22.5h10l481 -60l-351 94q-38 10 -62 41.5t-18 68.5q6 36 33 58.5t62 22.5q6 0 20 -2l448 -96l217 -37q1 0 3 -0.5t3 -0.5q23 0 30.5 23t-12.5 36l-186 125q-35 23 -42 63.5t18 73.5q27 38 76 38zM761 661l186 -125l-218 37l-5 2l-36 38
+l-238 262q-1 1 -2.5 3.5t-2.5 3.5q-24 31 -18.5 70t37.5 64q31 23 68 17.5t64 -33.5l142 -147q-2 -1 -5 -3.5t-4 -4.5q-32 -45 -23 -99t55 -85zM1648 1115l15 -266q4 -73 -11 -147l-48 -219q-12 -59 -67 -87l-106 -54q2 62 -39 109l-146 170q-53 61 -117 103l-222 148
+q-34 23 -76 23q-51 0 -88 -37l-235 312q-25 33 -18 73.5t41 63.5q33 22 71.5 14t62.5 -40l266 -352l-262 455q-21 35 -10.5 75t47.5 59q35 18 72.5 6t57.5 -46l241 -420l-136 337q-15 35 -4.5 74t44.5 56q37 19 76 6t56 -51l193 -415l101 -196q8 -15 23 -17.5t27 7.5t11 26
+l-12 224q-2 41 26 71t69 31q39 0 67 -28.5t30 -67.5z" />
+ <glyph glyph-name="uniF2A8" unicode="&#xf2a8;" horiz-adv-x="1792"
+d="M335 180q-2 0 -6 2q-86 57 -168.5 145t-139.5 180q-21 30 -21 69q0 9 2 19t4 18t7 18t8.5 16t10.5 17t10 15t12 15.5t11 14.5q184 251 452 365q-110 198 -110 211q0 19 17 29q116 64 128 64q18 0 28 -16l124 -229q92 19 192 19q266 0 497.5 -137.5t378.5 -369.5
+q20 -31 20 -69t-20 -69q-91 -142 -218.5 -253.5t-278.5 -175.5q110 -198 110 -211q0 -20 -17 -29q-116 -64 -127 -64q-19 0 -29 16l-124 229l-64 119l-444 820l7 7q-58 -24 -99 -47q3 -5 127 -234t243 -449t119 -223q0 -7 -9 -9q-13 -3 -72 -3q-57 0 -60 7l-456 841
+q-39 -28 -82 -68q24 -43 214 -393.5t190 -354.5q0 -10 -11 -10q-14 0 -82.5 22t-72.5 28l-106 197l-224 413q-44 -53 -78 -106q2 -3 18 -25t23 -34l176 -327q0 -10 -10 -10zM1165 282l49 -91q273 111 450 385q-180 277 -459 389q67 -64 103 -148.5t36 -176.5
+q0 -106 -47 -200.5t-132 -157.5zM848 896q0 -20 14 -34t34 -14q86 0 147 -61t61 -147q0 -20 14 -34t34 -14t34 14t14 34q0 126 -89 215t-215 89q-20 0 -34 -14t-14 -34zM1214 961l-9 4l7 -7z" />
+ <glyph glyph-name="uniF2A9" unicode="&#xf2a9;" horiz-adv-x="1280"
+d="M1050 430q0 -215 -147 -374q-148 -161 -378 -161q-232 0 -378 161q-147 159 -147 374q0 147 68 270.5t189 196.5t268 73q96 0 182 -31q-32 -62 -39 -126q-66 28 -143 28q-167 0 -280.5 -123t-113.5 -291q0 -170 112.5 -288.5t281.5 -118.5t281 118.5t112 288.5
+q0 89 -32 166q66 13 123 49q41 -98 41 -212zM846 619q0 -192 -79.5 -345t-238.5 -253l-14 -1q-29 0 -62 5q83 32 146.5 102.5t99.5 154.5t58.5 189t30 192.5t7.5 178.5q0 69 -3 103q55 -160 55 -326zM791 947v-2q-73 214 -206 440q88 -59 142.5 -186.5t63.5 -251.5z
+M1035 744q-83 0 -160 75q218 120 290 247q19 37 21 56q-42 -94 -139.5 -166.5t-204.5 -97.5q-35 54 -35 113q0 37 17 79t43 68q46 44 157 74q59 16 106 58.5t74 100.5q74 -105 74 -253q0 -109 -24 -170q-32 -77 -88.5 -130.5t-130.5 -53.5z" />
+ <glyph glyph-name="uniF2AA" unicode="&#xf2aa;"
+d="M1050 495q0 78 -28 147q-41 -25 -85 -34q22 -50 22 -114q0 -117 -77 -198.5t-193 -81.5t-193.5 81.5t-77.5 198.5q0 115 78 199.5t193 84.5q53 0 98 -19q4 43 27 87q-60 21 -125 21q-154 0 -257.5 -108.5t-103.5 -263.5t103.5 -261t257.5 -106t257.5 106.5t103.5 260.5z
+M872 850q2 -24 2 -71q0 -63 -5 -123t-20.5 -132.5t-40.5 -130t-68.5 -106t-100.5 -70.5q21 -3 42 -3h10q219 139 219 411q0 116 -38 225zM872 850q-4 80 -44 171.5t-98 130.5q92 -156 142 -302zM1207 955q0 102 -51 174q-41 -86 -124 -109q-69 -19 -109 -53.5t-40 -99.5
+q0 -40 24 -77q74 17 140.5 67t95.5 115q-4 -52 -74.5 -111.5t-138.5 -97.5q52 -52 110 -52q51 0 90 37t60 90q17 42 17 117zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5
+t84.5 -203.5z" />
+ <glyph glyph-name="uniF2AB" unicode="&#xf2ab;"
+d="M1279 388q0 22 -22 27q-67 15 -118 59t-80 108q-7 19 -7 25q0 15 19.5 26t43 17t43 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-12 0 -32 -8t-31 -8q-4 0 -12 2q5 95 5 114q0 79 -17 114q-36 78 -103 121.5t-152 43.5q-199 0 -275 -165q-17 -35 -17 -114q0 -19 5 -114
+q-4 -2 -14 -2q-12 0 -32 7.5t-30 7.5q-21 0 -38.5 -12t-17.5 -32q0 -21 19.5 -35.5t43 -20.5t43 -17t19.5 -26q0 -6 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -46 137 -68q2 -5 6 -26t11.5 -30.5t23.5 -9.5q12 0 37.5 4.5t39.5 4.5q35 0 67 -15t54 -32.5t57.5 -32.5
+t76.5 -15q43 0 79 15t57.5 32.5t53.5 32.5t67 15q14 0 39.5 -4t38.5 -4q16 0 23 10t11 30t6 25q137 22 137 68zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5
+t103 -385.5z" />
+ <glyph glyph-name="uniF2AC" unicode="&#xf2ac;" horiz-adv-x="1664"
+d="M848 1408q134 1 240.5 -68.5t163.5 -192.5q27 -58 27 -179q0 -47 -9 -191q14 -7 28 -7q18 0 51 13.5t51 13.5q29 0 56 -18t27 -46q0 -32 -31.5 -54t-69 -31.5t-69 -29t-31.5 -47.5q0 -15 12 -43q37 -82 102.5 -150t144.5 -101q28 -12 80 -23q28 -6 28 -35
+q0 -70 -219 -103q-7 -11 -11 -39t-14 -46.5t-33 -18.5q-20 0 -62 6.5t-64 6.5q-37 0 -62 -5q-32 -5 -63 -22.5t-58 -38t-58 -40.5t-76 -33.5t-99 -13.5q-52 0 -96.5 13.5t-75 33.5t-57.5 40.5t-58 38t-62 22.5q-26 5 -63 5q-24 0 -65.5 -7.5t-58.5 -7.5q-25 0 -35 18.5
+t-14 47.5t-11 40q-219 33 -219 103q0 29 28 35q52 11 80 23q78 32 144.5 101t102.5 150q12 28 12 43q0 28 -31.5 47.5t-69.5 29.5t-69.5 31.5t-31.5 52.5q0 27 26 45.5t55 18.5q15 0 48 -13t53 -13q18 0 32 7q-9 142 -9 190q0 122 27 180q64 137 172 198t264 63z" />
+ <glyph glyph-name="uniF2AD" unicode="&#xf2ad;"
+d="M1280 388q0 22 -22 27q-67 14 -118 58t-80 109q-7 14 -7 25q0 15 19.5 26t42.5 17t42.5 20.5t19.5 36.5q0 19 -18.5 31.5t-38.5 12.5q-11 0 -31 -8t-32 -8q-4 0 -12 2q5 63 5 115q0 78 -17 114q-36 78 -102.5 121.5t-152.5 43.5q-198 0 -275 -165q-18 -38 -18 -115
+q0 -38 6 -114q-10 -2 -15 -2q-11 0 -31.5 8t-30.5 8q-20 0 -37.5 -12.5t-17.5 -32.5q0 -21 19.5 -35.5t42.5 -20.5t42.5 -17t19.5 -26q0 -11 -7 -25q-64 -138 -198 -167q-22 -5 -22 -27q0 -47 138 -69q2 -5 6 -26t11 -30.5t23 -9.5q13 0 38.5 5t38.5 5q35 0 67.5 -15
+t54.5 -32.5t57.5 -32.5t76.5 -15q43 0 79 15t57.5 32.5t54 32.5t67.5 15q13 0 39 -4.5t39 -4.5q15 0 22.5 9.5t11.5 31t5 24.5q138 22 138 69zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960
+q119 0 203.5 -84.5t84.5 -203.5z" />
+ <glyph glyph-name="uniF2AE" unicode="&#xf2ae;" horiz-adv-x="2304"
+d="M2304 1536q-69 -46 -125 -92t-89 -81t-59.5 -71.5t-37.5 -57.5t-22 -44.5t-14 -29.5q-10 -18 -35.5 -136.5t-48.5 -164.5q-15 -29 -50 -60.5t-67.5 -50.5t-72.5 -41t-48 -28q-47 -31 -151 -231q-341 14 -630 -158q-92 -53 -303 -179q47 16 86 31t55 22l15 7
+q71 27 163 64.5t133.5 53.5t108 34.5t142.5 31.5q186 31 465 -7q1 0 10 -3q11 -6 14 -17t-3 -22l-194 -345q-15 -29 -47 -22q-128 24 -354 24q-146 0 -402 -44.5t-392 -46.5q-82 -1 -149 13t-107 37t-61 40t-33 34l-1 1v2q0 6 6 6q138 0 371 55q192 366 374.5 524t383.5 158
+q5 0 14.5 -0.5t38 -5t55 -12t61.5 -24.5t63 -39.5t54 -59t40 -82.5l102 177q2 4 21 42.5t44.5 86.5t61 109.5t84 133.5t100.5 137q66 82 128 141.5t121.5 96.5t92.5 53.5t88 39.5z" />
+ <glyph glyph-name="uniF2B0" unicode="&#xf2b0;"
+d="M1322 640q0 -45 -5 -76l-236 14l224 -78q-19 -73 -58 -141l-214 103l177 -158q-44 -61 -107 -108l-157 178l103 -215q-61 -37 -140 -59l-79 228l14 -240q-38 -6 -76 -6t-76 6l14 238l-78 -226q-74 19 -140 59l103 215l-157 -178q-59 43 -108 108l178 158l-214 -104
+q-39 69 -58 141l224 79l-237 -14q-5 42 -5 76q0 35 5 77l238 -14l-225 79q19 73 58 140l214 -104l-177 159q46 61 107 108l158 -178l-103 215q67 39 140 58l77 -224l-13 236q36 6 75 6q38 0 76 -6l-14 -237l78 225q74 -19 140 -59l-103 -214l158 178q61 -47 107 -108
+l-177 -159l213 104q37 -62 58 -141l-224 -78l237 14q5 -31 5 -77zM1352 640q0 160 -78.5 295.5t-213 214t-292.5 78.5q-119 0 -227 -46.5t-186.5 -125t-124.5 -187.5t-46 -229q0 -119 46 -228t124.5 -187.5t186.5 -125t227 -46.5q158 0 292.5 78.5t213 214t78.5 294.5z
+M1425 1023v-766l-657 -383l-657 383v766l657 383zM768 -183l708 412v823l-708 411l-708 -411v-823zM1536 1088v-896l-768 -448l-768 448v896l768 448z" />
+ <glyph glyph-name="uniF2B1" unicode="&#xf2b1;" horiz-adv-x="1664"
+d="M339 1318h691l-26 -72h-665q-110 0 -188.5 -79t-78.5 -189v-771q0 -95 60.5 -169.5t153.5 -93.5q23 -5 98 -5v-72h-45q-140 0 -239.5 100t-99.5 240v771q0 140 99.5 240t239.5 100zM1190 1536h247l-482 -1294q-23 -61 -40.5 -103.5t-45 -98t-54 -93.5t-64.5 -78.5
+t-79.5 -65t-95.5 -41t-116 -18.5v195q163 26 220 182q20 52 20 105q0 54 -20 106l-285 733h228l187 -585zM1664 978v-1111h-795q37 55 45 73h678v1038q0 85 -49.5 155t-129.5 99l25 67q101 -34 163.5 -123.5t62.5 -197.5z" />
+ <glyph glyph-name="uniF2B2" unicode="&#xf2b2;" horiz-adv-x="1792"
+d="M852 1227q0 -29 -17 -52.5t-45 -23.5t-45 23.5t-17 52.5t17 52.5t45 23.5t45 -23.5t17 -52.5zM688 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50 -21.5t-20 -51.5v-114q0 -30 20.5 -52t49.5 -22q30 0 50.5 22t20.5 52zM860 -149v114q0 30 -20 51.5t-50 21.5t-50.5 -21.5
+t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22q29 0 49.5 22t20.5 52zM1034 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1208 -149v114q0 30 -20.5 51.5t-50.5 21.5t-50.5 -21.5t-20.5 -51.5v-114
+q0 -30 20.5 -52t50.5 -22t50.5 22t20.5 52zM1476 535q-84 -160 -232 -259.5t-323 -99.5q-123 0 -229.5 51.5t-178.5 137t-113 197.5t-41 232q0 88 21 174q-104 -175 -104 -390q0 -162 65 -312t185 -251q30 57 91 57q56 0 86 -50q32 50 87 50q56 0 86 -50q32 50 87 50t87 -50
+q30 50 86 50q28 0 52.5 -15.5t37.5 -40.5q112 94 177 231.5t73 287.5zM1326 564q0 75 -72 75q-17 0 -47 -6q-95 -19 -149 -19q-226 0 -226 243q0 86 30 204q-83 -127 -83 -275q0 -150 89 -260.5t235 -110.5q111 0 210 70q13 48 13 79zM884 1223q0 50 -32 89.5t-81 39.5
+t-81 -39.5t-32 -89.5q0 -51 31.5 -90.5t81.5 -39.5t81.5 39.5t31.5 90.5zM1513 884q0 96 -37.5 179t-113 137t-173.5 54q-77 0 -149 -35t-127 -94q-48 -159 -48 -268q0 -104 45.5 -157t147.5 -53q53 0 142 19q36 6 53 6q51 0 77.5 -28t26.5 -80q0 -26 -4 -46
+q75 68 117.5 165.5t42.5 200.5zM1792 667q0 -111 -33.5 -249.5t-93.5 -204.5q-58 -64 -195 -142.5t-228 -104.5l-4 -1v-114q0 -43 -29.5 -75t-72.5 -32q-56 0 -86 50q-32 -50 -87 -50t-87 50q-30 -50 -86 -50q-55 0 -87 50q-30 -50 -86 -50q-47 0 -75 33.5t-28 81.5
+q-90 -68 -198 -68q-118 0 -211 80q54 1 106 20q-113 31 -182 127q32 -7 71 -7q89 0 164 46q-192 192 -240 306q-24 56 -24 160q0 57 9 125.5t31.5 146.5t55 141t86.5 105t120 42q59 0 81 -52q19 29 42 54q2 3 12 13t13 16q10 15 23 38t25 42t28 39q87 111 211.5 177
+t260.5 66q35 0 62 -4q59 64 146 64q83 0 140 -57q5 -5 5 -12q0 -5 -6 -13.5t-12.5 -16t-16 -17l-10.5 -10.5q17 -6 36 -18t19 -24q0 -6 -16 -25q157 -138 197 -378q25 30 60 30q45 0 100 -49q90 -80 90 -279z" />
+ <glyph glyph-name="uniF2B3" unicode="&#xf2b3;"
+d="M917 631q0 33 -6 64h-362v-132h217q-12 -76 -74.5 -120.5t-142.5 -44.5q-99 0 -169 71.5t-70 170.5t70 170.5t169 71.5q93 0 153 -59l104 101q-108 100 -257 100q-160 0 -272 -112.5t-112 -271.5t112 -271.5t272 -112.5q165 0 266.5 105t101.5 270zM1262 585h109v110
+h-109v110h-110v-110h-110v-110h110v-110h110v110zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+ <glyph glyph-name="uniF2B4" unicode="&#xf2b4;"
+d="M1536 1024v-839q0 -48 -49 -62q-174 -52 -338 -52q-73 0 -215.5 29.5t-227.5 29.5q-164 0 -370 -48v-338h-160v1368q-63 25 -101 81t-38 124q0 91 64 155t155 64t155 -64t64 -155q0 -68 -38 -124t-101 -81v-68q190 44 343 44q99 0 198 -15q14 -2 111.5 -22.5t149.5 -20.5
+q77 0 165 18q11 2 80 21t89 19q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="uniF2B5" unicode="&#xf2b5;" horiz-adv-x="2304"
+d="M192 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32zM1665 442q-10 13 -38.5 50t-41.5 54t-38 49t-42.5 53t-40.5 47t-45 49l-125 -140q-83 -94 -208.5 -92t-205.5 98q-57 69 -56.5 158t58.5 157l177 206q-22 11 -51 16.5t-47.5 6t-56.5 -0.5t-49 -1q-92 0 -158 -66
+l-158 -158h-155v-544q5 0 21 0.5t22 0t19.5 -2t20.5 -4.5t17.5 -8.5t18.5 -13.5l297 -292q115 -111 227 -111q78 0 125 47q57 -20 112.5 8t72.5 85q74 -6 127 44q20 18 36 45.5t14 50.5q10 -10 43 -10q43 0 77 21t49.5 53t12 71.5t-30.5 73.5zM1824 384h96v512h-93l-157 180
+q-66 76 -169 76h-167q-89 0 -146 -67l-209 -243q-28 -33 -28 -75t27 -75q43 -51 110 -52t111 49l193 218q25 23 53.5 21.5t47 -27t8.5 -56.5q16 -19 56 -63t60 -68q29 -36 82.5 -105.5t64.5 -84.5q52 -66 60 -140zM2112 384q40 0 56 32t0 64t-56 32t-56 -32t0 -64t56 -32z
+M2304 960v-640q0 -26 -19 -45t-45 -19h-434q-27 -65 -82 -106.5t-125 -51.5q-33 -48 -80.5 -81.5t-102.5 -45.5q-42 -53 -104.5 -81.5t-128.5 -24.5q-60 -34 -126 -39.5t-127.5 14t-117 53.5t-103.5 81l-287 282h-358q-26 0 -45 19t-19 45v672q0 26 19 45t45 19h421
+q14 14 47 48t47.5 48t44 40t50.5 37.5t51 25.5t62 19.5t68 5.5h117q99 0 181 -56q82 56 181 56h167q35 0 67 -6t56.5 -14.5t51.5 -26.5t44.5 -31t43 -39.5t39 -42t41 -48t41.5 -48.5h355q26 0 45 -19t19 -45z" />
+ <glyph glyph-name="uniF2B6" unicode="&#xf2b6;" horiz-adv-x="1792"
+d="M1792 882v-978q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v978q0 15 11 24q8 7 39 34.5t41.5 36t45.5 37.5t70 55.5t96 73t143.5 107t192.5 140.5q5 4 52.5 40t71.5 52.5t64 35t69 18.5t69 -18.5t65 -35.5t71 -52t52 -40q110 -80 192.5 -140.5t143.5 -107
+t96 -73t70 -55.5t45.5 -37.5t41.5 -36t39 -34.5q11 -9 11 -24zM1228 297q263 191 345 252q11 8 12.5 20.5t-6.5 23.5l-38 52q-8 11 -21 12.5t-24 -6.5q-231 -169 -343 -250q-5 -3 -52 -39t-71.5 -52.5t-64.5 -35t-69 -18.5t-69 18.5t-64.5 35t-71.5 52.5t-52 39
+q-186 134 -343 250q-11 8 -24 6.5t-21 -12.5l-38 -52q-8 -11 -6.5 -23.5t12.5 -20.5q82 -61 345 -252q10 -8 50 -38t65 -47t64 -39.5t77.5 -33.5t75.5 -11t75.5 11t79 34.5t64.5 39.5t65 47.5t48 36.5z" />
+ <glyph glyph-name="uniF2B7" unicode="&#xf2b7;" horiz-adv-x="1792"
+d="M1474 623l39 -51q8 -11 6.5 -23.5t-11.5 -20.5q-43 -34 -126.5 -98.5t-146.5 -113t-67 -51.5q-39 -32 -60 -48t-60.5 -41t-76.5 -36.5t-74 -11.5h-1h-1q-37 0 -74 11.5t-76 36.5t-61 41.5t-60 47.5q-5 4 -65 50.5t-143.5 111t-122.5 94.5q-11 8 -12.5 20.5t6.5 23.5
+l37 52q8 11 21.5 13t24.5 -7q94 -73 306 -236q5 -4 43.5 -35t60.5 -46.5t56.5 -32.5t58.5 -17h1h1q24 0 58.5 17t56.5 32.5t60.5 46.5t43.5 35q258 198 313 242q11 8 24 6.5t21 -12.5zM1664 -96v928q-90 83 -159 139q-91 74 -389 304q-3 2 -43 35t-61 48t-56 32.5t-59 17.5
+h-1h-1q-24 0 -59 -17.5t-56 -32.5t-61 -48t-43 -35q-215 -166 -315.5 -245.5t-129.5 -104t-82 -74.5q-14 -12 -21 -19v-928q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1792 832v-928q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v928q0 56 41 94
+q123 114 350 290.5t233 181.5q36 30 59 47.5t61.5 42t76 36.5t74.5 12h1h1q37 0 74.5 -12t76 -36.5t61.5 -42t59 -47.5q43 -36 156 -122t226 -177t201 -173q41 -38 41 -94z" />
+ <glyph glyph-name="uniF2B8" unicode="&#xf2b8;"
+d="M330 1l202 -214l-34 236l-216 213zM556 -225l274 218l-11 245l-300 -215zM245 413l227 -213l-48 327l-245 204zM495 189l317 214l-14 324l-352 -200zM843 178l95 -80l-2 239l-103 79q0 -1 1 -8.5t0 -12t-5 -7.5l-78 -52l85 -70q7 -6 7 -88zM138 930l256 -200l-68 465
+l-279 173zM1173 267l15 234l-230 -164l2 -240zM417 722l373 194l-19 441l-423 -163zM1270 357l20 233l-226 142l-2 -105l144 -95q6 -4 4 -9l-7 -119zM1461 496l30 222l-179 -128l-20 -228zM1273 329l-71 49l-8 -117q0 -5 -4 -8l-234 -187q-7 -5 -14 0l-98 83l7 -161
+q0 -5 -4 -8l-293 -234q-4 -2 -6 -2q-8 2 -8 3l-228 242q-4 4 -59 277q-2 7 5 11l61 37q-94 86 -95 92l-72 351q-2 7 6 12l94 45q-133 100 -135 108l-96 466q-2 10 7 13l433 135q5 0 8 -1l317 -153q6 -4 6 -9l20 -463q0 -7 -6 -10l-118 -61l126 -85q5 -2 5 -8l5 -123l121 74
+q5 4 11 0l84 -56l3 110q0 6 5 9l206 126q6 3 11 0l245 -135q4 -4 5 -7t-6.5 -60t-17.5 -124.5t-10 -70.5q0 -5 -4 -7l-191 -153q-6 -5 -13 0z" />
+ <glyph glyph-name="uniF2B9" unicode="&#xf2b9;" horiz-adv-x="1664"
+d="M1201 298q0 57 -5.5 107t-21 100.5t-39.5 86t-64 58t-91 22.5q-6 -4 -33.5 -20.5t-42.5 -24.5t-40.5 -20t-49 -17t-46.5 -5t-46.5 5t-49 17t-40.5 20t-42.5 24.5t-33.5 20.5q-51 0 -91 -22.5t-64 -58t-39.5 -86t-21 -100.5t-5.5 -107q0 -73 42 -121.5t103 -48.5h576
+q61 0 103 48.5t42 121.5zM1028 892q0 108 -76.5 184t-183.5 76t-183.5 -76t-76.5 -184q0 -107 76.5 -183t183.5 -76t183.5 76t76.5 183zM1664 352v-192q0 -14 -9 -23t-23 -9h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216
+q66 0 113 -47t47 -113v-224h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23v-192q0 -14 -9 -23t-23 -9h-96v-128h96q14 0 23 -9t9 -23z" />
+ <glyph glyph-name="uniF2BA" unicode="&#xf2ba;" horiz-adv-x="1664"
+d="M1028 892q0 -107 -76.5 -183t-183.5 -76t-183.5 76t-76.5 183q0 108 76.5 184t183.5 76t183.5 -76t76.5 -184zM980 672q46 0 82.5 -17t60 -47.5t39.5 -67t24 -81t11.5 -82.5t3.5 -79q0 -67 -39.5 -118.5t-105.5 -51.5h-576q-66 0 -105.5 51.5t-39.5 118.5q0 48 4.5 93.5
+t18.5 98.5t36.5 91.5t63 64.5t93.5 26h5q7 -4 32 -19.5t35.5 -21t33 -17t37 -16t35 -9t39.5 -4.5t39.5 4.5t35 9t37 16t33 17t35.5 21t32 19.5zM1664 928q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-128h96
+q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-96v-224q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h1216q66 0 113 -47t47 -113v-224h96q13 0 22.5 -9.5t9.5 -22.5v-192zM1408 -96v1472q0 13 -9.5 22.5t-22.5 9.5h-1216
+q-13 0 -22.5 -9.5t-9.5 -22.5v-1472q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5z" />
+ <glyph glyph-name="uniF2BB" unicode="&#xf2bb;" horiz-adv-x="2048"
+d="M1024 405q0 64 -9 117.5t-29.5 103t-60.5 78t-97 28.5q-6 -4 -30 -18t-37.5 -21.5t-35.5 -17.5t-43 -14.5t-42 -4.5t-42 4.5t-43 14.5t-35.5 17.5t-37.5 21.5t-30 18q-57 0 -97 -28.5t-60.5 -78t-29.5 -103t-9 -117.5t37 -106.5t91 -42.5h512q54 0 91 42.5t37 106.5z
+M867 925q0 94 -66.5 160.5t-160.5 66.5t-160.5 -66.5t-66.5 -160.5t66.5 -160.5t160.5 -66.5t160.5 66.5t66.5 160.5zM1792 416v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM1792 676v56q0 15 -10.5 25.5t-25.5 10.5h-568
+q-15 0 -25.5 -10.5t-10.5 -25.5v-56q0 -15 10.5 -25.5t25.5 -10.5h568q15 0 25.5 10.5t10.5 25.5zM1792 928v64q0 14 -9 23t-23 9h-576q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h576q14 0 23 9t9 23zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-352v96q0 14 -9 23t-23 9
+h-64q-14 0 -23 -9t-9 -23v-96h-768v96q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-96h-352q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2BC" unicode="&#xf2bc;" horiz-adv-x="2048"
+d="M1024 405q0 -64 -37 -106.5t-91 -42.5h-512q-54 0 -91 42.5t-37 106.5t9 117.5t29.5 103t60.5 78t97 28.5q6 -4 30 -18t37.5 -21.5t35.5 -17.5t43 -14.5t42 -4.5t42 4.5t43 14.5t35.5 17.5t37.5 21.5t30 18q57 0 97 -28.5t60.5 -78t29.5 -103t9 -117.5zM867 925
+q0 -94 -66.5 -160.5t-160.5 -66.5t-160.5 66.5t-66.5 160.5t66.5 160.5t160.5 66.5t160.5 -66.5t66.5 -160.5zM1792 480v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1792 732v-56q0 -15 -10.5 -25.5t-25.5 -10.5h-568
+q-15 0 -25.5 10.5t-10.5 25.5v56q0 15 10.5 25.5t25.5 10.5h568q15 0 25.5 -10.5t10.5 -25.5zM1792 992v-64q0 -14 -9 -23t-23 -9h-576q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h576q14 0 23 -9t9 -23zM1920 32v1216q0 13 -9.5 22.5t-22.5 9.5h-1728q-13 0 -22.5 -9.5
+t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h352v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h768v96q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-96h352q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113
+t113 47h1728q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2BD" unicode="&#xf2bd;" horiz-adv-x="1792"
+d="M1523 197q-22 155 -87.5 257.5t-184.5 118.5q-67 -74 -159.5 -115.5t-195.5 -41.5t-195.5 41.5t-159.5 115.5q-119 -16 -184.5 -118.5t-87.5 -257.5q106 -150 271 -237.5t356 -87.5t356 87.5t271 237.5zM1280 896q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5
+t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1792 640q0 -182 -71 -347.5t-190.5 -286t-285.5 -191.5t-349 -71q-182 0 -348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="uniF2BE" unicode="&#xf2be;" horiz-adv-x="1792"
+d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348q0 -181 -70.5 -347t-190.5 -286t-286 -191.5t-349 -71.5t-349 71t-285.5 191.5t-190.5 286t-71 347.5t71 348t191 286t286 191t348 71zM1515 185q149 205 149 455q0 156 -61 298t-164 245t-245 164t-298 61t-298 -61
+t-245 -164t-164 -245t-61 -298q0 -250 149 -455q66 327 306 327q131 -128 313 -128t313 128q240 0 306 -327zM1280 832q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5z" />
+ <glyph glyph-name="uniF2C0" unicode="&#xf2c0;"
+d="M1201 752q47 -14 89.5 -38t89 -73t79.5 -115.5t55 -172t22 -236.5q0 -154 -100 -263.5t-241 -109.5h-854q-141 0 -241 109.5t-100 263.5q0 131 22 236.5t55 172t79.5 115.5t89 73t89.5 38q-79 125 -79 272q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5
+t198.5 -40.5t163.5 -109.5t109.5 -163.5t40.5 -198.5q0 -147 -79 -272zM768 1408q-159 0 -271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5zM1195 -128q88 0 150.5 71.5t62.5 173.5q0 239 -78.5 377t-225.5 145
+q-145 -127 -336 -127t-336 127q-147 -7 -225.5 -145t-78.5 -377q0 -102 62.5 -173.5t150.5 -71.5h854z" />
+ <glyph glyph-name="uniF2C1" unicode="&#xf2c1;" horiz-adv-x="1280"
+d="M1024 278q0 -64 -37 -107t-91 -43h-512q-54 0 -91 43t-37 107t9 118t29.5 104t61 78.5t96.5 28.5q80 -75 188 -75t188 75q56 0 96.5 -28.5t61 -78.5t29.5 -104t9 -118zM870 797q0 -94 -67.5 -160.5t-162.5 -66.5t-162.5 66.5t-67.5 160.5t67.5 160.5t162.5 66.5
+t162.5 -66.5t67.5 -160.5zM1152 -96v1376h-1024v-1376q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1280 1376v-1472q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v1472q0 66 47 113t113 47h352v-96q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v96h352
+q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2C2" unicode="&#xf2c2;" horiz-adv-x="2048"
+d="M896 324q0 54 -7.5 100.5t-24.5 90t-51 68.5t-81 25q-64 -64 -156 -64t-156 64q-47 0 -81 -25t-51 -68.5t-24.5 -90t-7.5 -100.5q0 -55 31.5 -93.5t75.5 -38.5h426q44 0 75.5 38.5t31.5 93.5zM768 768q0 80 -56 136t-136 56t-136 -56t-56 -136t56 -136t136 -56t136 56
+t56 136zM1792 288v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1408 544v64q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1792 544v64q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23
+v-64q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1792 800v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM128 1152h1792v96q0 14 -9 23t-23 9h-1728q-14 0 -23 -9t-9 -23v-96zM2048 1248v-1216q0 -66 -47 -113t-113 -47h-1728
+q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2C3" unicode="&#xf2c3;" horiz-adv-x="2048"
+d="M896 324q0 -55 -31.5 -93.5t-75.5 -38.5h-426q-44 0 -75.5 38.5t-31.5 93.5q0 54 7.5 100.5t24.5 90t51 68.5t81 25q64 -64 156 -64t156 64q47 0 81 -25t51 -68.5t24.5 -90t7.5 -100.5zM768 768q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136z
+M1792 352v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1408 608v-64q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h320q14 0 23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v64
+q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 864v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704q14 0 23 -9t9 -23zM1920 32v1120h-1792v-1120q0 -13 9.5 -22.5t22.5 -9.5h1728q13 0 22.5 9.5t9.5 22.5zM2048 1248v-1216q0 -66 -47 -113t-113 -47
+h-1728q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1728q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2C4" unicode="&#xf2c4;" horiz-adv-x="1792"
+d="M1255 749q0 318 -105 474.5t-330 156.5q-222 0 -326 -157t-104 -474q0 -316 104 -471.5t326 -155.5q74 0 131 17q-22 43 -39 73t-44 65t-53.5 56.5t-63 36t-77.5 14.5q-46 0 -79 -16l-49 97q105 91 276 91q132 0 215.5 -54t150.5 -155q67 149 67 402zM1645 117h117
+q3 -27 -2 -67t-26.5 -95t-58 -100.5t-107 -78t-162.5 -32.5q-71 0 -130.5 19t-105.5 56t-79 78t-66 96q-97 -27 -205 -27q-150 0 -292.5 58t-253 158.5t-178 249t-67.5 317.5q0 170 67.5 319.5t178.5 250.5t253.5 159t291.5 58q121 0 238.5 -36t217 -106t176 -164.5
+t119.5 -219t43 -261.5q0 -190 -80.5 -347.5t-218.5 -264.5q47 -70 93.5 -106.5t104.5 -36.5q61 0 94 37.5t38 85.5z" />
+ <glyph glyph-name="uniF2C5" unicode="&#xf2c5;" horiz-adv-x="2304"
+d="M453 -101q0 -21 -16 -37.5t-37 -16.5q-1 0 -13 3q-63 15 -162 140q-225 284 -225 676q0 341 213 614q39 51 95 103.5t94 52.5q19 0 35 -13.5t16 -32.5q0 -27 -63 -90q-98 -102 -147 -184q-119 -199 -119 -449q0 -281 123 -491q50 -85 136 -173q2 -3 14.5 -16t19.5 -21
+t17 -20.5t14.5 -23.5t4.5 -21zM1796 33q0 -29 -17.5 -48.5t-46.5 -19.5h-1081q-26 0 -45 19t-19 45q0 29 17.5 48.5t46.5 19.5h1081q26 0 45 -19t19 -45zM1581 644q0 -134 -67 -233q-25 -38 -69.5 -78.5t-83.5 -60.5q-16 -10 -27 -10q-7 0 -15 6t-8 12q0 9 19 30t42 46
+t42 67.5t19 88.5q0 76 -35 130q-29 42 -46 42q-3 0 -3 -5q0 -12 7.5 -35.5t7.5 -36.5q0 -22 -21.5 -35t-44.5 -13q-66 0 -66 76q0 15 1.5 44t1.5 44q0 25 -10 46q-13 25 -42 53.5t-51 28.5q-5 0 -7 -0.5t-3.5 -2.5t-1.5 -6q0 -2 16 -26t16 -54q0 -37 -19 -68t-46 -54
+t-53.5 -46t-45.5 -54t-19 -68q0 -98 42 -160q29 -43 79 -63q16 -5 17 -10q1 -2 1 -5q0 -16 -18 -16q-6 0 -33 11q-119 43 -195 139.5t-76 218.5q0 55 24.5 115.5t60 115t70.5 108.5t59.5 113.5t24.5 111.5q0 53 -25 94q-29 48 -56 64q-19 9 -19 21q0 20 41 20q50 0 110 -29
+q41 -19 71 -44.5t49.5 -51t33.5 -62.5t22 -69t16 -80q0 -1 3 -17.5t4.5 -25t5.5 -25t9 -27t11 -21.5t14.5 -16.5t18.5 -5.5q23 0 37 14t14 37q0 25 -20 67t-20 52t10 10q27 0 93 -70q72 -76 102.5 -156t30.5 -186zM2304 615q0 -274 -138 -503q-19 -32 -48 -72t-68 -86.5
+t-81 -77t-74 -30.5q-16 0 -31 15.5t-15 31.5q0 15 29 50.5t68.5 77t48.5 52.5q183 230 183 531q0 131 -20.5 235t-72.5 211q-58 119 -163 228q-2 3 -13 13.5t-16.5 16.5t-15 17.5t-15 20t-9.5 18.5t-4 19q0 19 16 35.5t35 16.5q70 0 196 -169q98 -131 146 -273t60 -314
+q2 -42 2 -64z" />
+ <glyph glyph-name="uniF2C6" unicode="&#xf2c6;" horiz-adv-x="1792"
+d="M1189 229l147 693q9 44 -10.5 63t-51.5 7l-864 -333q-29 -11 -39.5 -25t-2.5 -26.5t32 -19.5l221 -69l513 323q21 14 32 6q7 -5 -4 -15l-415 -375v0v0l-16 -228q23 0 45 22l108 104l224 -165q64 -36 81 38zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71
+t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="uniF2C7" unicode="&#xf2c7;" horiz-adv-x="1024"
+d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v907h128v-907q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5
+t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192
+v128h192z" />
+ <glyph glyph-name="uniF2C8" unicode="&#xf2c8;" horiz-adv-x="1024"
+d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v651h128v-651q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5
+t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192
+v128h192z" />
+ <glyph glyph-name="uniF2C9" unicode="&#xf2c9;" horiz-adv-x="1024"
+d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v395h128v-395q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5
+t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192
+v128h192z" />
+ <glyph glyph-name="uniF2CA" unicode="&#xf2ca;" horiz-adv-x="1024"
+d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 60 35 110t93 71v139h128v-139q58 -21 93 -71t35 -110zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5
+t93.5 226.5zM896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192
+v128h192z" />
+ <glyph glyph-name="uniF2CB" unicode="&#xf2cb;" horiz-adv-x="1024"
+d="M640 192q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 79 56 135.5t136 56.5t136 -56.5t56 -135.5zM768 192q0 77 -34 144t-94 112v768q0 80 -56 136t-136 56t-136 -56t-56 -136v-768q-60 -45 -94 -112t-34 -144q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5t93.5 226.5z
+M896 192q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 182 128 313v711q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-711q128 -131 128 -313zM1024 768v-128h-192v128h192zM1024 1024v-128h-192v128h192zM1024 1280v-128h-192v128h192z" />
+ <glyph glyph-name="uniF2CC" unicode="&#xf2cc;" horiz-adv-x="1920"
+d="M1433 1287q10 -10 10 -23t-10 -23l-626 -626q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 23l44 44q-72 91 -81.5 207t46.5 215q-74 71 -176 71q-106 0 -181 -75t-75 -181v-1280h-256v1280q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5q106 0 201 -41
+t166 -115q94 39 197 24.5t185 -79.5l44 44q10 10 23 10t23 -10zM1344 1024q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1600 896q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1856 1024q26 0 45 -19t19 -45t-19 -45t-45 -19
+t-45 19t-19 45t19 45t45 19zM1216 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1408 832q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM1728 896q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 768
+q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 640q-26 0 -45 19t-19 45t19 45t45 19t45 -19t19 -45t-19 -45t-45 -19zM1600 768q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 512q-26 0 -45 19t-19 45t19 45t45 19t45 -19
+t19 -45t-19 -45t-45 -19zM1472 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1344 512q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1216 384
+q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1088 256q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19z" />
+ <glyph glyph-name="uniF2CD" unicode="&#xf2cd;" horiz-adv-x="1792"
+d="M1664 448v-192q0 -169 -128 -286v-194q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v118q-63 -22 -128 -22h-768q-65 0 -128 22v-110q0 -17 -9.5 -28.5t-22.5 -11.5h-64q-13 0 -22.5 11.5t-9.5 28.5v186q-128 117 -128 286v192h1536zM704 864q0 -14 -9 -23t-23 -9t-23 9
+t-9 23t9 23t23 9t23 -9t9 -23zM768 928q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM704 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 992q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1056q0 -14 -9 -23t-23 -9t-23 9
+t-9 23t9 23t23 9t23 -9t9 -23zM704 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1792 608v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v640q0 106 75 181t181 75q108 0 184 -78q46 19 98 12t93 -39l22 22q11 11 22 0l42 -42
+q11 -11 0 -22l-314 -314q-11 -11 -22 0l-42 42q-11 11 0 22l22 22q-36 46 -40.5 104t23.5 108q-37 35 -88 35q-53 0 -90.5 -37.5t-37.5 -90.5v-640h1504q14 0 23 -9t9 -23zM896 1056q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1120q0 -14 -9 -23t-23 -9
+t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM768 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1120q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM896 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM832 1248q0 -14 -9 -23
+t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1024 1184q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM960 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23zM1088 1248q0 -14 -9 -23t-23 -9t-23 9t-9 23t9 23t23 9t23 -9t9 -23z" />
+ <glyph glyph-name="uniF2CE" unicode="&#xf2ce;"
+d="M994 344q0 -86 -17 -197q-31 -215 -55 -313q-22 -90 -152 -90t-152 90q-24 98 -55 313q-17 110 -17 197q0 168 224 168t224 -168zM1536 768q0 -240 -134 -434t-350 -280q-8 -3 -15 3t-6 15q7 48 10 66q4 32 6 47q1 9 9 12q159 81 255.5 234t96.5 337q0 180 -91 330.5
+t-247 234.5t-337 74q-124 -7 -237 -61t-193.5 -140.5t-128 -202t-46.5 -240.5q1 -184 99 -336.5t257 -231.5q7 -3 9 -12q3 -21 6 -45q1 -9 5 -32.5t6 -35.5q1 -9 -6.5 -15t-15.5 -2q-148 58 -261 169.5t-173.5 264t-52.5 319.5q7 143 66 273.5t154.5 227t225 157.5t272.5 70
+q164 10 315.5 -46.5t261 -160.5t175 -250.5t65.5 -308.5zM994 800q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5zM1282 768q0 -122 -53.5 -228.5t-146.5 -177.5q-8 -6 -16 -2t-10 14q-6 52 -29 92q-7 10 3 20
+q58 54 91 127t33 155q0 111 -58.5 204t-157.5 141.5t-212 36.5q-133 -15 -229 -113t-109 -231q-10 -92 23.5 -176t98.5 -144q10 -10 3 -20q-24 -41 -29 -93q-2 -9 -10 -13t-16 2q-95 74 -148.5 183t-51.5 234q3 131 69 244t177 181.5t241 74.5q144 7 268 -60t196.5 -187.5
+t72.5 -263.5z" />
+ <glyph glyph-name="uniF2D0" unicode="&#xf2d0;" horiz-adv-x="1792"
+d="M256 128h1280v768h-1280v-768zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2D1" unicode="&#xf2d1;" horiz-adv-x="1792"
+d="M1792 224v-192q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2D2" unicode="&#xf2d2;" horiz-adv-x="2048"
+d="M256 0h768v512h-768v-512zM1280 512h512v768h-768v-256h96q66 0 113 -47t47 -113v-352zM2048 1376v-960q0 -66 -47 -113t-113 -47h-608v-352q0 -66 -47 -113t-113 -47h-960q-66 0 -113 47t-47 113v960q0 66 47 113t113 47h608v352q0 66 47 113t113 47h960q66 0 113 -47
+t47 -113z" />
+ <glyph glyph-name="uniF2D3" unicode="&#xf2d3;" horiz-adv-x="1792"
+d="M1175 215l146 146q10 10 10 23t-10 23l-233 233l233 233q10 10 10 23t-10 23l-146 146q-10 10 -23 10t-23 -10l-233 -233l-233 233q-10 10 -23 10t-23 -10l-146 -146q-10 -10 -10 -23t10 -23l233 -233l-233 -233q-10 -10 -10 -23t10 -23l146 -146q10 -10 23 -10t23 10
+l233 233l233 -233q10 -10 23 -10t23 10zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2D4" unicode="&#xf2d4;" horiz-adv-x="1792"
+d="M1257 425l-146 -146q-10 -10 -23 -10t-23 10l-169 169l-169 -169q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l169 169l-169 169q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l169 -169l169 169q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23
+l-169 -169l169 -169q10 -10 10 -23t-10 -23zM256 128h1280v1024h-1280v-1024zM1792 1248v-1216q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1472q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2D5" unicode="&#xf2d5;" horiz-adv-x="1792"
+d="M1070 358l306 564h-654l-306 -564h654zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="uniF2D6" unicode="&#xf2d6;" horiz-adv-x="1794"
+d="M1291 1060q-15 17 -35 8.5t-26 -28.5t5 -38q14 -17 40 -14.5t34 20.5t-18 52zM895 814q-8 -8 -19.5 -8t-18.5 8q-8 8 -8 19t8 18q7 8 18.5 8t19.5 -8q7 -7 7 -18t-7 -19zM1060 740l-35 -35q-12 -13 -29.5 -13t-30.5 13l-38 38q-12 13 -12 30t12 30l35 35q12 12 29.5 12
+t30.5 -12l38 -39q12 -12 12 -29.5t-12 -29.5zM951 870q-7 -8 -18.5 -8t-19.5 8q-7 8 -7 19t7 19q8 8 19 8t19 -8t8 -19t-8 -19zM1354 968q-34 -64 -107.5 -85.5t-127.5 16.5q-38 28 -61 66.5t-21 87.5t39 92t75.5 53t70.5 -5t70 -51q2 -2 13 -12.5t14.5 -13.5t13 -13.5
+t12.5 -15.5t10 -15.5t8.5 -18t4 -18.5t1 -21t-5 -22t-9.5 -24zM1555 486q3 20 -8.5 34.5t-27.5 21.5t-33 17t-23 20q-40 71 -84 98.5t-113 11.5q19 13 40 18.5t33 4.5l12 -1q2 45 -34 90q6 20 6.5 40.5t-2.5 30.5l-3 10q43 24 71 65t34 91q10 84 -43 150.5t-137 76.5
+q-60 7 -114 -18.5t-82 -74.5q-30 -51 -33.5 -101t14.5 -87t43.5 -64t56.5 -42q-45 4 -88 36t-57 88q-28 108 32 222q-16 21 -29 32q-50 0 -89 -19q19 24 42 37t36 14l13 1q0 50 -13 78q-10 21 -32.5 28.5t-47 -3.5t-37.5 -40q2 4 4 7q-7 -28 -6.5 -75.5t19 -117t48.5 -122.5
+q-25 -14 -47 -36q-35 -16 -85.5 -70.5t-84.5 -101.5l-33 -46q-90 -34 -181 -125.5t-75 -162.5q1 -16 11 -27q-15 -12 -30 -30q-21 -25 -21 -54t21.5 -40t63.5 6q41 19 77 49.5t55 60.5q-2 2 -6.5 5t-20.5 7.5t-33 3.5q23 5 51 12.5t40 10t27.5 6t26 4t23.5 0.5q14 -7 22 34
+q7 37 7 90q0 102 -40 150q106 -103 101 -219q-1 -29 -15 -50t-27 -27l-13 -6q-4 -7 -19 -32t-26 -45.5t-26.5 -52t-25 -61t-17 -63t-6.5 -66.5t10 -63q-35 54 -37 80q-22 -24 -34.5 -39t-33.5 -42t-30.5 -46t-16.5 -41t-0.5 -38t25.5 -27q45 -25 144 64t190.5 221.5
+t122.5 228.5q86 52 145 115.5t86 119.5q47 -93 154 -178q104 -83 167 -80q39 2 46 43zM1794 640q0 -182 -71 -348t-191 -286t-286.5 -191t-348.5 -71t-348.5 71t-286.5 191t-191 286t-71 348t71 348t191 286t286.5 191t348.5 71t348.5 -71t286.5 -191t191 -286t71 -348z" />
+ <glyph glyph-name="uniF2D7" unicode="&#xf2d7;"
+d="M518 1353v-655q103 -1 191.5 1.5t125.5 5.5l37 3q68 2 90.5 24.5t39.5 94.5l33 142h103l-14 -322l7 -319h-103l-29 127q-15 68 -45 93t-84 26q-87 8 -352 8v-556q0 -78 43.5 -115.5t133.5 -37.5h357q35 0 59.5 2t55 7.5t54 18t48.5 32t46 50.5t39 73l93 216h89
+q-6 -37 -31.5 -252t-30.5 -276q-146 5 -263.5 8t-162.5 4h-44h-628l-376 -12v102l127 25q67 13 91.5 37t25.5 79l8 643q3 402 -8 645q-2 61 -25.5 84t-91.5 36l-127 24v102l376 -12h702q139 0 374 27q-6 -68 -14 -194.5t-12 -219.5l-5 -92h-93l-32 124q-31 121 -74 179.5
+t-113 58.5h-548q-28 0 -35.5 -8.5t-7.5 -30.5z" />
+ <glyph glyph-name="uniF2D8" unicode="&#xf2d8;"
+d="M922 739v-182q0 -4 0.5 -15t0 -15l-1.5 -12t-3.5 -11.5t-6.5 -7.5t-11 -5.5t-16 -1.5v309q9 0 16 -1t11 -5t6.5 -5.5t3.5 -9.5t1 -10.5v-13.5v-14zM1238 643v-121q0 -1 0.5 -12.5t0 -15.5t-2.5 -11.5t-7.5 -10.5t-13.5 -3q-9 0 -14 9q-4 10 -4 165v7v8.5v9t1.5 8.5l3.5 7
+t5 5.5t8 1.5q6 0 10 -1.5t6.5 -4.5t4 -6t2 -8.5t0.5 -8v-9.5v-9zM180 407h122v472h-122v-472zM614 407h106v472h-159l-28 -221q-20 148 -32 221h-158v-472h107v312l45 -312h76l43 319v-319zM1039 712q0 67 -5 90q-3 16 -11 28.5t-17 20.5t-25 14t-26.5 8.5t-31 4t-29 1.5
+h-29.5h-12h-91v-472h56q169 -1 197 24.5t25 180.5q-1 62 -1 100zM1356 515v133q0 29 -2 45t-9.5 33.5t-24.5 25t-46 7.5q-46 0 -77 -34v154h-117v-472h110l7 30q30 -36 77 -36q50 0 66 30.5t16 83.5zM1536 1248v-1216q0 -66 -47 -113t-113 -47h-1216q-66 0 -113 47t-47 113
+v1216q0 66 47 113t113 47h1216q66 0 113 -47t47 -113z" />
+ <glyph glyph-name="uniF2D9" unicode="&#xf2d9;" horiz-adv-x="2176"
+d="M1143 -197q-6 1 -11 4q-13 8 -36 23t-86 65t-116.5 104.5t-112 140t-89.5 172.5q-17 3 -175 37q66 -213 235 -362t391 -184zM502 409l168 -28q-25 76 -41 167.5t-19 145.5l-4 53q-84 -82 -121 -224q5 -65 17 -114zM612 1018q-43 -64 -77 -148q44 46 74 68zM2049 584
+q0 161 -62 307t-167.5 252t-250.5 168.5t-304 62.5q-147 0 -281 -52.5t-240 -148.5q-30 -58 -45 -160q60 51 143 83.5t158.5 43t143 13.5t108.5 -1l40 -3q33 -1 53 -15.5t24.5 -33t6.5 -37t-1 -28.5q-126 11 -227.5 0.5t-183 -43.5t-142.5 -71.5t-131 -98.5
+q4 -36 11.5 -92.5t35.5 -178t62 -179.5q123 -6 247.5 14.5t214.5 53.5t162.5 67t109.5 59l37 24q22 16 39.5 20.5t30.5 -5t17 -34.5q14 -97 -39 -121q-208 -97 -467 -134q-135 -20 -317 -16q41 -96 110 -176.5t137 -127t130.5 -79t101.5 -43.5l39 -12q143 -23 263 15
+q195 99 314 289t119 418zM2123 621q-14 -135 -40 -212q-70 -208 -181.5 -346.5t-318.5 -253.5q-48 -33 -82 -44q-72 -26 -163 -16q-36 -3 -73 -3q-283 0 -504.5 173t-295.5 442q-1 0 -4 0.5t-5 0.5q-6 -50 2.5 -112.5t26 -115t36 -98t31.5 -71.5l14 -26q8 -12 54 -82
+q-71 38 -124.5 106.5t-78.5 140t-39.5 137t-17.5 107.5l-2 42q-5 2 -33.5 12.5t-48.5 18t-53 20.5t-57.5 25t-50 25.5t-42.5 27t-25 25.5q19 -10 50.5 -25.5t113 -45.5t145.5 -38l2 32q11 149 94 290q41 202 176 365q28 115 81 214q15 28 32 45t49 32q158 74 303.5 104
+t302 11t306.5 -97q220 -115 333 -336t87 -474z" />
+ <glyph glyph-name="uniF2DA" unicode="&#xf2da;" horiz-adv-x="1792"
+d="M1341 752q29 44 -6.5 129.5t-121.5 142.5q-58 39 -125.5 53.5t-118 4.5t-68.5 -37q-12 -23 -4.5 -28t42.5 -10q23 -3 38.5 -5t44.5 -9.5t56 -17.5q36 -13 67.5 -31.5t53 -37t40 -38.5t30.5 -38t22 -34.5t16.5 -28.5t12 -18.5t10.5 -6t11 9.5zM1704 178
+q-52 -127 -148.5 -220t-214.5 -141.5t-253 -60.5t-266 13.5t-251 91t-210 161.5t-141.5 235.5t-46.5 303.5q1 41 8.5 84.5t12.5 64t24 80.5t23 73q-51 -208 1 -397t173 -318t291 -206t346 -83t349 74.5t289 244.5q20 27 18 14q0 -4 -4 -14zM1465 627q0 -104 -40.5 -199
+t-108.5 -164t-162 -109.5t-198 -40.5t-198 40.5t-162 109.5t-108.5 164t-40.5 199t40.5 199t108.5 164t162 109.5t198 40.5t198 -40.5t162 -109.5t108.5 -164t40.5 -199zM1752 915q-65 147 -180.5 251t-253 153.5t-292 53.5t-301 -36.5t-275.5 -129t-220 -211.5t-131 -297
+t-10 -373q-49 161 -51.5 311.5t35.5 272.5t109 227t165.5 180.5t207 126t232 71t242.5 9t236 -54t216 -124.5t178 -197q33 -50 62 -121t31 -112zM1690 573q12 244 -136.5 416t-396.5 240q-8 0 -10 5t24 8q125 -4 230 -50t173 -120t116 -168.5t58.5 -199t-1 -208
+t-61.5 -197.5t-122.5 -167t-185 -117.5t-248.5 -46.5q108 30 201.5 80t174 123t129.5 176.5t55 225.5z" />
+ <glyph glyph-name="uniF2DB" unicode="&#xf2db;"
+d="M192 256v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 512v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 768v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16
+q0 16 16 16h112zM192 1024v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM192 1280v-128h-112q-16 0 -16 16v16h-48q-16 0 -16 16v32q0 16 16 16h48v16q0 16 16 16h112zM1280 1440v-1472q0 -40 -28 -68t-68 -28h-832q-40 0 -68 28
+t-28 68v1472q0 40 28 68t68 28h832q40 0 68 -28t28 -68zM1536 208v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 464v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 720v-32
+q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 976v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16h48q16 0 16 -16zM1536 1232v-32q0 -16 -16 -16h-48v-16q0 -16 -16 -16h-112v128h112q16 0 16 -16v-16
+h48q16 0 16 -16z" />
+ <glyph glyph-name="uniF2DC" unicode="&#xf2dc;" horiz-adv-x="1664"
+d="M1566 419l-167 -33l186 -107q23 -13 29.5 -38.5t-6.5 -48.5q-14 -23 -39 -29.5t-48 6.5l-186 106l55 -160q13 -38 -12 -63.5t-60.5 -20.5t-48.5 42l-102 300l-271 156v-313l208 -238q16 -18 17 -39t-11 -36.5t-28.5 -25t-37 -5.5t-36.5 22l-112 128v-214q0 -26 -19 -45
+t-45 -19t-45 19t-19 45v214l-112 -128q-16 -18 -36.5 -22t-37 5.5t-28.5 25t-11 36.5t17 39l208 238v313l-271 -156l-102 -300q-13 -37 -48.5 -42t-60.5 20.5t-12 63.5l55 160l-186 -106q-23 -13 -48 -6.5t-39 29.5q-13 23 -6.5 48.5t29.5 38.5l186 107l-167 33
+q-29 6 -42 29t-8.5 46.5t25.5 40t50 10.5l310 -62l271 157l-271 157l-310 -62q-4 -1 -13 -1q-27 0 -44 18t-19 40t11 43t40 26l167 33l-186 107q-23 13 -29.5 38.5t6.5 48.5t39 30t48 -7l186 -106l-55 160q-13 38 12 63.5t60.5 20.5t48.5 -42l102 -300l271 -156v313
+l-208 238q-16 18 -17 39t11 36.5t28.5 25t37 5.5t36.5 -22l112 -128v214q0 26 19 45t45 19t45 -19t19 -45v-214l112 128q16 18 36.5 22t37 -5.5t28.5 -25t11 -36.5t-17 -39l-208 -238v-313l271 156l102 300q13 37 48.5 42t60.5 -20.5t12 -63.5l-55 -160l186 106
+q23 13 48 6.5t39 -29.5q13 -23 6.5 -48.5t-29.5 -38.5l-186 -107l167 -33q27 -5 40 -26t11 -43t-19 -40t-44 -18q-9 0 -13 1l-310 62l-271 -157l271 -157l310 62q29 6 50 -10.5t25.5 -40t-8.5 -46.5t-42 -29z" />
+ <glyph glyph-name="uniF2DD" unicode="&#xf2dd;" horiz-adv-x="1792"
+d="M1473 607q7 118 -33 226.5t-113 189t-177 131t-221 57.5q-116 7 -225.5 -32t-192 -110.5t-135 -175t-59.5 -220.5q-7 -118 33 -226.5t113 -189t177.5 -131t221.5 -57.5q155 -9 293 59t224 195.5t94 283.5zM1792 1536l-349 -348q120 -117 180.5 -272t50.5 -321
+q-11 -183 -102 -339t-241 -255.5t-332 -124.5l-999 -132l347 347q-120 116 -180.5 271.5t-50.5 321.5q11 184 102 340t241.5 255.5t332.5 124.5q167 22 500 66t500 66z" />
+ <glyph glyph-name="uniF2DE" unicode="&#xf2de;" horiz-adv-x="1792"
+d="M948 508l163 -329h-51l-175 350l-171 -350h-49l179 374l-78 33l21 49l240 -102l-21 -50zM563 1100l304 -130l-130 -304l-304 130zM907 915l240 -103l-103 -239l-239 102zM1188 765l191 -81l-82 -190l-190 81zM1680 640q0 159 -62 304t-167.5 250.5t-250.5 167.5t-304 62
+t-304 -62t-250.5 -167.5t-167.5 -250.5t-62 -304t62 -304t167.5 -250.5t250.5 -167.5t304 -62t304 62t250.5 167.5t167.5 250.5t62 304zM1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71t348 -71
+t286 -191t191 -286t71 -348z" />
+ <glyph glyph-name="uniF2E0" unicode="&#xf2e0;" horiz-adv-x="1920"
+d="M1334 302q-4 24 -27.5 34t-49.5 10.5t-48.5 12.5t-25.5 38q-5 47 33 139.5t75 181t32 127.5q-14 101 -117 103q-45 1 -75 -16l-3 -2l-5 -2.5t-4.5 -2t-5 -2t-5 -0.5t-6 1.5t-6 3.5t-6.5 5q-3 2 -9 8.5t-9 9t-8.5 7.5t-9.5 7.5t-9.5 5.5t-11 4.5t-11.5 2.5q-30 5 -48 -3
+t-45 -31q-1 -1 -9 -8.5t-12.5 -11t-15 -10t-16.5 -5.5t-17 3q-54 27 -84 40q-41 18 -94 -5t-76 -65q-16 -28 -41 -98.5t-43.5 -132.5t-40 -134t-21.5 -73q-22 -69 18.5 -119t110.5 -46q30 2 50.5 15t38.5 46q7 13 79 199.5t77 194.5q6 11 21.5 18t29.5 0q27 -15 21 -53
+q-2 -18 -51 -139.5t-50 -132.5q-6 -38 19.5 -56.5t60.5 -7t55 49.5q4 8 45.5 92t81.5 163.5t46 88.5q20 29 41 28q29 0 25 -38q-2 -16 -65.5 -147.5t-70.5 -159.5q-12 -53 13 -103t74 -74q17 -9 51 -15.5t71.5 -8t62.5 14t20 48.5zM383 86q3 -15 -5 -27.5t-23 -15.5
+q-14 -3 -26.5 5t-15.5 23q-3 14 5 27t22 16t27 -5t16 -23zM953 -177q12 -17 8.5 -37.5t-20.5 -32.5t-37.5 -8t-32.5 21q-11 17 -7.5 37.5t20.5 32.5t37.5 8t31.5 -21zM177 635q-18 -27 -49.5 -33t-57.5 13q-26 18 -32 50t12 58q18 27 49.5 33t57.5 -12q26 -19 32 -50.5
+t-12 -58.5zM1467 -42q19 -28 13 -61.5t-34 -52.5t-60.5 -13t-51.5 34t-13 61t33 53q28 19 60.5 13t52.5 -34zM1579 562q69 -113 42.5 -244.5t-134.5 -207.5q-90 -63 -199 -60q-20 -80 -84.5 -127t-143.5 -44.5t-140 57.5q-12 -9 -13 -10q-103 -71 -225 -48.5t-193 126.5
+q-50 73 -53 164q-83 14 -142.5 70.5t-80.5 128t-2 152t81 138.5q-36 60 -38 128t24.5 125t79.5 98.5t121 50.5q32 85 99 148t146.5 91.5t168 17t159.5 -66.5q72 21 140 17.5t128.5 -36t104.5 -80t67.5 -115t17.5 -140.5q52 -16 87 -57t45.5 -89t-5.5 -99.5t-58 -87.5z
+M455 1222q14 -20 9.5 -44.5t-24.5 -38.5q-19 -14 -43.5 -9.5t-37.5 24.5q-14 20 -9.5 44.5t24.5 38.5q19 14 43.5 9.5t37.5 -24.5zM614 1503q4 -16 -5 -30.5t-26 -18.5t-31 5.5t-18 26.5q-3 17 6.5 31t25.5 18q17 4 31 -5.5t17 -26.5zM1800 555q4 -20 -6.5 -37t-30.5 -21
+q-19 -4 -36 6.5t-21 30.5t6.5 37t30.5 22q20 4 36.5 -7.5t20.5 -30.5zM1136 1448q16 -27 8.5 -58.5t-35.5 -47.5q-27 -16 -57.5 -8.5t-46.5 34.5q-16 28 -8.5 59t34.5 48t58 9t47 -36zM1882 792q4 -15 -4 -27.5t-23 -16.5q-15 -3 -27.5 5.5t-15.5 22.5q-3 15 5 28t23 16
+q14 3 26.5 -5t15.5 -23zM1691 1033q15 -22 10.5 -49t-26.5 -43q-22 -15 -49 -10t-42 27t-10 49t27 43t48.5 11t41.5 -28z" />
+ <glyph glyph-name="uniF2E1" unicode="&#xf2e1;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2E2" unicode="&#xf2e2;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2E3" unicode="&#xf2e3;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2E4" unicode="&#xf2e4;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2E5" unicode="&#xf2e5;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2E6" unicode="&#xf2e6;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2E7" unicode="&#xf2e7;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="_698" unicode="&#xf2e8;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2E9" unicode="&#xf2e9;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2EA" unicode="&#xf2ea;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2EB" unicode="&#xf2eb;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2EC" unicode="&#xf2ec;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2ED" unicode="&#xf2ed;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="uniF2EE" unicode="&#xf2ee;" horiz-adv-x="1792"
+ />
+ <glyph glyph-name="lessequal" unicode="&#xf500;" horiz-adv-x="1792"
+ />
+ </font>
+</defs></svg>
diff --git a/phpBB/assets/fonts/fontawesome-webfont.ttf b/phpBB/assets/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000000..35acda2fa1
--- /dev/null
+++ b/phpBB/assets/fonts/fontawesome-webfont.ttf
Binary files differ
diff --git a/phpBB/assets/fonts/fontawesome-webfont.woff b/phpBB/assets/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000000..400014a4b0
--- /dev/null
+++ b/phpBB/assets/fonts/fontawesome-webfont.woff
Binary files differ
diff --git a/phpBB/assets/fonts/fontawesome-webfont.woff2 b/phpBB/assets/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000000..4d13fc6040
--- /dev/null
+++ b/phpBB/assets/fonts/fontawesome-webfont.woff2
Binary files differ
diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js
index b079043396..5218a8c1be 100644
--- a/phpBB/assets/javascript/core.js
+++ b/phpBB/assets/javascript/core.js
@@ -20,6 +20,13 @@ var phpbbAlertTimer = null;
phpbb.isTouch = (window && typeof window.ontouchstart !== 'undefined');
+// Add ajax pre-filter to prevent cross-domain script execution
+$.ajaxPrefilter(function(s) {
+ if (s.crossDomain) {
+ s.contents.script = false;
+ }
+});
+
/**
* Display a loading screen
*
@@ -27,7 +34,10 @@ phpbb.isTouch = (window && typeof window.ontouchstart !== 'undefined');
*/
phpbb.loadingIndicator = function() {
if (!$loadingIndicator) {
- $loadingIndicator = $('<div />', { id: 'loading_indicator' });
+ $loadingIndicator = $('<div />', {
+ 'id': 'loading_indicator',
+ 'class': 'loading_indicator'
+ });
$loadingIndicator.appendTo('#page-footer');
}
@@ -176,7 +186,7 @@ phpbb.alert.close = function($alert, fadedark) {
phpbb.confirm = function(msg, callback, fadedark) {
var $confirmDiv = $('#phpbb_confirm');
$confirmDiv.find('.alert_text').html(msg);
- fadedark = fadedark || true;
+ fadedark = typeof fadedark !== 'undefined' ? fadedark : true;
$(document).on('keydown.phpbb.alert', function(e) {
if (e.keyCode === keymap.ENTER || e.keyCode === keymap.ESC) {
@@ -191,9 +201,7 @@ phpbb.confirm = function(msg, callback, fadedark) {
$confirmDiv.find('input[type="button"]').one('click.phpbb.confirmbox', function(e) {
var confirmed = this.name === 'confirm';
- if (confirmed) {
- callback(true);
- }
+ callback(confirmed);
$confirmDiv.find('input[type="button"]').off('click.phpbb.confirmbox');
phpbb.alert.close($confirmDiv, fadedark || !confirmed);
@@ -934,9 +942,9 @@ phpbb.addAjaxCallback('alt_text', function() {
$anchor.each(function() {
var $this = $(this);
altText = $this.attr('data-alt-text');
- $this.attr('data-alt-text', $this.text());
- $this.attr('title', $.trim(altText));
- $this.text(altText);
+ $this.attr('data-alt-text', $.trim($this.text()));
+ $this.attr('title', altText);
+ $this.children('span').text(altText);
});
});
@@ -965,12 +973,6 @@ phpbb.addAjaxCallback('toggle_link', function() {
$anchor.each(function() {
var $this = $(this);
- // Toggle link text
- toggleText = $this.attr('data-toggle-text');
- $this.attr('data-toggle-text', $this.text());
- $this.attr('title', $.trim(toggleText));
- $this.text(toggleText);
-
// Toggle link url
toggleUrl = $this.attr('data-toggle-url');
$this.attr('data-toggle-url', $this.attr('href'));
@@ -978,8 +980,14 @@ phpbb.addAjaxCallback('toggle_link', function() {
// Toggle class of link parent
toggleClass = $this.attr('data-toggle-class');
- $this.attr('data-toggle-class', $this.parent().attr('class'));
- $this.parent().attr('class', toggleClass);
+ $this.attr('data-toggle-class', $this.children().attr('class'));
+ $this.children('.icon').attr('class', toggleClass);
+
+ // Toggle link text
+ toggleText = $this.attr('data-toggle-text');
+ $this.attr('data-toggle-text', $this.children('span').text());
+ $this.attr('title', $.trim(toggleText));
+ $this.children('span').text(toggleText);
});
});
@@ -1330,6 +1338,7 @@ phpbb.toggleDropdown = function() {
$this.css({
marginLeft: 0,
left: 0,
+ marginRight: 0,
maxWidth: (windowWidth - 4) + 'px'
});
@@ -1641,7 +1650,7 @@ phpbb.lazyLoadAvatars = function loadAvatars() {
});
};
-$(window).load(phpbb.lazyLoadAvatars);
+$(window).on('load', phpbb.lazyLoadAvatars);
/**
* Apply code editor to all textarea elements with data-bbcode attribute
@@ -1653,7 +1662,7 @@ $(function() {
phpbb.registerPageDropdowns();
- $('#color_palette_placeholder').each(function() {
+ $('[data-orientation]').each(function() {
phpbb.registerPalette($(this));
});
diff --git a/phpBB/assets/javascript/editor.js b/phpBB/assets/javascript/editor.js
index 3abf5c84f4..24cbc09f58 100644
--- a/phpBB/assets/javascript/editor.js
+++ b/phpBB/assets/javascript/editor.js
@@ -18,16 +18,9 @@ var is_win = ((clientPC.indexOf('win') !== -1) || (clientPC.indexOf('16bit') !==
var baseHeight;
/**
-* Shows the help messages in the helpline window
-*/
-function helpline(help) {
- document.forms[form_name].helpbox.value = help_line[help];
-}
-
-/**
* Fix a bug involving the TextRange object. From
* http://www.frostjedi.com/terra/scripts/demo/caretBug.html
-*/
+*/
function initInsertions() {
var doc;
@@ -104,14 +97,13 @@ function bbfontstyle(bbopen, bbclose) {
}
// IE
else if (document.selection) {
- var range = textarea.createTextRange();
- range.move("character", new_pos);
+ var range = textarea.createTextRange();
+ range.move("character", new_pos);
range.select();
storeCaret(textarea);
}
textarea.focus();
- return;
}
/**
@@ -167,7 +159,7 @@ function attachInline(index, filename) {
/**
* Add quote text to message
*/
-function addquote(post_id, username, l_wrote) {
+function addquote(post_id, username, l_wrote, attributes) {
var message_name = 'message_' + post_id;
var theSelection = '';
var divarea = false;
@@ -177,6 +169,9 @@ function addquote(post_id, username, l_wrote) {
// Backwards compatibility
l_wrote = 'wrote';
}
+ if (typeof attributes !== 'object') {
+ attributes = {};
+ }
if (document.all) {
divarea = document.all[message_name];
@@ -213,7 +208,8 @@ function addquote(post_id, username, l_wrote) {
if (theSelection) {
if (bbcodeEnabled) {
- insert_text('[quote="' + username + '"]' + theSelection + '[/quote]');
+ attributes.author = username;
+ insert_text(generateQuote(theSelection, attributes));
} else {
insert_text(username + ' ' + l_wrote + ':' + '\n');
var lines = split_lines(theSelection);
@@ -222,8 +218,61 @@ function addquote(post_id, username, l_wrote) {
}
}
}
+}
- return;
+/**
+* Create a quote block for given text
+*
+* Possible attributes:
+* - author: author's name (usually a username)
+* - post_id: post_id of the post being quoted
+* - user_id: user_id of the user being quoted
+* - time: timestamp of the original message
+*
+* @param {!string} text Quote's text
+* @param {!Object} attributes Quote's attributes
+* @return {!string} Quote block to be used in a new post/text
+*/
+function generateQuote(text, attributes) {
+ text = text.replace(/^\s+/, '').replace(/\s+$/, '');
+ var quote = '[quote';
+ if (attributes.author) {
+ // Add the author as the BBCode's default attribute
+ quote += '=' + formatAttributeValue(attributes.author);
+ delete attributes.author;
+ }
+ for (var name in attributes) {
+ if (attributes.hasOwnProperty(name)) {
+ var value = attributes[name];
+ quote += ' ' + name + '=' + formatAttributeValue(value.toString());
+ }
+ }
+ quote += ']';
+ var newline = ((quote + text + '[/quote]').length > 80 || text.indexOf('\n') > -1) ? '\n' : '';
+ quote += newline + text + newline + '[/quote]';
+
+ return quote;
+}
+
+/**
+* Format given string to be used as an attribute value
+*
+* Will return the string as-is if it can be used in a BBCode without quotes. Otherwise,
+* it will use either single- or double- quotes depending on whichever requires less escaping.
+* Quotes and backslashes are escaped with backslashes where necessary
+*
+* @param {!string} str Original string
+* @return {!string} Same string if possible, escaped string within quotes otherwise
+*/
+function formatAttributeValue(str) {
+ if (!/[ "'\\\]]/.test(str)) {
+ // Return as-is if it contains none of: space, ' " \ or ]
+ return str;
+ }
+ var singleQuoted = "'" + str.replace(/[\\']/g, '\\$&') + "'",
+ doubleQuoted = '"' + str.replace(/[\\"]/g, '\\$&') + '"';
+
+ return (singleQuoted.length < doubleQuoted.length) ? singleQuoted : doubleQuoted;
}
function split_lines(text) {
@@ -361,7 +410,7 @@ function getCaretPosition(txtarea) {
$('textarea').on('keydown', function (e) {
if (e.which === 13 && (e.metaKey || e.ctrlKey)) {
- $(this).closest('form').submit();
+ $(this).closest('form').find(':submit').click();
}
});
});
diff --git a/phpBB/assets/javascript/installer.js b/phpBB/assets/javascript/installer.js
new file mode 100644
index 0000000000..a11b76b863
--- /dev/null
+++ b/phpBB/assets/javascript/installer.js
@@ -0,0 +1,615 @@
+/**
+ * Installer's AJAX frontend handler
+ */
+
+(function($) { // Avoid conflicts with other libraries
+ 'use strict';
+
+ // Installer variables
+ var pollTimer = null;
+ var nextReadPosition = 0;
+ var progressBarTriggered = false;
+ var progressTimer = null;
+ var currentProgress = 0;
+ var refreshRequested = false;
+ var transmissionOver = false;
+ var statusCount = 0;
+
+ // Template related variables
+ var $contentWrapper = $('.install-body').find('.main');
+
+ // Intercept form submits
+ interceptFormSubmit($('#install_install'));
+
+ /**
+ * Creates an XHR object
+ *
+ * jQuery cannot be used as the response is streamed, and
+ * as of now, jQuery does not provide access to the response until
+ * the connection is not closed.
+ *
+ * @return XMLHttpRequest
+ */
+ function createXhrObject() {
+ return new XMLHttpRequest();
+ }
+
+ /**
+ * Displays error, warning and log messages
+ *
+ * @param type
+ * @param messages
+ */
+ function addMessage(type, messages) {
+ // Get message containers
+ var $errorContainer = $('#error-container');
+ var $warningContainer = $('#warning-container');
+ var $logContainer = $('#log-container');
+
+ var $title, $description, $msgElement, arraySize = messages.length;
+ for (var i = 0; i < arraySize; i++) {
+ $msgElement = $('<div />');
+ $title = $('<strong />');
+ $title.text(messages[i].title);
+ $msgElement.append($title);
+
+ if (messages[i].hasOwnProperty('description')) {
+ $description = $('<p />');
+ $description.html(messages[i].description);
+ $msgElement.append($description);
+ }
+
+ switch (type) {
+ case 'error':
+ $msgElement.addClass('errorbox');
+ $errorContainer.append($msgElement);
+ break;
+ case 'warning':
+ $msgElement.addClass('warningbox');
+ $warningContainer.append($msgElement);
+ break;
+ case 'log':
+ $msgElement.addClass('log');
+ $logContainer.prepend($msgElement);
+ $logContainer.addClass('show_log_container');
+ break;
+ case 'success':
+ $msgElement.addClass('successbox');
+ $errorContainer.prepend($msgElement);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Render a download box
+ */
+ function addDownloadBox(downloadArray)
+ {
+ var $downloadContainer = $('#download-wrapper');
+ var $downloadBox, $title, $content, $link;
+
+ for (var i = 0; i < downloadArray.length; i++) {
+ $downloadBox = $('<div />');
+ $downloadBox.addClass('download-box');
+
+ $title = $('<strong />');
+ $title.text(downloadArray[i].title);
+ $downloadBox.append($title);
+
+ if (downloadArray[i].hasOwnProperty('msg')) {
+ $content = $('<p />');
+ $content.text(downloadArray[i].msg);
+ $downloadBox.append($content);
+ }
+
+ $link = $('<a />');
+ $link.addClass('button1');
+ $link.attr('href', downloadArray[i].href);
+ $link.text(downloadArray[i].download);
+ $downloadBox.append($link);
+
+ $downloadContainer.append($downloadBox);
+ }
+ }
+
+ /**
+ * Render update files' status
+ */
+ function addUpdateFileStatus(fileStatus)
+ {
+ var $statusContainer = $('#file-status-wrapper');
+ $statusContainer.html(fileStatus);
+ }
+
+ /**
+ * Displays a form from the response
+ *
+ * @param formHtml
+ */
+ function addForm(formHtml) {
+ var $formContainer = $('#form-wrapper');
+ $formContainer.html(formHtml);
+ var $form = $('#install_install');
+ interceptFormSubmit($form);
+ }
+
+ /**
+ * Handles navigation status updates
+ *
+ * @param navObj
+ */
+ function updateNavbarStatus(navObj) {
+ var navID, $stage, $stageListItem, $active;
+ $active = $('#activemenu');
+
+ if (navObj.hasOwnProperty('finished')) {
+ // This should be an Array
+ var navItems = navObj.finished;
+
+ for (var i = 0; i < navItems.length; i++) {
+ navID = 'installer-stage-' + navItems[i];
+ $stage = $('#' + navID);
+ $stageListItem = $stage.parent();
+
+ if ($active.length && $active.is($stageListItem)) {
+ $active.removeAttr('id');
+ }
+
+ $stage.addClass('completed');
+ }
+ }
+
+ if (navObj.hasOwnProperty('active')) {
+ navID = 'installer-stage-' + navObj.active;
+ $stage = $('#' + navID);
+ $stageListItem = $stage.parent();
+
+ if ($active.length && !$active.is($stageListItem)) {
+ $active.removeAttr('id');
+ }
+
+ $stageListItem.attr('id', 'activemenu');
+ }
+ }
+
+ /**
+ * Renders progress bar
+ *
+ * @param progressObject
+ */
+ function setProgress(progressObject) {
+ var $statusText, $progressBar, $progressText, $progressFiller, $progressFillerText;
+
+ if (progressObject.task_name.length) {
+ if (!progressBarTriggered) {
+ // Create progress bar
+ var $progressBarWrapper = $('#progress-bar-container');
+
+ // Create progress bar elements
+ $progressBar = $('<div />');
+ $progressBar.attr('id', 'progress-bar');
+ $progressText = $('<p />');
+ $progressText.attr('id', 'progress-bar-text');
+ $progressFiller = $('<div />');
+ $progressFiller.attr('id', 'progress-bar-filler');
+ $progressFillerText = $('<p />');
+ $progressFillerText.attr('id', 'progress-bar-filler-text');
+
+ $statusText = $('<p />');
+ $statusText.attr('id', 'progress-status-text');
+
+ $progressFiller.append($progressFillerText);
+ $progressBar.append($progressText);
+ $progressBar.append($progressFiller);
+
+ $progressBarWrapper.append($statusText);
+ $progressBarWrapper.append($progressBar);
+
+ $progressFillerText.css('width', $progressBar.width());
+
+ progressBarTriggered = true;
+ } else if (progressObject.hasOwnProperty('restart')) {
+ clearInterval(progressTimer);
+
+ $progressFiller = $('#progress-bar-filler');
+ $progressFillerText = $('#progress-bar-filler-text');
+ $progressText = $('#progress-bar-text');
+ $statusText = $('#progress-status-text');
+
+ $progressText.text('0%');
+ $progressFillerText.text('0%');
+ $progressFiller.css('width', '0%');
+
+ currentProgress = 0;
+ } else {
+ $statusText = $('#progress-status-text');
+ }
+
+ // Update progress bar
+ $statusText.text(progressObject.task_name + '…');
+ incrementProgressBar(Math.round(progressObject.task_num / progressObject.task_count * 100));
+ }
+ }
+
+ // Set cookies
+ function setCookies(cookies) {
+ var cookie;
+
+ for (var i = 0; i < cookies.length; i++) {
+ // Set cookie name and value
+ cookie = encodeURIComponent(cookies[i].name) + '=' + encodeURIComponent(cookies[i].value);
+ // Set path
+ cookie += '; path=/';
+ document.cookie = cookie;
+ }
+ }
+
+ // Redirects user
+ function redirect(url, use_ajax) {
+ if (use_ajax) {
+ resetPolling();
+
+ var xhReq = createXhrObject();
+ xhReq.open('GET', url, true);
+ xhReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ xhReq.send();
+
+ startPolling(xhReq);
+ } else {
+ window.location.href = url;
+ }
+ }
+
+ /**
+ * Parse messages from the response object
+ *
+ * @param messageJSON
+ */
+ function parseMessage(messageJSON) {
+ $('#loading_indicator').css('display', 'none');
+ var responseObject;
+
+ try {
+ responseObject = JSON.parse(messageJSON);
+ } catch (err) {
+ if (window.console) {
+ console.log('Failed to parse JSON object\n\nMessage: ' + err.message + '\n\nServer Response: ' + messageJSON);
+ } else {
+ alert('Failed to parse JSON object\n\nMessage: ' + err.message + '\n\nServer Response: ' + messageJSON);
+ }
+
+ resetPolling();
+ return;
+ }
+
+ // Parse object
+ if (responseObject.hasOwnProperty('errors')) {
+ addMessage('error', responseObject.errors);
+ }
+
+ if (responseObject.hasOwnProperty('warnings')) {
+ addMessage('warning', responseObject.warnings);
+ }
+
+ if (responseObject.hasOwnProperty('logs')) {
+ addMessage('log', responseObject.logs);
+ }
+
+ if (responseObject.hasOwnProperty('success')) {
+ addMessage('success', responseObject.success);
+ }
+
+ if (responseObject.hasOwnProperty('form')) {
+ addForm(responseObject.form);
+ }
+
+ if (responseObject.hasOwnProperty('progress')) {
+ setProgress(responseObject.progress);
+ }
+
+ if (responseObject.hasOwnProperty('download')) {
+ addDownloadBox(responseObject.download);
+ }
+
+ if (responseObject.hasOwnProperty('file_status')) {
+ addUpdateFileStatus(responseObject.file_status);
+ }
+
+ if (responseObject.hasOwnProperty('nav')) {
+ updateNavbarStatus(responseObject.nav);
+ }
+
+ if (responseObject.hasOwnProperty('cookies')) {
+ setCookies(responseObject.cookies);
+ }
+
+ if (responseObject.hasOwnProperty('refresh')) {
+ refreshRequested = true;
+ }
+
+ if (responseObject.hasOwnProperty('redirect')) {
+ redirect(responseObject.redirect.url, responseObject.redirect.use_ajax);
+ }
+
+ if (responseObject.hasOwnProperty('over')) {
+ if (responseObject.over) {
+ transmissionOver = true;
+ }
+ }
+ }
+
+ /**
+ * Processes status data
+ *
+ * @param status
+ */
+ function processTimeoutResponse(status) {
+ if (statusCount === 12) { // 1 minute hard cap
+ status = 'fail';
+ }
+
+ if (status === 'continue') {
+ refreshRequested = false;
+ doRefresh();
+ } else if (status === 'running') {
+ statusCount++;
+ $('#loading_indicator').css('display', 'block');
+ setTimeout(queryInstallerStatus, 5000);
+ } else {
+ $('#loading_indicator').css('display', 'none');
+ addMessage('error',
+ [{
+ title: installLang.title,
+ description: installLang.msg
+ }]
+ );
+ }
+ }
+
+ /**
+ * Queries the installer's status
+ */
+ function queryInstallerStatus() {
+ var url = $(location).attr('pathname');
+ var lookUp = 'install/app.php';
+ var position = url.indexOf(lookUp);
+
+ if (position === -1) {
+ lookUp = 'install';
+ position = url.indexOf(lookUp);
+
+ if (position === -1) {
+ return false;
+ }
+ }
+
+ url = url.substring(0, position) + lookUp + '/installer/status';
+ $.getJSON(url, function(data) {
+ processTimeoutResponse(data.status);
+ });
+ }
+
+ /**
+ * Process updates in streamed response
+ *
+ * @param xhReq XHR object
+ */
+ function pollContent(xhReq) {
+ var messages = xhReq.responseText;
+ var msgSeparator = '}\n\n';
+ var unprocessed, messageEndIndex, endOfMessageIndex, message;
+
+ do {
+ unprocessed = messages.substring(nextReadPosition);
+ messageEndIndex = unprocessed.indexOf(msgSeparator);
+
+ if (messageEndIndex !== -1) {
+ endOfMessageIndex = messageEndIndex + msgSeparator.length;
+ message = unprocessed.substring(0, endOfMessageIndex);
+ parseMessage($.trim(message));
+ nextReadPosition += endOfMessageIndex;
+ }
+ } while (messageEndIndex !== -1);
+
+ if (xhReq.readyState === 4) {
+ $('#loading_indicator').css('display', 'none');
+ resetPolling();
+
+ var timeoutDetected = !transmissionOver;
+
+ if (refreshRequested) {
+ refreshRequested = false;
+ doRefresh();
+ }
+
+ if (timeoutDetected) {
+ statusCount = 0;
+ queryInstallerStatus();
+ }
+ }
+ }
+
+ /**
+ * Animates the progress bar
+ *
+ * @param $progressText
+ * @param $progressFiller
+ * @param $progressFillerText
+ * @param progressLimit
+ */
+ function incrementFiller($progressText, $progressFiller, $progressFillerText, progressLimit) {
+ if (currentProgress >= progressLimit || currentProgress >= 100) {
+ clearInterval(progressTimer);
+ return;
+ }
+
+ var $progressBar = $('#progress-bar');
+
+ currentProgress++;
+ $progressFillerText.css('width', $progressBar.width());
+ $progressFillerText.text(currentProgress + '%');
+ $progressText.text(currentProgress + '%');
+ $progressFiller.css('width', currentProgress + '%');
+ }
+
+ /**
+ * Wrapper function for progress bar rendering and animating
+ *
+ * @param progressLimit
+ */
+ function incrementProgressBar(progressLimit) {
+ var $progressFiller = $('#progress-bar-filler');
+ var $progressFillerText = $('#progress-bar-filler-text');
+ var $progressText = $('#progress-bar-text');
+ var progressStart = $progressFiller.width() / $progressFiller.offsetParent().width() * 100;
+ currentProgress = Math.floor(progressStart);
+
+ clearInterval(progressTimer);
+ progressTimer = setInterval(function() {
+ incrementFiller($progressText, $progressFiller, $progressFillerText, progressLimit);
+ }, 10);
+ }
+
+ /**
+ * Resets the polling timer
+ */
+ function resetPolling() {
+ clearInterval(pollTimer);
+ nextReadPosition = 0;
+ }
+
+ /**
+ * Sets up timer for processing the streamed HTTP response
+ *
+ * @param xhReq
+ */
+ function startPolling(xhReq) {
+ resetPolling();
+ transmissionOver = false;
+ pollTimer = setInterval(function () {
+ pollContent(xhReq);
+ }, 250);
+ }
+
+ /**
+ * Refresh page
+ */
+ function doRefresh() {
+ resetPolling();
+
+ var xhReq = createXhrObject();
+ xhReq.open('GET', $(location).attr('pathname'), true);
+ xhReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ xhReq.send();
+
+ startPolling(xhReq);
+ }
+
+ /**
+ * Renders the AJAX UI layout
+ */
+ function setupAjaxLayout() {
+ progressBarTriggered = false;
+
+ // Clear content
+ $contentWrapper.html('');
+
+ var $header = $('<div />');
+ $header.attr('id', 'header-container');
+ $contentWrapper.append($header);
+
+ var $description = $('<div />');
+ $description.attr('id', 'description-container');
+ $contentWrapper.append($description);
+
+ var $errorContainer = $('<div />');
+ $errorContainer.attr('id', 'error-container');
+ $contentWrapper.append($errorContainer);
+
+ var $warningContainer = $('<div />');
+ $warningContainer.attr('id', 'warning-container');
+ $contentWrapper.append($warningContainer);
+
+ var $progressContainer = $('<div />');
+ $progressContainer.attr('id', 'progress-bar-container');
+ $contentWrapper.append($progressContainer);
+
+ var $logContainer = $('<div />');
+ $logContainer.attr('id', 'log-container');
+ $contentWrapper.append($logContainer);
+
+ var $installerContentWrapper = $('<div />');
+ $installerContentWrapper.attr('id', 'content-container');
+ $contentWrapper.append($installerContentWrapper);
+
+ var $installerDownloadWrapper = $('<div />');
+ $installerDownloadWrapper.attr('id', 'download-wrapper');
+ $installerContentWrapper.append($installerDownloadWrapper);
+
+ var $updaterFileStatusWrapper = $('<div />');
+ $updaterFileStatusWrapper.attr('id', 'file-status-wrapper');
+ $installerContentWrapper.append($updaterFileStatusWrapper);
+
+ var $formWrapper = $('<div />');
+ $formWrapper.attr('id', 'form-wrapper');
+ $installerContentWrapper.append($formWrapper);
+
+ var $spinner = $('<div />');
+ $spinner.attr('id', 'loading_indicator');
+ $spinner.html('&nbsp;');
+ $contentWrapper.append($spinner);
+ }
+
+ // Submits a form
+ function submitForm($form, $submitBtn) {
+ $form.css('display', 'none');
+
+ var xhReq = createXhrObject();
+ xhReq.open('POST', $form.attr('action'), true);
+ xhReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ xhReq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+ xhReq.send(getFormFields($form, $submitBtn));
+
+ // Disable language selector
+ $('#language_selector :input, label').css('display', 'none');
+
+ // Clear content
+ setupAjaxLayout();
+ $('#loading_indicator').css('display', 'block');
+
+ startPolling(xhReq);
+ }
+
+ /**
+ * Add submit button to the POST information
+ *
+ * @param $form
+ * @param $submitBtn
+ *
+ * @returns {*}
+ */
+ function getFormFields($form, $submitBtn) {
+ var formData = $form.serialize();
+ formData += ((formData.length) ? '&' : '') + encodeURIComponent($submitBtn.attr('name')) + '=';
+ formData += encodeURIComponent($submitBtn.attr('value'));
+
+ return formData;
+ }
+
+ /**
+ * Intercept form submit events and determine the submit button used
+ *
+ * @param $form
+ */
+ function interceptFormSubmit($form) {
+ if (!$form.length) {
+ return;
+ }
+
+ $form.find(':submit').bind('click', function (event) {
+ event.preventDefault();
+ submitForm($form, $(this));
+ });
+ }
+})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/assets/javascript/jquery.min.js b/phpBB/assets/javascript/jquery.min.js
index 73f33fb3aa..e836475870 100644
--- a/phpBB/assets/javascript/jquery.min.js
+++ b/phpBB/assets/javascript/jquery.min.js
@@ -1,4 +1,5 @@
-/*! jQuery v1.11.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
-!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m="1.11.0",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(l.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:k&&!k.call("\ufeff\xa0")?function(a){return null==a?"":k.call(a)}:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||n.guid++,e):void 0},now:function(){return+new Date},support:l}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="<select t=''><option selected=''></option></select>",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=jb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=kb(b);function nb(){}nb.prototype=d.filters=d.pseudos,d.setFilters=new nb;function ob(a,b){var c,e,f,g,h,i,j,k=x[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=Q.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?db.error(a):x(a,i).slice(0)}function pb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=a.document,A=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,B=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:A.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:z,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=z.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return y.find(a);this.length=1,this[0]=d}return this.context=z,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};B.prototype=n.fn,y=n(z);var C=/^(?:parents|prev(?:Until|All))/,D={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!n(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function E(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return E(a,"nextSibling")},prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(D[a]||(e=n.unique(e)),C.test(a)&&(e=e.reverse())),this.pushStack(e)}});var F=/\S+/g,G={};function H(a){var b=G[a]={};return n.each(a.match(F)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?G[a]||H(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&n.each(arguments,function(a,c){var d;while((d=n.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){if(a===!0?!--n.readyWait:!n.isReady){if(!z.body)return setTimeout(n.ready);n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(z,[n]),n.fn.trigger&&n(z).trigger("ready").off("ready"))}}});function J(){z.addEventListener?(z.removeEventListener("DOMContentLoaded",K,!1),a.removeEventListener("load",K,!1)):(z.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(z.addEventListener||"load"===event.type||"complete"===z.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===z.readyState)setTimeout(n.ready);else if(z.addEventListener)z.addEventListener("DOMContentLoaded",K,!1),a.addEventListener("load",K,!1);else{z.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&z.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!n.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}J(),n.ready()}}()}return I.promise(b)};var L="undefined",M;for(M in n(l))break;l.ownLast="0"!==M,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c=z.getElementsByTagName("body")[0];c&&(a=z.createElement("div"),a.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",b=z.createElement("div"),c.appendChild(a).appendChild(b),typeof b.style.zoom!==L&&(b.style.cssText="border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1",(l.inlineBlockNeedsLayout=3===b.offsetWidth)&&(c.style.zoom=1)),c.removeChild(a),a=b=null)}),function(){var a=z.createElement("div");if(null==l.deleteExpando){l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}}a=null}(),n.acceptData=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(n.acceptData(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f
-}}function S(a,b,c){if(n.acceptData(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d]));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=["Top","Right","Bottom","Left"],V=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},W=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},X=/^(?:checkbox|radio)$/i;!function(){var a=z.createDocumentFragment(),b=z.createElement("div"),c=z.createElement("input");if(b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a>",l.leadingWhitespace=3===b.firstChild.nodeType,l.tbody=!b.getElementsByTagName("tbody").length,l.htmlSerialize=!!b.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==z.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,a.appendChild(c),l.appendChecked=c.checked,b.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,a.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){l.noCloneEvent=!1}),b.cloneNode(!0).click()),null==l.deleteExpando){l.deleteExpando=!0;try{delete b.test}catch(d){l.deleteExpando=!1}}a=b=c=null}(),function(){var b,c,d=z.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),l[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var Y=/^(?:input|select|textarea)$/i,Z=/^key/,$=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,ab=/^([^.]*)(?:\.(.+)|)$/;function bb(){return!0}function cb(){return!1}function db(){try{return z.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof n===L||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(F)||[""],h=b.length;while(h--)f=ab.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(F)||[""],j=b.length;while(j--)if(h=ab.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,m,o=[d||z],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||z,3!==d.nodeType&&8!==d.nodeType&&!_.test(p+n.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[n.expando]?b:new n.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),k=n.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!n.isWindow(d)){for(i=k.delegateType||p,_.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||z)&&o.push(l.defaultView||l.parentWindow||a)}m=0;while((h=o[m++])&&!b.isPropagationStopped())b.type=m>1?i:k.bindType||p,f=(n._data(h,"events")||{})[b.type]&&n._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&n.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&n.acceptData(d)&&g&&d[p]&&!n.isWindow(d)){l=d[g],l&&(d[g]=null),n.event.triggered=p;try{d[p]()}catch(r){}n.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((n.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?n(c,this).index(i)>=0:n.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=$.test(e)?this.mouseHooks:Z.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||z),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||z,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==db()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===db()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=z.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===L&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&(a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault())?bb:cb):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:cb,isPropagationStopped:cb,isImmediatePropagationStopped:cb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=bb,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=bb,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=bb,this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submitBubbles||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?b.form:void 0;c&&!n._data(c,"submitBubbles")&&(n.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),n._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.changeBubbles||(n.event.special.change={setup:function(){return Y.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),n.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),n.event.simulate("change",this,a,!0)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;Y.test(b.nodeName)&&!n._data(b,"changeBubbles")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a,!0)}),n._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!Y.test(this.nodeName)}}),l.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=cb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return n().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=cb),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});function eb(a){var b=fb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var fb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gb=/ jQuery\d+="(?:null|\d+)"/g,hb=new RegExp("<(?:"+fb+")[\\s/>]","i"),ib=/^\s+/,jb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,kb=/<([\w:]+)/,lb=/<tbody/i,mb=/<|&#?\w+;/,nb=/<(?:script|style|link)/i,ob=/checked\s*(?:[^=]|=\s*.checked.)/i,pb=/^$|\/(?:java|ecma)script/i,qb=/^true\/(.*)/,rb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,sb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},tb=eb(z),ub=tb.appendChild(z.createElement("div"));sb.optgroup=sb.option,sb.tbody=sb.tfoot=sb.colgroup=sb.caption=sb.thead,sb.th=sb.td;function vb(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==L?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==L?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,vb(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function wb(a){X.test(a.type)&&(a.defaultChecked=a.checked)}function xb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function yb(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function zb(a){var b=qb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ab(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}function Bb(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Cb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(yb(b).text=a.text,zb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&X.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}n.extend({clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!hb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ub.innerHTML=a.outerHTML,ub.removeChild(f=ub.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=vb(f),h=vb(a),g=0;null!=(e=h[g]);++g)d[g]&&Cb(e,d[g]);if(b)if(c)for(h=h||vb(a),d=d||vb(f),g=0;null!=(e=h[g]);g++)Bb(e,d[g]);else Bb(a,f);return d=vb(f,"script"),d.length>0&&Ab(d,!i&&vb(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k,m=a.length,o=eb(b),p=[],q=0;m>q;q++)if(f=a[q],f||0===f)if("object"===n.type(f))n.merge(p,f.nodeType?[f]:f);else if(mb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(kb.exec(f)||["",""])[1].toLowerCase(),k=sb[i]||sb._default,h.innerHTML=k[1]+f.replace(jb,"<$1></$2>")+k[2],e=k[0];while(e--)h=h.lastChild;if(!l.leadingWhitespace&&ib.test(f)&&p.push(b.createTextNode(ib.exec(f)[0])),!l.tbody){f="table"!==i||lb.test(f)?"<table>"!==k[1]||lb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)n.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}n.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),l.appendChecked||n.grep(vb(p,"input"),wb),q=0;while(f=p[q++])if((!d||-1===n.inArray(f,d))&&(g=n.contains(f.ownerDocument,f),h=vb(o.appendChild(f),"script"),g&&Ab(h),c)){e=0;while(f=h[e++])pb.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.deleteExpando,m=n.event.special;null!=(d=a[h]);h++)if((b||n.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k?delete d[i]:typeof d.removeAttribute!==L?d.removeAttribute(i):d[i]=null,c.push(f))}}}),n.fn.extend({text:function(a){return W(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||z).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=xb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(vb(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&Ab(vb(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(vb(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return W(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(gb,""):void 0;if(!("string"!=typeof a||nb.test(a)||!l.htmlSerialize&&hb.test(a)||!l.leadingWhitespace&&ib.test(a)||sb[(kb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(jb,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(vb(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(vb(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,o=k-1,p=a[0],q=n.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&ob.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(i=n.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=n.map(vb(i,"script"),yb),f=g.length;k>j;j++)d=i,j!==o&&(d=n.clone(d,!0,!0),f&&n.merge(g,vb(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,n.map(g,zb),j=0;f>j;j++)d=g[j],pb.test(d.type||"")&&!n._data(d,"globalEval")&&n.contains(h,d)&&(d.src?n._evalUrl&&n._evalUrl(d.src):n.globalEval((d.text||d.textContent||d.innerHTML||"").replace(rb,"")));i=c=null}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],g=n(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Db,Eb={};function Fb(b,c){var d=n(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:n.css(d[0],"display");return d.detach(),e}function Gb(a){var b=z,c=Eb[a];return c||(c=Fb(a,b),"none"!==c&&c||(Db=(Db||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Db[0].contentWindow||Db[0].contentDocument).document,b.write(),b.close(),c=Fb(a,b),Db.detach()),Eb[a]=c),c}!function(){var a,b,c=z.createElement("div"),d="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";c.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],a.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(a.style.opacity),l.cssFloat=!!a.style.cssFloat,c.style.backgroundClip="content-box",c.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===c.style.backgroundClip,a=c=null,l.shrinkWrapBlocks=function(){var a,c,e,f;if(null==b){if(a=z.getElementsByTagName("body")[0],!a)return;f="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",c=z.createElement("div"),e=z.createElement("div"),a.appendChild(c).appendChild(e),b=!1,typeof e.style.zoom!==L&&(e.style.cssText=d+";width:1px;padding:1px;zoom:1",e.innerHTML="<div></div>",e.firstChild.style.width="5px",b=3!==e.offsetWidth),a.removeChild(c),a=c=e=null}return b}}();var Hb=/^margin/,Ib=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Jb,Kb,Lb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Jb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),Ib.test(g)&&Hb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):z.documentElement.currentStyle&&(Jb=function(a){return a.currentStyle},Kb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Jb(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ib.test(g)&&!Lb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Mb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h=z.createElement("div"),i="border:0;width:0;height:0;position:absolute;top:0;left:-9999px",j="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;padding:0;margin:0;border:0";h.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",b=h.getElementsByTagName("a")[0],b.style.cssText="float:left;opacity:.5",l.opacity=/^0.5/.test(b.style.opacity),l.cssFloat=!!b.style.cssFloat,h.style.backgroundClip="content-box",h.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===h.style.backgroundClip,b=h=null,n.extend(l,{reliableHiddenOffsets:function(){if(null!=c)return c;var a,b,d,e=z.createElement("div"),f=z.getElementsByTagName("body")[0];if(f)return e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=z.createElement("div"),a.style.cssText=i,f.appendChild(a).appendChild(e),e.innerHTML="<table><tr><td></td><td>t</td></tr></table>",b=e.getElementsByTagName("td"),b[0].style.cssText="padding:0;margin:0;border:0;display:none",d=0===b[0].offsetHeight,b[0].style.display="",b[1].style.display="none",c=d&&0===b[0].offsetHeight,f.removeChild(a),e=f=null,c},boxSizing:function(){return null==d&&k(),d},boxSizingReliable:function(){return null==e&&k(),e},pixelPosition:function(){return null==f&&k(),f},reliableMarginRight:function(){var b,c,d,e;if(null==g&&a.getComputedStyle){if(b=z.getElementsByTagName("body")[0],!b)return;c=z.createElement("div"),d=z.createElement("div"),c.style.cssText=i,b.appendChild(c).appendChild(d),e=d.appendChild(z.createElement("div")),e.style.cssText=d.style.cssText=j,e.style.marginRight=e.style.width="0",d.style.width="1px",g=!parseFloat((a.getComputedStyle(e,null)||{}).marginRight),b.removeChild(c)}return g}});function k(){var b,c,h=z.getElementsByTagName("body")[0];h&&(b=z.createElement("div"),c=z.createElement("div"),b.style.cssText=i,h.appendChild(b).appendChild(c),c.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;display:block;padding:1px;border:1px;width:4px;margin-top:1%;top:1%",n.swap(h,null!=h.style.zoom?{zoom:1}:{},function(){d=4===c.offsetWidth}),e=!0,f=!1,g=!0,a.getComputedStyle&&(f="1%"!==(a.getComputedStyle(c,null)||{}).top,e="4px"===(a.getComputedStyle(c,null)||{width:"4px"}).width),h.removeChild(b),c=h=null)}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Nb=/alpha\([^)]*\)/i,Ob=/opacity\s*=\s*([^)]*)/,Pb=/^(none|table(?!-c[ea]).+)/,Qb=new RegExp("^("+T+")(.*)$","i"),Rb=new RegExp("^([+-])=("+T+")","i"),Sb={position:"absolute",visibility:"hidden",display:"block"},Tb={letterSpacing:0,fontWeight:400},Ub=["Webkit","O","Moz","ms"];function Vb(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ub.length;while(e--)if(b=Ub[e]+c,b in a)return b;return d}function Wb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&V(d)&&(f[g]=n._data(d,"olddisplay",Gb(d.nodeName)))):f[g]||(e=V(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Xb(a,b,c){var d=Qb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Yb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+U[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+U[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+U[f]+"Width",!0,e))):(g+=n.css(a,"padding"+U[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+U[f]+"Width",!0,e)));return g}function Zb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Jb(a),g=l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Kb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ib.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Yb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Kb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=Vb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Rb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]="",i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Vb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Kb(a,b,d)),"normal"===f&&b in Tb&&(f=Tb[b]),""===c||c?(e=parseFloat(f),c===!0||n.isNumeric(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?0===a.offsetWidth&&Pb.test(n.css(a,"display"))?n.swap(a,Sb,function(){return Zb(a,b,d)}):Zb(a,b,d):void 0},set:function(a,c,d){var e=d&&Jb(a);return Xb(a,c,d?Yb(a,b,d,l.boxSizing()&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Ob.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Nb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Nb.test(f)?f.replace(Nb,e):f+" "+e)}}),n.cssHooks.marginRight=Mb(l.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},Kb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+U[d]+b]=f[d]||f[d-2]||f[0];return e}},Hb.test(a)||(n.cssHooks[a+b].set=Xb)}),n.fn.extend({css:function(a,b){return W(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Jb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)
-},a,b,arguments.length>1)},show:function(){return Wb(this,!0)},hide:function(){return Wb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){V(this)?n(this).show():n(this).hide()})}});function $b(a,b,c,d,e){return new $b.prototype.init(a,b,c,d,e)}n.Tween=$b,$b.prototype={constructor:$b,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=$b.propHooks[this.prop];return a&&a.get?a.get(this):$b.propHooks._default.get(this)},run:function(a){var b,c=$b.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):$b.propHooks._default.set(this),this}},$b.prototype.init.prototype=$b.prototype,$b.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},$b.propHooks.scrollTop=$b.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=$b.prototype.init,n.fx.step={};var _b,ac,bc=/^(?:toggle|show|hide)$/,cc=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),dc=/queueHooks$/,ec=[jc],fc={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=cc.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&cc.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function gc(){return setTimeout(function(){_b=void 0}),_b=n.now()}function hc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=U[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function ic(a,b,c){for(var d,e=(fc[b]||[]).concat(fc["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function jc(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&V(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k=Gb(a.nodeName),"none"===j&&(j=k),"inline"===j&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==k?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],bc.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}if(!n.isEmptyObject(o)){r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=ic(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function kc(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function lc(a,b,c){var d,e,f=0,g=ec.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=_b||gc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:_b||gc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(kc(k,j.opts.specialEasing);g>f;f++)if(d=ec[f].call(j,a,k,j.opts))return d;return n.map(k,ic,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(lc,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],fc[c]=fc[c]||[],fc[c].unshift(b)},prefilter:function(a,b){b?ec.unshift(a):ec.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(V).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=lc(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&dc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(hc(b,!0),a,d,e)}}),n.each({slideDown:hc("show"),slideUp:hc("hide"),slideToggle:hc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(_b=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),_b=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ac||(ac=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(ac),ac=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e=z.createElement("div");e.setAttribute("className","t"),e.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=e.getElementsByTagName("a")[0],c=z.createElement("select"),d=c.appendChild(z.createElement("option")),b=e.getElementsByTagName("input")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==e.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=d.selected,l.enctype=!!z.createElement("form").enctype,c.disabled=!0,l.optDisabled=!d.disabled,b=z.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value,a=b=c=d=e=null}();var mc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(mc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.text(a)}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(l.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var nc,oc,pc=n.expr.attrHandle,qc=/^(?:checked|selected)$/i,rc=l.getSetAttribute,sc=l.input;n.fn.extend({attr:function(a,b){return W(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===L?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?oc:nc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(F);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?sc&&rc||!qc.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(rc?c:d)},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),oc={set:function(a,b,c){return b===!1?n.removeAttr(a,c):sc&&rc||!qc.test(c)?a.setAttribute(!rc&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=pc[b]||n.find.attr;pc[b]=sc&&rc||!qc.test(b)?function(a,b,d){var e,f;return d||(f=pc[b],pc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,pc[b]=f),e}:function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),sc&&rc||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):nc&&nc.set(a,b,c)}}),rc||(nc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},pc.id=pc.name=pc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:nc.set},n.attrHooks.contenteditable={set:function(a,b,c){nc.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var tc=/^(?:input|select|textarea|button|object)$/i,uc=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return W(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):tc.test(a.nodeName)||uc.test(a.nodeName)&&a.href?0:-1}}}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var vc=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(F)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(vc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(F)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===L||"boolean"===c)&&(this.className&&n._data(this,"__className__",this.className),this.className=this.className||a===!1?"":n._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(vc," ").indexOf(b)>=0)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var wc=n.now(),xc=/\?/,yc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(yc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var zc,Ac,Bc=/#.*$/,Cc=/([?&])_=[^&]*/,Dc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ec=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Fc=/^(?:GET|HEAD)$/,Gc=/^\/\//,Hc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ic={},Jc={},Kc="*/".concat("*");try{Ac=location.href}catch(Lc){Ac=z.createElement("a"),Ac.href="",Ac=Ac.href}zc=Hc.exec(Ac.toLowerCase())||[];function Mc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(F)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nc(a,b,c,d){var e={},f=a===Jc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Oc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Pc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Qc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ac,type:"GET",isLocal:Ec.test(zc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Oc(Oc(a,n.ajaxSettings),b):Oc(n.ajaxSettings,a)},ajaxPrefilter:Mc(Ic),ajaxTransport:Mc(Jc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Dc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||Ac)+"").replace(Bc,"").replace(Gc,zc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(F)||[""],null==k.crossDomain&&(c=Hc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===zc[1]&&c[2]===zc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(zc[3]||("http:"===zc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),Nc(Ic,k,b,v),2===t)return v;h=k.global,h&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Fc.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(xc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Cc.test(e)?e.replace(Cc,"$1_="+wc++):e+(xc.test(e)?"&":"?")+"_="+wc++)),k.ifModified&&(n.lastModified[e]&&v.setRequestHeader("If-Modified-Since",n.lastModified[e]),n.etag[e]&&v.setRequestHeader("If-None-Match",n.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Kc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Nc(Jc,k,b,v)){v.readyState=1,h&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Pc(k,v,c)),u=Qc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(n.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!l.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||n.css(a,"display"))},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var Rc=/%20/g,Sc=/\[\]$/,Tc=/\r?\n/g,Uc=/^(?:submit|button|image|reset|file)$/i,Vc=/^(?:input|select|textarea|keygen)/i;function Wc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||Sc.test(a)?d(a,e):Wc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Wc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Wc(c,a[c],b,e);return d.join("&").replace(Rc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Vc.test(this.nodeName)&&!Uc.test(a)&&(this.checked||!X.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(Tc,"\r\n")}}):{name:b.name,value:c.replace(Tc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&$c()||_c()}:$c;var Xc=0,Yc={},Zc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Yc)Yc[a](void 0,!0)}),l.cors=!!Zc&&"withCredentials"in Zc,Zc=l.ajax=!!Zc,Zc&&n.ajaxTransport(function(a){if(!a.crossDomain||l.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Xc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Yc[g],b=void 0,f.onreadystatechange=n.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Yc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function $c(){try{return new a.XMLHttpRequest}catch(b){}}function _c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=z.head||n("head")[0]||z.documentElement;return{send:function(d,e){b=z.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var ad=[],bd=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=ad.pop()||n.expando+"_"+wc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(bd.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&bd.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(bd,"$1"+e):b.jsonp!==!1&&(b.url+=(xc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,ad.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||z;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var cd=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&cd)return cd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=a.slice(h,a.length),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&n.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var dd=a.document.documentElement;function ed(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?(typeof e.getBoundingClientRect!==L&&(d=e.getBoundingClientRect()),c=ed(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||dd;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||dd})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return W(this,function(a,d,e){var f=ed(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Mb(l.pixelPosition,function(a,c){return c?(c=Kb(a,b),Ib.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return W(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var fd=a.jQuery,gd=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=gd),b&&a.jQuery===n&&(a.jQuery=fd),n},typeof b===L&&(a.jQuery=a.$=n),n});
+/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=R.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q," ")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0;
+}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}}),function(){var a;l.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,e;return c=d.getElementsByTagName("body")[0],c&&c.style?(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(d.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(e),a):void 0}}();var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),V=["Top","Right","Bottom","Left"],W=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function X(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&U.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var Y=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)Y(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|&#?\w+;/,ha=/<tbody/i;function ia(a){Z.test(a.type)&&(a.defaultChecked=a.checked)}function ja(a,b,c,d,e){for(var f,g,h,i,j,k,m,o=a.length,p=ca(b),q=[],r=0;o>r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?"<table>"!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ma.test(f)?this.mouseHooks:la.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=g.srcElement||d),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,h.filter?h.filter(a,g):a},props:"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,e,f,g=b.button,h=b.fromElement;return null==a.pageX&&null!=b.clientX&&(e=a.target.ownerDocument||d,f=e.documentElement,c=e.body,a.pageX=b.clientX+(f&&f.scrollLeft||c&&c.scrollLeft||0)-(f&&f.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(f&&f.scrollTop||c&&c.scrollTop||0)-(f&&f.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&h&&(a.relatedTarget=h===a.target?b.toElement:h),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ra()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===ra()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=d.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)}:function(a,b,c){var d="on"+b;a.detachEvent&&("undefined"==typeof a[d]&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?pa:qa):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:qa,isPropagationStopped:qa,isImmediatePropagationStopped:qa,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=pa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=pa,a&&!this.isSimulated&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=pa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||n.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submit||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?n.prop(b,"form"):void 0;c&&!n._data(c,"submit")&&(n.event.add(c,"submit._submit",function(a){a._submitBubble=!0}),n._data(c,"submit",!0))})},postDispatch:function(a){a._submitBubble&&(delete a._submitBubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.change||(n.event.special.change={setup:function(){return ka.test(this.nodeName)?("checkbox"!==this.type&&"radio"!==this.type||(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._justChanged=!0)}),n.event.add(this,"click._change",function(a){this._justChanged&&!a.isTrigger&&(this._justChanged=!1),n.event.simulate("change",this,a)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;ka.test(b.nodeName)&&!n._data(b,"change")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a)}),n._data(b,"change",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!ka.test(this.nodeName)}}),l.focusin||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d){return sa(this,a,b,c,d)},one:function(a,b,c,d){return sa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=qa),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ta=/ jQuery\d+="(?:null|\d+)"/g,ua=new RegExp("<(?:"+ba+")[\\s/>]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/<script|<style|<link/i,xa=/checked\s*(?:[^=]|=\s*.checked.)/i,ya=/^true\/(.*)/,za=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement("div"));function Ca(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Da(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,"script"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,"script"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||"")&&!n._data(g,"globalEval")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||"").replace(za,"")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,"script"),d.length>0&&fa(d,!i&&ea(a,"script")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||"undefined"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,""):void 0;if("string"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:"block",BODY:"block"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),"none"!==c&&c||(Ja=(Ja||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Ja[0].contentWindow||Ja[0].contentDocument).document,b.write(),b.close(),c=La(a,b),Ja.detach()),Ka[a]=c),c}var Na=/^margin/,Oa=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Pa=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Qa=d.documentElement;!function(){var b,c,e,f,g,h,i=d.createElement("div"),j=d.createElement("div");if(j.style){j.style.cssText="float:left;opacity:.5",l.opacity="0.5"===j.style.opacity,l.cssFloat=!!j.style.cssFloat,j.style.backgroundClip="content-box",j.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===j.style.backgroundClip,i=d.createElement("div"),i.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",j.innerHTML="",i.appendChild(j),l.boxSizing=""===j.style.boxSizing||""===j.style.MozBoxSizing||""===j.style.WebkitBoxSizing,n.extend(l,{reliableHiddenOffsets:function(){return null==b&&k(),f},boxSizingReliable:function(){return null==b&&k(),e},pixelMarginRight:function(){return null==b&&k(),c},pixelPosition:function(){return null==b&&k(),b},reliableMarginRight:function(){return null==b&&k(),g},reliableMarginLeft:function(){return null==b&&k(),h}});function k(){var k,l,m=d.documentElement;m.appendChild(i),j.style.cssText="-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",b=e=h=!1,c=g=!0,a.getComputedStyle&&(l=a.getComputedStyle(j),b="1%"!==(l||{}).top,h="2px"===(l||{}).marginLeft,e="4px"===(l||{width:"4px"}).width,j.style.marginRight="50%",c="4px"===(l||{marginRight:"4px"}).marginRight,k=j.appendChild(d.createElement("div")),k.style.cssText=j.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",k.style.marginRight=k.style.width="0",j.style.width="1px",g=!parseFloat((a.getComputedStyle(k)||{}).marginRight),j.removeChild(k)),j.style.display="none",f=0===j.getClientRects().length,f&&(j.style.display="",j.innerHTML="<table><tr><td></td><td>t</td></tr></table>",j.childNodes[0].style.borderCollapse="separate",k=j.getElementsByTagName("td"),k[0].style.cssText="margin:0;border:0;padding:0;display:none",f=0===k[0].offsetHeight,f&&(k[0].style.display="",k[1].style.display="none",f=0===k[0].offsetHeight)),m.removeChild(i)}}}();var Ra,Sa,Ta=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ra=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c.getPropertyValue(b)||c[b]:void 0,""!==g&&void 0!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),c&&!l.pixelMarginRight()&&Oa.test(g)&&Na.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f),void 0===g?g:g+""}):Qa.currentStyle&&(Ra=function(a){return a.currentStyle},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Oa.test(g)&&!Ta.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Ua(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Va=/alpha\([^)]*\)/i,Wa=/opacity\s*=\s*([^)]*)/i,Xa=/^(none|table(?!-c[ea]).+)/,Ya=new RegExp("^("+T+")(.*)$","i"),Za={position:"absolute",visibility:"hidden",display:"block"},$a={letterSpacing:"0",fontWeight:"400"},_a=["Webkit","O","Moz","ms"],ab=d.createElement("div").style;function bb(a){if(a in ab)return a;var b=a.charAt(0).toUpperCase()+a.slice(1),c=_a.length;while(c--)if(a=_a[c]+b,a in ab)return a}function cb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&W(d)&&(f[g]=n._data(d,"olddisplay",Ma(d.nodeName)))):(e=W(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function db(a,b,c){var d=Ya.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function eb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+V[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+V[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+V[f]+"Width",!0,e))):(g+=n.css(a,"padding"+V[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+V[f]+"Width",!0,e)));return g}function fb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ra(a),g=l.boxSizing&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Sa(a,b,f),(0>e||null==e)&&(e=a.style[b]),Oa.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+eb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Sa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=U.exec(c))&&e[1]&&(c=X(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(n.cssNumber[h]?"":"px")),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Sa(a,b,d)),"normal"===f&&b in $a&&(f=$a[b]),""===c||c?(e=parseFloat(f),c===!0||isFinite(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Xa.test(n.css(a,"display"))&&0===a.offsetWidth?Pa(a,Za,function(){return fb(a,b,d)}):fb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ra(a);return db(a,c,d?eb(a,b,d,l.boxSizing&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Wa.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Va,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Va.test(f)?f.replace(Va,e):f+" "+e)}}),n.cssHooks.marginRight=Ua(l.reliableMarginRight,function(a,b){return b?Pa(a,{display:"inline-block"},Sa,[a,"marginRight"]):void 0}),n.cssHooks.marginLeft=Ua(l.reliableMarginLeft,function(a,b){return b?(parseFloat(Sa(a,"marginLeft"))||(n.contains(a.ownerDocument,a)?a.getBoundingClientRect().left-Pa(a,{
+marginLeft:0},function(){return a.getBoundingClientRect().left}):0))+"px":void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+V[d]+b]=f[d]||f[d-2]||f[0];return e}},Na.test(a)||(n.cssHooks[a+b].set=db)}),n.fn.extend({css:function(a,b){return Y(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ra(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return cb(this,!0)},hide:function(){return cb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){W(this)?n(this).show():n(this).hide()})}});function gb(a,b,c,d,e){return new gb.prototype.init(a,b,c,d,e)}n.Tween=gb,gb.prototype={constructor:gb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=gb.propHooks[this.prop];return a&&a.get?a.get(this):gb.propHooks._default.get(this)},run:function(a){var b,c=gb.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):gb.propHooks._default.set(this),this}},gb.prototype.init.prototype=gb.prototype,gb.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},gb.propHooks.scrollTop=gb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},n.fx=gb.prototype.init,n.fx.step={};var hb,ib,jb=/^(?:toggle|show|hide)$/,kb=/queueHooks$/;function lb(){return a.setTimeout(function(){hb=void 0}),hb=n.now()}function mb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=V[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function nb(a,b,c){for(var d,e=(qb.tweeners[b]||[]).concat(qb.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ob(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&W(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k="none"===j?n._data(a,"olddisplay")||Ma(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==Ma(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],jb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(o))"inline"===("none"===j?Ma(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=nb(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function pb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function qb(a,b,c){var d,e,f=0,g=qb.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=hb||lb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:hb||lb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(pb(k,j.opts.specialEasing);g>f;f++)if(d=qb.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,nb,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(qb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return X(c.elem,a,U.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],qb.tweeners[c]=qb.tweeners[c]||[],qb.tweeners[c].unshift(b)},prefilters:[ob],prefilter:function(a,b){b?qb.prefilters.unshift(a):qb.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(W).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=qb(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&kb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(mb(b,!0),a,d,e)}}),n.each({slideDown:mb("show"),slideUp:mb("hide"),slideToggle:mb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(hb=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),hb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ib||(ib=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(ib),ib=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a,b=d.createElement("input"),c=d.createElement("div"),e=d.createElement("select"),f=e.appendChild(d.createElement("option"));c=d.createElement("div"),c.setAttribute("className","t"),c.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],b.setAttribute("type","checkbox"),c.appendChild(b),a=c.getElementsByTagName("a")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==c.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=f.selected,l.enctype=!!d.createElement("form").enctype,e.disabled=!0,l.optDisabled=!f.disabled,b=d.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value}();var rb=/\r/g,sb=/[\x20\t\r\n\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a)).replace(sb," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute("disabled"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>-1)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var tb,ub,vb=n.expr.attrHandle,wb=/^(?:checked|selected)$/i,xb=l.getSetAttribute,yb=l.input;n.fn.extend({attr:function(a,b){return Y(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ub:tb)),void 0!==c?null===c?void n.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?yb&&xb||!wb.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(xb?c:d)}}),ub={set:function(a,b,c){return b===!1?n.removeAttr(a,c):yb&&xb||!wb.test(c)?a.setAttribute(!xb&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=vb[b]||n.find.attr;yb&&xb||!wb.test(b)?vb[b]=function(a,b,d){var e,f;return d||(f=vb[b],vb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,vb[b]=f),e}:vb[b]=function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),yb&&xb||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):tb&&tb.set(a,b,c)}}),xb||(tb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},vb.id=vb.name=vb.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:tb.set},n.attrHooks.contenteditable={set:function(a,b,c){tb.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var zb=/^(?:input|select|textarea|button|object)$/i,Ab=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return Y(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):zb.test(a.nodeName)||Ab.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var Bb=/[\t\r\n\f]/g;function Cb(a){return n.attr(a,"class")||""}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,Cb(this)))});if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(" "+e+" ").replace(Bb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=n.trim(d),e!==h&&n.attr(c,"class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,Cb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(" "+e+" ").replace(Bb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=n.trim(d),e!==h&&n.attr(c,"class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,Cb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=Cb(this),b&&n._data(this,"__className__",b),n.attr(this,"class",b||a===!1?"":n._data(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+Cb(c)+" ").replace(Bb," ").indexOf(b)>-1)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Db=a.location,Eb=n.now(),Fb=/\?/,Gb=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(Gb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new a.DOMParser,c=d.parseFromString(b,"text/xml")):(c=new a.ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var Hb=/#.*$/,Ib=/([?&])_=[^&]*/,Jb=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Kb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Lb=/^(?:GET|HEAD)$/,Mb=/^\/\//,Nb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ob={},Pb={},Qb="*/".concat("*"),Rb=Db.href,Sb=Nb.exec(Rb.toLowerCase())||[];function Tb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Ub(a,b,c,d){var e={},f=a===Pb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Vb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Wb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Xb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Rb,type:"GET",isLocal:Kb.test(Sb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Qb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Vb(Vb(a,n.ajaxSettings),b):Vb(n.ajaxSettings,a)},ajaxPrefilter:Tb(Ob),ajaxTransport:Tb(Pb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var d,e,f,g,h,i,j,k,l=n.ajaxSetup({},c),m=l.context||l,o=l.context&&(m.nodeType||m.jquery)?n(m):n.event,p=n.Deferred(),q=n.Callbacks("once memory"),r=l.statusCode||{},s={},t={},u=0,v="canceled",w={readyState:0,getResponseHeader:function(a){var b;if(2===u){if(!k){k={};while(b=Jb.exec(g))k[b[1].toLowerCase()]=b[2]}b=k[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===u?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return u||(a=t[c]=t[c]||a,s[a]=b),this},overrideMimeType:function(a){return u||(l.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>u)for(b in a)r[b]=[r[b],a[b]];else w.always(a[w.status]);return this},abort:function(a){var b=a||v;return j&&j.abort(b),y(0,b),this}};if(p.promise(w).complete=q.add,w.success=w.done,w.error=w.fail,l.url=((b||l.url||Rb)+"").replace(Hb,"").replace(Mb,Sb[1]+"//"),l.type=c.method||c.type||l.method||l.type,l.dataTypes=n.trim(l.dataType||"*").toLowerCase().match(G)||[""],null==l.crossDomain&&(d=Nb.exec(l.url.toLowerCase()),l.crossDomain=!(!d||d[1]===Sb[1]&&d[2]===Sb[2]&&(d[3]||("http:"===d[1]?"80":"443"))===(Sb[3]||("http:"===Sb[1]?"80":"443")))),l.data&&l.processData&&"string"!=typeof l.data&&(l.data=n.param(l.data,l.traditional)),Ub(Ob,l,c,w),2===u)return w;i=n.event&&l.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),l.type=l.type.toUpperCase(),l.hasContent=!Lb.test(l.type),f=l.url,l.hasContent||(l.data&&(f=l.url+=(Fb.test(f)?"&":"?")+l.data,delete l.data),l.cache===!1&&(l.url=Ib.test(f)?f.replace(Ib,"$1_="+Eb++):f+(Fb.test(f)?"&":"?")+"_="+Eb++)),l.ifModified&&(n.lastModified[f]&&w.setRequestHeader("If-Modified-Since",n.lastModified[f]),n.etag[f]&&w.setRequestHeader("If-None-Match",n.etag[f])),(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&w.setRequestHeader("Content-Type",l.contentType),w.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+("*"!==l.dataTypes[0]?", "+Qb+"; q=0.01":""):l.accepts["*"]);for(e in l.headers)w.setRequestHeader(e,l.headers[e]);if(l.beforeSend&&(l.beforeSend.call(m,w,l)===!1||2===u))return w.abort();v="abort";for(e in{success:1,error:1,complete:1})w[e](l[e]);if(j=Ub(Pb,l,c,w)){if(w.readyState=1,i&&o.trigger("ajaxSend",[w,l]),2===u)return w;l.async&&l.timeout>0&&(h=a.setTimeout(function(){w.abort("timeout")},l.timeout));try{u=1,j.send(s,y)}catch(x){if(!(2>u))throw x;y(-1,x)}}else y(-1,"No Transport");function y(b,c,d,e){var k,s,t,v,x,y=c;2!==u&&(u=2,h&&a.clearTimeout(h),j=void 0,g=e||"",w.readyState=b>0?4:0,k=b>=200&&300>b||304===b,d&&(v=Wb(l,w,d)),v=Xb(l,v,w,k),k?(l.ifModified&&(x=w.getResponseHeader("Last-Modified"),x&&(n.lastModified[f]=x),x=w.getResponseHeader("etag"),x&&(n.etag[f]=x)),204===b||"HEAD"===l.type?y="nocontent":304===b?y="notmodified":(y=v.state,s=v.data,t=v.error,k=!t)):(t=y,!b&&y||(y="error",0>b&&(b=0))),w.status=b,w.statusText=(c||y)+"",k?p.resolveWith(m,[s,y,w]):p.rejectWith(m,[w,y,t]),w.statusCode(r),r=void 0,i&&o.trigger(k?"ajaxSuccess":"ajaxError",[w,l,k?s:t]),q.fireWith(m,[w,y]),i&&(o.trigger("ajaxComplete",[w,l]),--n.active||n.event.trigger("ajaxStop")))}return w},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}});function Yb(a){return a.style&&a.style.display||n.css(a,"display")}function Zb(a){if(!n.contains(a.ownerDocument||d,a))return!0;while(a&&1===a.nodeType){if("none"===Yb(a)||"hidden"===a.type)return!0;a=a.parentNode}return!1}n.expr.filters.hidden=function(a){return l.reliableHiddenOffsets()?a.offsetWidth<=0&&a.offsetHeight<=0&&!a.getClientRects().length:Zb(a)},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var $b=/%20/g,_b=/\[\]$/,ac=/\r?\n/g,bc=/^(?:submit|button|image|reset|file)$/i,cc=/^(?:input|select|textarea|keygen)/i;function dc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||_b.test(a)?d(a,e):dc(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)dc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)dc(c,a[c],b,e);return d.join("&").replace($b,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&cc.test(this.nodeName)&&!bc.test(a)&&(this.checked||!Z.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(ac,"\r\n")}}):{name:b.name,value:c.replace(ac,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return this.isLocal?ic():d.documentMode>8?hc():/^(get|post|head|put|delete|options)$/i.test(this.type)&&hc()||ic()}:hc;var ec=0,fc={},gc=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in fc)fc[a](void 0,!0)}),l.cors=!!gc&&"withCredentials"in gc,gc=l.ajax=!!gc,gc&&n.ajaxTransport(function(b){if(!b.crossDomain||l.cors){var c;return{send:function(d,e){var f,g=b.xhr(),h=++ec;if(g.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(f in b.xhrFields)g[f]=b.xhrFields[f];b.mimeType&&g.overrideMimeType&&g.overrideMimeType(b.mimeType),b.crossDomain||d["X-Requested-With"]||(d["X-Requested-With"]="XMLHttpRequest");for(f in d)void 0!==d[f]&&g.setRequestHeader(f,d[f]+"");g.send(b.hasContent&&b.data||null),c=function(a,d){var f,i,j;if(c&&(d||4===g.readyState))if(delete fc[h],c=void 0,g.onreadystatechange=n.noop,d)4!==g.readyState&&g.abort();else{j={},f=g.status,"string"==typeof g.responseText&&(j.text=g.responseText);try{i=g.statusText}catch(k){i=""}f||!b.isLocal||b.crossDomain?1223===f&&(f=204):f=j.text?200:404}j&&e(f,i,j,g.getAllResponseHeaders())},b.async?4===g.readyState?a.setTimeout(c):g.onreadystatechange=fc[h]=c:c()},abort:function(){c&&c(void 0,!0)}}}});function hc(){try{return new a.XMLHttpRequest}catch(b){}}function ic(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=d.head||n("head")[0]||d.documentElement;return{send:function(e,f){b=d.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||f(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var jc=[],kc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=jc.pop()||n.expando+"_"+Eb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(kc.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&kc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(kc,"$1"+e):b.jsonp!==!1&&(b.url+=(Fb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,jc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||d;var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ja([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var lc=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&lc)return lc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=n.trim(a.slice(h,a.length)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function mc(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?("undefined"!=typeof e.getBoundingClientRect&&(d=e.getBoundingClientRect()),c=mc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Qa})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return Y(this,function(a,d,e){var f=mc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Ua(l.pixelPosition,function(a,c){return c?(c=Sa(a,b),Oa.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({
+padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return Y(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});
diff --git a/phpBB/assets/javascript/plupload.js b/phpBB/assets/javascript/plupload.js
index 8b3543880f..8c52aae819 100644
--- a/phpBB/assets/javascript/plupload.js
+++ b/phpBB/assets/javascript/plupload.js
@@ -21,7 +21,9 @@ phpbb.plupload.initialize = function() {
// Only execute if Plupload initialized successfully.
phpbb.plupload.uploader.bind('Init', function() {
phpbb.plupload.form = $(phpbb.plupload.config.form_hook)[0];
- phpbb.plupload.rowTpl = $('#attach-row-tpl')[0].outerHTML;
+ let $attachRowTemplate = $('#attach-row-tpl');
+ $attachRowTemplate.removeClass('attach-row-tpl');
+ phpbb.plupload.rowTpl = $attachRowTemplate[0].outerHTML;
// Hide the basic upload panel and remove the attach row template.
$('#attach-row-tpl, #attach-panel-basic').remove();
@@ -88,6 +90,12 @@ phpbb.plupload.getSerializedData = function() {
obj['attachment_data[' + i + '][' + key + ']'] = datum[key];
}
}
+
+ // Insert form data
+ var $pluploadForm = $(phpbb.plupload.config.form_hook).first();
+ obj.creation_time = $pluploadForm.find('input[type=hidden][name="creation_time"]').val();
+ obj.form_token = $pluploadForm.find('input[type=hidden][name="form_token"]').val();
+
return obj;
};
@@ -211,7 +219,7 @@ phpbb.plupload.updateHiddenData = function(row, attach, index) {
.attr('type', 'hidden')
.attr('name', 'attachment_data[' + index + '][' + key + ']')
.attr('value', attach[key]);
- $('textarea', row).after(input);
+ $(row).append(input);
}
};
@@ -262,6 +270,17 @@ phpbb.plupload.deleteFile = function(row, attachId) {
return;
}
+
+ // Handle errors while deleting file
+ if (typeof response.error !== 'undefined') {
+ phpbb.alert(phpbb.plupload.lang.ERROR, response.error.message);
+
+ // We will have to assume that the deletion failed. So leave the file status as uploaded.
+ row.find('.file-status').toggleClass('file-uploaded');
+
+ return;
+ }
+
phpbb.plupload.update(response, 'removal', index);
// Check if the user can upload files now if he had reached the max files limit.
phpbb.plupload.handleMaxFilesReached();
@@ -444,6 +463,44 @@ phpbb.plupload.fileError = function(file, error) {
phpbb.plupload.uploader = new plupload.Uploader(phpbb.plupload.config);
phpbb.plupload.initialize();
+/**
+ * Add a file filter to check for max file sizes per mime type.
+ */
+plupload.addFileFilter('mime_types_max_file_size', function(types, file, callback) {
+ if (file.size !== 'undefined') {
+ $(types).each(function(i, type) {
+ let extensions = [],
+ extsArray = type.extensions.split(',');
+
+ $(extsArray).each(function(i, extension) {
+ /^\s*\*\s*$/.test(extension) ? extensions.push("\\.*") : extensions.push("\\." + extension.replace(new RegExp("[" + "/^$.*+?|()[]{}\\".replace(/./g, "\\$&") + "]", "g"), "\\$&"));
+ });
+
+ let regex = new RegExp("(" + extensions.join("|") + ")$", "i");
+
+ if (regex.test(file.name)) {
+ if (type.max_file_size !== 'undefined' && type.max_file_size) {
+ if (file.size > type.max_file_size) {
+ phpbb.plupload.uploader.trigger('Error', {
+ code: plupload.FILE_SIZE_ERROR,
+ message: plupload.translate('File size error.'),
+ file: file
+ });
+
+ callback(false);
+ } else {
+ callback(true);
+ }
+ } else {
+ callback(true);
+ }
+
+ return false;
+ }
+ });
+ }
+});
+
var $fileList = $('#file-list');
/**
diff --git a/phpBB/assets/plupload/plupload.full.min.js b/phpBB/assets/plupload/plupload.full.min.js
index 2af434de4f..a58489dc64 100644
--- a/phpBB/assets/plupload/plupload.full.min.js
+++ b/phpBB/assets/plupload/plupload.full.min.js
@@ -1,6 +1,6 @@
/**
* mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
- * v1.3.4
+ * v1.5.7
*
* Copyright 2013, Moxiecode Systems AB
* Released under GPL License.
@@ -8,15 +8,15 @@
* License: http://www.plupload.com/license
* Contributing: http://www.plupload.com/contributing
*
- * Date: 2015-07-18
+ * Date: 2017-11-03
*/
-!function(e,t){"use strict";function n(e,t){for(var n,i=[],r=0;r<e.length;++r){if(n=s[e[r]]||o(e[r]),!n)throw"module definition dependecy not found: "+e[r];i.push(n)}t.apply(null,i)}function i(e,i,r){if("string"!=typeof e)throw"invalid module definition, module id must be defined and be a string";if(i===t)throw"invalid module definition, dependencies must be specified";if(r===t)throw"invalid module definition, definition function must be specified";n(i,function(){s[e]=r.apply(null,arguments)})}function r(e){return!!s[e]}function o(t){for(var n=e,i=t.split(/[.\/]/),r=0;r<i.length;++r){if(!n[i[r]])return;n=n[i[r]]}return n}function a(n){for(var i=0;i<n.length;i++){for(var r=e,o=n[i],a=o.split(/[.\/]/),u=0;u<a.length-1;++u)r[a[u]]===t&&(r[a[u]]={}),r=r[a[u]];r[a[a.length-1]]=s[o]}}var s={},u="moxie/core/utils/Basic",c="moxie/core/utils/Env",l="moxie/core/I18n",d="moxie/core/utils/Mime",h="moxie/core/utils/Dom",f="moxie/core/Exceptions",p="moxie/core/EventTarget",m="moxie/runtime/Runtime",g="moxie/runtime/RuntimeClient",v="moxie/file/FileInput",w="moxie/core/utils/Encode",y="moxie/file/Blob",E="moxie/file/File",_="moxie/file/FileDrop",b="moxie/file/FileReader",x="moxie/core/utils/Url",R="moxie/runtime/RuntimeTarget",A="moxie/file/FileReaderSync",I="moxie/xhr/FormData",T="moxie/xhr/XMLHttpRequest",S="moxie/runtime/Transporter",O="moxie/image/Image",D="moxie/runtime/html5/Runtime",N="moxie/core/utils/Events",L="moxie/runtime/html5/file/FileInput",C="moxie/runtime/html5/file/Blob",M="moxie/runtime/html5/file/FileDrop",F="moxie/runtime/html5/file/FileReader",P="moxie/runtime/html5/xhr/XMLHttpRequest",H="moxie/runtime/html5/utils/BinaryReader",B="moxie/runtime/html5/image/JPEGHeaders",k="moxie/runtime/html5/image/ExifParser",U="moxie/runtime/html5/image/JPEG",G="moxie/runtime/html5/image/PNG",z="moxie/runtime/html5/image/ImageInfo",q="moxie/runtime/html5/image/MegaPixel",j="moxie/runtime/html5/image/Image",X="moxie/runtime/flash/Runtime",V="moxie/runtime/flash/file/FileInput",W="moxie/runtime/flash/file/Blob",Y="moxie/runtime/flash/file/FileReader",$="moxie/runtime/flash/file/FileReaderSync",J="moxie/runtime/flash/xhr/XMLHttpRequest",Z="moxie/runtime/flash/runtime/Transporter",K="moxie/runtime/flash/image/Image",Q="moxie/runtime/silverlight/Runtime",ee="moxie/runtime/silverlight/file/FileInput",te="moxie/runtime/silverlight/file/Blob",ne="moxie/runtime/silverlight/file/FileDrop",ie="moxie/runtime/silverlight/file/FileReader",re="moxie/runtime/silverlight/file/FileReaderSync",oe="moxie/runtime/silverlight/xhr/XMLHttpRequest",ae="moxie/runtime/silverlight/runtime/Transporter",se="moxie/runtime/silverlight/image/Image",ue="moxie/runtime/html4/Runtime",ce="moxie/runtime/html4/file/FileInput",le="moxie/runtime/html4/file/FileReader",de="moxie/runtime/html4/xhr/XMLHttpRequest",he="moxie/runtime/html4/image/Image";i(u,[],function(){var e=function(e){var t;return e===t?"undefined":null===e?"null":e.nodeType?"node":{}.toString.call(e).match(/\s([a-z|A-Z]+)/)[1].toLowerCase()},t=function(i){var r;return n(arguments,function(o,s){s>0&&n(o,function(n,o){n!==r&&(e(i[o])===e(n)&&~a(e(n),["array","object"])?t(i[o],n):i[o]=n)})}),i},n=function(t,n){var i,r,o,a;if(t)if("number"===e(t.length)){for(o=0,i=t.length;i>o;o++)if(n(t[o],o)===!1)return}else if("object"===e(t))for(r in t)if(t.hasOwnProperty(r)&&n(t[r],r)===!1)return},i=function(t){var n;if(!t||"object"!==e(t))return!0;for(n in t)return!1;return!0},r=function(t,n){function i(r){"function"===e(t[r])&&t[r](function(e){++r<o&&!e?i(r):n(e)})}var r=0,o=t.length;"function"!==e(n)&&(n=function(){}),t&&t.length||n(),i(r)},o=function(e,t){var i=0,r=e.length,o=new Array(r);n(e,function(e,n){e(function(e){if(e)return t(e);var a=[].slice.call(arguments);a.shift(),o[n]=a,i++,i===r&&(o.unshift(null),t.apply(this,o))})})},a=function(e,t){if(t){if(Array.prototype.indexOf)return Array.prototype.indexOf.call(t,e);for(var n=0,i=t.length;i>n;n++)if(t[n]===e)return n}return-1},s=function(t,n){var i=[];"array"!==e(t)&&(t=[t]),"array"!==e(n)&&(n=[n]);for(var r in t)-1===a(t[r],n)&&i.push(t[r]);return i.length?i:!1},u=function(e,t){var i=[];return n(e,function(e){-1!==a(e,t)&&i.push(e)}),i.length?i:null},c=function(e){var t,n=[];for(t=0;t<e.length;t++)n[t]=e[t];return n},l=function(){var e=0;return function(t){var n=(new Date).getTime().toString(32),i;for(i=0;5>i;i++)n+=Math.floor(65535*Math.random()).toString(32);return(t||"o_")+n+(e++).toString(32)}}(),d=function(e){return e?String.prototype.trim?String.prototype.trim.call(e):e.toString().replace(/^\s*/,"").replace(/\s*$/,""):e},h=function(e){if("string"!=typeof e)return e;var t={t:1099511627776,g:1073741824,m:1048576,k:1024},n;return e=/^([0-9\.]+)([tmgk]?)$/.exec(e.toLowerCase().replace(/[^0-9\.tmkg]/g,"")),n=e[2],e=+e[1],t.hasOwnProperty(n)&&(e*=t[n]),Math.floor(e)},f=function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e(t)?t:""})};return{guid:l,typeOf:e,extend:t,each:n,isEmptyObj:i,inSeries:r,inParallel:o,inArray:a,arrayDiff:s,arrayIntersect:u,toArray:c,trim:d,sprintf:f,parseSizeStr:h}}),i(c,[u],function(e){function t(e,t,n){var i=0,r=0,o=0,a={dev:-6,alpha:-5,a:-5,beta:-4,b:-4,RC:-3,rc:-3,"#":-2,p:1,pl:1},s=function(e){return e=(""+e).replace(/[_\-+]/g,"."),e=e.replace(/([^.\d]+)/g,".$1.").replace(/\.{2,}/g,"."),e.length?e.split("."):[-8]},u=function(e){return e?isNaN(e)?a[e]||-7:parseInt(e,10):0};for(e=s(e),t=s(t),r=Math.max(e.length,t.length),i=0;r>i;i++)if(e[i]!=t[i]){if(e[i]=u(e[i]),t[i]=u(t[i]),e[i]<t[i]){o=-1;break}if(e[i]>t[i]){o=1;break}}if(!n)return o;switch(n){case">":case"gt":return o>0;case">=":case"ge":return o>=0;case"<=":case"le":return 0>=o;case"==":case"=":case"eq":return 0===o;case"<>":case"!=":case"ne":return 0!==o;case"":case"<":case"lt":return 0>o;default:return null}}var n=function(e){var t="",n="?",i="function",r="undefined",o="object",a="major",s="model",u="name",c="type",l="vendor",d="version",h="architecture",f="console",p="mobile",m="tablet",g={has:function(e,t){return-1!==t.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()}},v={rgx:function(){for(var t,n=0,a,s,u,c,l,d,h=arguments;n<h.length;n+=2){var f=h[n],p=h[n+1];if(typeof t===r){t={};for(u in p)c=p[u],typeof c===o?t[c[0]]=e:t[c]=e}for(a=s=0;a<f.length;a++)if(l=f[a].exec(this.getUA())){for(u=0;u<p.length;u++)d=l[++s],c=p[u],typeof c===o&&c.length>0?2==c.length?typeof c[1]==i?t[c[0]]=c[1].call(this,d):t[c[0]]=c[1]:3==c.length?typeof c[1]!==i||c[1].exec&&c[1].test?t[c[0]]=d?d.replace(c[1],c[2]):e:t[c[0]]=d?c[1].call(this,d,c[2]):e:4==c.length&&(t[c[0]]=d?c[3].call(this,d.replace(c[1],c[2])):e):t[c]=d?d:e;break}if(l)break}return t},str:function(t,i){for(var r in i)if(typeof i[r]===o&&i[r].length>0){for(var a=0;a<i[r].length;a++)if(g.has(i[r][a],t))return r===n?e:r}else if(g.has(i[r],t))return r===n?e:r;return t}},w={browser:{oldsafari:{major:{1:["/8","/1","/3"],2:"/4","?":"/"},version:{"1.0":"/8",1.2:"/1",1.3:"/3","2.0":"/412","2.0.2":"/416","2.0.3":"/417","2.0.4":"/419","?":"/"}}},device:{sprint:{model:{"Evo Shift 4G":"7373KT"},vendor:{HTC:"APA",Sprint:"Sprint"}}},os:{windows:{version:{ME:"4.90","NT 3.11":"NT3.51","NT 4.0":"NT4.0",2000:"NT 5.0",XP:["NT 5.1","NT 5.2"],Vista:"NT 6.0",7:"NT 6.1",8:"NT 6.2",8.1:"NT 6.3",RT:"ARM"}}}},y={browser:[[/(opera\smini)\/([\w\.-]+)/i,/(opera\s[mobiletab]+).+version\/([\w\.-]+)/i,/(opera).+version\/([\w\.]+)/i,/(opera)[\/\s]+([\w\.]+)/i],[u,d],[/\s(opr)\/([\w\.]+)/i],[[u,"Opera"],d],[/(kindle)\/([\w\.]+)/i,/(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,/(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,/(?:ms|\()(ie)\s([\w\.]+)/i,/(rekonq)\/([\w\.]+)*/i,/(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i],[u,d],[/(trident).+rv[:\s]([\w\.]+).+like\sgecko/i],[[u,"IE"],d],[/(edge)\/((\d+)?[\w\.]+)/i],[u,d],[/(yabrowser)\/([\w\.]+)/i],[[u,"Yandex"],d],[/(comodo_dragon)\/([\w\.]+)/i],[[u,/_/g," "],d],[/(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,/(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i],[u,d],[/(dolfin)\/([\w\.]+)/i],[[u,"Dolphin"],d],[/((?:android.+)crmo|crios)\/([\w\.]+)/i],[[u,"Chrome"],d],[/XiaoMi\/MiuiBrowser\/([\w\.]+)/i],[d,[u,"MIUI Browser"]],[/android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i],[d,[u,"Android Browser"]],[/FBAV\/([\w\.]+);/i],[d,[u,"Facebook"]],[/version\/([\w\.]+).+?mobile\/\w+\s(safari)/i],[d,[u,"Mobile Safari"]],[/version\/([\w\.]+).+?(mobile\s?safari|safari)/i],[d,u],[/webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i],[u,[d,v.str,w.browser.oldsafari.version]],[/(konqueror)\/([\w\.]+)/i,/(webkit|khtml)\/([\w\.]+)/i],[u,d],[/(navigator|netscape)\/([\w\.-]+)/i],[[u,"Netscape"],d],[/(swiftfox)/i,/(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,/(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,/(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i,/(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i,/(links)\s\(([\w\.]+)/i,/(gobrowser)\/?([\w\.]+)*/i,/(ice\s?browser)\/v?([\w\._]+)/i,/(mosaic)[\/\s]([\w\.]+)/i],[u,d]],engine:[[/windows.+\sedge\/([\w\.]+)/i],[d,[u,"EdgeHTML"]],[/(presto)\/([\w\.]+)/i,/(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,/(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,/(icab)[\/\s]([23]\.[\d\.]+)/i],[u,d],[/rv\:([\w\.]+).*(gecko)/i],[d,u]],os:[[/microsoft\s(windows)\s(vista|xp)/i],[u,d],[/(windows)\snt\s6\.2;\s(arm)/i,/(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i],[u,[d,v.str,w.os.windows.version]],[/(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i],[[u,"Windows"],[d,v.str,w.os.windows.version]],[/\((bb)(10);/i],[[u,"BlackBerry"],d],[/(blackberry)\w*\/?([\w\.]+)*/i,/(tizen)[\/\s]([\w\.]+)/i,/(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,/linux;.+(sailfish);/i],[u,d],[/(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i],[[u,"Symbian"],d],[/\((series40);/i],[u],[/mozilla.+\(mobile;.+gecko.+firefox/i],[[u,"Firefox OS"],d],[/(nintendo|playstation)\s([wids3portablevu]+)/i,/(mint)[\/\s\(]?(\w+)*/i,/(mageia|vectorlinux)[;\s]/i,/(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i,/(hurd|linux)\s?([\w\.]+)*/i,/(gnu)\s?([\w\.]+)*/i],[u,d],[/(cros)\s[\w]+\s([\w\.]+\w)/i],[[u,"Chromium OS"],d],[/(sunos)\s?([\w\.]+\d)*/i],[[u,"Solaris"],d],[/\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i],[u,d],[/(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i],[[u,"iOS"],[d,/_/g,"."]],[/(mac\sos\sx)\s?([\w\s\.]+\w)*/i,/(macintosh|mac(?=_powerpc)\s)/i],[[u,"Mac OS"],[d,/_/g,"."]],[/((?:open)?solaris)[\/\s-]?([\w\.]+)*/i,/(haiku)\s(\w+)/i,/(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,/(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,/(unix)\s?([\w\.]+)*/i],[u,d]]},E=function(e){var n=e||(window&&window.navigator&&window.navigator.userAgent?window.navigator.userAgent:t);this.getBrowser=function(){return v.rgx.apply(this,y.browser)},this.getEngine=function(){return v.rgx.apply(this,y.engine)},this.getOS=function(){return v.rgx.apply(this,y.os)},this.getResult=function(){return{ua:this.getUA(),browser:this.getBrowser(),engine:this.getEngine(),os:this.getOS()}},this.getUA=function(){return n},this.setUA=function(e){return n=e,this},this.setUA(n)};return E}(),i=function(){var t={define_property:function(){return!1}(),create_canvas:function(){var e=document.createElement("canvas");return!(!e.getContext||!e.getContext("2d"))}(),return_response_type:function(t){try{if(-1!==e.inArray(t,["","text","document"]))return!0;if(window.XMLHttpRequest){var n=new XMLHttpRequest;if(n.open("get","/"),"responseType"in n)return n.responseType=t,n.responseType!==t?!1:!0}}catch(i){}return!1},use_data_uri:function(){var e=new Image;return e.onload=function(){t.use_data_uri=1===e.width&&1===e.height},setTimeout(function(){e.src="data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="},1),!1}(),use_data_uri_over32kb:function(){return t.use_data_uri&&("IE"!==o.browser||o.version>=9)},use_data_uri_of:function(e){return t.use_data_uri&&33e3>e||t.use_data_uri_over32kb()},use_fileinput:function(){if(navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/))return!1;var e=document.createElement("input");return e.setAttribute("type","file"),!e.disabled}};return function(n){var i=[].slice.call(arguments);return i.shift(),"function"===e.typeOf(t[n])?t[n].apply(this,i):!!t[n]}}(),r=(new n).getResult(),o={can:i,uaParser:n,browser:r.browser.name,version:r.browser.version,os:r.os.name,osVersion:r.os.version,verComp:t,swf_url:"../flash/Moxie.swf",xap_url:"../silverlight/Moxie.xap",global_event_dispatcher:"moxie.core.EventTarget.instance.dispatchEvent"};return o.OS=o.os,o}),i(l,[u],function(e){var t={};return{addI18n:function(n){return e.extend(t,n)},translate:function(e){return t[e]||e},_:function(e){return this.translate(e)},sprintf:function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e.typeOf(t)?t:""})}}}),i(d,[u,l],function(e,t){var n="application/msword,doc dot,application/pdf,pdf,application/pgp-signature,pgp,application/postscript,ps ai eps,application/rtf,rtf,application/vnd.ms-excel,xls xlb,application/vnd.ms-powerpoint,ppt pps pot,application/zip,zip,application/x-shockwave-flash,swf swfl,application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx,application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx,application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx,application/vnd.openxmlformats-officedocument.presentationml.template,potx,application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx,application/x-javascript,js,application/json,json,audio/mpeg,mp3 mpga mpega mp2,audio/x-wav,wav,audio/x-m4a,m4a,audio/ogg,oga ogg,audio/aiff,aiff aif,audio/flac,flac,audio/aac,aac,audio/ac3,ac3,audio/x-ms-wma,wma,image/bmp,bmp,image/gif,gif,image/jpeg,jpg jpeg jpe,image/photoshop,psd,image/png,png,image/svg+xml,svg svgz,image/tiff,tiff tif,text/plain,asc txt text diff log,text/html,htm html xhtml,text/css,css,text/csv,csv,text/rtf,rtf,video/mpeg,mpeg mpg mpe m2v,video/quicktime,qt mov,video/mp4,mp4,video/x-m4v,m4v,video/x-flv,flv,video/x-ms-wmv,wmv,video/avi,avi,video/webm,webm,video/3gpp,3gpp 3gp,video/3gpp2,3g2,video/vnd.rn-realvideo,rv,video/ogg,ogv,video/x-matroska,mkv,application/vnd.oasis.opendocument.formula-template,otf,application/octet-stream,exe",i={mimes:{},extensions:{},addMimeType:function(e){var t=e.split(/,/),n,i,r;for(n=0;n<t.length;n+=2){for(r=t[n+1].split(/ /),i=0;i<r.length;i++)this.mimes[r[i]]=t[n];this.extensions[t[n]]=r}},extList2mimes:function(t,n){var i=this,r,o,a,s,u=[];for(o=0;o<t.length;o++)for(r=t[o].extensions.split(/\s*,\s*/),a=0;a<r.length;a++){if("*"===r[a])return[];if(s=i.mimes[r[a]],s&&-1===e.inArray(s,u)&&u.push(s),n&&/^\w+$/.test(r[a]))u.push("."+r[a]);else if(!s)return[]}return u},mimes2exts:function(t){var n=this,i=[];return e.each(t,function(t){if("*"===t)return i=[],!1;var r=t.match(/^(\w+)\/(\*|\w+)$/);r&&("*"===r[2]?e.each(n.extensions,function(e,t){new RegExp("^"+r[1]+"/").test(t)&&[].push.apply(i,n.extensions[t])}):n.extensions[t]&&[].push.apply(i,n.extensions[t]))}),i},mimes2extList:function(n){var i=[],r=[];return"string"===e.typeOf(n)&&(n=e.trim(n).split(/\s*,\s*/)),r=this.mimes2exts(n),i.push({title:t.translate("Files"),extensions:r.length?r.join(","):"*"}),i.mimes=n,i},getFileExtension:function(e){var t=e&&e.match(/\.([^.]+)$/);return t?t[1].toLowerCase():""},getFileMime:function(e){return this.mimes[this.getFileExtension(e)]||""}};return i.addMimeType(n),i}),i(h,[c],function(e){var t=function(e){return"string"!=typeof e?e:document.getElementById(e)},n=function(e,t){if(!e.className)return!1;var n=new RegExp("(^|\\s+)"+t+"(\\s+|$)");return n.test(e.className)},i=function(e,t){n(e,t)||(e.className=e.className?e.className.replace(/\s+$/,"")+" "+t:t)},r=function(e,t){if(e.className){var n=new RegExp("(^|\\s+)"+t+"(\\s+|$)");e.className=e.className.replace(n,function(e,t,n){return" "===t&&" "===n?" ":""})}},o=function(e,t){return e.currentStyle?e.currentStyle[t]:window.getComputedStyle?window.getComputedStyle(e,null)[t]:void 0},a=function(t,n){function i(e){var t,n,i=0,r=0;return e&&(n=e.getBoundingClientRect(),t="CSS1Compat"===s.compatMode?s.documentElement:s.body,i=n.left+t.scrollLeft,r=n.top+t.scrollTop),{x:i,y:r}}var r=0,o=0,a,s=document,u,c;if(t=t,n=n||s.body,t&&t.getBoundingClientRect&&"IE"===e.browser&&(!s.documentMode||s.documentMode<8))return u=i(t),c=i(n),{x:u.x-c.x,y:u.y-c.y};for(a=t;a&&a!=n&&a.nodeType;)r+=a.offsetLeft||0,o+=a.offsetTop||0,a=a.offsetParent;for(a=t.parentNode;a&&a!=n&&a.nodeType;)r-=a.scrollLeft||0,o-=a.scrollTop||0,a=a.parentNode;return{x:r,y:o}},s=function(e){return{w:e.offsetWidth||e.clientWidth,h:e.offsetHeight||e.clientHeight}};return{get:t,hasClass:n,addClass:i,removeClass:r,getStyle:o,getPos:a,getSize:s}}),i(f,[u],function(e){function t(e,t){var n;for(n in e)if(e[n]===t)return n;return null}return{RuntimeError:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": RuntimeError "+this.code}var i={NOT_INIT_ERR:1,NOT_SUPPORTED_ERR:9,JS_ERR:4};return e.extend(n,i),n.prototype=Error.prototype,n}(),OperationNotAllowedException:function(){function t(e){this.code=e,this.name="OperationNotAllowedException"}return e.extend(t,{NOT_ALLOWED_ERR:1}),t.prototype=Error.prototype,t}(),ImageError:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": ImageError "+this.code}var i={WRONG_FORMAT:1,MAX_RESOLUTION_ERR:2,INVALID_META_ERR:3};return e.extend(n,i),n.prototype=Error.prototype,n}(),FileException:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": FileException "+this.code}var i={NOT_FOUND_ERR:1,SECURITY_ERR:2,ABORT_ERR:3,NOT_READABLE_ERR:4,ENCODING_ERR:5,NO_MODIFICATION_ALLOWED_ERR:6,INVALID_STATE_ERR:7,SYNTAX_ERR:8};return e.extend(n,i),n.prototype=Error.prototype,n}(),DOMException:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": DOMException "+this.code}var i={INDEX_SIZE_ERR:1,DOMSTRING_SIZE_ERR:2,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,INVALID_CHARACTER_ERR:5,NO_DATA_ALLOWED_ERR:6,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INUSE_ATTRIBUTE_ERR:10,INVALID_STATE_ERR:11,SYNTAX_ERR:12,INVALID_MODIFICATION_ERR:13,NAMESPACE_ERR:14,INVALID_ACCESS_ERR:15,VALIDATION_ERR:16,TYPE_MISMATCH_ERR:17,SECURITY_ERR:18,NETWORK_ERR:19,ABORT_ERR:20,URL_MISMATCH_ERR:21,QUOTA_EXCEEDED_ERR:22,TIMEOUT_ERR:23,INVALID_NODE_TYPE_ERR:24,DATA_CLONE_ERR:25};return e.extend(n,i),n.prototype=Error.prototype,n}(),EventException:function(){function t(e){this.code=e,this.name="EventException"}return e.extend(t,{UNSPECIFIED_EVENT_TYPE_ERR:0}),t.prototype=Error.prototype,t}()}}),i(p,[c,f,u],function(e,t,n){function i(){var e={};n.extend(this,{uid:null,init:function(){this.uid||(this.uid=n.guid("uid_"))},addEventListener:function(t,i,r,o){var a=this,s;return this.hasOwnProperty("uid")||(this.uid=n.guid("uid_")),t=n.trim(t),/\s/.test(t)?void n.each(t.split(/\s+/),function(e){a.addEventListener(e,i,r,o)}):(t=t.toLowerCase(),r=parseInt(r,10)||0,s=e[this.uid]&&e[this.uid][t]||[],s.push({fn:i,priority:r,scope:o||this}),e[this.uid]||(e[this.uid]={}),void(e[this.uid][t]=s))},hasEventListener:function(t){var n=t?e[this.uid]&&e[this.uid][t]:e[this.uid];return n?n:!1},removeEventListener:function(t,i){t=t.toLowerCase();var r=e[this.uid]&&e[this.uid][t],o;if(r){if(i){for(o=r.length-1;o>=0;o--)if(r[o].fn===i){r.splice(o,1);break}}else r=[];r.length||(delete e[this.uid][t],n.isEmptyObj(e[this.uid])&&delete e[this.uid])}},removeAllEventListeners:function(){e[this.uid]&&delete e[this.uid]},dispatchEvent:function(i){var r,o,a,s,u={},c=!0,l;if("string"!==n.typeOf(i)){if(s=i,"string"!==n.typeOf(s.type))throw new t.EventException(t.EventException.UNSPECIFIED_EVENT_TYPE_ERR);i=s.type,s.total!==l&&s.loaded!==l&&(u.total=s.total,u.loaded=s.loaded),u.async=s.async||!1}if(-1!==i.indexOf("::")?!function(e){r=e[0],i=e[1]}(i.split("::")):r=this.uid,i=i.toLowerCase(),o=e[r]&&e[r][i]){o.sort(function(e,t){return t.priority-e.priority}),a=[].slice.call(arguments),a.shift(),u.type=i,a.unshift(u);var d=[];n.each(o,function(e){a[0].target=e.scope,d.push(u.async?function(t){setTimeout(function(){t(e.fn.apply(e.scope,a)===!1)},1)}:function(t){t(e.fn.apply(e.scope,a)===!1)})}),d.length&&n.inSeries(d,function(e){c=!e})}return c},bind:function(){this.addEventListener.apply(this,arguments)},unbind:function(){this.removeEventListener.apply(this,arguments)},unbindAll:function(){this.removeAllEventListeners.apply(this,arguments)},trigger:function(){return this.dispatchEvent.apply(this,arguments)},handleEventProps:function(e){var t=this;this.bind(e.join(" "),function(e){var t="on"+e.type.toLowerCase();"function"===n.typeOf(this[t])&&this[t].apply(this,arguments)}),n.each(e,function(e){e="on"+e.toLowerCase(e),"undefined"===n.typeOf(t[e])&&(t[e]=null)})}})}return i.instance=new i,i}),i(m,[c,u,h,p],function(e,t,n,i){function r(e,i,o,s,u){var c=this,l,d=t.guid(i+"_"),h=u||"browser";e=e||{},a[d]=this,o=t.extend({access_binary:!1,access_image_binary:!1,display_media:!1,do_cors:!1,drag_and_drop:!1,filter_by_extension:!0,resize_image:!1,report_upload_progress:!1,return_response_headers:!1,return_response_type:!1,return_status_code:!0,send_custom_headers:!1,select_file:!1,select_folder:!1,select_multiple:!0,send_binary_string:!1,send_browser_cookies:!0,send_multipart:!0,slice_blob:!1,stream_upload:!1,summon_file_dialog:!1,upload_filesize:!0,use_http_method:!0},o),e.preferred_caps&&(h=r.getMode(s,e.preferred_caps,h)),l=function(){var e={};return{exec:function(t,n,i,r){return l[n]&&(e[t]||(e[t]={context:this,instance:new l[n]}),e[t].instance[i])?e[t].instance[i].apply(this,r):void 0},removeInstance:function(t){delete e[t]},removeAllInstances:function(){var n=this;t.each(e,function(e,i){"function"===t.typeOf(e.instance.destroy)&&e.instance.destroy.call(e.context),n.removeInstance(i)})}}}(),t.extend(this,{initialized:!1,uid:d,type:i,mode:r.getMode(s,e.required_caps,h),shimid:d+"_container",clients:0,options:e,can:function(e,n){var i=arguments[2]||o;if("string"===t.typeOf(e)&&"undefined"===t.typeOf(n)&&(e=r.parseCaps(e)),"object"===t.typeOf(e)){for(var a in e)if(!this.can(a,e[a],i))return!1;return!0}return"function"===t.typeOf(i[e])?i[e].call(this,n):n===i[e]},getShimContainer:function(){var e,i=n.get(this.shimid);return i||(e=this.options.container?n.get(this.options.container):document.body,i=document.createElement("div"),i.id=this.shimid,i.className="moxie-shim moxie-shim-"+this.type,t.extend(i.style,{position:"absolute",top:"0px",left:"0px",width:"1px",height:"1px",overflow:"hidden"}),e.appendChild(i),e=null),i},getShim:function(){return l},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec.call(this,this.uid,e,t,n)},exec:function(e,t){var n=[].slice.call(arguments,2);return c[e]&&c[e][t]?c[e][t].apply(this,n):c.shimExec.apply(this,arguments)},destroy:function(){if(c){var e=n.get(this.shimid);e&&e.parentNode.removeChild(e),l&&l.removeAllInstances(),this.unbindAll(),delete a[this.uid],this.uid=null,d=c=l=e=null}}}),this.mode&&e.required_caps&&!this.can(e.required_caps)&&(this.mode=!1)}var o={},a={};return r.order="html5,flash,silverlight,html4",r.getRuntime=function(e){return a[e]?a[e]:!1},r.addConstructor=function(e,t){t.prototype=i.instance,o[e]=t},r.getConstructor=function(e){return o[e]||null},r.getInfo=function(e){var t=r.getRuntime(e);return t?{uid:t.uid,type:t.type,mode:t.mode,can:function(){return t.can.apply(t,arguments)}}:null},r.parseCaps=function(e){var n={};return"string"!==t.typeOf(e)?e||{}:(t.each(e.split(","),function(e){n[e]=!0}),n)},r.can=function(e,t){var n,i=r.getConstructor(e),o;return i?(n=new i({required_caps:t}),o=n.mode,n.destroy(),!!o):!1},r.thatCan=function(e,t){var n=(t||r.order).split(/\s*,\s*/);for(var i in n)if(r.can(n[i],e))return n[i];return null},r.getMode=function(e,n,i){var r=null;if("undefined"===t.typeOf(i)&&(i="browser"),n&&!t.isEmptyObj(e)){if(t.each(n,function(n,i){if(e.hasOwnProperty(i)){var o=e[i](n);if("string"==typeof o&&(o=[o]),r){if(!(r=t.arrayIntersect(r,o)))return r=!1}else r=o}}),r)return-1!==t.inArray(i,r)?i:r[0];if(r===!1)return!1}return i},r.capTrue=function(){return!0},r.capFalse=function(){return!1},r.capTest=function(e){return function(){return!!e}},r}),i(g,[c,f,u,m],function(e,t,n,i){return function r(){var e;n.extend(this,{connectRuntime:function(r){function o(n){var s,u;return n.length?(s=n.shift().toLowerCase(),(u=i.getConstructor(s))?(e=new u(r),e.bind("Init",function(){e.initialized=!0,setTimeout(function(){e.clients++,a.trigger("RuntimeInit",e)},1)}),e.bind("Error",function(){e.destroy(),o(n)}),e.mode?void e.init():void e.trigger("Error")):void o(n)):(a.trigger("RuntimeError",new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)),void(e=null))}var a=this,s;if("string"===n.typeOf(r)?s=r:"string"===n.typeOf(r.ruid)&&(s=r.ruid),s){if(e=i.getRuntime(s))return e.clients++,e;throw new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)}o((r.runtime_order||i.order).split(/\s*,\s*/))},disconnectRuntime:function(){e&&--e.clients<=0&&e.destroy(),e=null},getRuntime:function(){return e&&e.uid?e:e=null},exec:function(){return e?e.exec.apply(this,arguments):null}})}}),i(v,[u,c,d,h,f,p,l,m,g],function(e,t,n,i,r,o,a,s,u){function c(t){var o=this,c,d,h;if(-1!==e.inArray(e.typeOf(t),["string","node"])&&(t={browse_button:t}),d=i.get(t.browse_button),!d)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR);h={accept:[{title:a.translate("All Files"),extensions:"*"}],name:"file",multiple:!1,required_caps:!1,container:d.parentNode||document.body},t=e.extend({},h,t),"string"==typeof t.required_caps&&(t.required_caps=s.parseCaps(t.required_caps)),"string"==typeof t.accept&&(t.accept=n.mimes2extList(t.accept)),c=i.get(t.container),c||(c=document.body),"static"===i.getStyle(c,"position")&&(c.style.position="relative"),c=d=null,u.call(o),e.extend(o,{uid:e.guid("uid_"),ruid:null,shimid:null,files:null,init:function(){o.bind("RuntimeInit",function(n,r){o.ruid=r.uid,o.shimid=r.shimid,o.bind("Ready",function(){o.trigger("Refresh")},999),o.bind("Refresh",function(){var n,o,a,s;a=i.get(t.browse_button),s=i.get(r.shimid),a&&(n=i.getPos(a,i.get(t.container)),o=i.getSize(a),s&&e.extend(s.style,{top:n.y+"px",left:n.x+"px",width:o.w+"px",height:o.h+"px"})),s=a=null}),r.exec.call(o,"FileInput","init",t)}),o.connectRuntime(e.extend({},t,{required_caps:{select_file:!0}}))},disable:function(t){var n=this.getRuntime();n&&n.exec.call(this,"FileInput","disable","undefined"===e.typeOf(t)?!0:t)},refresh:function(){o.trigger("Refresh")},destroy:function(){var t=this.getRuntime();t&&(t.exec.call(this,"FileInput","destroy"),this.disconnectRuntime()),"array"===e.typeOf(this.files)&&e.each(this.files,function(e){e.destroy()}),this.files=null,this.unbindAll()}}),this.handleEventProps(l)}var l=["ready","change","cancel","mouseenter","mouseleave","mousedown","mouseup"];return c.prototype=o.instance,c}),i(w,[],function(){var e=function(e){return unescape(encodeURIComponent(e))},t=function(e){return decodeURIComponent(escape(e))},n=function(e,n){if("function"==typeof window.atob)return n?t(window.atob(e)):window.atob(e);var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",r,o,a,s,u,c,l,d,h=0,f=0,p="",m=[];if(!e)return e;e+="";do s=i.indexOf(e.charAt(h++)),u=i.indexOf(e.charAt(h++)),c=i.indexOf(e.charAt(h++)),l=i.indexOf(e.charAt(h++)),d=s<<18|u<<12|c<<6|l,r=d>>16&255,o=d>>8&255,a=255&d,64==c?m[f++]=String.fromCharCode(r):64==l?m[f++]=String.fromCharCode(r,o):m[f++]=String.fromCharCode(r,o,a);while(h<e.length);return p=m.join(""),n?t(p):p},i=function(t,n){if(n&&(t=e(t)),"function"==typeof window.btoa)return window.btoa(t);var i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",r,o,a,s,u,c,l,d,h=0,f=0,p="",m=[];if(!t)return t;do r=t.charCodeAt(h++),o=t.charCodeAt(h++),a=t.charCodeAt(h++),d=r<<16|o<<8|a,s=d>>18&63,u=d>>12&63,c=d>>6&63,l=63&d,m[f++]=i.charAt(s)+i.charAt(u)+i.charAt(c)+i.charAt(l);while(h<t.length);p=m.join("");var g=t.length%3;return(g?p.slice(0,g-3):p)+"===".slice(g||3)};return{utf8_encode:e,utf8_decode:t,atob:n,btoa:i}}),i(y,[u,w,g],function(e,t,n){function i(o,a){function s(t,n,o){var a,s=r[this.uid];return"string"===e.typeOf(s)&&s.length?(a=new i(null,{type:o,size:n-t}),a.detach(s.substr(t,a.size)),a):null}n.call(this),o&&this.connectRuntime(o),a?"string"===e.typeOf(a)&&(a={data:a}):a={},e.extend(this,{uid:a.uid||e.guid("uid_"),ruid:o,size:a.size||0,type:a.type||"",slice:function(e,t,n){return this.isDetached()?s.apply(this,arguments):this.getRuntime().exec.call(this,"Blob","slice",this.getSource(),e,t,n)},getSource:function(){return r[this.uid]?r[this.uid]:null},detach:function(e){if(this.ruid&&(this.getRuntime().exec.call(this,"Blob","destroy"),this.disconnectRuntime(),this.ruid=null),e=e||"","data:"==e.substr(0,5)){var n=e.indexOf(";base64,");this.type=e.substring(5,n),e=t.atob(e.substring(n+8))}this.size=e.length,r[this.uid]=e},isDetached:function(){return!this.ruid&&"string"===e.typeOf(r[this.uid])},destroy:function(){this.detach(),delete r[this.uid]}}),a.data?this.detach(a.data):r[this.uid]=a}var r={};return i}),i(E,[u,d,y],function(e,t,n){function i(i,r){r||(r={}),n.apply(this,arguments),this.type||(this.type=t.getFileMime(r.name));var o;if(r.name)o=r.name.replace(/\\/g,"/"),o=o.substr(o.lastIndexOf("/")+1);else if(this.type){var a=this.type.split("/")[0];o=e.guid((""!==a?a:"file")+"_"),t.extensions[this.type]&&(o+="."+t.extensions[this.type][0])}e.extend(this,{name:o||e.guid("file_"),relativePath:"",lastModifiedDate:r.lastModifiedDate||(new Date).toLocaleString()})}return i.prototype=n.prototype,i}),i(_,[l,h,f,u,c,E,g,p,d],function(e,t,n,i,r,o,a,s,u){function c(n){var r=this,o;"string"==typeof n&&(n={drop_zone:n}),o={accept:[{title:e.translate("All Files"),extensions:"*"}],required_caps:{drag_and_drop:!0}},n="object"==typeof n?i.extend({},o,n):o,n.container=t.get(n.drop_zone)||document.body,"static"===t.getStyle(n.container,"position")&&(n.container.style.position="relative"),"string"==typeof n.accept&&(n.accept=u.mimes2extList(n.accept)),a.call(r),i.extend(r,{uid:i.guid("uid_"),ruid:null,files:null,init:function(){r.bind("RuntimeInit",function(e,t){r.ruid=t.uid,t.exec.call(r,"FileDrop","init",n),r.dispatchEvent("ready")}),r.connectRuntime(n)},destroy:function(){var e=this.getRuntime();e&&(e.exec.call(this,"FileDrop","destroy"),this.disconnectRuntime()),this.files=null,this.unbindAll()}}),this.handleEventProps(l)}var l=["ready","dragenter","dragleave","drop","error"];return c.prototype=s.instance,c}),i(b,[u,w,f,p,y,g],function(e,t,n,i,r,o){function a(){function i(e,i){var o=this;if(this.trigger("loadstart"),this.readyState===a.LOADING)return this.trigger("error",new n.DOMException(n.DOMException.INVALID_STATE_ERR)),void this.trigger("loadend");if(!(i instanceof r))return this.trigger("error",new n.DOMException(n.DOMException.NOT_FOUND_ERR)),void this.trigger("loadend");if(this.result=null,this.readyState=a.LOADING,i.isDetached()){var s=i.getSource();switch(e){case"readAsText":case"readAsBinaryString":this.result=s;break;case"readAsDataURL":this.result="data:"+i.type+";base64,"+t.btoa(s)}this.readyState=a.DONE,this.trigger("load"),this.trigger("loadend")}else this.connectRuntime(i.ruid),this.exec("FileReader","read",e,i)}o.call(this),e.extend(this,{uid:e.guid("uid_"),readyState:a.EMPTY,result:null,error:null,readAsBinaryString:function(e){i.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){i.call(this,"readAsDataURL",e)},readAsText:function(e){i.call(this,"readAsText",e);
-},abort:function(){this.result=null,-1===e.inArray(this.readyState,[a.EMPTY,a.DONE])&&(this.readyState===a.LOADING&&(this.readyState=a.DONE),this.exec("FileReader","abort"),this.trigger("abort"),this.trigger("loadend"))},destroy:function(){this.abort(),this.exec("FileReader","destroy"),this.disconnectRuntime(),this.unbindAll()}}),this.handleEventProps(s),this.bind("Error",function(e,t){this.readyState=a.DONE,this.error=t},999),this.bind("Load",function(e){this.readyState=a.DONE},999)}var s=["loadstart","progress","load","abort","error","loadend"];return a.EMPTY=0,a.LOADING=1,a.DONE=2,a.prototype=i.instance,a}),i(x,[],function(){var e=function(t,n){for(var i=["source","scheme","authority","userInfo","user","pass","host","port","relative","path","directory","file","query","fragment"],r=i.length,o={http:80,https:443},a={},s=/^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/,u=s.exec(t||"");r--;)u[r]&&(a[i[r]]=u[r]);if(!a.scheme){n&&"string"!=typeof n||(n=e(n||document.location.href)),a.scheme=n.scheme,a.host=n.host,a.port=n.port;var c="";/^[^\/]/.test(a.path)&&(c=n.path,c=/\/[^\/]*\.[^\/]*$/.test(c)?c.replace(/\/[^\/]+$/,"/"):c.replace(/\/?$/,"/")),a.path=c+(a.path||"")}return a.port||(a.port=o[a.scheme]||80),a.port=parseInt(a.port,10),a.path||(a.path="/"),delete a.source,a},t=function(t){var n={http:80,https:443},i="object"==typeof t?t:e(t);return i.scheme+"://"+i.host+(i.port!==n[i.scheme]?":"+i.port:"")+i.path+(i.query?i.query:"")},n=function(t){function n(e){return[e.scheme,e.host,e.port].join("/")}return"string"==typeof t&&(t=e(t)),n(e())===n(t)};return{parseUrl:e,resolveUrl:t,hasSameOrigin:n}}),i(R,[u,g,p],function(e,t,n){function i(){this.uid=e.guid("uid_"),t.call(this),this.destroy=function(){this.disconnectRuntime(),this.unbindAll()}}return i.prototype=n.instance,i}),i(A,[u,g,w],function(e,t,n){return function(){function i(e,t){if(!t.isDetached()){var i=this.connectRuntime(t.ruid).exec.call(this,"FileReaderSync","read",e,t);return this.disconnectRuntime(),i}var r=t.getSource();switch(e){case"readAsBinaryString":return r;case"readAsDataURL":return"data:"+t.type+";base64,"+n.btoa(r);case"readAsText":for(var o="",a=0,s=r.length;s>a;a++)o+=String.fromCharCode(r[a]);return o}}t.call(this),e.extend(this,{uid:e.guid("uid_"),readAsBinaryString:function(e){return i.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){return i.call(this,"readAsDataURL",e)},readAsText:function(e){return i.call(this,"readAsText",e)}})}}),i(I,[f,u,y],function(e,t,n){function i(){var e,i=[];t.extend(this,{append:function(r,o){var a=this,s=t.typeOf(o);o instanceof n?e={name:r,value:o}:"array"===s?(r+="[]",t.each(o,function(e){a.append(r,e)})):"object"===s?t.each(o,function(e,t){a.append(r+"["+t+"]",e)}):"null"===s||"undefined"===s||"number"===s&&isNaN(o)?a.append(r,"false"):i.push({name:r,value:o.toString()})},hasBlob:function(){return!!this.getBlob()},getBlob:function(){return e&&e.value||null},getBlobName:function(){return e&&e.name||null},each:function(n){t.each(i,function(e){n(e.value,e.name)}),e&&n(e.value,e.name)},destroy:function(){e=null,i=[]}})}return i}),i(T,[u,f,p,w,x,m,R,y,A,I,c,d],function(e,t,n,i,r,o,a,s,u,c,l,d){function h(){this.uid=e.guid("uid_")}function f(){function n(e,t){return w.hasOwnProperty(e)?1===arguments.length?l.can("define_property")?w[e]:v[e]:void(l.can("define_property")?w[e]=t:v[e]=t):void 0}function u(t){function i(){B&&(B.destroy(),B=null),s.dispatchEvent("loadend"),s=null}function r(r){B.bind("LoadStart",function(e){n("readyState",f.LOADING),s.dispatchEvent("readystatechange"),s.dispatchEvent(e),O&&s.upload.dispatchEvent(e)}),B.bind("Progress",function(e){n("readyState")!==f.LOADING&&(n("readyState",f.LOADING),s.dispatchEvent("readystatechange")),s.dispatchEvent(e)}),B.bind("UploadProgress",function(e){O&&s.upload.dispatchEvent({type:"progress",lengthComputable:!1,total:e.total,loaded:e.loaded})}),B.bind("Load",function(t){n("readyState",f.DONE),n("status",Number(r.exec.call(B,"XMLHttpRequest","getStatus")||0)),n("statusText",p[n("status")]||""),n("response",r.exec.call(B,"XMLHttpRequest","getResponse",n("responseType"))),~e.inArray(n("responseType"),["text",""])?n("responseText",n("response")):"document"===n("responseType")&&n("responseXML",n("response")),k=r.exec.call(B,"XMLHttpRequest","getAllResponseHeaders"),s.dispatchEvent("readystatechange"),n("status")>0?(O&&s.upload.dispatchEvent(t),s.dispatchEvent(t)):(N=!0,s.dispatchEvent("error")),i()}),B.bind("Abort",function(e){s.dispatchEvent(e),i()}),B.bind("Error",function(e){N=!0,n("readyState",f.DONE),s.dispatchEvent("readystatechange"),D=!0,s.dispatchEvent(e),i()}),r.exec.call(B,"XMLHttpRequest","send",{url:E,method:_,async:y,user:x,password:R,headers:b,mimeType:I,encoding:A,responseType:s.responseType,withCredentials:s.withCredentials,options:H},t)}var s=this;C=(new Date).getTime(),B=new a,"string"==typeof H.required_caps&&(H.required_caps=o.parseCaps(H.required_caps)),H.required_caps=e.extend({},H.required_caps,{return_response_type:s.responseType}),t instanceof c&&(H.required_caps.send_multipart=!0),e.isEmptyObj(b)||(H.required_caps.send_custom_headers=!0),L||(H.required_caps.do_cors=!0),H.ruid?r(B.connectRuntime(H)):(B.bind("RuntimeInit",function(e,t){r(t)}),B.bind("RuntimeError",function(e,t){s.dispatchEvent("RuntimeError",t)}),B.connectRuntime(H))}function g(){n("responseText",""),n("responseXML",null),n("response",null),n("status",0),n("statusText",""),C=M=null}var v=this,w={timeout:0,readyState:f.UNSENT,withCredentials:!1,status:0,statusText:"",responseType:"",responseXML:null,responseText:null,response:null},y=!0,E,_,b={},x,R,A=null,I=null,T=!1,S=!1,O=!1,D=!1,N=!1,L=!1,C,M,F=null,P=null,H={},B,k="",U;e.extend(this,w,{uid:e.guid("uid_"),upload:new h,open:function(o,a,s,u,c){var l;if(!o||!a)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(/[\u0100-\uffff]/.test(o)||i.utf8_encode(o)!==o)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(~e.inArray(o.toUpperCase(),["CONNECT","DELETE","GET","HEAD","OPTIONS","POST","PUT","TRACE","TRACK"])&&(_=o.toUpperCase()),~e.inArray(_,["CONNECT","TRACE","TRACK"]))throw new t.DOMException(t.DOMException.SECURITY_ERR);if(a=i.utf8_encode(a),l=r.parseUrl(a),L=r.hasSameOrigin(l),E=r.resolveUrl(a),(u||c)&&!L)throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);if(x=u||l.user,R=c||l.pass,y=s||!0,y===!1&&(n("timeout")||n("withCredentials")||""!==n("responseType")))throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);T=!y,S=!1,b={},g.call(this),n("readyState",f.OPENED),this.dispatchEvent("readystatechange")},setRequestHeader:function(r,o){var a=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","cookie","cookie2","content-transfer-encoding","date","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","user-agent","via"];if(n("readyState")!==f.OPENED||S)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(/[\u0100-\uffff]/.test(r)||i.utf8_encode(r)!==r)throw new t.DOMException(t.DOMException.SYNTAX_ERR);return r=e.trim(r).toLowerCase(),~e.inArray(r,a)||/^(proxy\-|sec\-)/.test(r)?!1:(b[r]?b[r]+=", "+o:b[r]=o,!0)},getAllResponseHeaders:function(){return k||""},getResponseHeader:function(t){return t=t.toLowerCase(),N||~e.inArray(t,["set-cookie","set-cookie2"])?null:k&&""!==k&&(U||(U={},e.each(k.split(/\r\n/),function(t){var n=t.split(/:\s+/);2===n.length&&(n[0]=e.trim(n[0]),U[n[0].toLowerCase()]={header:n[0],value:e.trim(n[1])})})),U.hasOwnProperty(t))?U[t].header+": "+U[t].value:null},overrideMimeType:function(i){var r,o;if(~e.inArray(n("readyState"),[f.LOADING,f.DONE]))throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(i=e.trim(i.toLowerCase()),/;/.test(i)&&(r=i.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))&&(i=r[1],r[2]&&(o=r[2])),!d.mimes[i])throw new t.DOMException(t.DOMException.SYNTAX_ERR);F=i,P=o},send:function(n,r){if(H="string"===e.typeOf(r)?{ruid:r}:r?r:{},this.readyState!==f.OPENED||S)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(n instanceof s)H.ruid=n.ruid,I=n.type||"application/octet-stream";else if(n instanceof c){if(n.hasBlob()){var o=n.getBlob();H.ruid=o.ruid,I=o.type||"application/octet-stream"}}else"string"==typeof n&&(A="UTF-8",I="text/plain;charset=UTF-8",n=i.utf8_encode(n));this.withCredentials||(this.withCredentials=H.required_caps&&H.required_caps.send_browser_cookies&&!L),O=!T&&this.upload.hasEventListener(),N=!1,D=!n,T||(S=!0),u.call(this,n)},abort:function(){if(N=!0,T=!1,~e.inArray(n("readyState"),[f.UNSENT,f.OPENED,f.DONE]))n("readyState",f.UNSENT);else{if(n("readyState",f.DONE),S=!1,!B)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);B.getRuntime().exec.call(B,"XMLHttpRequest","abort",D),D=!0}},destroy:function(){B&&("function"===e.typeOf(B.destroy)&&B.destroy(),B=null),this.unbindAll(),this.upload&&(this.upload.unbindAll(),this.upload=null)}}),this.handleEventProps(m.concat(["readystatechange"])),this.upload.handleEventProps(m)}var p={100:"Continue",101:"Switching Protocols",102:"Processing",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",207:"Multi-Status",226:"IM Used",300:"Multiple Choices",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",306:"Reserved",307:"Temporary Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Requested Range Not Satisfiable",417:"Expectation Failed",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",426:"Upgrade Required",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",510:"Not Extended"};h.prototype=n.instance;var m=["loadstart","progress","abort","error","load","timeout","loadend"],g=1,v=2;return f.UNSENT=0,f.OPENED=1,f.HEADERS_RECEIVED=2,f.LOADING=3,f.DONE=4,f.prototype=n.instance,f}),i(S,[u,w,g,p],function(e,t,n,i){function r(){function i(){l=d=0,c=this.result=null}function o(t,n){var i=this;u=n,i.bind("TransportingProgress",function(t){d=t.loaded,l>d&&-1===e.inArray(i.state,[r.IDLE,r.DONE])&&a.call(i)},999),i.bind("TransportingComplete",function(){d=l,i.state=r.DONE,c=null,i.result=u.exec.call(i,"Transporter","getAsBlob",t||"")},999),i.state=r.BUSY,i.trigger("TransportingStarted"),a.call(i)}function a(){var e=this,n,i=l-d;h>i&&(h=i),n=t.btoa(c.substr(d,h)),u.exec.call(e,"Transporter","receive",n,l)}var s,u,c,l,d,h;n.call(this),e.extend(this,{uid:e.guid("uid_"),state:r.IDLE,result:null,transport:function(t,n,r){var a=this;if(r=e.extend({chunk_size:204798},r),(s=r.chunk_size%3)&&(r.chunk_size+=3-s),h=r.chunk_size,i.call(this),c=t,l=t.length,"string"===e.typeOf(r)||r.ruid)o.call(a,n,this.connectRuntime(r));else{var u=function(e,t){a.unbind("RuntimeInit",u),o.call(a,n,t)};this.bind("RuntimeInit",u),this.connectRuntime(r)}},abort:function(){var e=this;e.state=r.IDLE,u&&(u.exec.call(e,"Transporter","clear"),e.trigger("TransportingAborted")),i.call(e)},destroy:function(){this.unbindAll(),u=null,this.disconnectRuntime(),i.call(this)}})}return r.IDLE=0,r.BUSY=1,r.DONE=2,r.prototype=i.instance,r}),i(O,[u,h,f,A,T,m,g,S,c,p,y,E,w],function(e,t,n,i,r,o,a,s,u,c,l,d,h){function f(){function i(e){e||(e=this.exec("Image","getInfo")),this.size=e.size,this.width=e.width,this.height=e.height,this.type=e.type,this.meta=e.meta,""===this.name&&(this.name=e.name)}function c(t){var i=e.typeOf(t);try{if(t instanceof f){if(!t.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);m.apply(this,arguments)}else if(t instanceof l){if(!~e.inArray(t.type,["image/jpeg","image/png"]))throw new n.ImageError(n.ImageError.WRONG_FORMAT);g.apply(this,arguments)}else if(-1!==e.inArray(i,["blob","file"]))c.call(this,new d(null,t),arguments[1]);else if("string"===i)"data:"===t.substr(0,5)?c.call(this,new l(null,{data:t}),arguments[1]):v.apply(this,arguments);else{if("node"!==i||"img"!==t.nodeName.toLowerCase())throw new n.DOMException(n.DOMException.TYPE_MISMATCH_ERR);c.call(this,t.src,arguments[1])}}catch(r){this.trigger("error",r.code)}}function m(t,n){var i=this.connectRuntime(t.ruid);this.ruid=i.uid,i.exec.call(this,"Image","loadFromImage",t,"undefined"===e.typeOf(n)?!0:n)}function g(t,n){function i(e){r.ruid=e.uid,e.exec.call(r,"Image","loadFromBlob",t)}var r=this;r.name=t.name||"",t.isDetached()?(this.bind("RuntimeInit",function(e,t){i(t)}),n&&"string"==typeof n.required_caps&&(n.required_caps=o.parseCaps(n.required_caps)),this.connectRuntime(e.extend({required_caps:{access_image_binary:!0,resize_image:!0}},n))):i(this.connectRuntime(t.ruid))}function v(e,t){var n=this,i;i=new r,i.open("get",e),i.responseType="blob",i.onprogress=function(e){n.trigger(e)},i.onload=function(){g.call(n,i.response,!0)},i.onerror=function(e){n.trigger(e)},i.onloadend=function(){i.destroy()},i.bind("RuntimeError",function(e,t){n.trigger("RuntimeError",t)}),i.send(null,t)}a.call(this),e.extend(this,{uid:e.guid("uid_"),ruid:null,name:"",size:0,width:0,height:0,type:"",meta:{},clone:function(){this.load.apply(this,arguments)},load:function(){c.apply(this,arguments)},downsize:function(t){var i={width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90,crop:!1,preserveHeaders:!0,resample:!1};t="object"==typeof t?e.extend(i,t):e.extend(i,{width:arguments[0],height:arguments[1],crop:arguments[2],preserveHeaders:arguments[3]});try{if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);if(this.width>f.MAX_RESIZE_WIDTH||this.height>f.MAX_RESIZE_HEIGHT)throw new n.ImageError(n.ImageError.MAX_RESOLUTION_ERR);this.exec("Image","downsize",t.width,t.height,t.crop,t.preserveHeaders)}catch(r){this.trigger("error",r.code)}},crop:function(e,t,n){this.downsize(e,t,!0,n)},getAsCanvas:function(){if(!u.can("create_canvas"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);var e=this.connectRuntime(this.ruid);return e.exec.call(this,"Image","getAsCanvas")},getAsBlob:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsBlob",e||"image/jpeg",t||90)},getAsDataURL:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsDataURL",e||"image/jpeg",t||90)},getAsBinaryString:function(e,t){var n=this.getAsDataURL(e,t);return h.atob(n.substring(n.indexOf("base64,")+7))},embed:function(i,r){function o(t,r){var o=this;if(u.can("create_canvas")){var l=o.getAsCanvas();if(l)return i.appendChild(l),l=null,o.destroy(),void a.trigger("embedded")}var d=o.getAsDataURL(t,r);if(!d)throw new n.ImageError(n.ImageError.WRONG_FORMAT);if(u.can("use_data_uri_of",d.length))i.innerHTML='<img src="'+d+'" width="'+o.width+'" height="'+o.height+'" />',o.destroy(),a.trigger("embedded");else{var f=new s;f.bind("TransportingComplete",function(){c=a.connectRuntime(this.result.ruid),a.bind("Embedded",function(){e.extend(c.getShimContainer().style,{top:"0px",left:"0px",width:o.width+"px",height:o.height+"px"}),c=null},999),c.exec.call(a,"ImageView","display",this.result.uid,width,height),o.destroy()}),f.transport(h.atob(d.substring(d.indexOf("base64,")+7)),t,{required_caps:{display_media:!0},runtime_order:"flash,silverlight",container:i})}}var a=this,c;r=e.extend({width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90},r||{});try{if(!(i=t.get(i)))throw new n.DOMException(n.DOMException.INVALID_NODE_TYPE_ERR);if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);this.width>f.MAX_RESIZE_WIDTH||this.height>f.MAX_RESIZE_HEIGHT;var l=new f;return l.bind("Resize",function(){o.call(this,r.type,r.quality)}),l.bind("Load",function(){l.downsize(r)}),this.meta.thumb&&this.meta.thumb.width>=r.width&&this.meta.thumb.height>=r.height?l.load(this.meta.thumb.data):l.clone(this,!1),l}catch(d){this.trigger("error",d.code)}},destroy:function(){this.ruid&&(this.getRuntime().exec.call(this,"Image","destroy"),this.disconnectRuntime()),this.unbindAll()}}),this.handleEventProps(p),this.bind("Load Resize",function(){i.call(this)},999)}var p=["progress","load","error","resize","embedded"];return f.MAX_RESIZE_WIDTH=8192,f.MAX_RESIZE_HEIGHT=8192,f.prototype=c.instance,f}),i(D,[u,f,m,c],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue,c=e.extend({access_binary:s(window.FileReader||window.File&&window.File.getAsDataURL),access_image_binary:function(){return r.can("access_binary")&&!!a.Image},display_media:s(i.can("create_canvas")||i.can("use_data_uri_over32kb")),do_cors:s(window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest),drag_and_drop:s(function(){var e=document.createElement("div");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&("IE"!==i.browser||i.verComp(i.version,9,">"))}()),filter_by_extension:s(function(){return"Chrome"===i.browser&&i.verComp(i.version,28,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||"Safari"===i.browser&&i.verComp(i.version,7,">=")}()),return_response_headers:u,return_response_type:function(e){return"json"===e&&window.JSON?!0:i.can("return_response_type",e)},return_status_code:u,report_upload_progress:s(window.XMLHttpRequest&&(new XMLHttpRequest).upload),resize_image:function(){return r.can("access_binary")&&i.can("create_canvas")},select_file:function(){return i.can("use_fileinput")&&window.File},select_folder:function(){return r.can("select_file")&&"Chrome"===i.browser&&i.verComp(i.version,21,">=")},select_multiple:function(){return!(!r.can("select_file")||"Safari"===i.browser&&"Windows"===i.os||"iOS"===i.os&&i.verComp(i.osVersion,"7.0.0",">")&&i.verComp(i.osVersion,"8.0.0","<"))},send_binary_string:s(window.XMLHttpRequest&&((new XMLHttpRequest).sendAsBinary||window.Uint8Array&&window.ArrayBuffer)),send_custom_headers:s(window.XMLHttpRequest),send_multipart:function(){return!!(window.XMLHttpRequest&&(new XMLHttpRequest).upload&&window.FormData)||r.can("send_binary_string")},slice_blob:s(window.File&&(File.prototype.mozSlice||File.prototype.webkitSlice||File.prototype.slice)),stream_upload:function(){return r.can("slice_blob")&&r.can("send_multipart")},summon_file_dialog:function(){return r.can("select_file")&&("Firefox"===i.browser&&i.verComp(i.version,4,">=")||"Opera"===i.browser&&i.verComp(i.version,12,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||!!~e.inArray(i.browser,["Chrome","Safari"]))},upload_filesize:u},arguments[2]);n.call(this,t,arguments[1]||o,c),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html5",a={};return n.addConstructor(o,r),a}),i(N,[u],function(e){function t(){this.returnValue=!1}function n(){this.cancelBubble=!0}var i={},r="moxie_"+e.guid(),o=function(o,a,s,u){var c,l;a=a.toLowerCase(),o.addEventListener?(c=s,o.addEventListener(a,c,!1)):o.attachEvent&&(c=function(){var e=window.event;e.target||(e.target=e.srcElement),e.preventDefault=t,e.stopPropagation=n,s(e)},o.attachEvent("on"+a,c)),o[r]||(o[r]=e.guid()),i.hasOwnProperty(o[r])||(i[o[r]]={}),l=i[o[r]],l.hasOwnProperty(a)||(l[a]=[]),l[a].push({func:c,orig:s,key:u})},a=function(t,n,o){var a,s;if(n=n.toLowerCase(),t[r]&&i[t[r]]&&i[t[r]][n]){a=i[t[r]][n];for(var u=a.length-1;u>=0&&(a[u].orig!==o&&a[u].key!==o||(t.removeEventListener?t.removeEventListener(n,a[u].func,!1):t.detachEvent&&t.detachEvent("on"+n,a[u].func),a[u].orig=null,a[u].func=null,a.splice(u,1),o===s));u--);if(a.length||delete i[t[r]][n],e.isEmptyObj(i[t[r]])){delete i[t[r]];try{delete t[r]}catch(c){t[r]=s}}}},s=function(t,n){t&&t[r]&&e.each(i[t[r]],function(e,i){a(t,i,n)})};return{addEvent:o,removeEvent:a,removeAllEvents:s}}),i(L,[D,E,u,h,N,d,c],function(e,t,n,i,r,o,a){function s(){var e;n.extend(this,{init:function(s){var u=this,c=u.getRuntime(),l,d,h,f,p,m;e=s,h=e.accept.mimes||o.extList2mimes(e.accept,c.can("filter_by_extension")),d=c.getShimContainer(),d.innerHTML='<input id="'+c.uid+'" type="file" style="font-size:999px;opacity:0;"'+(e.multiple&&c.can("select_multiple")?"multiple":"")+(e.directory&&c.can("select_folder")?"webkitdirectory directory":"")+(h?' accept="'+h.join(",")+'"':"")+" />",l=i.get(c.uid),n.extend(l.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),f=i.get(e.browse_button),c.can("summon_file_dialog")&&("static"===i.getStyle(f,"position")&&(f.style.position="relative"),p=parseInt(i.getStyle(f,"z-index"),10)||1,f.style.zIndex=p,d.style.zIndex=p-1,r.addEvent(f,"click",function(e){var t=i.get(c.uid);t&&!t.disabled&&t.click(),e.preventDefault()},u.uid)),m=c.can("summon_file_dialog")?f:d,r.addEvent(m,"mouseover",function(){u.trigger("mouseenter")},u.uid),r.addEvent(m,"mouseout",function(){u.trigger("mouseleave")},u.uid),r.addEvent(m,"mousedown",function(){u.trigger("mousedown")},u.uid),r.addEvent(i.get(e.container),"mouseup",function(){u.trigger("mouseup")},u.uid),l.onchange=function g(i){if(u.files=[],n.each(this.files,function(n){var i="";return e.directory&&"."==n.name?!0:(n.webkitRelativePath&&(i="/"+n.webkitRelativePath.replace(/^\//,"")),n=new t(c.uid,n),n.relativePath=i,void u.files.push(n))}),"IE"!==a.browser&&"IEMobile"!==a.browser)this.value="";else{var r=this.cloneNode(!0);this.parentNode.replaceChild(r,this),r.onchange=g}u.files.length&&u.trigger("change")},u.trigger({type:"ready",async:!0}),d=null},disable:function(e){var t=this.getRuntime(),n;(n=i.get(t.uid))&&(n.disabled=!!e)},destroy:function(){var t=this.getRuntime(),n=t.getShim(),o=t.getShimContainer();r.removeAllEvents(o,this.uid),r.removeAllEvents(e&&i.get(e.container),this.uid),r.removeAllEvents(e&&i.get(e.browse_button),this.uid),o&&(o.innerHTML=""),n.removeInstance(this.uid),e=o=n=null}})}return e.FileInput=s}),i(C,[D,y],function(e,t){function n(){function e(e,t,n){var i;if(!window.File.prototype.slice)return(i=window.File.prototype.webkitSlice||window.File.prototype.mozSlice)?i.call(e,t,n):null;try{return e.slice(),e.slice(t,n)}catch(r){return e.slice(t,n-t)}}this.slice=function(){return new t(this.getRuntime().uid,e.apply(this,arguments))}}return e.Blob=n}),i(M,[D,E,u,h,N,d],function(e,t,n,i,r,o){function a(){function e(e){if(!e.dataTransfer||!e.dataTransfer.types)return!1;var t=n.toArray(e.dataTransfer.types||[]);return-1!==n.inArray("Files",t)||-1!==n.inArray("public.file-url",t)||-1!==n.inArray("application/x-moz-file",t)}function a(e,n){if(u(e)){var i=new t(g,e);i.relativePath=n||"",f.push(i)}}function s(e){for(var t=[],i=0;i<e.length;i++)[].push.apply(t,e[i].extensions.split(/\s*,\s*/));return-1===n.inArray("*",t)?t:[]}function u(e){if(!p.length)return!0;var t=o.getFileExtension(e.name);return!t||-1!==n.inArray(t,p)}function c(e,t){var i=[];n.each(e,function(e){var t=e.webkitGetAsEntry();t&&(t.isFile?a(e.getAsFile(),t.fullPath):i.push(t))}),i.length?l(i,t):t()}function l(e,t){var i=[];n.each(e,function(e){i.push(function(t){d(e,t)})}),n.inSeries(i,function(){t()})}function d(e,t){e.isFile?e.file(function(n){a(n,e.fullPath),t()},function(){t()}):e.isDirectory?h(e,t):t()}function h(e,t){function n(e){r.readEntries(function(t){t.length?([].push.apply(i,t),n(e)):e()},e)}var i=[],r=e.createReader();n(function(){l(i,t)})}var f=[],p=[],m,g;n.extend(this,{init:function(t){var i=this,o;m=t,g=i.ruid,p=s(m.accept),o=m.container,r.addEvent(o,"dragover",function(t){e(t)&&(t.preventDefault(),t.dataTransfer.dropEffect="copy")},i.uid),r.addEvent(o,"drop",function(t){e(t)&&(t.preventDefault(),f=[],t.dataTransfer.items&&t.dataTransfer.items[0].webkitGetAsEntry?c(t.dataTransfer.items,function(){i.files=f,i.trigger("drop")}):(n.each(t.dataTransfer.files,function(e){a(e)}),i.files=f,i.trigger("drop")))},i.uid),r.addEvent(o,"dragenter",function(e){i.trigger("dragenter")},i.uid),r.addEvent(o,"dragleave",function(e){i.trigger("dragleave")},i.uid)},destroy:function(){r.removeAllEvents(m&&i.get(m.container),this.uid),g=f=p=m=null}})}return e.FileDrop=a}),i(F,[D,w,u],function(e,t,n){function i(){function e(e){return t.atob(e.substring(e.indexOf("base64,")+7))}var i,r=!1;n.extend(this,{read:function(t,o){var a=this;a.result="",i=new window.FileReader,i.addEventListener("progress",function(e){a.trigger(e)}),i.addEventListener("load",function(t){a.result=r?e(i.result):i.result,a.trigger(t)}),i.addEventListener("error",function(e){a.trigger(e,i.error)}),i.addEventListener("loadend",function(e){i=null,a.trigger(e)}),"function"===n.typeOf(i[t])?(r=!1,i[t](o.getSource())):"readAsBinaryString"===t&&(r=!0,i.readAsDataURL(o.getSource()))},abort:function(){i&&i.abort()},destroy:function(){i=null}})}return e.FileReader=i}),i(P,[D,u,d,x,E,y,I,f,c],function(e,t,n,i,r,o,a,s,u){function c(){function e(e,t){var n=this,i,r;i=t.getBlob().getSource(),r=new window.FileReader,r.onload=function(){t.append(t.getBlobName(),new o(null,{type:i.type,data:r.result})),h.send.call(n,e,t)},r.readAsBinaryString(i)}function c(){return!window.XMLHttpRequest||"IE"===u.browser&&u.verComp(u.version,8,"<")?function(){for(var e=["Msxml2.XMLHTTP.6.0","Microsoft.XMLHTTP"],t=0;t<e.length;t++)try{return new ActiveXObject(e[t])}catch(n){}}():new window.XMLHttpRequest}function l(e){var t=e.responseXML,n=e.responseText;return"IE"===u.browser&&n&&t&&!t.documentElement&&/[^\/]+\/[^\+]+\+xml/.test(e.getResponseHeader("Content-Type"))&&(t=new window.ActiveXObject("Microsoft.XMLDOM"),t.async=!1,t.validateOnParse=!1,t.loadXML(n)),t&&("IE"===u.browser&&0!==t.parseError||!t.documentElement||"parsererror"===t.documentElement.tagName)?null:t}function d(e){var t="----moxieboundary"+(new Date).getTime(),n="--",i="\r\n",r="",a=this.getRuntime();if(!a.can("send_binary_string"))throw new s.RuntimeError(s.RuntimeError.NOT_SUPPORTED_ERR);return f.setRequestHeader("Content-Type","multipart/form-data; boundary="+t),e.each(function(e,a){r+=e instanceof o?n+t+i+'Content-Disposition: form-data; name="'+a+'"; filename="'+unescape(encodeURIComponent(e.name||"blob"))+'"'+i+"Content-Type: "+(e.type||"application/octet-stream")+i+i+e.getSource()+i:n+t+i+'Content-Disposition: form-data; name="'+a+'"'+i+i+unescape(encodeURIComponent(e))+i}),r+=n+t+n+i}var h=this,f,p;t.extend(this,{send:function(n,r){var s=this,l="Mozilla"===u.browser&&u.verComp(u.version,4,">=")&&u.verComp(u.version,7,"<"),h="Android Browser"===u.browser,m=!1;if(p=n.url.replace(/^.+?\/([\w\-\.]+)$/,"$1").toLowerCase(),f=c(),f.open(n.method,n.url,n.async,n.user,n.password),r instanceof o)r.isDetached()&&(m=!0),r=r.getSource();else if(r instanceof a){if(r.hasBlob())if(r.getBlob().isDetached())r=d.call(s,r),m=!0;else if((l||h)&&"blob"===t.typeOf(r.getBlob().getSource())&&window.FileReader)return void e.call(s,n,r);if(r instanceof a){var g=new window.FormData;r.each(function(e,t){e instanceof o?g.append(t,e.getSource()):g.append(t,e)}),r=g}}f.upload?(n.withCredentials&&(f.withCredentials=!0),f.addEventListener("load",function(e){s.trigger(e)}),f.addEventListener("error",function(e){s.trigger(e)}),f.addEventListener("progress",function(e){s.trigger(e)}),f.upload.addEventListener("progress",function(e){s.trigger({type:"UploadProgress",loaded:e.loaded,total:e.total})})):f.onreadystatechange=function v(){switch(f.readyState){case 1:break;case 2:break;case 3:var e,t;try{i.hasSameOrigin(n.url)&&(e=f.getResponseHeader("Content-Length")||0),f.responseText&&(t=f.responseText.length)}catch(r){e=t=0}s.trigger({type:"progress",lengthComputable:!!e,total:parseInt(e,10),loaded:t});break;case 4:f.onreadystatechange=function(){},s.trigger(0===f.status?"error":"load")}},t.isEmptyObj(n.headers)||t.each(n.headers,function(e,t){f.setRequestHeader(t,e)}),""!==n.responseType&&"responseType"in f&&("json"!==n.responseType||u.can("return_response_type","json")?f.responseType=n.responseType:f.responseType="text"),m?f.sendAsBinary?f.sendAsBinary(r):!function(){for(var e=new Uint8Array(r.length),t=0;t<r.length;t++)e[t]=255&r.charCodeAt(t);f.send(e.buffer)}():f.send(r),s.trigger("loadstart")},getStatus:function(){try{if(f)return f.status}catch(e){}return 0},getResponse:function(e){var t=this.getRuntime();try{switch(e){case"blob":var i=new r(t.uid,f.response),o=f.getResponseHeader("Content-Disposition");if(o){var a=o.match(/filename=([\'\"'])([^\1]+)\1/);a&&(p=a[2])}return i.name=p,i.type||(i.type=n.getFileMime(p)),i;case"json":return u.can("return_response_type","json")?f.response:200===f.status&&window.JSON?JSON.parse(f.responseText):null;case"document":return l(f);default:return""!==f.responseText?f.responseText:null}}catch(s){return null}},getAllResponseHeaders:function(){try{return f.getAllResponseHeaders()}catch(e){}return""},abort:function(){f&&f.abort()},destroy:function(){h=p=null}})}return e.XMLHttpRequest=c}),i(H,[u],function(e){function t(e){e instanceof ArrayBuffer?n.apply(this,arguments):i.apply(this,arguments)}function n(t){var n=new DataView(t);e.extend(this,{readByteAt:function(e){return n.getUint8(e)},writeByteAt:function(e,t){n.setUint8(e,t)},SEGMENT:function(e,i,r){switch(arguments.length){case 2:return t.slice(e,e+i);case 1:return t.slice(e);case 3:if(null===r&&(r=new ArrayBuffer),r instanceof ArrayBuffer){var o=new Uint8Array(this.length()-i+r.byteLength);e>0&&o.set(new Uint8Array(t.slice(0,e)),0),o.set(new Uint8Array(r),e),o.set(new Uint8Array(t.slice(e+i)),e+r.byteLength),this.clear(),t=o.buffer,n=new DataView(t);break}default:return t}},length:function(){return t?t.byteLength:0},clear:function(){n=t=null}})}function i(t){function n(e,n,i){i=3===arguments.length?i:t.length-n-1,t=t.substr(0,n)+e+t.substr(i+n)}e.extend(this,{readByteAt:function(e){return t.charCodeAt(e)},writeByteAt:function(e,t){n(String.fromCharCode(t),e,1)},SEGMENT:function(e,i,r){switch(arguments.length){case 1:return t.substr(e);case 2:return t.substr(e,i);case 3:n(null!==r?r:"",e,i);break;default:return t}},length:function(){return t?t.length:0},clear:function(){t=null}})}return e.extend(t.prototype,{littleEndian:!1,read:function(e,t){var n,i,r;if(e+t>this.length())throw new Error("You are trying to read outside the source boundaries.");for(i=this.littleEndian?0:-8*(t-1),r=0,n=0;t>r;r++)n|=this.readByteAt(e+r)<<Math.abs(i+8*r);return n},write:function(e,t,n){var i,r,o="";if(e>this.length())throw new Error("You are trying to write outside the source boundaries.");for(i=this.littleEndian?0:-8*(n-1),r=0;n>r;r++)this.writeByteAt(e+r,t>>Math.abs(i+8*r)&255)},BYTE:function(e){return this.read(e,1)},SHORT:function(e){return this.read(e,2)},LONG:function(e){return this.read(e,4)},SLONG:function(e){var t=this.read(e,4);return t>2147483647?t-4294967296:t},CHAR:function(e){return String.fromCharCode(this.read(e,1))},STRING:function(e,t){return this.asArray("CHAR",e,t).join("")},asArray:function(e,t,n){for(var i=[],r=0;n>r;r++)i[r]=this[e](t+r);return i}}),t}),i(B,[H,f],function(e,t){return function n(i){var r=[],o,a,s,u=0;if(o=new e(i),65496!==o.SHORT(0))throw o.clear(),new t.ImageError(t.ImageError.WRONG_FORMAT);for(a=2;a<=o.length();)if(s=o.SHORT(a),s>=65488&&65495>=s)a+=2;else{if(65498===s||65497===s)break;u=o.SHORT(a+2)+2,s>=65505&&65519>=s&&r.push({hex:s,name:"APP"+(15&s),start:a,length:u,segment:o.SEGMENT(a,u)}),a+=u}return o.clear(),{headers:r,restore:function(t){var n,i,o;for(o=new e(t),a=65504==o.SHORT(2)?4+o.SHORT(4):2,i=0,n=r.length;n>i;i++)o.SEGMENT(a,0,r[i].segment),a+=r[i].length;return t=o.SEGMENT(),o.clear(),t},strip:function(t){var i,r,o,a;for(o=new n(t),r=o.headers,o.purge(),i=new e(t),a=r.length;a--;)i.SEGMENT(r[a].start,r[a].length,"");return t=i.SEGMENT(),i.clear(),t},get:function(e){for(var t=[],n=0,i=r.length;i>n;n++)r[n].name===e.toUpperCase()&&t.push(r[n].segment);return t},
-set:function(e,t){var n=[],i,o,a;for("string"==typeof t?n.push(t):n=t,i=o=0,a=r.length;a>i&&(r[i].name===e.toUpperCase()&&(r[i].segment=n[o],r[i].length=n[o].length,o++),!(o>=n.length));i++);},purge:function(){this.headers=r=[]}}}}),i(k,[u,H,f],function(e,n,i){function r(o){function a(n,r){var o=this,a,s,u,c,h,f,p,m,g=[],v={},w={1:"BYTE",7:"UNDEFINED",2:"ASCII",3:"SHORT",4:"LONG",5:"RATIONAL",9:"SLONG",10:"SRATIONAL"},y={BYTE:1,UNDEFINED:1,ASCII:1,SHORT:2,LONG:4,RATIONAL:8,SLONG:4,SRATIONAL:8};for(a=o.SHORT(n),s=0;a>s;s++)if(g=[],p=n+2+12*s,u=r[o.SHORT(p)],u!==t){if(c=w[o.SHORT(p+=2)],h=o.LONG(p+=2),f=y[c],!f)throw new i.ImageError(i.ImageError.INVALID_META_ERR);if(p+=4,f*h>4&&(p=o.LONG(p)+d.tiffHeader),p+f*h>=this.length())throw new i.ImageError(i.ImageError.INVALID_META_ERR);"ASCII"!==c?(g=o.asArray(c,p,h),m=1==h?g[0]:g,l.hasOwnProperty(u)&&"object"!=typeof m?v[u]=l[u][m]:v[u]=m):v[u]=e.trim(o.STRING(p,h).replace(/\0$/,""))}return v}function s(e,t,n){var i,r,o,a=0;if("string"==typeof t){var s=c[e.toLowerCase()];for(var u in s)if(s[u]===t){t=u;break}}i=d[e.toLowerCase()+"IFD"],r=this.SHORT(i);for(var l=0;r>l;l++)if(o=i+12*l+2,this.SHORT(o)==t){a=o+8;break}if(!a)return!1;try{this.write(a,n,4)}catch(h){return!1}return!0}var u,c,l,d,h,f;if(n.call(this,o),c={tiff:{274:"Orientation",270:"ImageDescription",271:"Make",272:"Model",305:"Software",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer"},exif:{36864:"ExifVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",36867:"DateTimeOriginal",33434:"ExposureTime",33437:"FNumber",34855:"ISOSpeedRatings",37377:"ShutterSpeedValue",37378:"ApertureValue",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37386:"FocalLength",41986:"ExposureMode",41987:"WhiteBalance",41990:"SceneCaptureType",41988:"DigitalZoomRatio",41992:"Contrast",41993:"Saturation",41994:"Sharpness"},gps:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude"},thumb:{513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength"}},l={ColorSpace:{1:"sRGB",0:"Uncalibrated"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{1:"Daylight",2:"Fliorescent",3:"Tungsten",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 -5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},ExposureMode:{0:"Auto exposure",1:"Manual exposure",2:"Auto bracket"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},GPSLatitudeRef:{N:"North latitude",S:"South latitude"},GPSLongitudeRef:{E:"East longitude",W:"West longitude"}},d={tiffHeader:10},h=d.tiffHeader,u={clear:this.clear},e.extend(this,{read:function(){try{return r.prototype.read.apply(this,arguments)}catch(e){throw new i.ImageError(i.ImageError.INVALID_META_ERR)}},write:function(){try{return r.prototype.write.apply(this,arguments)}catch(e){throw new i.ImageError(i.ImageError.INVALID_META_ERR)}},UNDEFINED:function(){return this.BYTE.apply(this,arguments)},RATIONAL:function(e){return this.LONG(e)/this.LONG(e+4)},SRATIONAL:function(e){return this.SLONG(e)/this.SLONG(e+4)},ASCII:function(e){return this.CHAR(e)},TIFF:function(){return f||null},EXIF:function(){var t=null;if(d.exifIFD){try{t=a.call(this,d.exifIFD,c.exif)}catch(n){return null}if(t.ExifVersion&&"array"===e.typeOf(t.ExifVersion)){for(var i=0,r="";i<t.ExifVersion.length;i++)r+=String.fromCharCode(t.ExifVersion[i]);t.ExifVersion=r}}return t},GPS:function(){var t=null;if(d.gpsIFD){try{t=a.call(this,d.gpsIFD,c.gps)}catch(n){return null}t.GPSVersionID&&"array"===e.typeOf(t.GPSVersionID)&&(t.GPSVersionID=t.GPSVersionID.join("."))}return t},thumb:function(){if(d.IFD1)try{var e=a.call(this,d.IFD1,c.thumb);if("JPEGInterchangeFormat"in e)return this.SEGMENT(d.tiffHeader+e.JPEGInterchangeFormat,e.JPEGInterchangeFormatLength)}catch(t){}return null},setExif:function(e,t){return"PixelXDimension"!==e&&"PixelYDimension"!==e?!1:s.call(this,"exif",e,t)},clear:function(){u.clear(),o=c=l=f=d=u=null}}),65505!==this.SHORT(0)||"EXIF\x00"!==this.STRING(4,5).toUpperCase())throw new i.ImageError(i.ImageError.INVALID_META_ERR);if(this.littleEndian=18761==this.SHORT(h),42!==this.SHORT(h+=2))throw new i.ImageError(i.ImageError.INVALID_META_ERR);d.IFD0=d.tiffHeader+this.LONG(h+=2),f=a.call(this,d.IFD0,c.tiff),"ExifIFDPointer"in f&&(d.exifIFD=d.tiffHeader+f.ExifIFDPointer,delete f.ExifIFDPointer),"GPSInfoIFDPointer"in f&&(d.gpsIFD=d.tiffHeader+f.GPSInfoIFDPointer,delete f.GPSInfoIFDPointer),e.isEmptyObj(f)&&(f=null);var p=this.LONG(d.IFD0+12*this.SHORT(d.IFD0)+2);p&&(d.IFD1=d.tiffHeader+p)}return r.prototype=n.prototype,r}),i(U,[u,f,B,H,k],function(e,t,n,i,r){function o(o){function a(e){var t=0,n,i;for(e||(e=c);t<=e.length();){if(n=e.SHORT(t+=2),n>=65472&&65475>=n)return t+=5,{height:e.SHORT(t),width:e.SHORT(t+=2)};i=e.SHORT(t+=2),t+=i-2}return null}function s(){var e=d.thumb(),t,n;return e&&(t=new i(e),n=a(t),t.clear(),n)?(n.data=e,n):null}function u(){d&&l&&c&&(d.clear(),l.purge(),c.clear(),h=l=d=c=null)}var c,l,d,h;if(c=new i(o),65496!==c.SHORT(0))throw new t.ImageError(t.ImageError.WRONG_FORMAT);l=new n(o);try{d=new r(l.get("app1")[0])}catch(f){}h=a.call(this),e.extend(this,{type:"image/jpeg",size:c.length(),width:h&&h.width||0,height:h&&h.height||0,setExif:function(t,n){return d?("object"===e.typeOf(t)?e.each(t,function(e,t){d.setExif(t,e)}):d.setExif(t,n),void l.set("app1",d.SEGMENT())):!1},writeHeaders:function(){return l.restore(arguments.length?arguments[0]:o)},stripHeaders:function(e){return l.strip(e)},purge:function(){u.call(this)}}),d&&(this.meta={tiff:d.TIFF(),exif:d.EXIF(),gps:d.GPS(),thumb:s()})}return o}),i(G,[f,u,H],function(e,t,n){function i(i){function r(){var e,t;return e=a.call(this,8),"IHDR"==e.type?(t=e.start,{width:s.LONG(t),height:s.LONG(t+=4)}):null}function o(){s&&(s.clear(),i=l=u=c=s=null)}function a(e){var t,n,i,r;return t=s.LONG(e),n=s.STRING(e+=4,4),i=e+=4,r=s.LONG(e+t),{length:t,type:n,start:i,CRC:r}}var s,u,c,l;s=new n(i),function(){var t=0,n=0,i=[35152,20039,3338,6666];for(n=0;n<i.length;n++,t+=2)if(i[n]!=s.SHORT(t))throw new e.ImageError(e.ImageError.WRONG_FORMAT)}(),l=r.call(this),t.extend(this,{type:"image/png",size:s.length(),width:l.width,height:l.height,purge:function(){o.call(this)}}),o.call(this)}return i}),i(z,[u,f,U,G],function(e,t,n,i){return function(r){var o=[n,i],a;a=function(){for(var e=0;e<o.length;e++)try{return new o[e](r)}catch(n){}throw new t.ImageError(t.ImageError.WRONG_FORMAT)}(),e.extend(this,{type:"",size:0,width:0,height:0,setExif:function(){},writeHeaders:function(e){return e},stripHeaders:function(e){return e},purge:function(){r=null}}),e.extend(this,a),this.purge=function(){a.purge(),a=null}}}),i(q,[],function(){function e(e,i,r){var o=e.naturalWidth,a=e.naturalHeight,s=r.width,u=r.height,c=r.x||0,l=r.y||0,d=i.getContext("2d");t(e)&&(o/=2,a/=2);var h=1024,f=document.createElement("canvas");f.width=f.height=h;for(var p=f.getContext("2d"),m=n(e,o,a),g=0;a>g;){for(var v=g+h>a?a-g:h,w=0;o>w;){var y=w+h>o?o-w:h;p.clearRect(0,0,h,h),p.drawImage(e,-w,-g);var E=w*s/o+c<<0,_=Math.ceil(y*s/o),b=g*u/a/m+l<<0,x=Math.ceil(v*u/a/m);d.drawImage(f,0,0,y,v,E,b,_,x),w+=h}g+=h}f=p=null}function t(e){var t=e.naturalWidth,n=e.naturalHeight;if(t*n>1048576){var i=document.createElement("canvas");i.width=i.height=1;var r=i.getContext("2d");return r.drawImage(e,-t+1,0),0===r.getImageData(0,0,1,1).data[3]}return!1}function n(e,t,n){var i=document.createElement("canvas");i.width=1,i.height=n;var r=i.getContext("2d");r.drawImage(e,0,0);for(var o=r.getImageData(0,0,1,n).data,a=0,s=n,u=n;u>a;){var c=o[4*(u-1)+3];0===c?s=u:a=u,u=s+a>>1}i=null;var l=u/n;return 0===l?1:l}return{isSubsampled:t,renderTo:e}}),i(j,[D,u,f,w,y,E,z,q,d,c],function(e,t,n,i,r,o,a,s,u,c){function l(){function e(){if(!_&&!y)throw new n.ImageError(n.DOMException.INVALID_STATE_ERR);return _||y}function l(e){return i.atob(e.substring(e.indexOf("base64,")+7))}function d(e,t){return"data:"+(t||"")+";base64,"+i.btoa(e)}function h(e){var t=this;y=new Image,y.onerror=function(){v.call(this),t.trigger("error",n.ImageError.WRONG_FORMAT)},y.onload=function(){t.trigger("load")},y.src="data:"==e.substr(0,5)?e:d(e,x.type)}function f(e,t){var i=this,r;return window.FileReader?(r=new FileReader,r.onload=function(){t(this.result)},r.onerror=function(){i.trigger("error",n.ImageError.WRONG_FORMAT)},r.readAsDataURL(e),void 0):t(e.getAsDataURL())}function p(n,i,r,o){var a=this,s,u,c=0,l=0,d,h,f,p;if(A=o,p=this.meta&&this.meta.tiff&&this.meta.tiff.Orientation||1,-1!==t.inArray(p,[5,6,7,8])){var v=n;n=i,i=v}return d=e(),r?(n=Math.min(n,d.width),i=Math.min(i,d.height),s=Math.max(n/d.width,i/d.height)):s=Math.min(n/d.width,i/d.height),s>1&&!r&&o?void this.trigger("Resize"):(_||(_=document.createElement("canvas")),h=Math.round(d.width*s),f=Math.round(d.height*s),r?(_.width=n,_.height=i,h>n&&(c=Math.round((h-n)/2)),f>i&&(l=Math.round((f-i)/2))):(_.width=h,_.height=f),A||g(_.width,_.height,p),m.call(this,d,_,-c,-l,h,f),this.width=_.width,this.height=_.height,R=!0,void a.trigger("Resize"))}function m(e,t,n,i,r,o){if("iOS"===c.OS)s.renderTo(e,t,{width:r,height:o,x:n,y:i});else{var a=t.getContext("2d");a.drawImage(e,n,i,r,o)}}function g(e,t,n){switch(n){case 5:case 6:case 7:case 8:_.width=t,_.height=e;break;default:_.width=e,_.height=t}var i=_.getContext("2d");switch(n){case 2:i.translate(e,0),i.scale(-1,1);break;case 3:i.translate(e,t),i.rotate(Math.PI);break;case 4:i.translate(0,t),i.scale(1,-1);break;case 5:i.rotate(.5*Math.PI),i.scale(1,-1);break;case 6:i.rotate(.5*Math.PI),i.translate(0,-t);break;case 7:i.rotate(.5*Math.PI),i.translate(e,-t),i.scale(-1,1);break;case 8:i.rotate(-.5*Math.PI),i.translate(-e,0)}}function v(){E&&(E.purge(),E=null),b=y=_=x=null,R=!1}var w=this,y,E,_,b,x,R=!1,A=!0;t.extend(this,{loadFromBlob:function(e){var t=this,i=t.getRuntime(),r=arguments.length>1?arguments[1]:!0;if(!i.can("access_binary"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);return x=e,e.isDetached()?(b=e.getSource(),void h.call(this,b)):void f.call(this,e.getSource(),function(e){r&&(b=l(e)),h.call(t,e)})},loadFromImage:function(e,t){this.meta=e.meta,x=new o(null,{name:e.name,size:e.size,type:e.type}),h.call(this,t?b=e.getAsBinaryString():e.getAsDataURL())},getInfo:function(){var t=this.getRuntime(),n;return!E&&b&&t.can("access_image_binary")&&(E=new a(b)),n={width:e().width||0,height:e().height||0,type:x.type||u.getFileMime(x.name),size:b&&b.length||x.size||0,name:x.name||"",meta:E&&E.meta||this.meta||{}},!n.meta||!n.meta.thumb||n.meta.thumb.data instanceof r||(n.meta.thumb.data=new r(null,{type:"image/jpeg",data:n.meta.thumb.data})),n},downsize:function(){p.apply(this,arguments)},getAsCanvas:function(){return _&&(_.id=this.uid+"_canvas"),_},getAsBlob:function(e,t){return e!==this.type&&p.call(this,this.width,this.height,!1),new o(null,{name:x.name||"",type:e,data:w.getAsBinaryString.call(this,e,t)})},getAsDataURL:function(e){var t=arguments[1]||90;if(!R)return y.src;if("image/jpeg"!==e)return _.toDataURL("image/png");try{return _.toDataURL("image/jpeg",t/100)}catch(n){return _.toDataURL("image/jpeg")}},getAsBinaryString:function(e,t){if(!R)return b||(b=l(w.getAsDataURL(e,t))),b;if("image/jpeg"!==e)b=l(w.getAsDataURL(e,t));else{var n;t||(t=90);try{n=_.toDataURL("image/jpeg",t/100)}catch(i){n=_.toDataURL("image/jpeg")}b=l(n),E&&(b=E.stripHeaders(b),A&&(E.meta&&E.meta.exif&&E.setExif({PixelXDimension:this.width,PixelYDimension:this.height}),b=E.writeHeaders(b)),E.purge(),E=null)}return R=!1,b},destroy:function(){w=null,v.call(this),this.getRuntime().getShim().removeInstance(this.uid)}})}return e.Image=l}),i(X,[u,c,h,f,m],function(e,t,n,i,r){function o(){var e;try{e=navigator.plugins["Shockwave Flash"],e=e.description}catch(t){try{e=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(n){e="0.0"}}return e=e.match(/\d+/g),parseFloat(e[0]+"."+e[1])}function a(e){var i=n.get(e);i&&"OBJECT"==i.nodeName&&("IE"===t.browser?(i.style.display="none",function r(){4==i.readyState?s(e):setTimeout(r,10)}()):i.parentNode.removeChild(i))}function s(e){var t=n.get(e);if(t){for(var i in t)"function"==typeof t[i]&&(t[i]=null);t.parentNode.removeChild(t)}}function u(s){var u=this,d;s=e.extend({swf_url:t.swf_url},s),r.call(this,s,c,{access_binary:function(e){return e&&"browser"===u.mode},access_image_binary:function(e){return e&&"browser"===u.mode},display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:function(){return"client"===u.mode},resize_image:r.capTrue,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!e.arrayDiff(t,["","text","document"])||"browser"===u.mode},return_status_code:function(t){return"browser"===u.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:function(e){return e&&"browser"===u.mode},send_browser_cookies:function(e){return e&&"browser"===u.mode},send_custom_headers:function(e){return e&&"browser"===u.mode},send_multipart:r.capTrue,slice_blob:function(e){return e&&"browser"===u.mode},stream_upload:function(e){return e&&"browser"===u.mode},summon_file_dialog:!1,upload_filesize:function(t){return e.parseSizeStr(t)<=2097152||"client"===u.mode},use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}},{access_binary:function(e){return e?"browser":"client"},access_image_binary:function(e){return e?"browser":"client"},report_upload_progress:function(e){return e?"browser":"client"},return_response_type:function(t){return e.arrayDiff(t,["","text","json","document"])?"browser":["client","browser"]},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"browser":["client","browser"]},send_binary_string:function(e){return e?"browser":"client"},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"browser":"client"},stream_upload:function(e){return e?"client":"browser"},upload_filesize:function(t){return e.parseSizeStr(t)>=2097152?"client":"browser"}},"client"),o()<10&&(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid)},shimExec:function(e,t){var n=[].slice.call(arguments,2);return u.getShim().exec(this.uid,e,t,n)},init:function(){var n,r,o;o=this.getShimContainer(),e.extend(o.style,{position:"absolute",top:"-8px",left:"-8px",width:"9px",height:"9px",overflow:"hidden"}),n='<object id="'+this.uid+'" type="application/x-shockwave-flash" data="'+s.swf_url+'" ',"IE"===t.browser&&(n+='classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '),n+='width="100%" height="100%" style="outline:0"><param name="movie" value="'+s.swf_url+'" /><param name="flashvars" value="uid='+escape(this.uid)+"&target="+t.global_event_dispatcher+'" /><param name="wmode" value="transparent" /><param name="allowscriptaccess" value="always" /></object>',"IE"===t.browser?(r=document.createElement("div"),o.appendChild(r),r.outerHTML=n,r=o=null):o.innerHTML=n,d=setTimeout(function(){u&&!u.initialized&&u.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},5e3)},destroy:function(e){return function(){a(u.uid),e.call(u),clearTimeout(d),s=d=e=u=null}}(this.destroy)},l)}var c="flash",l={};return r.addConstructor(c,u),l}),i(V,[X,E,u],function(e,t,n){var i={init:function(e){var i=this,r=this.getRuntime();this.bind("Change",function(){var e=r.shimExec.call(i,"FileInput","getFiles");i.files=[],n.each(e,function(e){i.files.push(new t(r.uid,e))})},999),this.getRuntime().shimExec.call(this,"FileInput","init",{name:e.name,accept:e.accept,multiple:e.multiple}),this.trigger("ready")}};return e.FileInput=i}),i(W,[X,y],function(e,t){var n={slice:function(e,n,i,r){var o=this.getRuntime();return 0>n?n=Math.max(e.size+n,0):n>0&&(n=Math.min(n,e.size)),0>i?i=Math.max(e.size+i,0):i>0&&(i=Math.min(i,e.size)),e=o.shimExec.call(this,"Blob","slice",n,i,r||""),e&&(e=new t(o.uid,e)),e}};return e.Blob=n}),i(Y,[X,w],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i=this;return i.result="","readAsDataURL"===e&&(i.result="data:"+(t.type||"")+";base64,"),i.bind("Progress",function(t,r){r&&(i.result+=n(r,e))},999),i.getRuntime().shimExec.call(this,"FileReader","readAsBase64",t.uid)}};return e.FileReader=i}),i($,[X,w],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i,r=this.getRuntime();return(i=r.shimExec.call(this,"FileReaderSync","readAsBase64",t.uid))?("readAsDataURL"===e&&(i="data:"+(t.type||"")+";base64,"+i),n(i,e,t.type)):null}};return e.FileReaderSync=i}),i(J,[X,u,y,E,A,I,S],function(e,t,n,i,r,o,a){var s={send:function(e,i){function r(){e.transport=l.mode,l.shimExec.call(c,"XMLHttpRequest","send",e,i)}function s(e,t){l.shimExec.call(c,"XMLHttpRequest","appendBlob",e,t.uid),i=null,r()}function u(e,t){var n=new a;n.bind("TransportingComplete",function(){t(this.result)}),n.transport(e.getSource(),e.type,{ruid:l.uid})}var c=this,l=c.getRuntime();if(t.isEmptyObj(e.headers)||t.each(e.headers,function(e,t){l.shimExec.call(c,"XMLHttpRequest","setRequestHeader",t,e.toString())}),i instanceof o){var d;if(i.each(function(e,t){e instanceof n?d=t:l.shimExec.call(c,"XMLHttpRequest","append",t,e)}),i.hasBlob()){var h=i.getBlob();h.isDetached()?u(h,function(e){h.destroy(),s(d,e)}):s(d,h)}else i=null,r()}else i instanceof n?i.isDetached()?u(i,function(e){i.destroy(),i=e.uid,r()}):(i=i.uid,r()):r()},getResponse:function(e){var n,o,a=this.getRuntime();if(o=a.shimExec.call(this,"XMLHttpRequest","getResponseAsBlob")){if(o=new i(a.uid,o),"blob"===e)return o;try{if(n=new r,~t.inArray(e,["","text"]))return n.readAsText(o);if("json"===e&&window.JSON)return JSON.parse(n.readAsText(o))}finally{o.destroy()}}return null},abort:function(e){var t=this.getRuntime();t.shimExec.call(this,"XMLHttpRequest","abort"),this.dispatchEvent("readystatechange"),this.dispatchEvent("abort")}};return e.XMLHttpRequest=s}),i(Z,[X,y],function(e,t){var n={getAsBlob:function(e){var n=this.getRuntime(),i=n.shimExec.call(this,"Transporter","getAsBlob",e);return i?new t(n.uid,i):null}};return e.Transporter=n}),i(K,[X,u,S,y,A],function(e,t,n,i,r){var o={loadFromBlob:function(e){function t(e){r.shimExec.call(i,"Image","loadFromBlob",e.uid),i=r=null}var i=this,r=i.getRuntime();if(e.isDetached()){var o=new n;o.bind("TransportingComplete",function(){t(o.result.getSource())}),o.transport(e.getSource(),e.type,{ruid:r.uid})}else t(e.getSource())},loadFromImage:function(e){var t=this.getRuntime();return t.shimExec.call(this,"Image","loadFromImage",e.uid)},getInfo:function(){var e=this.getRuntime(),t=e.shimExec.call(this,"Image","getInfo");return!t.meta||!t.meta.thumb||t.meta.thumb.data instanceof i||(t.meta.thumb.data=new i(e.uid,t.meta.thumb.data)),t},getAsBlob:function(e,t){var n=this.getRuntime(),r=n.shimExec.call(this,"Image","getAsBlob",e,t);return r?new i(n.uid,r):null},getAsDataURL:function(){var e=this.getRuntime(),t=e.Image.getAsBlob.apply(this,arguments),n;return t?(n=new r,n.readAsDataURL(t)):null}};return e.Image=o}),i(Q,[u,c,h,f,m],function(e,t,n,i,r){function o(e){var t=!1,n=null,i,r,o,a,s,u=0;try{try{n=new ActiveXObject("AgControl.AgControl"),n.IsVersionSupported(e)&&(t=!0),n=null}catch(c){var l=navigator.plugins["Silverlight Plug-In"];if(l){for(i=l.description,"1.0.30226.2"===i&&(i="2.0.30226.2"),r=i.split(".");r.length>3;)r.pop();for(;r.length<4;)r.push(0);for(o=e.split(".");o.length>4;)o.pop();do a=parseInt(o[u],10),s=parseInt(r[u],10),u++;while(u<o.length&&a===s);s>=a&&!isNaN(a)&&(t=!0)}}}catch(d){t=!1}return t}function a(a){var c=this,l;a=e.extend({xap_url:t.xap_url},a),r.call(this,a,s,{access_binary:r.capTrue,access_image_binary:r.capTrue,display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:r.capTrue,resize_image:r.capTrue,return_response_headers:function(e){return e&&"client"===c.mode},return_response_type:function(e){return"json"!==e?!0:!!window.JSON},return_status_code:function(t){return"client"===c.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:r.capTrue,send_browser_cookies:function(e){return e&&"browser"===c.mode},send_custom_headers:function(e){return e&&"client"===c.mode},send_multipart:r.capTrue,slice_blob:r.capTrue,stream_upload:!0,summon_file_dialog:!1,upload_filesize:r.capTrue,use_http_method:function(t){return"client"===c.mode||!e.arrayDiff(t,["GET","POST"])}},{return_response_headers:function(e){return e?"client":"browser"},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"client":["client","browser"]},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"client":"browser"},use_http_method:function(t){return e.arrayDiff(t,["GET","POST"])?"client":["client","browser"]}}),o("2.0.31005.0")&&"Opera"!==t.browser||(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid).content.Moxie},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec(this.uid,e,t,n)},init:function(){var e;e=this.getShimContainer(),e.innerHTML='<object id="'+this.uid+'" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;"><param name="source" value="'+a.xap_url+'"/><param name="background" value="Transparent"/><param name="windowless" value="true"/><param name="enablehtmlaccess" value="true"/><param name="initParams" value="uid='+this.uid+",target="+t.global_event_dispatcher+'"/></object>',l=setTimeout(function(){c&&!c.initialized&&c.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},"Windows"!==t.OS?1e4:5e3)},destroy:function(e){return function(){e.call(c),clearTimeout(l),a=l=e=c=null}}(this.destroy)},u)}var s="silverlight",u={};return r.addConstructor(s,a),u}),i(ee,[Q,E,u],function(e,t,n){var i={init:function(e){function i(e){for(var t="",n=0;n<e.length;n++)t+=(""!==t?"|":"")+e[n].title+" | *."+e[n].extensions.replace(/,/g,";*.");return t}var r=this,o=this.getRuntime();this.bind("Change",function(){var e=o.shimExec.call(r,"FileInput","getFiles");r.files=[],n.each(e,function(e){r.files.push(new t(o.uid,e))})},999),this.getRuntime().shimExec.call(this,"FileInput","init",i(e.accept),e.name,e.multiple),this.trigger("ready")}};return e.FileInput=i}),i(te,[Q,u,W],function(e,t,n){return e.Blob=t.extend({},n)}),i(ne,[Q,h,N],function(e,t,n){var i={init:function(){var e=this,i=e.getRuntime(),r;return r=i.getShimContainer(),n.addEvent(r,"dragover",function(e){e.preventDefault(),e.stopPropagation(),e.dataTransfer.dropEffect="copy"},e.uid),n.addEvent(r,"dragenter",function(e){e.preventDefault();var n=t.get(i.uid).dragEnter(e);n&&e.stopPropagation()},e.uid),n.addEvent(r,"drop",function(e){e.preventDefault();var n=t.get(i.uid).dragDrop(e);n&&e.stopPropagation()},e.uid),i.shimExec.call(this,"FileDrop","init")}};return e.FileDrop=i}),i(ie,[Q,u,Y],function(e,t,n){return e.FileReader=t.extend({},n)}),i(re,[Q,u,$],function(e,t,n){return e.FileReaderSync=t.extend({},n)}),i(oe,[Q,u,J],function(e,t,n){return e.XMLHttpRequest=t.extend({},n)}),i(ae,[Q,u,Z],function(e,t,n){return e.Transporter=t.extend({},n)}),i(se,[Q,u,y,K],function(e,t,n,i){return e.Image=t.extend({},i,{getInfo:function(){var e=this.getRuntime(),i=["tiff","exif","gps","thumb"],r={meta:{}},o=e.shimExec.call(this,"Image","getInfo");return o.meta&&(t.each(i,function(e){var t=o.meta[e],n,i,a,s;if(t&&t.keys)for(r.meta[e]={},i=0,a=t.keys.length;a>i;i++)n=t.keys[i],s=t[n],s&&(/^(\d|[1-9]\d+)$/.test(s)?s=parseInt(s,10):/^\d*\.\d+$/.test(s)&&(s=parseFloat(s)),r.meta[e][n]=s)}),!r.meta||!r.meta.thumb||r.meta.thumb.data instanceof n||(r.meta.thumb.data=new n(e.uid,r.meta.thumb.data))),r.width=parseInt(o.width,10),r.height=parseInt(o.height,10),r.size=parseInt(o.size,10),r.type=o.type,r.name=o.name,r}})}),i(ue,[u,f,m,c],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue;n.call(this,t,o,{access_binary:s(window.FileReader||window.File&&File.getAsDataURL),access_image_binary:!1,display_media:s(a.Image&&(i.can("create_canvas")||i.can("use_data_uri_over32kb"))),do_cors:!1,drag_and_drop:!1,filter_by_extension:s(function(){return"Chrome"===i.browser&&i.verComp(i.version,28,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||"Safari"===i.browser&&i.verComp(i.version,7,">=")}()),resize_image:function(){return a.Image&&r.can("access_binary")&&i.can("create_canvas")},report_upload_progress:!1,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!!~e.inArray(t,["text","document",""])},return_status_code:function(t){return!e.arrayDiff(t,[200,404])},select_file:function(){return i.can("use_fileinput")},select_multiple:!1,send_binary_string:!1,send_custom_headers:!1,send_multipart:!0,slice_blob:!1,stream_upload:function(){return r.can("select_file")},summon_file_dialog:function(){return r.can("select_file")&&("Firefox"===i.browser&&i.verComp(i.version,4,">=")||"Opera"===i.browser&&i.verComp(i.version,12,">=")||"IE"===i.browser&&i.verComp(i.version,10,">=")||!!~e.inArray(i.browser,["Chrome","Safari"]))},upload_filesize:u,use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}}),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html4",a={};return n.addConstructor(o,r),a}),i(ce,[ue,E,u,h,N,d,c],function(e,t,n,i,r,o,a){function s(){function e(){var o=this,l=o.getRuntime(),d,h,f,p,m,g;g=n.guid("uid_"),d=l.getShimContainer(),s&&(f=i.get(s+"_form"),f&&n.extend(f.style,{top:"100%"})),p=document.createElement("form"),p.setAttribute("id",g+"_form"),p.setAttribute("method","post"),p.setAttribute("enctype","multipart/form-data"),p.setAttribute("encoding","multipart/form-data"),n.extend(p.style,{overflow:"hidden",position:"absolute",top:0,left:0,width:"100%",height:"100%"}),m=document.createElement("input"),m.setAttribute("id",g),m.setAttribute("type","file"),m.setAttribute("name",c.name||"Filedata"),m.setAttribute("accept",u.join(",")),n.extend(m.style,{fontSize:"999px",opacity:0}),p.appendChild(m),d.appendChild(p),n.extend(m.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),"IE"===a.browser&&a.verComp(a.version,10,"<")&&n.extend(m.style,{filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)"}),m.onchange=function(){var n;if(this.value){if(this.files){if(n=this.files[0],0===n.size)return void p.parentNode.removeChild(p)}else n={name:this.value};n=new t(l.uid,n),this.onchange=function(){},e.call(o),o.files=[n],m.setAttribute("id",n.uid),p.setAttribute("id",n.uid+"_form"),o.trigger("change"),m=p=null}},l.can("summon_file_dialog")&&(h=i.get(c.browse_button),r.removeEvent(h,"click",o.uid),r.addEvent(h,"click",function(e){m&&!m.disabled&&m.click(),e.preventDefault()},o.uid)),s=g,d=f=h=null}var s,u=[],c;n.extend(this,{init:function(t){var n=this,a=n.getRuntime(),s;c=t,u=t.accept.mimes||o.extList2mimes(t.accept,a.can("filter_by_extension")),s=a.getShimContainer(),function(){var e,o,u;e=i.get(t.browse_button),a.can("summon_file_dialog")&&("static"===i.getStyle(e,"position")&&(e.style.position="relative"),o=parseInt(i.getStyle(e,"z-index"),10)||1,e.style.zIndex=o,s.style.zIndex=o-1),u=a.can("summon_file_dialog")?e:s,r.addEvent(u,"mouseover",function(){n.trigger("mouseenter")},n.uid),r.addEvent(u,"mouseout",function(){n.trigger("mouseleave")},n.uid),r.addEvent(u,"mousedown",function(){n.trigger("mousedown")},n.uid),r.addEvent(i.get(t.container),"mouseup",function(){n.trigger("mouseup")},n.uid),e=null}(),e.call(this),s=null,n.trigger({type:"ready",async:!0})},disable:function(e){var t;(t=i.get(s))&&(t.disabled=!!e)},destroy:function(){var e=this.getRuntime(),t=e.getShim(),n=e.getShimContainer();r.removeAllEvents(n,this.uid),r.removeAllEvents(c&&i.get(c.container),this.uid),r.removeAllEvents(c&&i.get(c.browse_button),this.uid),n&&(n.innerHTML=""),t.removeInstance(this.uid),s=u=c=n=t=null}})}return e.FileInput=s}),i(le,[ue,F],function(e,t){return e.FileReader=t}),i(de,[ue,u,h,x,f,N,y,I],function(e,t,n,i,r,o,a,s){function u(){function e(e){var t=this,i,r,a,s,u=!1;if(l){if(i=l.id.replace(/_iframe$/,""),r=n.get(i+"_form")){for(a=r.getElementsByTagName("input"),s=a.length;s--;)switch(a[s].getAttribute("type")){case"hidden":a[s].parentNode.removeChild(a[s]);break;case"file":u=!0}a=[],u||r.parentNode.removeChild(r),r=null}setTimeout(function(){o.removeEvent(l,"load",t.uid),l.parentNode&&l.parentNode.removeChild(l);var n=t.getRuntime().getShimContainer();n.children.length||n.parentNode.removeChild(n),n=l=null,e()},1)}}var u,c,l;t.extend(this,{send:function(d,h){function f(){var n=m.getShimContainer()||document.body,r=document.createElement("div");r.innerHTML='<iframe id="'+g+'_iframe" name="'+g+'_iframe" src="javascript:&quot;&quot;" style="display:none"></iframe>',l=r.firstChild,n.appendChild(l),o.addEvent(l,"load",function(){var n;try{n=l.contentWindow.document||l.contentDocument||window.frames[l.id].document,/^4(0[0-9]|1[0-7]|2[2346])\s/.test(n.title)?u=n.title.replace(/^(\d+).*$/,"$1"):(u=200,c=t.trim(n.body.innerHTML),p.trigger({type:"progress",loaded:c.length,total:c.length}),y&&p.trigger({type:"uploadprogress",loaded:y.size||1025,total:y.size||1025}))}catch(r){if(!i.hasSameOrigin(d.url))return void e.call(p,function(){p.trigger("error")});u=404}e.call(p,function(){p.trigger("load")})},p.uid)}var p=this,m=p.getRuntime(),g,v,w,y;if(u=c=null,h instanceof s&&h.hasBlob()){if(y=h.getBlob(),g=y.uid,w=n.get(g),v=n.get(g+"_form"),!v)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR)}else g=t.guid("uid_"),v=document.createElement("form"),v.setAttribute("id",g+"_form"),v.setAttribute("method",d.method),v.setAttribute("enctype","multipart/form-data"),v.setAttribute("encoding","multipart/form-data"),m.getShimContainer().appendChild(v);v.setAttribute("target",g+"_iframe"),h instanceof s&&h.each(function(e,n){if(e instanceof a)w&&w.setAttribute("name",n);else{var i=document.createElement("input");t.extend(i,{type:"hidden",name:n,value:e}),w?v.insertBefore(i,w):v.appendChild(i)}}),v.setAttribute("action",d.url),f(),v.submit(),p.trigger("loadstart")},getStatus:function(){return u},getResponse:function(e){if("json"===e&&"string"===t.typeOf(c)&&window.JSON)try{
-return JSON.parse(c.replace(/^\s*<pre[^>]*>/,"").replace(/<\/pre>\s*$/,""))}catch(n){return null}return c},abort:function(){var t=this;l&&l.contentWindow&&(l.contentWindow.stop?l.contentWindow.stop():l.contentWindow.document.execCommand?l.contentWindow.document.execCommand("Stop"):l.src="about:blank"),e.call(this,function(){t.dispatchEvent("abort")})}})}return e.XMLHttpRequest=u}),i(he,[ue,j],function(e,t){return e.Image=t}),a([u,c,l,d,h,f,p,m,g,v,w,y,E,_,b,x,R,A,I,T,S,O,N])}(this);;(function(e){"use strict";var t={},n=e.moxie.core.utils.Basic.inArray;return function r(e){var i,s;for(i in e)s=typeof e[i],s==="object"&&!~n(i,["Exceptions","Env","Mime"])?r(e[i]):s==="function"&&(t[i]=e[i])}(e.moxie),t.Env=e.moxie.core.utils.Env,t.Mime=e.moxie.core.utils.Mime,t.Exceptions=e.moxie.core.Exceptions,e.mOxie=t,e.o||(e.o=t),t})(this);
+!function(e,t){var i=function(){var e={};return t.apply(e,arguments),e.moxie};"function"==typeof define&&define.amd?define("moxie",[],i):"object"==typeof module&&module.exports?module.exports=i():e.moxie=i()}(this||window,function(){!function(e,t){"use strict";function i(e,t){for(var i,n=[],r=0;r<e.length;++r){if(i=s[e[r]]||o(e[r]),!i)throw"module definition dependecy not found: "+e[r];n.push(i)}t.apply(null,n)}function n(e,n,r){if("string"!=typeof e)throw"invalid module definition, module id must be defined and be a string";if(n===t)throw"invalid module definition, dependencies must be specified";if(r===t)throw"invalid module definition, definition function must be specified";i(n,function(){s[e]=r.apply(null,arguments)})}function r(e){return!!s[e]}function o(t){for(var i=e,n=t.split(/[.\/]/),r=0;r<n.length;++r){if(!i[n[r]])return;i=i[n[r]]}return i}function a(i){for(var n=0;n<i.length;n++){for(var r=e,o=i[n],a=o.split(/[.\/]/),u=0;u<a.length-1;++u)r[a[u]]===t&&(r[a[u]]={}),r=r[a[u]];r[a[a.length-1]]=s[o]}}var s={};n("moxie/core/utils/Basic",[],function(){function e(e){var t;return e===t?"undefined":null===e?"null":e.nodeType?"node":{}.toString.call(e).match(/\s([a-z|A-Z]+)/)[1].toLowerCase()}function t(){return s(!1,!1,arguments)}function i(){return s(!0,!1,arguments)}function n(){return s(!1,!0,arguments)}function r(){return s(!0,!0,arguments)}function o(t){switch(e(t)){case"array":return s(!1,!0,[[],t]);case"object":return s(!1,!0,[{},t]);default:return t}}function a(i){switch(e(i)){case"array":return Array.prototype.slice.call(i);case"object":return t({},i)}return i}function s(t,i,n){var r,o=n[0];return c(n,function(n,u){u>0&&c(n,function(n,u){var c=-1!==h(e(n),["array","object"]);return n===r||t&&o[u]===r?!0:(c&&i&&(n=a(n)),e(o[u])===e(n)&&c?s(t,i,[o[u],n]):o[u]=n,void 0)})}),o}function u(e,t){function i(){this.constructor=e}for(var n in t)({}).hasOwnProperty.call(t,n)&&(e[n]=t[n]);return i.prototype=t.prototype,e.prototype=new i,e.parent=t.prototype,e}function c(e,t){var i,n,r,o;if(e){try{i=e.length}catch(a){i=o}if(i===o||"number"!=typeof i){for(n in e)if(e.hasOwnProperty(n)&&t(e[n],n)===!1)return}else for(r=0;i>r;r++)if(t(e[r],r)===!1)return}}function l(t){var i;if(!t||"object"!==e(t))return!0;for(i in t)return!1;return!0}function d(t,i){function n(r){"function"===e(t[r])&&t[r](function(e){++r<o&&!e?n(r):i(e)})}var r=0,o=t.length;"function"!==e(i)&&(i=function(){}),t&&t.length||i(),n(r)}function m(e,t){var i=0,n=e.length,r=new Array(n);c(e,function(e,o){e(function(e){if(e)return t(e);var a=[].slice.call(arguments);a.shift(),r[o]=a,i++,i===n&&(r.unshift(null),t.apply(this,r))})})}function h(e,t){if(t){if(Array.prototype.indexOf)return Array.prototype.indexOf.call(t,e);for(var i=0,n=t.length;n>i;i++)if(t[i]===e)return i}return-1}function f(t,i){var n=[];"array"!==e(t)&&(t=[t]),"array"!==e(i)&&(i=[i]);for(var r in t)-1===h(t[r],i)&&n.push(t[r]);return n.length?n:!1}function p(e,t){var i=[];return c(e,function(e){-1!==h(e,t)&&i.push(e)}),i.length?i:null}function g(e){var t,i=[];for(t=0;t<e.length;t++)i[t]=e[t];return i}function x(e){return e?String.prototype.trim?String.prototype.trim.call(e):e.toString().replace(/^\s*/,"").replace(/\s*$/,""):e}function v(e){if("string"!=typeof e)return e;var t,i={t:1099511627776,g:1073741824,m:1048576,k:1024};return e=/^([0-9\.]+)([tmgk]?)$/.exec(e.toLowerCase().replace(/[^0-9\.tmkg]/g,"")),t=e[2],e=+e[1],i.hasOwnProperty(t)&&(e*=i[t]),Math.floor(e)}function w(e){var t=[].slice.call(arguments,1);return e.replace(/%([a-z])/g,function(e,i){var n=t.shift();switch(i){case"s":return n+"";case"d":return parseInt(n,10);case"f":return parseFloat(n);case"c":return"";default:return n}})}function y(e,t){var i=this;setTimeout(function(){e.call(i)},t||1)}var E=function(){var e=0;return function(t){var i,n=(new Date).getTime().toString(32);for(i=0;5>i;i++)n+=Math.floor(65535*Math.random()).toString(32);return(t||"o_")+n+(e++).toString(32)}}();return{guid:E,typeOf:e,extend:t,extendIf:i,extendImmutable:n,extendImmutableIf:r,clone:o,inherit:u,each:c,isEmptyObj:l,inSeries:d,inParallel:m,inArray:h,arrayDiff:f,arrayIntersect:p,toArray:g,trim:x,sprintf:w,parseSizeStr:v,delay:y}}),n("moxie/core/utils/Encode",[],function(){var e=function(e){return unescape(encodeURIComponent(e))},t=function(e){return decodeURIComponent(escape(e))},i=function(e,i){if("function"==typeof window.atob)return i?t(window.atob(e)):window.atob(e);var n,r,o,a,s,u,c,l,d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",m=0,h=0,f="",p=[];if(!e)return e;e+="";do a=d.indexOf(e.charAt(m++)),s=d.indexOf(e.charAt(m++)),u=d.indexOf(e.charAt(m++)),c=d.indexOf(e.charAt(m++)),l=a<<18|s<<12|u<<6|c,n=255&l>>16,r=255&l>>8,o=255&l,p[h++]=64==u?String.fromCharCode(n):64==c?String.fromCharCode(n,r):String.fromCharCode(n,r,o);while(m<e.length);return f=p.join(""),i?t(f):f},n=function(t,i){if(i&&(t=e(t)),"function"==typeof window.btoa)return window.btoa(t);var n,r,o,a,s,u,c,l,d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",m=0,h=0,f="",p=[];if(!t)return t;do n=t.charCodeAt(m++),r=t.charCodeAt(m++),o=t.charCodeAt(m++),l=n<<16|r<<8|o,a=63&l>>18,s=63&l>>12,u=63&l>>6,c=63&l,p[h++]=d.charAt(a)+d.charAt(s)+d.charAt(u)+d.charAt(c);while(m<t.length);f=p.join("");var g=t.length%3;return(g?f.slice(0,g-3):f)+"===".slice(g||3)};return{utf8_encode:e,utf8_decode:t,atob:i,btoa:n}}),n("moxie/core/utils/Env",["moxie/core/utils/Basic"],function(e){function i(e,t,i){var n=0,r=0,o=0,a={dev:-6,alpha:-5,a:-5,beta:-4,b:-4,RC:-3,rc:-3,"#":-2,p:1,pl:1},s=function(e){return e=(""+e).replace(/[_\-+]/g,"."),e=e.replace(/([^.\d]+)/g,".$1.").replace(/\.{2,}/g,"."),e.length?e.split("."):[-8]},u=function(e){return e?isNaN(e)?a[e]||-7:parseInt(e,10):0};for(e=s(e),t=s(t),r=Math.max(e.length,t.length),n=0;r>n;n++)if(e[n]!=t[n]){if(e[n]=u(e[n]),t[n]=u(t[n]),e[n]<t[n]){o=-1;break}if(e[n]>t[n]){o=1;break}}if(!i)return o;switch(i){case">":case"gt":return o>0;case">=":case"ge":return o>=0;case"<=":case"le":return 0>=o;case"==":case"=":case"eq":return 0===o;case"<>":case"!=":case"ne":return 0!==o;case"":case"<":case"lt":return 0>o;default:return null}}var n=function(e){var t="",i="?",n="function",r="undefined",o="object",a="name",s="version",u={has:function(e,t){return-1!==t.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()}},c={rgx:function(){for(var t,i,a,s,u,c,l,d=0,m=arguments;d<m.length;d+=2){var h=m[d],f=m[d+1];if(typeof t===r){t={};for(s in f)u=f[s],typeof u===o?t[u[0]]=e:t[u]=e}for(i=a=0;i<h.length;i++)if(c=h[i].exec(this.getUA())){for(s=0;s<f.length;s++)l=c[++a],u=f[s],typeof u===o&&u.length>0?2==u.length?t[u[0]]=typeof u[1]==n?u[1].call(this,l):u[1]:3==u.length?t[u[0]]=typeof u[1]!==n||u[1].exec&&u[1].test?l?l.replace(u[1],u[2]):e:l?u[1].call(this,l,u[2]):e:4==u.length&&(t[u[0]]=l?u[3].call(this,l.replace(u[1],u[2])):e):t[u]=l?l:e;break}if(c)break}return t},str:function(t,n){for(var r in n)if(typeof n[r]===o&&n[r].length>0){for(var a=0;a<n[r].length;a++)if(u.has(n[r][a],t))return r===i?e:r}else if(u.has(n[r],t))return r===i?e:r;return t}},l={browser:{oldsafari:{major:{1:["/8","/1","/3"],2:"/4","?":"/"},version:{"1.0":"/8",1.2:"/1",1.3:"/3","2.0":"/412","2.0.2":"/416","2.0.3":"/417","2.0.4":"/419","?":"/"}}},device:{sprint:{model:{"Evo Shift 4G":"7373KT"},vendor:{HTC:"APA",Sprint:"Sprint"}}},os:{windows:{version:{ME:"4.90","NT 3.11":"NT3.51","NT 4.0":"NT4.0",2000:"NT 5.0",XP:["NT 5.1","NT 5.2"],Vista:"NT 6.0",7:"NT 6.1",8:"NT 6.2",8.1:"NT 6.3",RT:"ARM"}}}},d={browser:[[/(opera\smini)\/([\w\.-]+)/i,/(opera\s[mobiletab]+).+version\/([\w\.-]+)/i,/(opera).+version\/([\w\.]+)/i,/(opera)[\/\s]+([\w\.]+)/i],[a,s],[/\s(opr)\/([\w\.]+)/i],[[a,"Opera"],s],[/(kindle)\/([\w\.]+)/i,/(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,/(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,/(?:ms|\()(ie)\s([\w\.]+)/i,/(rekonq)\/([\w\.]+)*/i,/(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i],[a,s],[/(trident).+rv[:\s]([\w\.]+).+like\sgecko/i],[[a,"IE"],s],[/(edge)\/((\d+)?[\w\.]+)/i],[a,s],[/(yabrowser)\/([\w\.]+)/i],[[a,"Yandex"],s],[/(comodo_dragon)\/([\w\.]+)/i],[[a,/_/g," "],s],[/(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,/(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i],[a,s],[/(dolfin)\/([\w\.]+)/i],[[a,"Dolphin"],s],[/((?:android.+)crmo|crios)\/([\w\.]+)/i],[[a,"Chrome"],s],[/XiaoMi\/MiuiBrowser\/([\w\.]+)/i],[s,[a,"MIUI Browser"]],[/android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i],[s,[a,"Android Browser"]],[/FBAV\/([\w\.]+);/i],[s,[a,"Facebook"]],[/version\/([\w\.]+).+?mobile\/\w+\s(safari)/i],[s,[a,"Mobile Safari"]],[/version\/([\w\.]+).+?(mobile\s?safari|safari)/i],[s,a],[/webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i],[a,[s,c.str,l.browser.oldsafari.version]],[/(konqueror)\/([\w\.]+)/i,/(webkit|khtml)\/([\w\.]+)/i],[a,s],[/(navigator|netscape)\/([\w\.-]+)/i],[[a,"Netscape"],s],[/(swiftfox)/i,/(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,/(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,/(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i,/(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i,/(links)\s\(([\w\.]+)/i,/(gobrowser)\/?([\w\.]+)*/i,/(ice\s?browser)\/v?([\w\._]+)/i,/(mosaic)[\/\s]([\w\.]+)/i],[a,s]],engine:[[/windows.+\sedge\/([\w\.]+)/i],[s,[a,"EdgeHTML"]],[/(presto)\/([\w\.]+)/i,/(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,/(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,/(icab)[\/\s]([23]\.[\d\.]+)/i],[a,s],[/rv\:([\w\.]+).*(gecko)/i],[s,a]],os:[[/microsoft\s(windows)\s(vista|xp)/i],[a,s],[/(windows)\snt\s6\.2;\s(arm)/i,/(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i],[a,[s,c.str,l.os.windows.version]],[/(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i],[[a,"Windows"],[s,c.str,l.os.windows.version]],[/\((bb)(10);/i],[[a,"BlackBerry"],s],[/(blackberry)\w*\/?([\w\.]+)*/i,/(tizen)[\/\s]([\w\.]+)/i,/(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,/linux;.+(sailfish);/i],[a,s],[/(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i],[[a,"Symbian"],s],[/\((series40);/i],[a],[/mozilla.+\(mobile;.+gecko.+firefox/i],[[a,"Firefox OS"],s],[/(nintendo|playstation)\s([wids3portablevu]+)/i,/(mint)[\/\s\(]?(\w+)*/i,/(mageia|vectorlinux)[;\s]/i,/(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i,/(hurd|linux)\s?([\w\.]+)*/i,/(gnu)\s?([\w\.]+)*/i],[a,s],[/(cros)\s[\w]+\s([\w\.]+\w)/i],[[a,"Chromium OS"],s],[/(sunos)\s?([\w\.]+\d)*/i],[[a,"Solaris"],s],[/\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i],[a,s],[/(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i],[[a,"iOS"],[s,/_/g,"."]],[/(mac\sos\sx)\s?([\w\s\.]+\w)*/i,/(macintosh|mac(?=_powerpc)\s)/i],[[a,"Mac OS"],[s,/_/g,"."]],[/((?:open)?solaris)[\/\s-]?([\w\.]+)*/i,/(haiku)\s(\w+)/i,/(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,/(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,/(unix)\s?([\w\.]+)*/i],[a,s]]},m=function(e){var i=e||(window&&window.navigator&&window.navigator.userAgent?window.navigator.userAgent:t);this.getBrowser=function(){return c.rgx.apply(this,d.browser)},this.getEngine=function(){return c.rgx.apply(this,d.engine)},this.getOS=function(){return c.rgx.apply(this,d.os)},this.getResult=function(){return{ua:this.getUA(),browser:this.getBrowser(),engine:this.getEngine(),os:this.getOS()}},this.getUA=function(){return i},this.setUA=function(e){return i=e,this},this.setUA(i)};return m}(),r=function(){var i={access_global_ns:function(){return!!window.moxie},define_property:function(){return!1}(),create_canvas:function(){var e=document.createElement("canvas"),t=!(!e.getContext||!e.getContext("2d"));return i.create_canvas=t,t},return_response_type:function(t){try{if(-1!==e.inArray(t,["","text","document"]))return!0;if(window.XMLHttpRequest){var i=new XMLHttpRequest;if(i.open("get","/"),"responseType"in i)return i.responseType=t,i.responseType!==t?!1:!0}}catch(n){}return!1},use_blob_uri:function(){var e=window.URL;return i.use_blob_uri=e&&"createObjectURL"in e&&"revokeObjectURL"in e&&("IE"!==a.browser||a.verComp(a.version,"11.0.46",">=")),i.use_blob_uri},use_data_uri:function(){var e=new Image;return e.onload=function(){i.use_data_uri=1===e.width&&1===e.height},setTimeout(function(){e.src="data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="},1),!1}(),use_data_uri_over32kb:function(){return i.use_data_uri&&("IE"!==a.browser||a.version>=9)},use_data_uri_of:function(e){return i.use_data_uri&&33e3>e||i.use_data_uri_over32kb()},use_fileinput:function(){if(navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/))return!1;var e=document.createElement("input");return e.setAttribute("type","file"),i.use_fileinput=!e.disabled},use_webgl:function(){var e,n=document.createElement("canvas"),r=null;try{r=n.getContext("webgl")||n.getContext("experimental-webgl")}catch(o){}return r||(r=null),e=!!r,i.use_webgl=e,n=t,e}};return function(t){var n=[].slice.call(arguments);return n.shift(),"function"===e.typeOf(i[t])?i[t].apply(this,n):!!i[t]}}(),o=(new n).getResult(),a={can:r,uaParser:n,browser:o.browser.name,version:o.browser.version,os:o.os.name,osVersion:o.os.version,verComp:i,swf_url:"../flash/Moxie.swf",xap_url:"../silverlight/Moxie.xap",global_event_dispatcher:"moxie.core.EventTarget.instance.dispatchEvent"};return a.OS=a.os,a}),n("moxie/core/Exceptions",["moxie/core/utils/Basic"],function(e){function t(e,t){var i;for(i in e)if(e[i]===t)return i;return null}return{RuntimeError:function(){function i(e,i){this.code=e,this.name=t(n,e),this.message=this.name+(i||": RuntimeError "+this.code)}var n={NOT_INIT_ERR:1,EXCEPTION_ERR:3,NOT_SUPPORTED_ERR:9,JS_ERR:4};return e.extend(i,n),i.prototype=Error.prototype,i}(),OperationNotAllowedException:function(){function t(e){this.code=e,this.name="OperationNotAllowedException"}return e.extend(t,{NOT_ALLOWED_ERR:1}),t.prototype=Error.prototype,t}(),ImageError:function(){function i(e){this.code=e,this.name=t(n,e),this.message=this.name+": ImageError "+this.code}var n={WRONG_FORMAT:1,MAX_RESOLUTION_ERR:2,INVALID_META_ERR:3};return e.extend(i,n),i.prototype=Error.prototype,i}(),FileException:function(){function i(e){this.code=e,this.name=t(n,e),this.message=this.name+": FileException "+this.code}var n={NOT_FOUND_ERR:1,SECURITY_ERR:2,ABORT_ERR:3,NOT_READABLE_ERR:4,ENCODING_ERR:5,NO_MODIFICATION_ALLOWED_ERR:6,INVALID_STATE_ERR:7,SYNTAX_ERR:8};return e.extend(i,n),i.prototype=Error.prototype,i}(),DOMException:function(){function i(e){this.code=e,this.name=t(n,e),this.message=this.name+": DOMException "+this.code}var n={INDEX_SIZE_ERR:1,DOMSTRING_SIZE_ERR:2,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,INVALID_CHARACTER_ERR:5,NO_DATA_ALLOWED_ERR:6,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INUSE_ATTRIBUTE_ERR:10,INVALID_STATE_ERR:11,SYNTAX_ERR:12,INVALID_MODIFICATION_ERR:13,NAMESPACE_ERR:14,INVALID_ACCESS_ERR:15,VALIDATION_ERR:16,TYPE_MISMATCH_ERR:17,SECURITY_ERR:18,NETWORK_ERR:19,ABORT_ERR:20,URL_MISMATCH_ERR:21,QUOTA_EXCEEDED_ERR:22,TIMEOUT_ERR:23,INVALID_NODE_TYPE_ERR:24,DATA_CLONE_ERR:25};return e.extend(i,n),i.prototype=Error.prototype,i}(),EventException:function(){function t(e){this.code=e,this.name="EventException"}return e.extend(t,{UNSPECIFIED_EVENT_TYPE_ERR:0}),t.prototype=Error.prototype,t}()}}),n("moxie/core/utils/Dom",["moxie/core/utils/Env"],function(e){var t=function(e){return"string"!=typeof e?e:document.getElementById(e)},i=function(e,t){if(!e.className)return!1;var i=new RegExp("(^|\\s+)"+t+"(\\s+|$)");return i.test(e.className)},n=function(e,t){i(e,t)||(e.className=e.className?e.className.replace(/\s+$/,"")+" "+t:t)},r=function(e,t){if(e.className){var i=new RegExp("(^|\\s+)"+t+"(\\s+|$)");e.className=e.className.replace(i,function(e,t,i){return" "===t&&" "===i?" ":""})}},o=function(e,t){return e.currentStyle?e.currentStyle[t]:window.getComputedStyle?window.getComputedStyle(e,null)[t]:void 0},a=function(t,i){function n(e){var t,i,n=0,r=0;return e&&(i=e.getBoundingClientRect(),t="CSS1Compat"===c.compatMode?c.documentElement:c.body,n=i.left+t.scrollLeft,r=i.top+t.scrollTop),{x:n,y:r}}var r,o,a,s=0,u=0,c=document;if(t=t,i=i||c.body,t&&t.getBoundingClientRect&&"IE"===e.browser&&(!c.documentMode||c.documentMode<8))return o=n(t),a=n(i),{x:o.x-a.x,y:o.y-a.y};for(r=t;r&&r!=i&&r.nodeType;)s+=r.offsetLeft||0,u+=r.offsetTop||0,r=r.offsetParent;for(r=t.parentNode;r&&r!=i&&r.nodeType;)s-=r.scrollLeft||0,u-=r.scrollTop||0,r=r.parentNode;return{x:s,y:u}},s=function(e){return{w:e.offsetWidth||e.clientWidth,h:e.offsetHeight||e.clientHeight}};return{get:t,hasClass:i,addClass:n,removeClass:r,getStyle:o,getPos:a,getSize:s}}),n("moxie/core/EventTarget",["moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Basic"],function(e,t,i){function n(){this.uid=i.guid()}var r={};return i.extend(n.prototype,{init:function(){this.uid||(this.uid=i.guid("uid_"))},addEventListener:function(e,t,n,o){var a,s=this;return this.hasOwnProperty("uid")||(this.uid=i.guid("uid_")),e=i.trim(e),/\s/.test(e)?(i.each(e.split(/\s+/),function(e){s.addEventListener(e,t,n,o)}),void 0):(e=e.toLowerCase(),n=parseInt(n,10)||0,a=r[this.uid]&&r[this.uid][e]||[],a.push({fn:t,priority:n,scope:o||this}),r[this.uid]||(r[this.uid]={}),r[this.uid][e]=a,void 0)},hasEventListener:function(e){var t;return e?(e=e.toLowerCase(),t=r[this.uid]&&r[this.uid][e]):t=r[this.uid],t?t:!1},removeEventListener:function(e,t){var n,o,a=this;if(e=e.toLowerCase(),/\s/.test(e))return i.each(e.split(/\s+/),function(e){a.removeEventListener(e,t)}),void 0;if(n=r[this.uid]&&r[this.uid][e]){if(t){for(o=n.length-1;o>=0;o--)if(n[o].fn===t){n.splice(o,1);break}}else n=[];n.length||(delete r[this.uid][e],i.isEmptyObj(r[this.uid])&&delete r[this.uid])}},removeAllEventListeners:function(){r[this.uid]&&delete r[this.uid]},dispatchEvent:function(e){var n,o,a,s,u,c={},l=!0;if("string"!==i.typeOf(e)){if(s=e,"string"!==i.typeOf(s.type))throw new t.EventException(t.EventException.UNSPECIFIED_EVENT_TYPE_ERR);e=s.type,s.total!==u&&s.loaded!==u&&(c.total=s.total,c.loaded=s.loaded),c.async=s.async||!1}if(-1!==e.indexOf("::")?function(t){n=t[0],e=t[1]}(e.split("::")):n=this.uid,e=e.toLowerCase(),o=r[n]&&r[n][e]){o.sort(function(e,t){return t.priority-e.priority}),a=[].slice.call(arguments),a.shift(),c.type=e,a.unshift(c);var d=[];i.each(o,function(e){a[0].target=e.scope,c.async?d.push(function(t){setTimeout(function(){t(e.fn.apply(e.scope,a)===!1)},1)}):d.push(function(t){t(e.fn.apply(e.scope,a)===!1)})}),d.length&&i.inSeries(d,function(e){l=!e})}return l},bindOnce:function(e,t,i,n){var r=this;r.bind.call(this,e,function o(){return r.unbind(e,o),t.apply(this,arguments)},i,n)},bind:function(){this.addEventListener.apply(this,arguments)},unbind:function(){this.removeEventListener.apply(this,arguments)},unbindAll:function(){this.removeAllEventListeners.apply(this,arguments)},trigger:function(){return this.dispatchEvent.apply(this,arguments)},handleEventProps:function(e){var t=this;this.bind(e.join(" "),function(e){var t="on"+e.type.toLowerCase();"function"===i.typeOf(this[t])&&this[t].apply(this,arguments)}),i.each(e,function(e){e="on"+e.toLowerCase(e),"undefined"===i.typeOf(t[e])&&(t[e]=null)})}}),n.instance=new n,n}),n("moxie/runtime/Runtime",["moxie/core/utils/Env","moxie/core/utils/Basic","moxie/core/utils/Dom","moxie/core/EventTarget"],function(e,t,i,n){function r(e,n,o,s,u){var c,l=this,d=t.guid(n+"_"),m=u||"browser";e=e||{},a[d]=this,o=t.extend({access_binary:!1,access_image_binary:!1,display_media:!1,do_cors:!1,drag_and_drop:!1,filter_by_extension:!0,resize_image:!1,report_upload_progress:!1,return_response_headers:!1,return_response_type:!1,return_status_code:!0,send_custom_headers:!1,select_file:!1,select_folder:!1,select_multiple:!0,send_binary_string:!1,send_browser_cookies:!0,send_multipart:!0,slice_blob:!1,stream_upload:!1,summon_file_dialog:!1,upload_filesize:!0,use_http_method:!0},o),e.preferred_caps&&(m=r.getMode(s,e.preferred_caps,m)),c=function(){var e={};return{exec:function(t,i,n,r){return c[i]&&(e[t]||(e[t]={context:this,instance:new c[i]}),e[t].instance[n])?e[t].instance[n].apply(this,r):void 0},removeInstance:function(t){delete e[t]},removeAllInstances:function(){var i=this;t.each(e,function(e,n){"function"===t.typeOf(e.instance.destroy)&&e.instance.destroy.call(e.context),i.removeInstance(n)})}}}(),t.extend(this,{initialized:!1,uid:d,type:n,mode:r.getMode(s,e.required_caps,m),shimid:d+"_container",clients:0,options:e,can:function(e,i){var n=arguments[2]||o;if("string"===t.typeOf(e)&&"undefined"===t.typeOf(i)&&(e=r.parseCaps(e)),"object"===t.typeOf(e)){for(var a in e)if(!this.can(a,e[a],n))return!1;return!0}return"function"===t.typeOf(n[e])?n[e].call(this,i):i===n[e]},getShimContainer:function(){var e,n=i.get(this.shimid);return n||(e=i.get(this.options.container)||document.body,n=document.createElement("div"),n.id=this.shimid,n.className="moxie-shim moxie-shim-"+this.type,t.extend(n.style,{position:"absolute",top:"0px",left:"0px",width:"1px",height:"1px",overflow:"hidden"}),e.appendChild(n),e=null),n},getShim:function(){return c},shimExec:function(e,t){var i=[].slice.call(arguments,2);return l.getShim().exec.call(this,this.uid,e,t,i)},exec:function(e,t){var i=[].slice.call(arguments,2);return l[e]&&l[e][t]?l[e][t].apply(this,i):l.shimExec.apply(this,arguments)},destroy:function(){if(l){var e=i.get(this.shimid);e&&e.parentNode.removeChild(e),c&&c.removeAllInstances(),this.unbindAll(),delete a[this.uid],this.uid=null,d=l=c=e=null}}}),this.mode&&e.required_caps&&!this.can(e.required_caps)&&(this.mode=!1)}var o={},a={};return r.order="html5,flash,silverlight,html4",r.getRuntime=function(e){return a[e]?a[e]:!1},r.addConstructor=function(e,t){t.prototype=n.instance,o[e]=t},r.getConstructor=function(e){return o[e]||null},r.getInfo=function(e){var t=r.getRuntime(e);return t?{uid:t.uid,type:t.type,mode:t.mode,can:function(){return t.can.apply(t,arguments)}}:null},r.parseCaps=function(e){var i={};return"string"!==t.typeOf(e)?e||{}:(t.each(e.split(","),function(e){i[e]=!0}),i)},r.can=function(e,t){var i,n,o=r.getConstructor(e);return o?(i=new o({required_caps:t}),n=i.mode,i.destroy(),!!n):!1},r.thatCan=function(e,t){var i=(t||r.order).split(/\s*,\s*/);for(var n in i)if(r.can(i[n],e))return i[n];return null},r.getMode=function(e,i,n){var r=null;if("undefined"===t.typeOf(n)&&(n="browser"),i&&!t.isEmptyObj(e)){if(t.each(i,function(i,n){if(e.hasOwnProperty(n)){var o=e[n](i);if("string"==typeof o&&(o=[o]),r){if(!(r=t.arrayIntersect(r,o)))return r=!1}else r=o}}),r)return-1!==t.inArray(n,r)?n:r[0];if(r===!1)return!1}return n},r.getGlobalEventTarget=function(){if(/^moxie\./.test(e.global_event_dispatcher)&&!e.can("access_global_ns")){var i=t.guid("moxie_event_target_");window[i]=function(e,t){n.instance.dispatchEvent(e,t)},e.global_event_dispatcher=i}return e.global_event_dispatcher},r.capTrue=function(){return!0},r.capFalse=function(){return!1},r.capTest=function(e){return function(){return!!e}},r}),n("moxie/runtime/RuntimeClient",["moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Basic","moxie/runtime/Runtime"],function(e,t,i,n){return function(){var e;i.extend(this,{connectRuntime:function(r){function o(i){var a,u;return i.length?(a=i.shift().toLowerCase(),(u=n.getConstructor(a))?(e=new u(r),e.bind("Init",function(){e.initialized=!0,setTimeout(function(){e.clients++,s.ruid=e.uid,s.trigger("RuntimeInit",e)},1)}),e.bind("Error",function(){e.destroy(),o(i)}),e.bind("Exception",function(e,i){var n=i.name+"(#"+i.code+")"+(i.message?", from: "+i.message:"");s.trigger("RuntimeError",new t.RuntimeError(t.RuntimeError.EXCEPTION_ERR,n))}),e.mode?(e.init(),void 0):(e.trigger("Error"),void 0)):(o(i),void 0)):(s.trigger("RuntimeError",new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)),e=null,void 0)}var a,s=this;if("string"===i.typeOf(r)?a=r:"string"===i.typeOf(r.ruid)&&(a=r.ruid),a){if(e=n.getRuntime(a))return s.ruid=a,e.clients++,e;throw new t.RuntimeError(t.RuntimeError.NOT_INIT_ERR)}o((r.runtime_order||n.order).split(/\s*,\s*/))},disconnectRuntime:function(){e&&--e.clients<=0&&e.destroy(),e=null},getRuntime:function(){return e&&e.uid?e:e=null},exec:function(){return e?e.exec.apply(this,arguments):null},can:function(t){return e?e.can(t):!1}})}}),n("moxie/file/Blob",["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/runtime/RuntimeClient"],function(e,t,i){function n(o,a){function s(t,i,o){var a,s=r[this.uid];return"string"===e.typeOf(s)&&s.length?(a=new n(null,{type:o,size:i-t}),a.detach(s.substr(t,a.size)),a):null}i.call(this),o&&this.connectRuntime(o),a?"string"===e.typeOf(a)&&(a={data:a}):a={},e.extend(this,{uid:a.uid||e.guid("uid_"),ruid:o,size:a.size||0,type:a.type||"",slice:function(e,t,i){return this.isDetached()?s.apply(this,arguments):this.getRuntime().exec.call(this,"Blob","slice",this.getSource(),e,t,i)},getSource:function(){return r[this.uid]?r[this.uid]:null},detach:function(e){if(this.ruid&&(this.getRuntime().exec.call(this,"Blob","destroy"),this.disconnectRuntime(),this.ruid=null),e=e||"","data:"==e.substr(0,5)){var i=e.indexOf(";base64,");this.type=e.substring(5,i),e=t.atob(e.substring(i+8))}this.size=e.length,r[this.uid]=e},isDetached:function(){return!this.ruid&&"string"===e.typeOf(r[this.uid])},destroy:function(){this.detach(),delete r[this.uid]}}),a.data?this.detach(a.data):r[this.uid]=a}var r={};return n}),n("moxie/core/I18n",["moxie/core/utils/Basic"],function(e){var t={};return{addI18n:function(i){return e.extend(t,i)},translate:function(e){return t[e]||e},_:function(e){return this.translate(e)},sprintf:function(t){var i=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=i.shift();return"undefined"!==e.typeOf(t)?t:""})}}}),n("moxie/core/utils/Mime",["moxie/core/utils/Basic","moxie/core/I18n"],function(e,t){var i="application/msword,doc dot,application/pdf,pdf,application/pgp-signature,pgp,application/postscript,ps ai eps,application/rtf,rtf,application/vnd.ms-excel,xls xlb xlt xla,application/vnd.ms-powerpoint,ppt pps pot ppa,application/zip,zip,application/x-shockwave-flash,swf swfl,application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx,application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx,application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx,application/vnd.openxmlformats-officedocument.presentationml.template,potx,application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx,application/x-javascript,js,application/json,json,audio/mpeg,mp3 mpga mpega mp2,audio/x-wav,wav,audio/x-m4a,m4a,audio/ogg,oga ogg,audio/aiff,aiff aif,audio/flac,flac,audio/aac,aac,audio/ac3,ac3,audio/x-ms-wma,wma,image/bmp,bmp,image/gif,gif,image/jpeg,jpg jpeg jpe,image/photoshop,psd,image/png,png,image/svg+xml,svg svgz,image/tiff,tiff tif,text/plain,asc txt text diff log,text/html,htm html xhtml,text/css,css,text/csv,csv,text/rtf,rtf,video/mpeg,mpeg mpg mpe m2v,video/quicktime,qt mov,video/mp4,mp4,video/x-m4v,m4v,video/x-flv,flv,video/x-ms-wmv,wmv,video/avi,avi,video/webm,webm,video/3gpp,3gpp 3gp,video/3gpp2,3g2,video/vnd.rn-realvideo,rv,video/ogg,ogv,video/x-matroska,mkv,application/vnd.oasis.opendocument.formula-template,otf,application/octet-stream,exe",n={},r={},o=function(e){var t,i,o,a=e.split(/,/);for(t=0;t<a.length;t+=2){for(o=a[t+1].split(/ /),i=0;i<o.length;i++)n[o[i]]=a[t];r[a[t]]=o}},a=function(t,i){var n,r,o,a,s=[];for(r=0;r<t.length;r++)for(n=t[r].extensions.toLowerCase().split(/\s*,\s*/),o=0;o<n.length;o++){if("*"===n[o])return[];if(a=s[n[o]],i&&/^\w+$/.test(n[o]))s.push("."+n[o]);else if(a&&-1===e.inArray(a,s))s.push(a);else if(!a)return[]}return s},s=function(t){var i=[];return e.each(t,function(t){if(t=t.toLowerCase(),"*"===t)return i=[],!1;var n=t.match(/^(\w+)\/(\*|\w+)$/);n&&("*"===n[2]?e.each(r,function(e,t){new RegExp("^"+n[1]+"/").test(t)&&[].push.apply(i,r[t])}):r[t]&&[].push.apply(i,r[t]))}),i},u=function(i){var n=[],r=[];return"string"===e.typeOf(i)&&(i=e.trim(i).split(/\s*,\s*/)),r=s(i),n.push({title:t.translate("Files"),extensions:r.length?r.join(","):"*"}),n},c=function(e){var t=e&&e.match(/\.([^.]+)$/);return t?t[1].toLowerCase():""},l=function(e){return n[c(e)]||""};return o(i),{mimes:n,extensions:r,addMimeType:o,extList2mimes:a,mimes2exts:s,mimes2extList:u,getFileExtension:c,getFileMime:l}}),n("moxie/file/FileInput",["moxie/core/utils/Basic","moxie/core/utils/Env","moxie/core/utils/Mime","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/core/I18n","moxie/runtime/Runtime","moxie/runtime/RuntimeClient"],function(e,t,i,n,r,o,a,s,u){function c(t){var o,c,d;if(-1!==e.inArray(e.typeOf(t),["string","node"])&&(t={browse_button:t}),c=n.get(t.browse_button),!c)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR);d={accept:[{title:a.translate("All Files"),extensions:"*"}],multiple:!1,required_caps:!1,container:c.parentNode||document.body},t=e.extend({},d,t),"string"==typeof t.required_caps&&(t.required_caps=s.parseCaps(t.required_caps)),"string"==typeof t.accept&&(t.accept=i.mimes2extList(t.accept)),o=n.get(t.container),o||(o=document.body),"static"===n.getStyle(o,"position")&&(o.style.position="relative"),o=c=null,u.call(this),e.extend(this,{uid:e.guid("uid_"),ruid:null,shimid:null,files:null,init:function(){var i=this;i.bind("RuntimeInit",function(r,o){i.ruid=o.uid,i.shimid=o.shimid,i.bind("Ready",function(){i.trigger("Refresh")},999),i.bind("Refresh",function(){var i,r,a,s,u;a=n.get(t.browse_button),s=n.get(o.shimid),a&&(i=n.getPos(a,n.get(t.container)),r=n.getSize(a),u=parseInt(n.getStyle(a,"z-index"),10)||0,s&&e.extend(s.style,{top:i.y+"px",left:i.x+"px",width:r.w+"px",height:r.h+"px",zIndex:u+1})),s=a=null}),o.exec.call(i,"FileInput","init",t)}),i.connectRuntime(e.extend({},t,{required_caps:{select_file:!0}}))},getOption:function(e){return t[e]},setOption:function(e,n){if(t.hasOwnProperty(e)){var o=t[e];switch(e){case"accept":"string"==typeof n&&(n=i.mimes2extList(n));break;case"container":case"required_caps":throw new r.FileException(r.FileException.NO_MODIFICATION_ALLOWED_ERR)}t[e]=n,this.exec("FileInput","setOption",e,n),this.trigger("OptionChanged",e,n,o)}},disable:function(t){var i=this.getRuntime();i&&this.exec("FileInput","disable","undefined"===e.typeOf(t)?!0:t)},refresh:function(){this.trigger("Refresh")},destroy:function(){var t=this.getRuntime();t&&(t.exec.call(this,"FileInput","destroy"),this.disconnectRuntime()),"array"===e.typeOf(this.files)&&e.each(this.files,function(e){e.destroy()}),this.files=null,this.unbindAll()}}),this.handleEventProps(l)}var l=["ready","change","cancel","mouseenter","mouseleave","mousedown","mouseup"];return c.prototype=o.instance,c}),n("moxie/file/File",["moxie/core/utils/Basic","moxie/core/utils/Mime","moxie/file/Blob"],function(e,t,i){function n(n,r){r||(r={}),i.apply(this,arguments),this.type||(this.type=t.getFileMime(r.name));var o;if(r.name)o=r.name.replace(/\\/g,"/"),o=o.substr(o.lastIndexOf("/")+1);else if(this.type){var a=this.type.split("/")[0];o=e.guid((""!==a?a:"file")+"_"),t.extensions[this.type]&&(o+="."+t.extensions[this.type][0])}e.extend(this,{name:o||e.guid("file_"),relativePath:"",lastModifiedDate:r.lastModifiedDate||(new Date).toLocaleString()})}return n.prototype=i.prototype,n}),n("moxie/file/FileDrop",["moxie/core/I18n","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/utils/Basic","moxie/core/utils/Env","moxie/file/File","moxie/runtime/RuntimeClient","moxie/core/EventTarget","moxie/core/utils/Mime"],function(e,t,i,n,r,o,a,s,u){function c(i){var r,o=this;"string"==typeof i&&(i={drop_zone:i}),r={accept:[{title:e.translate("All Files"),extensions:"*"}],required_caps:{drag_and_drop:!0}},i="object"==typeof i?n.extend({},r,i):r,i.container=t.get(i.drop_zone)||document.body,"static"===t.getStyle(i.container,"position")&&(i.container.style.position="relative"),"string"==typeof i.accept&&(i.accept=u.mimes2extList(i.accept)),a.call(o),n.extend(o,{uid:n.guid("uid_"),ruid:null,files:null,init:function(){o.bind("RuntimeInit",function(e,t){o.ruid=t.uid,t.exec.call(o,"FileDrop","init",i),o.dispatchEvent("ready")
+}),o.connectRuntime(i)},destroy:function(){var e=this.getRuntime();e&&(e.exec.call(this,"FileDrop","destroy"),this.disconnectRuntime()),this.files=null,this.unbindAll()}}),this.handleEventProps(l)}var l=["ready","dragenter","dragleave","drop","error"];return c.prototype=s.instance,c}),n("moxie/file/FileReader",["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/core/Exceptions","moxie/core/EventTarget","moxie/file/Blob","moxie/runtime/RuntimeClient"],function(e,t,i,n,r,o){function a(){function n(e,n){if(this.trigger("loadstart"),this.readyState===a.LOADING)return this.trigger("error",new i.DOMException(i.DOMException.INVALID_STATE_ERR)),this.trigger("loadend"),void 0;if(!(n instanceof r))return this.trigger("error",new i.DOMException(i.DOMException.NOT_FOUND_ERR)),this.trigger("loadend"),void 0;if(this.result=null,this.readyState=a.LOADING,n.isDetached()){var o=n.getSource();switch(e){case"readAsText":case"readAsBinaryString":this.result=o;break;case"readAsDataURL":this.result="data:"+n.type+";base64,"+t.btoa(o)}this.readyState=a.DONE,this.trigger("load"),this.trigger("loadend")}else this.connectRuntime(n.ruid),this.exec("FileReader","read",e,n)}o.call(this),e.extend(this,{uid:e.guid("uid_"),readyState:a.EMPTY,result:null,error:null,readAsBinaryString:function(e){n.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){n.call(this,"readAsDataURL",e)},readAsText:function(e){n.call(this,"readAsText",e)},abort:function(){this.result=null,-1===e.inArray(this.readyState,[a.EMPTY,a.DONE])&&(this.readyState===a.LOADING&&(this.readyState=a.DONE),this.exec("FileReader","abort"),this.trigger("abort"),this.trigger("loadend"))},destroy:function(){this.abort(),this.exec("FileReader","destroy"),this.disconnectRuntime(),this.unbindAll()}}),this.handleEventProps(s),this.bind("Error",function(e,t){this.readyState=a.DONE,this.error=t},999),this.bind("Load",function(){this.readyState=a.DONE},999)}var s=["loadstart","progress","load","abort","error","loadend"];return a.EMPTY=0,a.LOADING=1,a.DONE=2,a.prototype=n.instance,a}),n("moxie/core/utils/Url",["moxie/core/utils/Basic"],function(e){var t=function(i,n){var r,o=["source","scheme","authority","userInfo","user","pass","host","port","relative","path","directory","file","query","fragment"],a=o.length,s={http:80,https:443},u={},c=/^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[\da-fA-F:]+\]|[^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/,l=c.exec(i||""),d=/^\/\/\w/.test(i);switch(e.typeOf(n)){case"undefined":n=t(document.location.href,!1);break;case"string":n=t(n,!1)}for(;a--;)l[a]&&(u[o[a]]=l[a]);if(r=!d&&!u.scheme,(d||r)&&(u.scheme=n.scheme),r){u.host=n.host,u.port=n.port;var m="";/^[^\/]/.test(u.path)&&(m=n.path,m=/\/[^\/]*\.[^\/]*$/.test(m)?m.replace(/\/[^\/]+$/,"/"):m.replace(/\/?$/,"/")),u.path=m+(u.path||"")}return u.port||(u.port=s[u.scheme]||80),u.port=parseInt(u.port,10),u.path||(u.path="/"),delete u.source,u},i=function(e){var i={http:80,https:443},n="object"==typeof e?e:t(e);return n.scheme+"://"+n.host+(n.port!==i[n.scheme]?":"+n.port:"")+n.path+(n.query?n.query:"")},n=function(e){function i(e){return[e.scheme,e.host,e.port].join("/")}return"string"==typeof e&&(e=t(e)),i(t())===i(e)};return{parseUrl:t,resolveUrl:i,hasSameOrigin:n}}),n("moxie/runtime/RuntimeTarget",["moxie/core/utils/Basic","moxie/runtime/RuntimeClient","moxie/core/EventTarget"],function(e,t,i){function n(){this.uid=e.guid("uid_"),t.call(this),this.destroy=function(){this.disconnectRuntime(),this.unbindAll()}}return n.prototype=i.instance,n}),n("moxie/file/FileReaderSync",["moxie/core/utils/Basic","moxie/runtime/RuntimeClient","moxie/core/utils/Encode"],function(e,t,i){return function(){function n(e,t){if(!t.isDetached()){var n=this.connectRuntime(t.ruid).exec.call(this,"FileReaderSync","read",e,t);return this.disconnectRuntime(),n}var r=t.getSource();switch(e){case"readAsBinaryString":return r;case"readAsDataURL":return"data:"+t.type+";base64,"+i.btoa(r);case"readAsText":for(var o="",a=0,s=r.length;s>a;a++)o+=String.fromCharCode(r[a]);return o}}t.call(this),e.extend(this,{uid:e.guid("uid_"),readAsBinaryString:function(e){return n.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){return n.call(this,"readAsDataURL",e)},readAsText:function(e){return n.call(this,"readAsText",e)}})}}),n("moxie/xhr/FormData",["moxie/core/Exceptions","moxie/core/utils/Basic","moxie/file/Blob"],function(e,t,i){function n(){var e,n=[];t.extend(this,{append:function(r,o){var a=this,s=t.typeOf(o);o instanceof i?e={name:r,value:o}:"array"===s?(r+="[]",t.each(o,function(e){a.append(r,e)})):"object"===s?t.each(o,function(e,t){a.append(r+"["+t+"]",e)}):"null"===s||"undefined"===s||"number"===s&&isNaN(o)?a.append(r,"false"):n.push({name:r,value:o.toString()})},hasBlob:function(){return!!this.getBlob()},getBlob:function(){return e&&e.value||null},getBlobName:function(){return e&&e.name||null},each:function(i){t.each(n,function(e){i(e.value,e.name)}),e&&i(e.value,e.name)},destroy:function(){e=null,n=[]}})}return n}),n("moxie/xhr/XMLHttpRequest",["moxie/core/utils/Basic","moxie/core/Exceptions","moxie/core/EventTarget","moxie/core/utils/Encode","moxie/core/utils/Url","moxie/runtime/Runtime","moxie/runtime/RuntimeTarget","moxie/file/Blob","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/core/utils/Env","moxie/core/utils/Mime"],function(e,t,i,n,r,o,a,s,u,c,l,d){function m(){this.uid=e.guid("uid_")}function h(){function i(e,t){return I.hasOwnProperty(e)?1===arguments.length?l.can("define_property")?I[e]:A[e]:(l.can("define_property")?I[e]=t:A[e]=t,void 0):void 0}function u(t){function n(){_&&(_.destroy(),_=null),s.dispatchEvent("loadend"),s=null}function r(r){_.bind("LoadStart",function(e){i("readyState",h.LOADING),s.dispatchEvent("readystatechange"),s.dispatchEvent(e),L&&s.upload.dispatchEvent(e)}),_.bind("Progress",function(e){i("readyState")!==h.LOADING&&(i("readyState",h.LOADING),s.dispatchEvent("readystatechange")),s.dispatchEvent(e)}),_.bind("UploadProgress",function(e){L&&s.upload.dispatchEvent({type:"progress",lengthComputable:!1,total:e.total,loaded:e.loaded})}),_.bind("Load",function(t){i("readyState",h.DONE),i("status",Number(r.exec.call(_,"XMLHttpRequest","getStatus")||0)),i("statusText",f[i("status")]||""),i("response",r.exec.call(_,"XMLHttpRequest","getResponse",i("responseType"))),~e.inArray(i("responseType"),["text",""])?i("responseText",i("response")):"document"===i("responseType")&&i("responseXML",i("response")),U=r.exec.call(_,"XMLHttpRequest","getAllResponseHeaders"),s.dispatchEvent("readystatechange"),i("status")>0?(L&&s.upload.dispatchEvent(t),s.dispatchEvent(t)):(F=!0,s.dispatchEvent("error")),n()}),_.bind("Abort",function(e){s.dispatchEvent(e),n()}),_.bind("Error",function(e){F=!0,i("readyState",h.DONE),s.dispatchEvent("readystatechange"),M=!0,s.dispatchEvent(e),n()}),r.exec.call(_,"XMLHttpRequest","send",{url:x,method:v,async:T,user:w,password:y,headers:S,mimeType:D,encoding:O,responseType:s.responseType,withCredentials:s.withCredentials,options:k},t)}var s=this;E=(new Date).getTime(),_=new a,"string"==typeof k.required_caps&&(k.required_caps=o.parseCaps(k.required_caps)),k.required_caps=e.extend({},k.required_caps,{return_response_type:s.responseType}),t instanceof c&&(k.required_caps.send_multipart=!0),e.isEmptyObj(S)||(k.required_caps.send_custom_headers=!0),B||(k.required_caps.do_cors=!0),k.ruid?r(_.connectRuntime(k)):(_.bind("RuntimeInit",function(e,t){r(t)}),_.bind("RuntimeError",function(e,t){s.dispatchEvent("RuntimeError",t)}),_.connectRuntime(k))}function g(){i("responseText",""),i("responseXML",null),i("response",null),i("status",0),i("statusText",""),E=b=null}var x,v,w,y,E,b,_,R,A=this,I={timeout:0,readyState:h.UNSENT,withCredentials:!1,status:0,statusText:"",responseType:"",responseXML:null,responseText:null,response:null},T=!0,S={},O=null,D=null,N=!1,C=!1,L=!1,M=!1,F=!1,B=!1,P=null,H=null,k={},U="";e.extend(this,I,{uid:e.guid("uid_"),upload:new m,open:function(o,a,s,u,c){var l;if(!o||!a)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(/[\u0100-\uffff]/.test(o)||n.utf8_encode(o)!==o)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(~e.inArray(o.toUpperCase(),["CONNECT","DELETE","GET","HEAD","OPTIONS","POST","PUT","TRACE","TRACK"])&&(v=o.toUpperCase()),~e.inArray(v,["CONNECT","TRACE","TRACK"]))throw new t.DOMException(t.DOMException.SECURITY_ERR);if(a=n.utf8_encode(a),l=r.parseUrl(a),B=r.hasSameOrigin(l),x=r.resolveUrl(a),(u||c)&&!B)throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);if(w=u||l.user,y=c||l.pass,T=s||!0,T===!1&&(i("timeout")||i("withCredentials")||""!==i("responseType")))throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);N=!T,C=!1,S={},g.call(this),i("readyState",h.OPENED),this.dispatchEvent("readystatechange")},setRequestHeader:function(r,o){var a=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","cookie","cookie2","content-transfer-encoding","date","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","user-agent","via"];if(i("readyState")!==h.OPENED||C)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(/[\u0100-\uffff]/.test(r)||n.utf8_encode(r)!==r)throw new t.DOMException(t.DOMException.SYNTAX_ERR);return r=e.trim(r).toLowerCase(),~e.inArray(r,a)||/^(proxy\-|sec\-)/.test(r)?!1:(S[r]?S[r]+=", "+o:S[r]=o,!0)},hasRequestHeader:function(e){return e&&S[e.toLowerCase()]||!1},getAllResponseHeaders:function(){return U||""},getResponseHeader:function(t){return t=t.toLowerCase(),F||~e.inArray(t,["set-cookie","set-cookie2"])?null:U&&""!==U&&(R||(R={},e.each(U.split(/\r\n/),function(t){var i=t.split(/:\s+/);2===i.length&&(i[0]=e.trim(i[0]),R[i[0].toLowerCase()]={header:i[0],value:e.trim(i[1])})})),R.hasOwnProperty(t))?R[t].header+": "+R[t].value:null},overrideMimeType:function(n){var r,o;if(~e.inArray(i("readyState"),[h.LOADING,h.DONE]))throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(n=e.trim(n.toLowerCase()),/;/.test(n)&&(r=n.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))&&(n=r[1],r[2]&&(o=r[2])),!d.mimes[n])throw new t.DOMException(t.DOMException.SYNTAX_ERR);P=n,H=o},send:function(i,r){if(k="string"===e.typeOf(r)?{ruid:r}:r?r:{},this.readyState!==h.OPENED||C)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(i instanceof s)k.ruid=i.ruid,D=i.type||"application/octet-stream";else if(i instanceof c){if(i.hasBlob()){var o=i.getBlob();k.ruid=o.ruid,D=o.type||"application/octet-stream"}}else"string"==typeof i&&(O="UTF-8",D="text/plain;charset=UTF-8",i=n.utf8_encode(i));this.withCredentials||(this.withCredentials=k.required_caps&&k.required_caps.send_browser_cookies&&!B),L=!N&&this.upload.hasEventListener(),F=!1,M=!i,N||(C=!0),u.call(this,i)},abort:function(){if(F=!0,N=!1,~e.inArray(i("readyState"),[h.UNSENT,h.OPENED,h.DONE]))i("readyState",h.UNSENT);else{if(i("readyState",h.DONE),C=!1,!_)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);_.getRuntime().exec.call(_,"XMLHttpRequest","abort",M),M=!0}},destroy:function(){_&&("function"===e.typeOf(_.destroy)&&_.destroy(),_=null),this.unbindAll(),this.upload&&(this.upload.unbindAll(),this.upload=null)}}),this.handleEventProps(p.concat(["readystatechange"])),this.upload.handleEventProps(p)}var f={100:"Continue",101:"Switching Protocols",102:"Processing",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",207:"Multi-Status",226:"IM Used",300:"Multiple Choices",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",306:"Reserved",307:"Temporary Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Requested Range Not Satisfiable",417:"Expectation Failed",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",426:"Upgrade Required",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",510:"Not Extended"};m.prototype=i.instance;var p=["loadstart","progress","abort","error","load","timeout","loadend"];return h.UNSENT=0,h.OPENED=1,h.HEADERS_RECEIVED=2,h.LOADING=3,h.DONE=4,h.prototype=i.instance,h}),n("moxie/runtime/Transporter",["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/runtime/RuntimeClient","moxie/core/EventTarget"],function(e,t,i,n){function r(){function n(){l=d=0,c=this.result=null}function o(t,i){var n=this;u=i,n.bind("TransportingProgress",function(t){d=t.loaded,l>d&&-1===e.inArray(n.state,[r.IDLE,r.DONE])&&a.call(n)},999),n.bind("TransportingComplete",function(){d=l,n.state=r.DONE,c=null,n.result=u.exec.call(n,"Transporter","getAsBlob",t||"")},999),n.state=r.BUSY,n.trigger("TransportingStarted"),a.call(n)}function a(){var e,i=this,n=l-d;m>n&&(m=n),e=t.btoa(c.substr(d,m)),u.exec.call(i,"Transporter","receive",e,l)}var s,u,c,l,d,m;i.call(this),e.extend(this,{uid:e.guid("uid_"),state:r.IDLE,result:null,transport:function(t,i,r){var a=this;if(r=e.extend({chunk_size:204798},r),(s=r.chunk_size%3)&&(r.chunk_size+=3-s),m=r.chunk_size,n.call(this),c=t,l=t.length,"string"===e.typeOf(r)||r.ruid)o.call(a,i,this.connectRuntime(r));else{var u=function(e,t){a.unbind("RuntimeInit",u),o.call(a,i,t)};this.bind("RuntimeInit",u),this.connectRuntime(r)}},abort:function(){var e=this;e.state=r.IDLE,u&&(u.exec.call(e,"Transporter","clear"),e.trigger("TransportingAborted")),n.call(e)},destroy:function(){this.unbindAll(),u=null,this.disconnectRuntime(),n.call(this)}})}return r.IDLE=0,r.BUSY=1,r.DONE=2,r.prototype=n.instance,r}),n("moxie/image/Image",["moxie/core/utils/Basic","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/file/FileReaderSync","moxie/xhr/XMLHttpRequest","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/runtime/Transporter","moxie/core/utils/Env","moxie/core/EventTarget","moxie/file/Blob","moxie/file/File","moxie/core/utils/Encode"],function(e,t,i,n,r,o,a,s,u,c,l,d,m){function h(){function n(e){try{return e||(e=this.exec("Image","getInfo")),this.size=e.size,this.width=e.width,this.height=e.height,this.type=e.type,this.meta=e.meta,""===this.name&&(this.name=e.name),!0}catch(t){return this.trigger("error",t.code),!1}}function c(t){var n=e.typeOf(t);try{if(t instanceof h){if(!t.size)throw new i.DOMException(i.DOMException.INVALID_STATE_ERR);p.apply(this,arguments)}else if(t instanceof l){if(!~e.inArray(t.type,["image/jpeg","image/png"]))throw new i.ImageError(i.ImageError.WRONG_FORMAT);g.apply(this,arguments)}else if(-1!==e.inArray(n,["blob","file"]))c.call(this,new d(null,t),arguments[1]);else if("string"===n)"data:"===t.substr(0,5)?c.call(this,new l(null,{data:t}),arguments[1]):x.apply(this,arguments);else{if("node"!==n||"img"!==t.nodeName.toLowerCase())throw new i.DOMException(i.DOMException.TYPE_MISMATCH_ERR);c.call(this,t.src,arguments[1])}}catch(r){this.trigger("error",r.code)}}function p(t,i){var n=this.connectRuntime(t.ruid);this.ruid=n.uid,n.exec.call(this,"Image","loadFromImage",t,"undefined"===e.typeOf(i)?!0:i)}function g(t,i){function n(e){r.ruid=e.uid,e.exec.call(r,"Image","loadFromBlob",t)}var r=this;r.name=t.name||"",t.isDetached()?(this.bind("RuntimeInit",function(e,t){n(t)}),i&&"string"==typeof i.required_caps&&(i.required_caps=o.parseCaps(i.required_caps)),this.connectRuntime(e.extend({required_caps:{access_image_binary:!0,resize_image:!0}},i))):n(this.connectRuntime(t.ruid))}function x(e,t){var i,n=this;i=new r,i.open("get",e),i.responseType="blob",i.onprogress=function(e){n.trigger(e)},i.onload=function(){g.call(n,i.response,!0)},i.onerror=function(e){n.trigger(e)},i.onloadend=function(){i.destroy()},i.bind("RuntimeError",function(e,t){n.trigger("RuntimeError",t)}),i.send(null,t)}a.call(this),e.extend(this,{uid:e.guid("uid_"),ruid:null,name:"",size:0,width:0,height:0,type:"",meta:{},clone:function(){this.load.apply(this,arguments)},load:function(){c.apply(this,arguments)},resize:function(t){var n,r,o=this,a={x:0,y:0,width:o.width,height:o.height},s=e.extendIf({width:o.width,height:o.height,type:o.type||"image/jpeg",quality:90,crop:!1,fit:!0,preserveHeaders:!0,resample:"default",multipass:!0},t);try{if(!o.size)throw new i.DOMException(i.DOMException.INVALID_STATE_ERR);if(o.width>h.MAX_RESIZE_WIDTH||o.height>h.MAX_RESIZE_HEIGHT)throw new i.ImageError(i.ImageError.MAX_RESOLUTION_ERR);if(n=o.meta&&o.meta.tiff&&o.meta.tiff.Orientation||1,-1!==e.inArray(n,[5,6,7,8])){var u=s.width;s.width=s.height,s.height=u}if(s.crop){switch(r=Math.max(s.width/o.width,s.height/o.height),t.fit?(a.width=Math.min(Math.ceil(s.width/r),o.width),a.height=Math.min(Math.ceil(s.height/r),o.height),r=s.width/a.width):(a.width=Math.min(s.width,o.width),a.height=Math.min(s.height,o.height),r=1),"boolean"==typeof s.crop&&(s.crop="cc"),s.crop.toLowerCase().replace(/_/,"-")){case"rb":case"right-bottom":a.x=o.width-a.width,a.y=o.height-a.height;break;case"cb":case"center-bottom":a.x=Math.floor((o.width-a.width)/2),a.y=o.height-a.height;break;case"lb":case"left-bottom":a.x=0,a.y=o.height-a.height;break;case"lt":case"left-top":a.x=0,a.y=0;break;case"ct":case"center-top":a.x=Math.floor((o.width-a.width)/2),a.y=0;break;case"rt":case"right-top":a.x=o.width-a.width,a.y=0;break;case"rc":case"right-center":case"right-middle":a.x=o.width-a.width,a.y=Math.floor((o.height-a.height)/2);break;case"lc":case"left-center":case"left-middle":a.x=0,a.y=Math.floor((o.height-a.height)/2);break;case"cc":case"center-center":case"center-middle":default:a.x=Math.floor((o.width-a.width)/2),a.y=Math.floor((o.height-a.height)/2)}a.x=Math.max(a.x,0),a.y=Math.max(a.y,0)}else r=Math.min(s.width/o.width,s.height/o.height),r>1&&!s.fit&&(r=1);this.exec("Image","resize",a,r,s)}catch(c){o.trigger("error",c.code)}},downsize:function(t){var i,n={width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90,crop:!1,fit:!1,preserveHeaders:!0,resample:"default"};i="object"==typeof t?e.extend(n,t):e.extend(n,{width:arguments[0],height:arguments[1],crop:arguments[2],preserveHeaders:arguments[3]}),this.resize(i)},crop:function(e,t,i){this.downsize(e,t,!0,i)},getAsCanvas:function(){if(!u.can("create_canvas"))throw new i.RuntimeError(i.RuntimeError.NOT_SUPPORTED_ERR);return this.exec("Image","getAsCanvas")},getAsBlob:function(e,t){if(!this.size)throw new i.DOMException(i.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsBlob",e||"image/jpeg",t||90)},getAsDataURL:function(e,t){if(!this.size)throw new i.DOMException(i.DOMException.INVALID_STATE_ERR);return this.exec("Image","getAsDataURL",e||"image/jpeg",t||90)},getAsBinaryString:function(e,t){var i=this.getAsDataURL(e,t);return m.atob(i.substring(i.indexOf("base64,")+7))},embed:function(n,r){function o(t,r){var o=this;if(u.can("create_canvas")){var l=o.getAsCanvas();if(l)return n.appendChild(l),l=null,o.destroy(),c.trigger("embedded"),void 0}var d=o.getAsDataURL(t,r);if(!d)throw new i.ImageError(i.ImageError.WRONG_FORMAT);if(u.can("use_data_uri_of",d.length))n.innerHTML='<img src="'+d+'" width="'+o.width+'" height="'+o.height+'" alt="" />',o.destroy(),c.trigger("embedded");else{var h=new s;h.bind("TransportingComplete",function(){a=c.connectRuntime(this.result.ruid),c.bind("Embedded",function(){e.extend(a.getShimContainer().style,{top:"0px",left:"0px",width:o.width+"px",height:o.height+"px"}),a=null},999),a.exec.call(c,"ImageView","display",this.result.uid,width,height),o.destroy()}),h.transport(m.atob(d.substring(d.indexOf("base64,")+7)),t,{required_caps:{display_media:!0},runtime_order:"flash,silverlight",container:n})}}var a,c=this,l=e.extend({width:this.width,height:this.height,type:this.type||"image/jpeg",quality:90,fit:!0,resample:"nearest"},r);try{if(!(n=t.get(n)))throw new i.DOMException(i.DOMException.INVALID_NODE_TYPE_ERR);if(!this.size)throw new i.DOMException(i.DOMException.INVALID_STATE_ERR);this.width>h.MAX_RESIZE_WIDTH||this.height>h.MAX_RESIZE_HEIGHT;var d=new h;return d.bind("Resize",function(){o.call(this,l.type,l.quality)}),d.bind("Load",function(){this.downsize(l)}),this.meta.thumb&&this.meta.thumb.width>=l.width&&this.meta.thumb.height>=l.height?d.load(this.meta.thumb.data):d.clone(this,!1),d}catch(f){this.trigger("error",f.code)}},destroy:function(){this.ruid&&(this.getRuntime().exec.call(this,"Image","destroy"),this.disconnectRuntime()),this.meta&&this.meta.thumb&&this.meta.thumb.data.destroy(),this.unbindAll()}}),this.handleEventProps(f),this.bind("Load Resize",function(){return n.call(this)},999)}var f=["progress","load","error","resize","embedded"];return h.MAX_RESIZE_WIDTH=8192,h.MAX_RESIZE_HEIGHT=8192,h.prototype=c.instance,h}),n("moxie/runtime/html5/Runtime",["moxie/core/utils/Basic","moxie/core/Exceptions","moxie/runtime/Runtime","moxie/core/utils/Env"],function(e,t,i,n){function o(t){var o=this,u=i.capTest,c=i.capTrue,l=e.extend({access_binary:u(window.FileReader||window.File&&window.File.getAsDataURL),access_image_binary:function(){return o.can("access_binary")&&!!s.Image},display_media:u((n.can("create_canvas")||n.can("use_data_uri_over32kb"))&&r("moxie/image/Image")),do_cors:u(window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest),drag_and_drop:u(function(){var e=document.createElement("div");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&("IE"!==n.browser||n.verComp(n.version,9,">"))}()),filter_by_extension:u(function(){return!("Chrome"===n.browser&&n.verComp(n.version,28,"<")||"IE"===n.browser&&n.verComp(n.version,10,"<")||"Safari"===n.browser&&n.verComp(n.version,7,"<")||"Firefox"===n.browser&&n.verComp(n.version,37,"<"))}()),return_response_headers:c,return_response_type:function(e){return"json"===e&&window.JSON?!0:n.can("return_response_type",e)},return_status_code:c,report_upload_progress:u(window.XMLHttpRequest&&(new XMLHttpRequest).upload),resize_image:function(){return o.can("access_binary")&&n.can("create_canvas")},select_file:function(){return n.can("use_fileinput")&&window.File},select_folder:function(){return o.can("select_file")&&("Chrome"===n.browser&&n.verComp(n.version,21,">=")||"Firefox"===n.browser&&n.verComp(n.version,42,">="))},select_multiple:function(){return!(!o.can("select_file")||"Safari"===n.browser&&"Windows"===n.os||"iOS"===n.os&&n.verComp(n.osVersion,"7.0.0",">")&&n.verComp(n.osVersion,"8.0.0","<"))},send_binary_string:u(window.XMLHttpRequest&&((new XMLHttpRequest).sendAsBinary||window.Uint8Array&&window.ArrayBuffer)),send_custom_headers:u(window.XMLHttpRequest),send_multipart:function(){return!!(window.XMLHttpRequest&&(new XMLHttpRequest).upload&&window.FormData)||o.can("send_binary_string")},slice_blob:u(window.File&&(File.prototype.mozSlice||File.prototype.webkitSlice||File.prototype.slice)),stream_upload:function(){return o.can("slice_blob")&&o.can("send_multipart")},summon_file_dialog:function(){return o.can("select_file")&&!("Firefox"===n.browser&&n.verComp(n.version,4,"<")||"Opera"===n.browser&&n.verComp(n.version,12,"<")||"IE"===n.browser&&n.verComp(n.version,10,"<"))},upload_filesize:c,use_http_method:c},arguments[2]);i.call(this,t,arguments[1]||a,l),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(o),e=o=null}}(this.destroy)}),e.extend(this.getShim(),s)}var a="html5",s={};return i.addConstructor(a,o),s}),n("moxie/runtime/html5/file/Blob",["moxie/runtime/html5/Runtime","moxie/file/Blob"],function(e,t){function i(){function e(e,t,i){var n;if(!window.File.prototype.slice)return(n=window.File.prototype.webkitSlice||window.File.prototype.mozSlice)?n.call(e,t,i):null;try{return e.slice(),e.slice(t,i)}catch(r){return e.slice(t,i-t)}}this.slice=function(){return new t(this.getRuntime().uid,e.apply(this,arguments))},this.destroy=function(){this.getRuntime().getShim().removeInstance(this.uid)}}return e.Blob=i}),n("moxie/core/utils/Events",["moxie/core/utils/Basic"],function(e){function t(){this.returnValue=!1}function i(){this.cancelBubble=!0}var n={},r="moxie_"+e.guid(),o=function(o,a,s,u){var c,l;a=a.toLowerCase(),o.addEventListener?(c=s,o.addEventListener(a,c,!1)):o.attachEvent&&(c=function(){var e=window.event;e.target||(e.target=e.srcElement),e.preventDefault=t,e.stopPropagation=i,s(e)},o.attachEvent("on"+a,c)),o[r]||(o[r]=e.guid()),n.hasOwnProperty(o[r])||(n[o[r]]={}),l=n[o[r]],l.hasOwnProperty(a)||(l[a]=[]),l[a].push({func:c,orig:s,key:u})},a=function(t,i,o){var a,s;if(i=i.toLowerCase(),t[r]&&n[t[r]]&&n[t[r]][i]){a=n[t[r]][i];for(var u=a.length-1;u>=0&&(a[u].orig!==o&&a[u].key!==o||(t.removeEventListener?t.removeEventListener(i,a[u].func,!1):t.detachEvent&&t.detachEvent("on"+i,a[u].func),a[u].orig=null,a[u].func=null,a.splice(u,1),o===s));u--);if(a.length||delete n[t[r]][i],e.isEmptyObj(n[t[r]])){delete n[t[r]];try{delete t[r]}catch(c){t[r]=s}}}},s=function(t,i){t&&t[r]&&e.each(n[t[r]],function(e,n){a(t,n,i)})};return{addEvent:o,removeEvent:a,removeAllEvents:s}}),n("moxie/runtime/html5/file/FileInput",["moxie/runtime/html5/Runtime","moxie/file/File","moxie/core/utils/Basic","moxie/core/utils/Dom","moxie/core/utils/Events","moxie/core/utils/Mime","moxie/core/utils/Env"],function(e,t,i,n,r,o,a){function s(){var e,s;i.extend(this,{init:function(u){var c,l,d,m,h,f,p=this,g=p.getRuntime();e=u,d=o.extList2mimes(e.accept,g.can("filter_by_extension")),l=g.getShimContainer(),l.innerHTML='<input id="'+g.uid+'" type="file" style="font-size:999px;opacity:0;"'+(e.multiple&&g.can("select_multiple")?"multiple":"")+(e.directory&&g.can("select_folder")?"webkitdirectory directory":"")+(d?' accept="'+d.join(",")+'"':"")+" />",c=n.get(g.uid),i.extend(c.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),m=n.get(e.browse_button),s=n.getStyle(m,"z-index")||"auto",g.can("summon_file_dialog")&&("static"===n.getStyle(m,"position")&&(m.style.position="relative"),r.addEvent(m,"click",function(e){var t=n.get(g.uid);t&&!t.disabled&&t.click(),e.preventDefault()},p.uid),p.bind("Refresh",function(){h=parseInt(s,10)||1,n.get(e.browse_button).style.zIndex=h,this.getRuntime().getShimContainer().style.zIndex=h-1})),f=g.can("summon_file_dialog")?m:l,r.addEvent(f,"mouseover",function(){p.trigger("mouseenter")},p.uid),r.addEvent(f,"mouseout",function(){p.trigger("mouseleave")},p.uid),r.addEvent(f,"mousedown",function(){p.trigger("mousedown")},p.uid),r.addEvent(n.get(e.container),"mouseup",function(){p.trigger("mouseup")},p.uid),(g.can("summon_file_dialog")?c:m).setAttribute("tabindex",-1),c.onchange=function x(){if(p.files=[],i.each(this.files,function(i){var n="";return e.directory&&"."==i.name?!0:(i.webkitRelativePath&&(n="/"+i.webkitRelativePath.replace(/^\//,"")),i=new t(g.uid,i),i.relativePath=n,p.files.push(i),void 0)}),"IE"!==a.browser&&"IEMobile"!==a.browser)this.value="";else{var n=this.cloneNode(!0);this.parentNode.replaceChild(n,this),n.onchange=x}p.files.length&&p.trigger("change")},p.trigger({type:"ready",async:!0}),l=null},setOption:function(e,t){var i=this.getRuntime(),r=n.get(i.uid);switch(e){case"accept":if(t){var a=t.mimes||o.extList2mimes(t,i.can("filter_by_extension"));r.setAttribute("accept",a.join(","))}else r.removeAttribute("accept");break;case"directory":t&&i.can("select_folder")?(r.setAttribute("directory",""),r.setAttribute("webkitdirectory","")):(r.removeAttribute("directory"),r.removeAttribute("webkitdirectory"));break;case"multiple":t&&i.can("select_multiple")?r.setAttribute("multiple",""):r.removeAttribute("multiple")}},disable:function(e){var t,i=this.getRuntime();(t=n.get(i.uid))&&(t.disabled=!!e)},destroy:function(){var t=this.getRuntime(),i=t.getShim(),o=t.getShimContainer(),a=e&&n.get(e.container),u=e&&n.get(e.browse_button);a&&r.removeAllEvents(a,this.uid),u&&(r.removeAllEvents(u,this.uid),u.style.zIndex=s),o&&(r.removeAllEvents(o,this.uid),o.innerHTML=""),i.removeInstance(this.uid),e=o=a=u=i=null}})}return e.FileInput=s}),n("moxie/runtime/html5/file/FileDrop",["moxie/runtime/html5/Runtime","moxie/file/File","moxie/core/utils/Basic","moxie/core/utils/Dom","moxie/core/utils/Events","moxie/core/utils/Mime"],function(e,t,i,n,r,o){function a(){function e(e){if(!e.dataTransfer||!e.dataTransfer.types)return!1;var t=i.toArray(e.dataTransfer.types||[]);return-1!==i.inArray("Files",t)||-1!==i.inArray("public.file-url",t)||-1!==i.inArray("application/x-moz-file",t)}function a(e,i){if(u(e)){var n=new t(f,e);n.relativePath=i||"",p.push(n)}}function s(e){for(var t=[],n=0;n<e.length;n++)[].push.apply(t,e[n].extensions.split(/\s*,\s*/));return-1===i.inArray("*",t)?t:[]}function u(e){if(!g.length)return!0;var t=o.getFileExtension(e.name);return!t||-1!==i.inArray(t,g)}function c(e,t){var n=[];i.each(e,function(e){var t=e.webkitGetAsEntry();t&&(t.isFile?a(e.getAsFile(),t.fullPath):n.push(t))}),n.length?l(n,t):t()}function l(e,t){var n=[];i.each(e,function(e){n.push(function(t){d(e,t)})}),i.inSeries(n,function(){t()})}function d(e,t){e.isFile?e.file(function(i){a(i,e.fullPath),t()},function(){t()}):e.isDirectory?m(e,t):t()}function m(e,t){function i(e){r.readEntries(function(t){t.length?([].push.apply(n,t),i(e)):e()},e)}var n=[],r=e.createReader();i(function(){l(n,t)})}var h,f,p=[],g=[];i.extend(this,{init:function(t){var n,o=this;h=t,f=o.ruid,g=s(h.accept),n=h.container,r.addEvent(n,"dragover",function(t){e(t)&&(t.preventDefault(),t.dataTransfer.dropEffect="copy")},o.uid),r.addEvent(n,"drop",function(t){e(t)&&(t.preventDefault(),p=[],t.dataTransfer.items&&t.dataTransfer.items[0].webkitGetAsEntry?c(t.dataTransfer.items,function(){o.files=p,o.trigger("drop")}):(i.each(t.dataTransfer.files,function(e){a(e)}),o.files=p,o.trigger("drop")))},o.uid),r.addEvent(n,"dragenter",function(){o.trigger("dragenter")},o.uid),r.addEvent(n,"dragleave",function(){o.trigger("dragleave")},o.uid)},destroy:function(){r.removeAllEvents(h&&n.get(h.container),this.uid),f=p=g=h=null,this.getRuntime().getShim().removeInstance(this.uid)}})}return e.FileDrop=a}),n("moxie/runtime/html5/file/FileReader",["moxie/runtime/html5/Runtime","moxie/core/utils/Encode","moxie/core/utils/Basic"],function(e,t,i){function n(){function e(e){return t.atob(e.substring(e.indexOf("base64,")+7))}var n,r=!1;i.extend(this,{read:function(t,o){var a=this;a.result="",n=new window.FileReader,n.addEventListener("progress",function(e){a.trigger(e)}),n.addEventListener("load",function(t){a.result=r?e(n.result):n.result,a.trigger(t)}),n.addEventListener("error",function(e){a.trigger(e,n.error)}),n.addEventListener("loadend",function(e){n=null,a.trigger(e)}),"function"===i.typeOf(n[t])?(r=!1,n[t](o.getSource())):"readAsBinaryString"===t&&(r=!0,n.readAsDataURL(o.getSource()))},abort:function(){n&&n.abort()},destroy:function(){n=null,this.getRuntime().getShim().removeInstance(this.uid)}})}return e.FileReader=n}),n("moxie/runtime/html5/xhr/XMLHttpRequest",["moxie/runtime/html5/Runtime","moxie/core/utils/Basic","moxie/core/utils/Mime","moxie/core/utils/Url","moxie/file/File","moxie/file/Blob","moxie/xhr/FormData","moxie/core/Exceptions","moxie/core/utils/Env"],function(e,t,i,n,r,o,a,s,u){function c(){function e(e,t){var i,n,r=this;i=t.getBlob().getSource(),n=new window.FileReader,n.onload=function(){t.append(t.getBlobName(),new o(null,{type:i.type,data:n.result})),f.send.call(r,e,t)},n.readAsBinaryString(i)}function c(){return!window.XMLHttpRequest||"IE"===u.browser&&u.verComp(u.version,8,"<")?function(){for(var e=["Msxml2.XMLHTTP.6.0","Microsoft.XMLHTTP"],t=0;t<e.length;t++)try{return new ActiveXObject(e[t])}catch(i){}}():new window.XMLHttpRequest}function l(e){var t=e.responseXML,i=e.responseText;return"IE"===u.browser&&i&&t&&!t.documentElement&&/[^\/]+\/[^\+]+\+xml/.test(e.getResponseHeader("Content-Type"))&&(t=new window.ActiveXObject("Microsoft.XMLDOM"),t.async=!1,t.validateOnParse=!1,t.loadXML(i)),t&&("IE"===u.browser&&0!==t.parseError||!t.documentElement||"parsererror"===t.documentElement.tagName)?null:t
+}function d(e){var t="----moxieboundary"+(new Date).getTime(),i="--",n="\r\n",r="",a=this.getRuntime();if(!a.can("send_binary_string"))throw new s.RuntimeError(s.RuntimeError.NOT_SUPPORTED_ERR);return m.setRequestHeader("Content-Type","multipart/form-data; boundary="+t),e.each(function(e,a){r+=e instanceof o?i+t+n+'Content-Disposition: form-data; name="'+a+'"; filename="'+unescape(encodeURIComponent(e.name||"blob"))+'"'+n+"Content-Type: "+(e.type||"application/octet-stream")+n+n+e.getSource()+n:i+t+n+'Content-Disposition: form-data; name="'+a+'"'+n+n+unescape(encodeURIComponent(e))+n}),r+=i+t+i+n}var m,h,f=this;t.extend(this,{send:function(i,r){var s=this,l="Mozilla"===u.browser&&u.verComp(u.version,4,">=")&&u.verComp(u.version,7,"<"),f="Android Browser"===u.browser,p=!1;if(h=i.url.replace(/^.+?\/([\w\-\.]+)$/,"$1").toLowerCase(),m=c(),m.open(i.method,i.url,i.async,i.user,i.password),r instanceof o)r.isDetached()&&(p=!0),r=r.getSource();else if(r instanceof a){if(r.hasBlob())if(r.getBlob().isDetached())r=d.call(s,r),p=!0;else if((l||f)&&"blob"===t.typeOf(r.getBlob().getSource())&&window.FileReader)return e.call(s,i,r),void 0;if(r instanceof a){var g=new window.FormData;r.each(function(e,t){e instanceof o?g.append(t,e.getSource()):g.append(t,e)}),r=g}}m.upload?(i.withCredentials&&(m.withCredentials=!0),m.addEventListener("load",function(e){s.trigger(e)}),m.addEventListener("error",function(e){s.trigger(e)}),m.addEventListener("progress",function(e){s.trigger(e)}),m.upload.addEventListener("progress",function(e){s.trigger({type:"UploadProgress",loaded:e.loaded,total:e.total})})):m.onreadystatechange=function(){switch(m.readyState){case 1:break;case 2:break;case 3:var e,t;try{n.hasSameOrigin(i.url)&&(e=m.getResponseHeader("Content-Length")||0),m.responseText&&(t=m.responseText.length)}catch(r){e=t=0}s.trigger({type:"progress",lengthComputable:!!e,total:parseInt(e,10),loaded:t});break;case 4:m.onreadystatechange=function(){};try{if(m.status>=200&&m.status<400){s.trigger("load");break}}catch(r){}s.trigger("error")}},t.isEmptyObj(i.headers)||t.each(i.headers,function(e,t){m.setRequestHeader(t,e)}),""!==i.responseType&&"responseType"in m&&(m.responseType="json"!==i.responseType||u.can("return_response_type","json")?i.responseType:"text"),p?m.sendAsBinary?m.sendAsBinary(r):function(){for(var e=new Uint8Array(r.length),t=0;t<r.length;t++)e[t]=255&r.charCodeAt(t);m.send(e.buffer)}():m.send(r),s.trigger("loadstart")},getStatus:function(){try{if(m)return m.status}catch(e){}return 0},getResponse:function(e){var t=this.getRuntime();try{switch(e){case"blob":var n=new r(t.uid,m.response),o=m.getResponseHeader("Content-Disposition");if(o){var a=o.match(/filename=([\'\"'])([^\1]+)\1/);a&&(h=a[2])}return n.name=h,n.type||(n.type=i.getFileMime(h)),n;case"json":return u.can("return_response_type","json")?m.response:200===m.status&&window.JSON?JSON.parse(m.responseText):null;case"document":return l(m);default:return""!==m.responseText?m.responseText:null}}catch(s){return null}},getAllResponseHeaders:function(){try{return m.getAllResponseHeaders()}catch(e){}return""},abort:function(){m&&m.abort()},destroy:function(){f=h=null,this.getRuntime().getShim().removeInstance(this.uid)}})}return e.XMLHttpRequest=c}),n("moxie/runtime/html5/utils/BinaryReader",["moxie/core/utils/Basic"],function(e){function t(e){e instanceof ArrayBuffer?i.apply(this,arguments):n.apply(this,arguments)}function i(t){var i=new DataView(t);e.extend(this,{readByteAt:function(e){return i.getUint8(e)},writeByteAt:function(e,t){i.setUint8(e,t)},SEGMENT:function(e,n,r){switch(arguments.length){case 2:return t.slice(e,e+n);case 1:return t.slice(e);case 3:if(null===r&&(r=new ArrayBuffer),r instanceof ArrayBuffer){var o=new Uint8Array(this.length()-n+r.byteLength);e>0&&o.set(new Uint8Array(t.slice(0,e)),0),o.set(new Uint8Array(r),e),o.set(new Uint8Array(t.slice(e+n)),e+r.byteLength),this.clear(),t=o.buffer,i=new DataView(t);break}default:return t}},length:function(){return t?t.byteLength:0},clear:function(){i=t=null}})}function n(t){function i(e,i,n){n=3===arguments.length?n:t.length-i-1,t=t.substr(0,i)+e+t.substr(n+i)}e.extend(this,{readByteAt:function(e){return t.charCodeAt(e)},writeByteAt:function(e,t){i(String.fromCharCode(t),e,1)},SEGMENT:function(e,n,r){switch(arguments.length){case 1:return t.substr(e);case 2:return t.substr(e,n);case 3:i(null!==r?r:"",e,n);break;default:return t}},length:function(){return t?t.length:0},clear:function(){t=null}})}return e.extend(t.prototype,{littleEndian:!1,read:function(e,t){var i,n,r;if(e+t>this.length())throw new Error("You are trying to read outside the source boundaries.");for(n=this.littleEndian?0:-8*(t-1),r=0,i=0;t>r;r++)i|=this.readByteAt(e+r)<<Math.abs(n+8*r);return i},write:function(e,t,i){var n,r;if(e>this.length())throw new Error("You are trying to write outside the source boundaries.");for(n=this.littleEndian?0:-8*(i-1),r=0;i>r;r++)this.writeByteAt(e+r,255&t>>Math.abs(n+8*r))},BYTE:function(e){return this.read(e,1)},SHORT:function(e){return this.read(e,2)},LONG:function(e){return this.read(e,4)},SLONG:function(e){var t=this.read(e,4);return t>2147483647?t-4294967296:t},CHAR:function(e){return String.fromCharCode(this.read(e,1))},STRING:function(e,t){return this.asArray("CHAR",e,t).join("")},asArray:function(e,t,i){for(var n=[],r=0;i>r;r++)n[r]=this[e](t+r);return n}}),t}),n("moxie/runtime/html5/image/JPEGHeaders",["moxie/runtime/html5/utils/BinaryReader","moxie/core/Exceptions"],function(e,t){return function i(n){var r,o,a,s=[],u=0;if(r=new e(n),65496!==r.SHORT(0))throw r.clear(),new t.ImageError(t.ImageError.WRONG_FORMAT);for(o=2;o<=r.length();)if(a=r.SHORT(o),a>=65488&&65495>=a)o+=2;else{if(65498===a||65497===a)break;u=r.SHORT(o+2)+2,a>=65505&&65519>=a&&s.push({hex:a,name:"APP"+(15&a),start:o,length:u,segment:r.SEGMENT(o,u)}),o+=u}return r.clear(),{headers:s,restore:function(t){var i,n,r;for(r=new e(t),o=65504==r.SHORT(2)?4+r.SHORT(4):2,n=0,i=s.length;i>n;n++)r.SEGMENT(o,0,s[n].segment),o+=s[n].length;return t=r.SEGMENT(),r.clear(),t},strip:function(t){var n,r,o,a;for(o=new i(t),r=o.headers,o.purge(),n=new e(t),a=r.length;a--;)n.SEGMENT(r[a].start,r[a].length,"");return t=n.SEGMENT(),n.clear(),t},get:function(e){for(var t=[],i=0,n=s.length;n>i;i++)s[i].name===e.toUpperCase()&&t.push(s[i].segment);return t},set:function(e,t){var i,n,r,o=[];for("string"==typeof t?o.push(t):o=t,i=n=0,r=s.length;r>i&&(s[i].name===e.toUpperCase()&&(s[i].segment=o[n],s[i].length=o[n].length,n++),!(n>=o.length));i++);},purge:function(){this.headers=s=[]}}}}),n("moxie/runtime/html5/image/ExifParser",["moxie/core/utils/Basic","moxie/runtime/html5/utils/BinaryReader","moxie/core/Exceptions"],function(e,i,n){function r(o){function a(i,r){var o,a,s,u,c,m,h,f,p=this,g=[],x={},v={1:"BYTE",7:"UNDEFINED",2:"ASCII",3:"SHORT",4:"LONG",5:"RATIONAL",9:"SLONG",10:"SRATIONAL"},w={BYTE:1,UNDEFINED:1,ASCII:1,SHORT:2,LONG:4,RATIONAL:8,SLONG:4,SRATIONAL:8};for(o=p.SHORT(i),a=0;o>a;a++)if(g=[],h=i+2+12*a,s=r[p.SHORT(h)],s!==t){if(u=v[p.SHORT(h+=2)],c=p.LONG(h+=2),m=w[u],!m)throw new n.ImageError(n.ImageError.INVALID_META_ERR);if(h+=4,m*c>4&&(h=p.LONG(h)+d.tiffHeader),h+m*c>=this.length())throw new n.ImageError(n.ImageError.INVALID_META_ERR);"ASCII"!==u?(g=p.asArray(u,h,c),f=1==c?g[0]:g,x[s]=l.hasOwnProperty(s)&&"object"!=typeof f?l[s][f]:f):x[s]=e.trim(p.STRING(h,c).replace(/\0$/,""))}return x}function s(e,t,i){var n,r,o,a=0;if("string"==typeof t){var s=c[e.toLowerCase()];for(var u in s)if(s[u]===t){t=u;break}}n=d[e.toLowerCase()+"IFD"],r=this.SHORT(n);for(var l=0;r>l;l++)if(o=n+12*l+2,this.SHORT(o)==t){a=o+8;break}if(!a)return!1;try{this.write(a,i,4)}catch(m){return!1}return!0}var u,c,l,d,m,h;if(i.call(this,o),c={tiff:{274:"Orientation",270:"ImageDescription",271:"Make",272:"Model",305:"Software",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer"},exif:{36864:"ExifVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",36867:"DateTimeOriginal",33434:"ExposureTime",33437:"FNumber",34855:"ISOSpeedRatings",37377:"ShutterSpeedValue",37378:"ApertureValue",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37386:"FocalLength",41986:"ExposureMode",41987:"WhiteBalance",41990:"SceneCaptureType",41988:"DigitalZoomRatio",41992:"Contrast",41993:"Saturation",41994:"Sharpness"},gps:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude"},thumb:{513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength"}},l={ColorSpace:{1:"sRGB",0:"Uncalibrated"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{1:"Daylight",2:"Fliorescent",3:"Tungsten",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 -5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},ExposureMode:{0:"Auto exposure",1:"Manual exposure",2:"Auto bracket"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},GPSLatitudeRef:{N:"North latitude",S:"South latitude"},GPSLongitudeRef:{E:"East longitude",W:"West longitude"}},d={tiffHeader:10},m=d.tiffHeader,u={clear:this.clear},e.extend(this,{read:function(){try{return r.prototype.read.apply(this,arguments)}catch(e){throw new n.ImageError(n.ImageError.INVALID_META_ERR)}},write:function(){try{return r.prototype.write.apply(this,arguments)}catch(e){throw new n.ImageError(n.ImageError.INVALID_META_ERR)}},UNDEFINED:function(){return this.BYTE.apply(this,arguments)},RATIONAL:function(e){return this.LONG(e)/this.LONG(e+4)},SRATIONAL:function(e){return this.SLONG(e)/this.SLONG(e+4)},ASCII:function(e){return this.CHAR(e)},TIFF:function(){return h||null},EXIF:function(){var t=null;if(d.exifIFD){try{t=a.call(this,d.exifIFD,c.exif)}catch(i){return null}if(t.ExifVersion&&"array"===e.typeOf(t.ExifVersion)){for(var n=0,r="";n<t.ExifVersion.length;n++)r+=String.fromCharCode(t.ExifVersion[n]);t.ExifVersion=r}}return t},GPS:function(){var t=null;if(d.gpsIFD){try{t=a.call(this,d.gpsIFD,c.gps)}catch(i){return null}t.GPSVersionID&&"array"===e.typeOf(t.GPSVersionID)&&(t.GPSVersionID=t.GPSVersionID.join("."))}return t},thumb:function(){if(d.IFD1)try{var e=a.call(this,d.IFD1,c.thumb);if("JPEGInterchangeFormat"in e)return this.SEGMENT(d.tiffHeader+e.JPEGInterchangeFormat,e.JPEGInterchangeFormatLength)}catch(t){}return null},setExif:function(e,t){return"PixelXDimension"!==e&&"PixelYDimension"!==e?!1:s.call(this,"exif",e,t)},clear:function(){u.clear(),o=c=l=h=d=u=null}}),65505!==this.SHORT(0)||"EXIF\0"!==this.STRING(4,5).toUpperCase())throw new n.ImageError(n.ImageError.INVALID_META_ERR);if(this.littleEndian=18761==this.SHORT(m),42!==this.SHORT(m+=2))throw new n.ImageError(n.ImageError.INVALID_META_ERR);d.IFD0=d.tiffHeader+this.LONG(m+=2),h=a.call(this,d.IFD0,c.tiff),"ExifIFDPointer"in h&&(d.exifIFD=d.tiffHeader+h.ExifIFDPointer,delete h.ExifIFDPointer),"GPSInfoIFDPointer"in h&&(d.gpsIFD=d.tiffHeader+h.GPSInfoIFDPointer,delete h.GPSInfoIFDPointer),e.isEmptyObj(h)&&(h=null);var f=this.LONG(d.IFD0+12*this.SHORT(d.IFD0)+2);f&&(d.IFD1=d.tiffHeader+f)}return r.prototype=i.prototype,r}),n("moxie/runtime/html5/image/JPEG",["moxie/core/utils/Basic","moxie/core/Exceptions","moxie/runtime/html5/image/JPEGHeaders","moxie/runtime/html5/utils/BinaryReader","moxie/runtime/html5/image/ExifParser"],function(e,t,i,n,r){function o(o){function a(e){var t,i,n=0;for(e||(e=c);n<=e.length();){if(t=e.SHORT(n+=2),t>=65472&&65475>=t)return n+=5,{height:e.SHORT(n),width:e.SHORT(n+=2)};i=e.SHORT(n+=2),n+=i-2}return null}function s(){var e,t,i=d.thumb();return i&&(e=new n(i),t=a(e),e.clear(),t)?(t.data=i,t):null}function u(){d&&l&&c&&(d.clear(),l.purge(),c.clear(),m=l=d=c=null)}var c,l,d,m;if(c=new n(o),65496!==c.SHORT(0))throw new t.ImageError(t.ImageError.WRONG_FORMAT);l=new i(o);try{d=new r(l.get("app1")[0])}catch(h){}m=a.call(this),e.extend(this,{type:"image/jpeg",size:c.length(),width:m&&m.width||0,height:m&&m.height||0,setExif:function(t,i){return d?("object"===e.typeOf(t)?e.each(t,function(e,t){d.setExif(t,e)}):d.setExif(t,i),l.set("app1",d.SEGMENT()),void 0):!1},writeHeaders:function(){return arguments.length?l.restore(arguments[0]):l.restore(o)},stripHeaders:function(e){return l.strip(e)},purge:function(){u.call(this)}}),d&&(this.meta={tiff:d.TIFF(),exif:d.EXIF(),gps:d.GPS(),thumb:s()})}return o}),n("moxie/runtime/html5/image/PNG",["moxie/core/Exceptions","moxie/core/utils/Basic","moxie/runtime/html5/utils/BinaryReader"],function(e,t,i){function n(n){function r(){var e,t;return e=a.call(this,8),"IHDR"==e.type?(t=e.start,{width:s.LONG(t),height:s.LONG(t+=4)}):null}function o(){s&&(s.clear(),n=l=u=c=s=null)}function a(e){var t,i,n,r;return t=s.LONG(e),i=s.STRING(e+=4,4),n=e+=4,r=s.LONG(e+t),{length:t,type:i,start:n,CRC:r}}var s,u,c,l;s=new i(n),function(){var t=0,i=0,n=[35152,20039,3338,6666];for(i=0;i<n.length;i++,t+=2)if(n[i]!=s.SHORT(t))throw new e.ImageError(e.ImageError.WRONG_FORMAT)}(),l=r.call(this),t.extend(this,{type:"image/png",size:s.length(),width:l.width,height:l.height,purge:function(){o.call(this)}}),o.call(this)}return n}),n("moxie/runtime/html5/image/ImageInfo",["moxie/core/utils/Basic","moxie/core/Exceptions","moxie/runtime/html5/image/JPEG","moxie/runtime/html5/image/PNG"],function(e,t,i,n){return function(r){var o,a=[i,n];o=function(){for(var e=0;e<a.length;e++)try{return new a[e](r)}catch(i){}throw new t.ImageError(t.ImageError.WRONG_FORMAT)}(),e.extend(this,{type:"",size:0,width:0,height:0,setExif:function(){},writeHeaders:function(e){return e},stripHeaders:function(e){return e},purge:function(){r=null}}),e.extend(this,o),this.purge=function(){o.purge(),o=null}}}),n("moxie/runtime/html5/image/ResizerCanvas",[],function(){function e(i,n,r){var o=i.width>i.height?"width":"height",a=Math.round(i[o]*n),s=!1;"nearest"!==r&&(.5>n||n>2)&&(n=.5>n?.5:2,s=!0);var u=t(i,n);return s?e(u,a/u[o],r):u}function t(e,t){var i=e.width,n=e.height,r=Math.round(i*t),o=Math.round(n*t),a=document.createElement("canvas");return a.width=r,a.height=o,a.getContext("2d").drawImage(e,0,0,i,n,0,0,r,o),e=null,a}return{scale:e}}),n("moxie/runtime/html5/image/Image",["moxie/runtime/html5/Runtime","moxie/core/utils/Basic","moxie/core/Exceptions","moxie/core/utils/Encode","moxie/file/Blob","moxie/file/File","moxie/runtime/html5/image/ImageInfo","moxie/runtime/html5/image/ResizerCanvas","moxie/core/utils/Mime","moxie/core/utils/Env"],function(e,t,i,n,r,o,a,s,u){function c(){function e(){if(!v&&!g)throw new i.ImageError(i.DOMException.INVALID_STATE_ERR);return v||g}function c(){var t=e();return"canvas"==t.nodeName.toLowerCase()?t:(v=document.createElement("canvas"),v.width=t.width,v.height=t.height,v.getContext("2d").drawImage(t,0,0),v)}function l(e){return n.atob(e.substring(e.indexOf("base64,")+7))}function d(e,t){return"data:"+(t||"")+";base64,"+n.btoa(e)}function m(e){var t=this;g=new Image,g.onerror=function(){p.call(this),t.trigger("error",i.ImageError.WRONG_FORMAT)},g.onload=function(){t.trigger("load")},g.src="data:"==e.substr(0,5)?e:d(e,y.type)}function h(e,t){var n,r=this;return window.FileReader?(n=new FileReader,n.onload=function(){t.call(r,this.result)},n.onerror=function(){r.trigger("error",i.ImageError.WRONG_FORMAT)},n.readAsDataURL(e),void 0):t.call(this,e.getAsDataURL())}function f(e,i){var n=Math.PI/180,r=document.createElement("canvas"),o=r.getContext("2d"),a=e.width,s=e.height;switch(t.inArray(i,[5,6,7,8])>-1?(r.width=s,r.height=a):(r.width=a,r.height=s),i){case 2:o.translate(a,0),o.scale(-1,1);break;case 3:o.translate(a,s),o.rotate(180*n);break;case 4:o.translate(0,s),o.scale(1,-1);break;case 5:o.rotate(90*n),o.scale(1,-1);break;case 6:o.rotate(90*n),o.translate(0,-s);break;case 7:o.rotate(90*n),o.translate(a,-s),o.scale(-1,1);break;case 8:o.rotate(-90*n),o.translate(-a,0)}return o.drawImage(e,0,0,a,s),r}function p(){x&&(x.purge(),x=null),w=g=v=y=null,b=!1}var g,x,v,w,y,E=this,b=!1,_=!0;t.extend(this,{loadFromBlob:function(e){var t=this.getRuntime(),n=arguments.length>1?arguments[1]:!0;if(!t.can("access_binary"))throw new i.RuntimeError(i.RuntimeError.NOT_SUPPORTED_ERR);return y=e,e.isDetached()?(w=e.getSource(),m.call(this,w),void 0):(h.call(this,e.getSource(),function(e){n&&(w=l(e)),m.call(this,e)}),void 0)},loadFromImage:function(e,t){this.meta=e.meta,y=new o(null,{name:e.name,size:e.size,type:e.type}),m.call(this,t?w=e.getAsBinaryString():e.getAsDataURL())},getInfo:function(){var t,i=this.getRuntime();return!x&&w&&i.can("access_image_binary")&&(x=new a(w)),t={width:e().width||0,height:e().height||0,type:y.type||u.getFileMime(y.name),size:w&&w.length||y.size||0,name:y.name||"",meta:null},_&&(t.meta=x&&x.meta||this.meta||{},!t.meta||!t.meta.thumb||t.meta.thumb.data instanceof r||(t.meta.thumb.data=new r(null,{type:"image/jpeg",data:t.meta.thumb.data}))),t},resize:function(t,i,n){var r=document.createElement("canvas");if(r.width=t.width,r.height=t.height,r.getContext("2d").drawImage(e(),t.x,t.y,t.width,t.height,0,0,r.width,r.height),v=s.scale(r,i),_=n.preserveHeaders,!_){var o=this.meta&&this.meta.tiff&&this.meta.tiff.Orientation||1;v=f(v,o)}this.width=v.width,this.height=v.height,b=!0,this.trigger("Resize")},getAsCanvas:function(){return v||(v=c()),v.id=this.uid+"_canvas",v},getAsBlob:function(e,t){return e!==this.type?(b=!0,new o(null,{name:y.name||"",type:e,data:E.getAsDataURL(e,t)})):new o(null,{name:y.name||"",type:e,data:E.getAsBinaryString(e,t)})},getAsDataURL:function(e){var t=arguments[1]||90;if(!b)return g.src;if(c(),"image/jpeg"!==e)return v.toDataURL("image/png");try{return v.toDataURL("image/jpeg",t/100)}catch(i){return v.toDataURL("image/jpeg")}},getAsBinaryString:function(e,t){if(!b)return w||(w=l(E.getAsDataURL(e,t))),w;if("image/jpeg"!==e)w=l(E.getAsDataURL(e,t));else{var i;t||(t=90),c();try{i=v.toDataURL("image/jpeg",t/100)}catch(n){i=v.toDataURL("image/jpeg")}w=l(i),x&&(w=x.stripHeaders(w),_&&(x.meta&&x.meta.exif&&x.setExif({PixelXDimension:this.width,PixelYDimension:this.height}),w=x.writeHeaders(w)),x.purge(),x=null)}return b=!1,w},destroy:function(){E=null,p.call(this),this.getRuntime().getShim().removeInstance(this.uid)}})}return e.Image=c}),n("moxie/runtime/flash/Runtime",["moxie/core/utils/Basic","moxie/core/utils/Env","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/runtime/Runtime"],function(e,t,i,n,o){function a(){var e;try{e=navigator.plugins["Shockwave Flash"],e=e.description}catch(t){try{e=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(i){e="0.0"}}return e=e.match(/\d+/g),parseFloat(e[0]+"."+e[1])}function s(e){var n=i.get(e);n&&"OBJECT"==n.nodeName&&("IE"===t.browser?(n.style.display="none",function r(){4==n.readyState?u(e):setTimeout(r,10)}()):n.parentNode.removeChild(n))}function u(e){var t=i.get(e);if(t){for(var n in t)"function"==typeof t[n]&&(t[n]=null);t.parentNode.removeChild(t)}}function c(u){var c,m=this;u=e.extend({swf_url:t.swf_url},u),o.call(this,u,l,{access_binary:function(e){return e&&"browser"===m.mode},access_image_binary:function(e){return e&&"browser"===m.mode},display_media:o.capTest(r("moxie/image/Image")),do_cors:o.capTrue,drag_and_drop:!1,report_upload_progress:function(){return"client"===m.mode},resize_image:o.capTrue,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!e.arrayDiff(t,["","text","document"])||"browser"===m.mode},return_status_code:function(t){return"browser"===m.mode||!e.arrayDiff(t,[200,404])},select_file:o.capTrue,select_multiple:o.capTrue,send_binary_string:function(e){return e&&"browser"===m.mode},send_browser_cookies:function(e){return e&&"browser"===m.mode},send_custom_headers:function(e){return e&&"browser"===m.mode},send_multipart:o.capTrue,slice_blob:function(e){return e&&"browser"===m.mode},stream_upload:function(e){return e&&"browser"===m.mode},summon_file_dialog:!1,upload_filesize:function(t){return e.parseSizeStr(t)<=2097152||"client"===m.mode},use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}},{access_binary:function(e){return e?"browser":"client"},access_image_binary:function(e){return e?"browser":"client"},report_upload_progress:function(e){return e?"browser":"client"},return_response_type:function(t){return e.arrayDiff(t,["","text","json","document"])?"browser":["client","browser"]},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"browser":["client","browser"]},send_binary_string:function(e){return e?"browser":"client"},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"browser":"client"},slice_blob:function(e){return e?"browser":"client"},stream_upload:function(e){return e?"client":"browser"},upload_filesize:function(t){return e.parseSizeStr(t)>=2097152?"client":"browser"}},"client"),a()<11.3&&(this.mode=!1),e.extend(this,{getShim:function(){return i.get(this.uid)},shimExec:function(e,t){var i=[].slice.call(arguments,2);return m.getShim().exec(this.uid,e,t,i)},init:function(){var i,r,a;a=this.getShimContainer(),e.extend(a.style,{position:"absolute",top:"-8px",left:"-8px",width:"9px",height:"9px",overflow:"hidden"}),i='<object id="'+this.uid+'" type="application/x-shockwave-flash" data="'+u.swf_url+'" ',"IE"===t.browser&&(i+='classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '),i+='width="100%" height="100%" style="outline:0"><param name="movie" value="'+u.swf_url+'" />'+'<param name="flashvars" value="uid='+escape(this.uid)+"&target="+o.getGlobalEventTarget()+'" />'+'<param name="wmode" value="transparent" />'+'<param name="allowscriptaccess" value="always" />'+"</object>","IE"===t.browser?(r=document.createElement("div"),a.appendChild(r),r.outerHTML=i,r=a=null):a.innerHTML=i,c=setTimeout(function(){m&&!m.initialized&&m.trigger("Error",new n.RuntimeError(n.RuntimeError.NOT_INIT_ERR))},5e3)},destroy:function(e){return function(){s(m.uid),e.call(m),clearTimeout(c),u=c=e=m=null}}(this.destroy)},d)}var l="flash",d={};return o.addConstructor(l,c),d}),n("moxie/runtime/flash/file/Blob",["moxie/runtime/flash/Runtime","moxie/file/Blob"],function(e,t){var i={slice:function(e,i,n,r){var o=this.getRuntime();return 0>i?i=Math.max(e.size+i,0):i>0&&(i=Math.min(i,e.size)),0>n?n=Math.max(e.size+n,0):n>0&&(n=Math.min(n,e.size)),e=o.shimExec.call(this,"Blob","slice",i,n,r||""),e&&(e=new t(o.uid,e)),e}};return e.Blob=i}),n("moxie/runtime/flash/file/FileInput",["moxie/runtime/flash/Runtime","moxie/file/File","moxie/core/utils/Dom","moxie/core/utils/Basic"],function(e,t,i,n){var r={init:function(e){var r=this,o=this.getRuntime(),a=i.get(e.browse_button);a&&(a.setAttribute("tabindex",-1),a=null),this.bind("Change",function(){var e=o.shimExec.call(r,"FileInput","getFiles");r.files=[],n.each(e,function(e){r.files.push(new t(o.uid,e))})},999),this.getRuntime().shimExec.call(this,"FileInput","init",{accept:e.accept,multiple:e.multiple}),this.trigger("ready")}};return e.FileInput=r}),n("moxie/runtime/flash/file/FileReader",["moxie/runtime/flash/Runtime","moxie/core/utils/Encode"],function(e,t){function i(e,i){switch(i){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var n={read:function(e,t){var n=this;return n.result="","readAsDataURL"===e&&(n.result="data:"+(t.type||"")+";base64,"),n.bind("Progress",function(t,r){r&&(n.result+=i(r,e))},999),n.getRuntime().shimExec.call(this,"FileReader","readAsBase64",t.uid)}};return e.FileReader=n}),n("moxie/runtime/flash/file/FileReaderSync",["moxie/runtime/flash/Runtime","moxie/core/utils/Encode"],function(e,t){function i(e,i){switch(i){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var n={read:function(e,t){var n,r=this.getRuntime();return(n=r.shimExec.call(this,"FileReaderSync","readAsBase64",t.uid))?("readAsDataURL"===e&&(n="data:"+(t.type||"")+";base64,"+n),i(n,e,t.type)):null}};return e.FileReaderSync=n}),n("moxie/runtime/flash/runtime/Transporter",["moxie/runtime/flash/Runtime","moxie/file/Blob"],function(e,t){var i={getAsBlob:function(e){var i=this.getRuntime(),n=i.shimExec.call(this,"Transporter","getAsBlob",e);return n?new t(i.uid,n):null}};return e.Transporter=i}),n("moxie/runtime/flash/xhr/XMLHttpRequest",["moxie/runtime/flash/Runtime","moxie/core/utils/Basic","moxie/file/Blob","moxie/file/File","moxie/file/FileReaderSync","moxie/runtime/flash/file/FileReaderSync","moxie/xhr/FormData","moxie/runtime/Transporter","moxie/runtime/flash/runtime/Transporter"],function(e,t,i,n,r,o,a,s){var u={send:function(e,n){function r(){e.transport=l.mode,l.shimExec.call(c,"XMLHttpRequest","send",e,n)}function o(e,t){l.shimExec.call(c,"XMLHttpRequest","appendBlob",e,t.uid),n=null,r()}function u(e,t){var i=new s;i.bind("TransportingComplete",function(){t(this.result)}),i.transport(e.getSource(),e.type,{ruid:l.uid})}var c=this,l=c.getRuntime();if(t.isEmptyObj(e.headers)||t.each(e.headers,function(e,t){l.shimExec.call(c,"XMLHttpRequest","setRequestHeader",t,e.toString())}),n instanceof a){var d;if(n.each(function(e,t){e instanceof i?d=t:l.shimExec.call(c,"XMLHttpRequest","append",t,e)}),n.hasBlob()){var m=n.getBlob();m.isDetached()?u(m,function(e){m.destroy(),o(d,e)}):o(d,m)}else n=null,r()}else n instanceof i?n.isDetached()?u(n,function(e){n.destroy(),n=e.uid,r()}):(n=n.uid,r()):r()},getResponse:function(e){var i,o,a=this.getRuntime();if(o=a.shimExec.call(this,"XMLHttpRequest","getResponseAsBlob")){if(o=new n(a.uid,o),"blob"===e)return o;try{if(i=new r,~t.inArray(e,["","text"]))return i.readAsText(o);if("json"===e&&window.JSON)return JSON.parse(i.readAsText(o))}finally{o.destroy()}}return null},abort:function(){var e=this.getRuntime();e.shimExec.call(this,"XMLHttpRequest","abort"),this.dispatchEvent("readystatechange"),this.dispatchEvent("abort")}};return e.XMLHttpRequest=u}),n("moxie/runtime/flash/image/Image",["moxie/runtime/flash/Runtime","moxie/core/utils/Basic","moxie/runtime/Transporter","moxie/file/Blob","moxie/file/FileReaderSync"],function(e,t,i,n,r){var o={loadFromBlob:function(e){function t(e){r.shimExec.call(n,"Image","loadFromBlob",e.uid),n=r=null}var n=this,r=n.getRuntime();if(e.isDetached()){var o=new i;o.bind("TransportingComplete",function(){t(o.result.getSource())}),o.transport(e.getSource(),e.type,{ruid:r.uid})}else t(e.getSource())},loadFromImage:function(e){var t=this.getRuntime();return t.shimExec.call(this,"Image","loadFromImage",e.uid)},getInfo:function(){var e=this.getRuntime(),t=e.shimExec.call(this,"Image","getInfo");return t.meta&&t.meta.thumb&&t.meta.thumb.data&&!(e.meta.thumb.data instanceof n)&&(t.meta.thumb.data=new n(e.uid,t.meta.thumb.data)),t},getAsBlob:function(e,t){var i=this.getRuntime(),r=i.shimExec.call(this,"Image","getAsBlob",e,t);return r?new n(i.uid,r):null},getAsDataURL:function(){var e,t=this.getRuntime(),i=t.Image.getAsBlob.apply(this,arguments);return i?(e=new r,e.readAsDataURL(i)):null}};return e.Image=o}),n("moxie/runtime/silverlight/Runtime",["moxie/core/utils/Basic","moxie/core/utils/Env","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/runtime/Runtime"],function(e,t,i,n,o){function a(e){var t,i,n,r,o,a=!1,s=null,u=0;try{try{s=new ActiveXObject("AgControl.AgControl"),s.IsVersionSupported(e)&&(a=!0),s=null}catch(c){var l=navigator.plugins["Silverlight Plug-In"];if(l){for(t=l.description,"1.0.30226.2"===t&&(t="2.0.30226.2"),i=t.split(".");i.length>3;)i.pop();for(;i.length<4;)i.push(0);for(n=e.split(".");n.length>4;)n.pop();do r=parseInt(n[u],10),o=parseInt(i[u],10),u++;while(u<n.length&&r===o);o>=r&&!isNaN(r)&&(a=!0)}}}catch(d){a=!1}return a}function s(s){var l,d=this;s=e.extend({xap_url:t.xap_url},s),o.call(this,s,u,{access_binary:o.capTrue,access_image_binary:o.capTrue,display_media:o.capTest(r("moxie/image/Image")),do_cors:o.capTrue,drag_and_drop:!1,report_upload_progress:o.capTrue,resize_image:o.capTrue,return_response_headers:function(e){return e&&"client"===d.mode},return_response_type:function(e){return"json"!==e?!0:!!window.JSON},return_status_code:function(t){return"client"===d.mode||!e.arrayDiff(t,[200,404])},select_file:o.capTrue,select_multiple:o.capTrue,send_binary_string:o.capTrue,send_browser_cookies:function(e){return e&&"browser"===d.mode},send_custom_headers:function(e){return e&&"client"===d.mode},send_multipart:o.capTrue,slice_blob:o.capTrue,stream_upload:!0,summon_file_dialog:!1,upload_filesize:o.capTrue,use_http_method:function(t){return"client"===d.mode||!e.arrayDiff(t,["GET","POST"])}},{return_response_headers:function(e){return e?"client":"browser"},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"client":["client","browser"]},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"client":"browser"},use_http_method:function(t){return e.arrayDiff(t,["GET","POST"])?"client":["client","browser"]}}),a("2.0.31005.0")&&"Opera"!==t.browser||(this.mode=!1),e.extend(this,{getShim:function(){return i.get(this.uid).content.Moxie},shimExec:function(e,t){var i=[].slice.call(arguments,2);return d.getShim().exec(this.uid,e,t,i)},init:function(){var e;e=this.getShimContainer(),e.innerHTML='<object id="'+this.uid+'" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">'+'<param name="source" value="'+s.xap_url+'"/>'+'<param name="background" value="Transparent"/>'+'<param name="windowless" value="true"/>'+'<param name="enablehtmlaccess" value="true"/>'+'<param name="initParams" value="uid='+this.uid+",target="+o.getGlobalEventTarget()+'"/>'+"</object>",l=setTimeout(function(){d&&!d.initialized&&d.trigger("Error",new n.RuntimeError(n.RuntimeError.NOT_INIT_ERR))},"Windows"!==t.OS?1e4:5e3)},destroy:function(e){return function(){e.call(d),clearTimeout(l),s=l=e=d=null}}(this.destroy)},c)}var u="silverlight",c={};return o.addConstructor(u,s),c}),n("moxie/runtime/silverlight/file/Blob",["moxie/runtime/silverlight/Runtime","moxie/core/utils/Basic","moxie/runtime/flash/file/Blob"],function(e,t,i){return e.Blob=t.extend({},i)}),n("moxie/runtime/silverlight/file/FileInput",["moxie/runtime/silverlight/Runtime","moxie/file/File","moxie/core/utils/Dom","moxie/core/utils/Basic"],function(e,t,i,n){function r(e){for(var t="",i=0;i<e.length;i++)t+=(""!==t?"|":"")+e[i].title+" | *."+e[i].extensions.replace(/,/g,";*.");return t}var o={init:function(e){var o=this,a=this.getRuntime(),s=i.get(e.browse_button);s&&(s.setAttribute("tabindex",-1),s=null),this.bind("Change",function(){var e=a.shimExec.call(o,"FileInput","getFiles");
+o.files=[],n.each(e,function(e){o.files.push(new t(a.uid,e))})},999),a.shimExec.call(this,"FileInput","init",r(e.accept),e.multiple),this.trigger("ready")},setOption:function(e,t){"accept"==e&&(t=r(t)),this.getRuntime().shimExec.call(this,"FileInput","setOption",e,t)}};return e.FileInput=o}),n("moxie/runtime/silverlight/file/FileDrop",["moxie/runtime/silverlight/Runtime","moxie/core/utils/Dom","moxie/core/utils/Events"],function(e,t,i){var n={init:function(){var e,n=this,r=n.getRuntime();return e=r.getShimContainer(),i.addEvent(e,"dragover",function(e){e.preventDefault(),e.stopPropagation(),e.dataTransfer.dropEffect="copy"},n.uid),i.addEvent(e,"dragenter",function(e){e.preventDefault();var i=t.get(r.uid).dragEnter(e);i&&e.stopPropagation()},n.uid),i.addEvent(e,"drop",function(e){e.preventDefault();var i=t.get(r.uid).dragDrop(e);i&&e.stopPropagation()},n.uid),r.shimExec.call(this,"FileDrop","init")}};return e.FileDrop=n}),n("moxie/runtime/silverlight/file/FileReader",["moxie/runtime/silverlight/Runtime","moxie/core/utils/Basic","moxie/runtime/flash/file/FileReader"],function(e,t,i){return e.FileReader=t.extend({},i)}),n("moxie/runtime/silverlight/file/FileReaderSync",["moxie/runtime/silverlight/Runtime","moxie/core/utils/Basic","moxie/runtime/flash/file/FileReaderSync"],function(e,t,i){return e.FileReaderSync=t.extend({},i)}),n("moxie/runtime/silverlight/runtime/Transporter",["moxie/runtime/silverlight/Runtime","moxie/core/utils/Basic","moxie/runtime/flash/runtime/Transporter"],function(e,t,i){return e.Transporter=t.extend({},i)}),n("moxie/runtime/silverlight/xhr/XMLHttpRequest",["moxie/runtime/silverlight/Runtime","moxie/core/utils/Basic","moxie/runtime/flash/xhr/XMLHttpRequest","moxie/runtime/silverlight/file/FileReaderSync","moxie/runtime/silverlight/runtime/Transporter"],function(e,t,i){return e.XMLHttpRequest=t.extend({},i)}),n("moxie/runtime/silverlight/image/Image",["moxie/runtime/silverlight/Runtime","moxie/core/utils/Basic","moxie/file/Blob","moxie/runtime/flash/image/Image"],function(e,t,i,n){return e.Image=t.extend({},n,{getInfo:function(){var e=this.getRuntime(),n=["tiff","exif","gps","thumb"],r={meta:{}},o=e.shimExec.call(this,"Image","getInfo");return o.meta&&(t.each(n,function(e){var t,i,n,a,s=o.meta[e];if(s&&s.keys)for(r.meta[e]={},i=0,n=s.keys.length;n>i;i++)t=s.keys[i],a=s[t],a&&(/^(\d|[1-9]\d+)$/.test(a)?a=parseInt(a,10):/^\d*\.\d+$/.test(a)&&(a=parseFloat(a)),r.meta[e][t]=a)}),r.meta&&r.meta.thumb&&r.meta.thumb.data&&!(e.meta.thumb.data instanceof i)&&(r.meta.thumb.data=new i(e.uid,r.meta.thumb.data))),r.width=parseInt(o.width,10),r.height=parseInt(o.height,10),r.size=parseInt(o.size,10),r.type=o.type,r.name=o.name,r},resize:function(e,t,i){this.getRuntime().shimExec.call(this,"Image","resize",e.x,e.y,e.width,e.height,t,i.preserveHeaders,i.resample)}})}),n("moxie/runtime/html4/Runtime",["moxie/core/utils/Basic","moxie/core/Exceptions","moxie/runtime/Runtime","moxie/core/utils/Env"],function(e,t,i,n){function o(t){var o=this,u=i.capTest,c=i.capTrue;i.call(this,t,a,{access_binary:u(window.FileReader||window.File&&File.getAsDataURL),access_image_binary:!1,display_media:u((n.can("create_canvas")||n.can("use_data_uri_over32kb"))&&r("moxie/image/Image")),do_cors:!1,drag_and_drop:!1,filter_by_extension:u(function(){return!("Chrome"===n.browser&&n.verComp(n.version,28,"<")||"IE"===n.browser&&n.verComp(n.version,10,"<")||"Safari"===n.browser&&n.verComp(n.version,7,"<")||"Firefox"===n.browser&&n.verComp(n.version,37,"<"))}()),resize_image:function(){return s.Image&&o.can("access_binary")&&n.can("create_canvas")},report_upload_progress:!1,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!!~e.inArray(t,["text","document",""])},return_status_code:function(t){return!e.arrayDiff(t,[200,404])},select_file:function(){return n.can("use_fileinput")},select_multiple:!1,send_binary_string:!1,send_custom_headers:!1,send_multipart:!0,slice_blob:!1,stream_upload:function(){return o.can("select_file")},summon_file_dialog:function(){return o.can("select_file")&&!("Firefox"===n.browser&&n.verComp(n.version,4,"<")||"Opera"===n.browser&&n.verComp(n.version,12,"<")||"IE"===n.browser&&n.verComp(n.version,10,"<"))},upload_filesize:c,use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}}),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(o),e=o=null}}(this.destroy)}),e.extend(this.getShim(),s)}var a="html4",s={};return i.addConstructor(a,o),s}),n("moxie/runtime/html4/file/FileInput",["moxie/runtime/html4/Runtime","moxie/file/File","moxie/core/utils/Basic","moxie/core/utils/Dom","moxie/core/utils/Events","moxie/core/utils/Mime","moxie/core/utils/Env"],function(e,t,i,n,r,o,a){function s(){function e(){var o,c,d,m,h,f,p=this,g=p.getRuntime();f=i.guid("uid_"),o=g.getShimContainer(),s&&(d=n.get(s+"_form"),d&&(i.extend(d.style,{top:"100%"}),d.firstChild.setAttribute("tabindex",-1))),m=document.createElement("form"),m.setAttribute("id",f+"_form"),m.setAttribute("method","post"),m.setAttribute("enctype","multipart/form-data"),m.setAttribute("encoding","multipart/form-data"),i.extend(m.style,{overflow:"hidden",position:"absolute",top:0,left:0,width:"100%",height:"100%"}),h=document.createElement("input"),h.setAttribute("id",f),h.setAttribute("type","file"),h.setAttribute("accept",l.join(",")),g.can("summon_file_dialog")&&h.setAttribute("tabindex",-1),i.extend(h.style,{fontSize:"999px",opacity:0}),m.appendChild(h),o.appendChild(m),i.extend(h.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),"IE"===a.browser&&a.verComp(a.version,10,"<")&&i.extend(h.style,{filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)"}),h.onchange=function(){var i;this.value&&(i=this.files?this.files[0]:{name:this.value},i=new t(g.uid,i),this.onchange=function(){},e.call(p),p.files=[i],h.setAttribute("id",i.uid),m.setAttribute("id",i.uid+"_form"),p.trigger("change"),h=m=null)},g.can("summon_file_dialog")&&(c=n.get(u.browse_button),r.removeEvent(c,"click",p.uid),r.addEvent(c,"click",function(e){h&&!h.disabled&&h.click(),e.preventDefault()},p.uid)),s=f,o=d=c=null}var s,u,c,l=[];i.extend(this,{init:function(t){var i,a=this,s=a.getRuntime();u=t,l=o.extList2mimes(t.accept,s.can("filter_by_extension")),i=s.getShimContainer(),function(){var e,o,l;e=n.get(t.browse_button),c=n.getStyle(e,"z-index")||"auto",s.can("summon_file_dialog")?("static"===n.getStyle(e,"position")&&(e.style.position="relative"),a.bind("Refresh",function(){o=parseInt(c,10)||1,n.get(u.browse_button).style.zIndex=o,this.getRuntime().getShimContainer().style.zIndex=o-1})):e.setAttribute("tabindex",-1),l=s.can("summon_file_dialog")?e:i,r.addEvent(l,"mouseover",function(){a.trigger("mouseenter")},a.uid),r.addEvent(l,"mouseout",function(){a.trigger("mouseleave")},a.uid),r.addEvent(l,"mousedown",function(){a.trigger("mousedown")},a.uid),r.addEvent(n.get(t.container),"mouseup",function(){a.trigger("mouseup")},a.uid),e=null}(),e.call(this),i=null,a.trigger({type:"ready",async:!0})},setOption:function(e,t){var i,r=this.getRuntime();"accept"==e&&(l=t.mimes||o.extList2mimes(t,r.can("filter_by_extension"))),i=n.get(s),i&&i.setAttribute("accept",l.join(","))},disable:function(e){var t;(t=n.get(s))&&(t.disabled=!!e)},destroy:function(){var e=this.getRuntime(),t=e.getShim(),i=e.getShimContainer(),o=u&&n.get(u.container),a=u&&n.get(u.browse_button);o&&r.removeAllEvents(o,this.uid),a&&(r.removeAllEvents(a,this.uid),a.style.zIndex=c),i&&(r.removeAllEvents(i,this.uid),i.innerHTML=""),t.removeInstance(this.uid),s=l=u=i=o=a=t=null}})}return e.FileInput=s}),n("moxie/runtime/html4/file/FileReader",["moxie/runtime/html4/Runtime","moxie/runtime/html5/file/FileReader"],function(e,t){return e.FileReader=t}),n("moxie/runtime/html4/xhr/XMLHttpRequest",["moxie/runtime/html4/Runtime","moxie/core/utils/Basic","moxie/core/utils/Dom","moxie/core/utils/Url","moxie/core/Exceptions","moxie/core/utils/Events","moxie/file/Blob","moxie/xhr/FormData"],function(e,t,i,n,r,o,a,s){function u(){function e(e){var t,n,r,a,s=this,u=!1;if(l){if(t=l.id.replace(/_iframe$/,""),n=i.get(t+"_form")){for(r=n.getElementsByTagName("input"),a=r.length;a--;)switch(r[a].getAttribute("type")){case"hidden":r[a].parentNode.removeChild(r[a]);break;case"file":u=!0}r=[],u||n.parentNode.removeChild(n),n=null}setTimeout(function(){o.removeEvent(l,"load",s.uid),l.parentNode&&l.parentNode.removeChild(l);var t=s.getRuntime().getShimContainer();t.children.length||t.parentNode.removeChild(t),t=l=null,e()},1)}}var u,c,l;t.extend(this,{send:function(d,m){function h(){var i=w.getShimContainer()||document.body,r=document.createElement("div");r.innerHTML='<iframe id="'+f+'_iframe" name="'+f+'_iframe" src="javascript:&quot;&quot;" style="display:none"></iframe>',l=r.firstChild,i.appendChild(l),o.addEvent(l,"load",function(){var i;try{i=l.contentWindow.document||l.contentDocument||window.frames[l.id].document,/^4(0[0-9]|1[0-7]|2[2346])\s/.test(i.title)?u=i.title.replace(/^(\d+).*$/,"$1"):(u=200,c=t.trim(i.body.innerHTML),v.trigger({type:"progress",loaded:c.length,total:c.length}),x&&v.trigger({type:"uploadprogress",loaded:x.size||1025,total:x.size||1025}))}catch(r){if(!n.hasSameOrigin(d.url))return e.call(v,function(){v.trigger("error")}),void 0;u=404}e.call(v,function(){v.trigger("load")})},v.uid)}var f,p,g,x,v=this,w=v.getRuntime();if(u=c=null,m instanceof s&&m.hasBlob()){if(x=m.getBlob(),f=x.uid,g=i.get(f),p=i.get(f+"_form"),!p)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR)}else f=t.guid("uid_"),p=document.createElement("form"),p.setAttribute("id",f+"_form"),p.setAttribute("method",d.method),p.setAttribute("enctype","multipart/form-data"),p.setAttribute("encoding","multipart/form-data"),w.getShimContainer().appendChild(p);p.setAttribute("target",f+"_iframe"),m instanceof s&&m.each(function(e,i){if(e instanceof a)g&&g.setAttribute("name",i);else{var n=document.createElement("input");t.extend(n,{type:"hidden",name:i,value:e}),g?p.insertBefore(n,g):p.appendChild(n)}}),p.setAttribute("action",d.url),h(),p.submit(),v.trigger("loadstart")},getStatus:function(){return u},getResponse:function(e){if("json"===e&&"string"===t.typeOf(c)&&window.JSON)try{return JSON.parse(c.replace(/^\s*<pre[^>]*>/,"").replace(/<\/pre>\s*$/,""))}catch(i){return null}return c},abort:function(){var t=this;l&&l.contentWindow&&(l.contentWindow.stop?l.contentWindow.stop():l.contentWindow.document.execCommand?l.contentWindow.document.execCommand("Stop"):l.src="about:blank"),e.call(this,function(){t.dispatchEvent("abort")})},destroy:function(){this.getRuntime().getShim().removeInstance(this.uid)}})}return e.XMLHttpRequest=u}),n("moxie/runtime/html4/image/Image",["moxie/runtime/html4/Runtime","moxie/runtime/html5/image/Image"],function(e,t){return e.Image=t}),a(["moxie/core/utils/Basic","moxie/core/utils/Encode","moxie/core/utils/Env","moxie/core/Exceptions","moxie/core/utils/Dom","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/core/I18n","moxie/core/utils/Mime","moxie/file/FileInput","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/image/Image","moxie/core/utils/Events","moxie/runtime/html5/image/ResizerCanvas"])}(this)});
/**
* Plupload - multi-runtime File Uploader
- * v2.1.8
+ * v2.3.6
*
* Copyright 2013, Moxiecode Systems AB
* Released under GPL License.
@@ -24,6 +24,6 @@ return JSON.parse(c.replace(/^\s*<pre[^>]*>/,"").replace(/<\/pre>\s*$/,""))}catc
* License: http://www.plupload.com/license
* Contributing: http://www.plupload.com/contributing
*
- * Date: 2015-07-21
+ * Date: 2017-11-03
*/
-;(function(e,t,n){function s(e){function r(e,t,r){var i={chunks:"slice_blob",jpgresize:"send_binary_string",pngresize:"send_binary_string",progress:"report_upload_progress",multi_selection:"select_multiple",dragdrop:"drag_and_drop",drop_element:"drag_and_drop",headers:"send_custom_headers",urlstream_upload:"send_binary_string",canSendBinary:"send_binary",triggerDialog:"summon_file_dialog"};i[e]?n[i[e]]=t:r||(n[e]=t)}var t=e.required_features,n={};if(typeof t=="string")o.each(t.split(/\s*,\s*/),function(e){r(e,!0)});else if(typeof t=="object")o.each(t,function(e,t){r(t,e)});else if(t===!0){e.chunk_size>0&&(n.slice_blob=!0);if(e.resize.enabled||!e.multipart)n.send_binary_string=!0;o.each(e,function(e,t){r(t,!!e,!0)})}return n}var r=e.setTimeout,i={},o={VERSION:"2.1.8",STOPPED:1,STARTED:2,QUEUED:1,UPLOADING:2,FAILED:4,DONE:5,GENERIC_ERROR:-100,HTTP_ERROR:-200,IO_ERROR:-300,SECURITY_ERROR:-400,INIT_ERROR:-500,FILE_SIZE_ERROR:-600,FILE_EXTENSION_ERROR:-601,FILE_DUPLICATE_ERROR:-602,IMAGE_FORMAT_ERROR:-700,MEMORY_ERROR:-701,IMAGE_DIMENSIONS_ERROR:-702,mimeTypes:t.mimes,ua:t.ua,typeOf:t.typeOf,extend:t.extend,guid:t.guid,get:function(n){var r=[],i;t.typeOf(n)!=="array"&&(n=[n]);var s=n.length;while(s--)i=t.get(n[s]),i&&r.push(i);return r.length?r:null},each:t.each,getPos:t.getPos,getSize:t.getSize,xmlEncode:function(e){var t={"<":"lt",">":"gt","&":"amp",'"':"quot","'":"#39"},n=/[<>&\"\']/g;return e?(""+e).replace(n,function(e){return t[e]?"&"+t[e]+";":e}):e},toArray:t.toArray,inArray:t.inArray,addI18n:t.addI18n,translate:t.translate,isEmptyObj:t.isEmptyObj,hasClass:t.hasClass,addClass:t.addClass,removeClass:t.removeClass,getStyle:t.getStyle,addEvent:t.addEvent,removeEvent:t.removeEvent,removeAllEvents:t.removeAllEvents,cleanName:function(e){var t,n;n=[/[\300-\306]/g,"A",/[\340-\346]/g,"a",/\307/g,"C",/\347/g,"c",/[\310-\313]/g,"E",/[\350-\353]/g,"e",/[\314-\317]/g,"I",/[\354-\357]/g,"i",/\321/g,"N",/\361/g,"n",/[\322-\330]/g,"O",/[\362-\370]/g,"o",/[\331-\334]/g,"U",/[\371-\374]/g,"u"];for(t=0;t<n.length;t+=2)e=e.replace(n[t],n[t+1]);return e=e.replace(/\s+/g,"_"),e=e.replace(/[^a-z0-9_\-\.]+/gi,""),e},buildUrl:function(e,t){var n="";return o.each(t,function(e,t){n+=(n?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(e)}),n&&(e+=(e.indexOf("?")>0?"&":"?")+n),e},formatSize:function(e){function t(e,t){return Math.round(e*Math.pow(10,t))/Math.pow(10,t)}if(e===n||/\D/.test(e))return o.translate("N/A");var r=Math.pow(1024,4);return e>r?t(e/r,1)+" "+o.translate("tb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("gb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("mb"):e>1024?Math.round(e/1024)+" "+o.translate("kb"):e+" "+o.translate("b")},parseSize:t.parseSizeStr,predictRuntime:function(e,n){var r,i;return r=new o.Uploader(e),i=t.Runtime.thatCan(r.getOption().required_features,n||e.runtimes),r.destroy(),i},addFileFilter:function(e,t){i[e]=t}};o.addFileFilter("mime_types",function(e,t,n){e.length&&!e.regexp.test(t.name)?(this.trigger("Error",{code:o.FILE_EXTENSION_ERROR,message:o.translate("File extension error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("max_file_size",function(e,t,n){var r;e=o.parseSize(e),t.size!==r&&e&&t.size>e?(this.trigger("Error",{code:o.FILE_SIZE_ERROR,message:o.translate("File size error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("prevent_duplicates",function(e,t,n){if(e){var r=this.files.length;while(r--)if(t.name===this.files[r].name&&t.size===this.files[r].size){this.trigger("Error",{code:o.FILE_DUPLICATE_ERROR,message:o.translate("Duplicate file error."),file:t}),n(!1);return}}n(!0)}),o.Uploader=function(e){function g(){var e,t=0,n;if(this.state==o.STARTED){for(n=0;n<f.length;n++)!e&&f[n].status==o.QUEUED?(e=f[n],this.trigger("BeforeUpload",e)&&(e.status=o.UPLOADING,this.trigger("UploadFile",e))):t++;t==f.length&&(this.state!==o.STOPPED&&(this.state=o.STOPPED,this.trigger("StateChanged")),this.trigger("UploadComplete",f))}}function y(e){e.percent=e.size>0?Math.ceil(e.loaded/e.size*100):100,b()}function b(){var e,t;d.reset();for(e=0;e<f.length;e++)t=f[e],t.size!==n?(d.size+=t.origSize,d.loaded+=t.loaded*t.origSize/t.size):d.size=n,t.status==o.DONE?d.uploaded++:t.status==o.FAILED?d.failed++:d.queued++;d.size===n?d.percent=f.length>0?Math.ceil(d.uploaded/f.length*100):0:(d.bytesPerSec=Math.ceil(d.loaded/((+(new Date)-p||1)/1e3)),d.percent=d.size>0?Math.ceil(d.loaded/d.size*100):0)}function w(){var e=c[0]||h[0];return e?e.getRuntime().uid:!1}function E(e,n){if(e.ruid){var r=t.Runtime.getInfo(e.ruid);if(r)return r.can(n)}return!1}function S(){this.bind("FilesAdded FilesRemoved",function(e){e.trigger("QueueChanged"),e.refresh()}),this.bind("CancelUpload",O),this.bind("BeforeUpload",C),this.bind("UploadFile",k),this.bind("UploadProgress",L),this.bind("StateChanged",A),this.bind("QueueChanged",b),this.bind("Error",_),this.bind("FileUploaded",M),this.bind("Destroy",D)}function x(e,n){var r=this,i=0,s=[],u={runtime_order:e.runtimes,required_caps:e.required_features,preferred_caps:l,swf_url:e.flash_swf_url,xap_url:e.silverlight_xap_url};o.each(e.runtimes.split(/\s*,\s*/),function(t){e[t]&&(u[t]=e[t])}),e.browse_button&&o.each(e.browse_button,function(n){s.push(function(s){var a=new t.FileInput(o.extend({},u,{accept:e.filters.mime_types,name:e.file_data_name,multiple:e.multi_selection,container:e.container,browse_button:n}));a.onready=function(){var e=t.Runtime.getInfo(this.ruid);t.extend(r.features,{chunks:e.can("slice_blob"),multipart:e.can("send_multipart"),multi_selection:e.can("select_multiple")}),i++,c.push(this),s()},a.onchange=function(){r.addFile(this.files)},a.bind("mouseenter mouseleave mousedown mouseup",function(r){v||(e.browse_button_hover&&("mouseenter"===r.type?t.addClass(n,e.browse_button_hover):"mouseleave"===r.type&&t.removeClass(n,e.browse_button_hover)),e.browse_button_active&&("mousedown"===r.type?t.addClass(n,e.browse_button_active):"mouseup"===r.type&&t.removeClass(n,e.browse_button_active)))}),a.bind("mousedown",function(){r.trigger("Browse")}),a.bind("error runtimeerror",function(){a=null,s()}),a.init()})}),e.drop_element&&o.each(e.drop_element,function(e){s.push(function(n){var s=new t.FileDrop(o.extend({},u,{drop_zone:e}));s.onready=function(){var e=t.Runtime.getInfo(this.ruid);r.features.dragdrop=e.can("drag_and_drop"),i++,h.push(this),n()},s.ondrop=function(){r.addFile(this.files)},s.bind("error runtimeerror",function(){s=null,n()}),s.init()})}),t.inSeries(s,function(){typeof n=="function"&&n(i)})}function T(e,r,i){var s=new t.Image;try{s.onload=function(){if(r.width>this.width&&r.height>this.height&&r.quality===n&&r.preserve_headers&&!r.crop)return this.destroy(),i(e);s.downsize(r.width,r.height,r.crop,r.preserve_headers)},s.onresize=function(){i(this.getAsBlob(e.type,r.quality)),this.destroy()},s.onerror=function(){i(e)},s.load(e)}catch(o){i(e)}}function N(e,n,r){function f(e,t,n){var r=a[e];switch(e){case"max_file_size":e==="max_file_size"&&(a.max_file_size=a.filters.max_file_size=t);break;case"chunk_size":if(t=o.parseSize(t))a[e]=t,a.send_file_name=!0;break;case"multipart":a[e]=t,t||(a.send_file_name=!0);break;case"unique_names":a[e]=t,t&&(a.send_file_name=!0);break;case"filters":o.typeOf(t)==="array"&&(t={mime_types:t}),n?o.extend(a.filters,t):a.filters=t,t.mime_types&&(a.filters.mime_types.regexp=function(e){var t=[];return o.each(e,function(e){o.each(e.extensions.split(/,/),function(e){/^\s*\*\s*$/.test(e)?t.push("\\.*"):t.push("\\."+e.replace(new RegExp("["+"/^$.*+?|()[]{}\\".replace(/./g,"\\$&")+"]","g"),"\\$&"))})}),new RegExp("("+t.join("|")+")$","i")}(a.filters.mime_types));break;case"resize":n?o.extend(a.resize,t,{enabled:!0}):a.resize=t;break;case"prevent_duplicates":a.prevent_duplicates=a.filters.prevent_duplicates=!!t;break;case"browse_button":case"drop_element":t=o.get(t);case"container":case"runtimes":case"multi_selection":case"flash_swf_url":case"silverlight_xap_url":a[e]=t,n||(u=!0);break;default:a[e]=t}n||i.trigger("OptionChanged",e,t,r)}var i=this,u=!1;typeof e=="object"?o.each(e,function(e,t){f(t,e,r)}):f(e,n,r),r?(a.required_features=s(o.extend({},a)),l=s(o.extend({},a,{required_features:!0}))):u&&(i.trigger("Destroy"),x.call(i,a,function(e){e?(i.runtime=t.Runtime.getInfo(w()).type,i.trigger("Init",{runtime:i.runtime}),i.trigger("PostInit")):i.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})}))}function C(e,t){if(e.settings.unique_names){var n=t.name.match(/\.([^.]+)$/),r="part";n&&(r=n[1]),t.target_name=t.id+"."+r}}function k(e,n){function h(){u-->0?r(p,1e3):(n.loaded=f,e.trigger("Error",{code:o.HTTP_ERROR,message:o.translate("HTTP Error."),file:n,response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()}))}function p(){var d,v,g={},y;if(n.status!==o.UPLOADING||e.state===o.STOPPED)return;e.settings.send_file_name&&(g.name=n.target_name||n.name),s&&a.chunks&&c.size>s?(y=Math.min(s,c.size-f),d=c.slice(f,f+y)):(y=c.size,d=c),s&&a.chunks&&(e.settings.send_chunk_number?(g.chunk=Math.ceil(f/s),g.chunks=Math.ceil(c.size/s)):(g.offset=f,g.total=c.size)),m=new t.XMLHttpRequest,m.upload&&(m.upload.onprogress=function(t){n.loaded=Math.min(n.size,f+t.loaded),e.trigger("UploadProgress",n)}),m.onload=function(){if(m.status>=400){h();return}u=e.settings.max_retries,y<c.size?(d.destroy(),f+=y,n.loaded=Math.min(f,c.size),e.trigger("ChunkUploaded",n,{offset:n.loaded,total:c.size,response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()}),t.Env.browser==="Android Browser"&&e.trigger("UploadProgress",n)):n.loaded=n.size,d=v=null,!f||f>=c.size?(n.size!=n.origSize&&(c.destroy(),c=null),e.trigger("UploadProgress",n),n.status=o.DONE,e.trigger("FileUploaded",n,{response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()})):r(p,1)},m.onerror=function(){h()},m.onloadend=function(){this.destroy(),m=null},e.settings.multipart&&a.multipart?(m.open("post",i,!0),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),v=new t.FormData,o.each(o.extend(g,e.settings.multipart_params),function(e,t){v.append(t,e)}),v.append(e.settings.file_data_name,d),m.send(v,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url})):(i=o.buildUrl(e.settings.url,o.extend(g,e.settings.multipart_params)),m.open("post",i,!0),m.setRequestHeader("Content-Type","application/octet-stream"),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),m.send(d,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url}))}var i=e.settings.url,s=e.settings.chunk_size,u=e.settings.max_retries,a=e.features,f=0,c;n.loaded&&(f=n.loaded=s?s*Math.floor(n.loaded/s):0),c=n.getSource(),e.settings.resize.enabled&&E(c,"send_binary_string")&&!!~t.inArray(c.type,["image/jpeg","image/png"])?T.call(this,c,e.settings.resize,function(e){c=e,n.size=e.size,p()}):p()}function L(e,t){y(t)}function A(e){if(e.state==o.STARTED)p=+(new Date);else if(e.state==o.STOPPED)for(var t=e.files.length-1;t>=0;t--)e.files[t].status==o.UPLOADING&&(e.files[t].status=o.QUEUED,b())}function O(){m&&m.abort()}function M(e){b(),r(function(){g.call(e)},1)}function _(e,t){t.code===o.INIT_ERROR?e.destroy():t.code===o.HTTP_ERROR&&(t.file.status=o.FAILED,y(t.file),e.state==o.STARTED&&(e.trigger("CancelUpload"),r(function(){g.call(e)},1)))}function D(e){e.stop(),o.each(f,function(e){e.destroy()}),f=[],c.length&&(o.each(c,function(e){e.destroy()}),c=[]),h.length&&(o.each(h,function(e){e.destroy()}),h=[]),l={},v=!1,p=m=null,d.reset()}var u=o.guid(),a,f=[],l={},c=[],h=[],p,d,v=!1,m;a={runtimes:t.Runtime.order,max_retries:0,chunk_size:0,multipart:!0,multi_selection:!0,file_data_name:"file",flash_swf_url:"js/Moxie.swf",silverlight_xap_url:"js/Moxie.xap",filters:{mime_types:[],prevent_duplicates:!1,max_file_size:0},resize:{enabled:!1,preserve_headers:!0,crop:!1},send_file_name:!0,send_chunk_number:!0},N.call(this,e,null,!0),d=new o.QueueProgress,o.extend(this,{id:u,uid:u,state:o.STOPPED,features:{},runtime:null,files:f,settings:a,total:d,init:function(){var e=this;typeof a.preinit=="function"?a.preinit(e):o.each(a.preinit,function(t,n){e.bind(n,t)}),S.call(this);if(!a.browse_button||!a.url){this.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")});return}x.call(this,a,function(n){typeof a.init=="function"?a.init(e):o.each(a.init,function(t,n){e.bind(n,t)}),n?(e.runtime=t.Runtime.getInfo(w()).type,e.trigger("Init",{runtime:e.runtime}),e.trigger("PostInit")):e.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})})},setOption:function(e,t){N.call(this,e,t,!this.runtime)},getOption:function(e){return e?a[e]:a},refresh:function(){c.length&&o.each(c,function(e){e.trigger("Refresh")}),this.trigger("Refresh")},start:function(){this.state!=o.STARTED&&(this.state=o.STARTED,this.trigger("StateChanged"),g.call(this))},stop:function(){this.state!=o.STOPPED&&(this.state=o.STOPPED,this.trigger("StateChanged"),this.trigger("CancelUpload"))},disableBrowse:function(){v=arguments[0]!==n?arguments[0]:!0,c.length&&o.each(c,function(e){e.disable(v)}),this.trigger("DisableBrowse",v)},getFile:function(e){var t;for(t=f.length-1;t>=0;t--)if(f[t].id===e)return f[t]},addFile:function(e,n){function c(e,n){var r=[];t.each(s.settings.filters,function(t,n){i[n]&&r.push(function(r){i[n].call(s,t,e,function(e){r(!e)})})}),t.inSeries(r,n)}function h(e){var i=t.typeOf(e);if(e instanceof t.File){if(!e.ruid&&!e.isDetached()){if(!l)return!1;e.ruid=l,e.connectRuntime(l)}h(new o.File(e))}else e instanceof t.Blob?(h(e.getSource()),e.destroy()):e instanceof o.File?(n&&(e.name=n),u.push(function(t){c(e,function(n){n||(f.push(e),a.push(e),s.trigger("FileFiltered",e)),r(t,1)})})):t.inArray(i,["file","blob"])!==-1?h(new t.File(null,e)):i==="node"&&t.typeOf(e.files)==="filelist"?t.each(e.files,h):i==="array"&&(n=null,t.each(e,h))}var s=this,u=[],a=[],l;l=w(),h(e),u.length&&t.inSeries(u,function(){a.length&&s.trigger("FilesAdded",a)})},removeFile:function(e){var t=typeof e=="string"?e:e.id;for(var n=f.length-1;n>=0;n--)if(f[n].id===t)return this.splice(n,1)[0]},splice:function(e,t){var r=f.splice(e===n?0:e,t===n?f.length:t),i=!1;return this.state==o.STARTED&&(o.each(r,function(e){if(e.status===o.UPLOADING)return i=!0,!1}),i&&this.stop()),this.trigger("FilesRemoved",r),o.each(r,function(e){e.destroy()}),i&&this.start(),r},dispatchEvent:function(e){var t,n,r;e=e.toLowerCase(),t=this.hasEventListener(e);if(t){t.sort(function(e,t){return t.priority-e.priority}),n=[].slice.call(arguments),n.shift(),n.unshift(this);for(var i=0;i<t.length;i++)if(t[i].fn.apply(t[i].scope,n)===!1)return!1}return!0},bind:function(e,t,n,r){o.Uploader.prototype.bind.call(this,e,t,r,n)},destroy:function(){this.trigger("Destroy"),a=d=null,this.unbindAll()}})},o.Uploader.prototype=t.EventTarget.instance,o.File=function(){function n(n){o.extend(this,{id:o.guid(),name:n.name||n.fileName,type:n.type||"",size:n.size||n.fileSize,origSize:n.size||n.fileSize,loaded:0,percent:0,status:o.QUEUED,lastModifiedDate:n.lastModifiedDate||(new Date).toLocaleString(),getNative:function(){var e=this.getSource().getSource();return t.inArray(t.typeOf(e),["blob","file"])!==-1?e:null},getSource:function(){return e[this.id]?e[this.id]:null},destroy:function(){var t=this.getSource();t&&(t.destroy(),delete e[this.id])}}),e[this.id]=n}var e={};return n}(),o.QueueProgress=function(){var e=this;e.size=0,e.loaded=0,e.uploaded=0,e.failed=0,e.queued=0,e.percent=0,e.bytesPerSec=0,e.reset=function(){e.size=e.loaded=e.uploaded=e.failed=e.queued=e.percent=e.bytesPerSec=0}},e.plupload=o})(window,mOxie); \ No newline at end of file
+!function(e,t){var i=function(){var e={};return t.apply(e,arguments),e.plupload};"function"==typeof define&&define.amd?define("plupload",["./moxie"],i):"object"==typeof module&&module.exports?module.exports=i(require("./moxie")):e.plupload=i(e.moxie)}(this||window,function(e){!function(e,t,i){function n(e){function t(e,t,i){var r={chunks:"slice_blob",jpgresize:"send_binary_string",pngresize:"send_binary_string",progress:"report_upload_progress",multi_selection:"select_multiple",dragdrop:"drag_and_drop",drop_element:"drag_and_drop",headers:"send_custom_headers",urlstream_upload:"send_binary_string",canSendBinary:"send_binary",triggerDialog:"summon_file_dialog"};r[e]?n[r[e]]=t:i||(n[e]=t)}var i=e.required_features,n={};return"string"==typeof i?l.each(i.split(/\s*,\s*/),function(e){t(e,!0)}):"object"==typeof i?l.each(i,function(e,i){t(i,e)}):i===!0&&(e.chunk_size&&e.chunk_size>0&&(n.slice_blob=!0),l.isEmptyObj(e.resize)&&e.multipart!==!1||(n.send_binary_string=!0),e.http_method&&(n.use_http_method=e.http_method),l.each(e,function(e,i){t(i,!!e,!0)})),n}var r=window.setTimeout,s={},a=t.core.utils,o=t.runtime.Runtime,l={VERSION:"2.3.6",STOPPED:1,STARTED:2,QUEUED:1,UPLOADING:2,FAILED:4,DONE:5,GENERIC_ERROR:-100,HTTP_ERROR:-200,IO_ERROR:-300,SECURITY_ERROR:-400,INIT_ERROR:-500,FILE_SIZE_ERROR:-600,FILE_EXTENSION_ERROR:-601,FILE_DUPLICATE_ERROR:-602,IMAGE_FORMAT_ERROR:-700,MEMORY_ERROR:-701,IMAGE_DIMENSIONS_ERROR:-702,moxie:t,mimeTypes:a.Mime.mimes,ua:a.Env,typeOf:a.Basic.typeOf,extend:a.Basic.extend,guid:a.Basic.guid,getAll:function(e){var t,i=[];"array"!==l.typeOf(e)&&(e=[e]);for(var n=e.length;n--;)t=l.get(e[n]),t&&i.push(t);return i.length?i:null},get:a.Dom.get,each:a.Basic.each,getPos:a.Dom.getPos,getSize:a.Dom.getSize,xmlEncode:function(e){var t={"<":"lt",">":"gt","&":"amp",'"':"quot","'":"#39"},i=/[<>&\"\']/g;return e?(""+e).replace(i,function(e){return t[e]?"&"+t[e]+";":e}):e},toArray:a.Basic.toArray,inArray:a.Basic.inArray,inSeries:a.Basic.inSeries,addI18n:t.core.I18n.addI18n,translate:t.core.I18n.translate,sprintf:a.Basic.sprintf,isEmptyObj:a.Basic.isEmptyObj,hasClass:a.Dom.hasClass,addClass:a.Dom.addClass,removeClass:a.Dom.removeClass,getStyle:a.Dom.getStyle,addEvent:a.Events.addEvent,removeEvent:a.Events.removeEvent,removeAllEvents:a.Events.removeAllEvents,cleanName:function(e){var t,i;for(i=[/[\300-\306]/g,"A",/[\340-\346]/g,"a",/\307/g,"C",/\347/g,"c",/[\310-\313]/g,"E",/[\350-\353]/g,"e",/[\314-\317]/g,"I",/[\354-\357]/g,"i",/\321/g,"N",/\361/g,"n",/[\322-\330]/g,"O",/[\362-\370]/g,"o",/[\331-\334]/g,"U",/[\371-\374]/g,"u"],t=0;t<i.length;t+=2)e=e.replace(i[t],i[t+1]);return e=e.replace(/\s+/g,"_"),e=e.replace(/[^a-z0-9_\-\.]+/gi,"")},buildUrl:function(e,t){var i="";return l.each(t,function(e,t){i+=(i?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(e)}),i&&(e+=(e.indexOf("?")>0?"&":"?")+i),e},formatSize:function(e){function t(e,t){return Math.round(e*Math.pow(10,t))/Math.pow(10,t)}if(e===i||/\D/.test(e))return l.translate("N/A");var n=Math.pow(1024,4);return e>n?t(e/n,1)+" "+l.translate("tb"):e>(n/=1024)?t(e/n,1)+" "+l.translate("gb"):e>(n/=1024)?t(e/n,1)+" "+l.translate("mb"):e>1024?Math.round(e/1024)+" "+l.translate("kb"):e+" "+l.translate("b")},parseSize:a.Basic.parseSizeStr,predictRuntime:function(e,t){var i,n;return i=new l.Uploader(e),n=o.thatCan(i.getOption().required_features,t||e.runtimes),i.destroy(),n},addFileFilter:function(e,t){s[e]=t}};l.addFileFilter("mime_types",function(e,t,i){e.length&&!e.regexp.test(t.name)?(this.trigger("Error",{code:l.FILE_EXTENSION_ERROR,message:l.translate("File extension error."),file:t}),i(!1)):i(!0)}),l.addFileFilter("max_file_size",function(e,t,i){var n;e=l.parseSize(e),t.size!==n&&e&&t.size>e?(this.trigger("Error",{code:l.FILE_SIZE_ERROR,message:l.translate("File size error."),file:t}),i(!1)):i(!0)}),l.addFileFilter("prevent_duplicates",function(e,t,i){if(e)for(var n=this.files.length;n--;)if(t.name===this.files[n].name&&t.size===this.files[n].size)return this.trigger("Error",{code:l.FILE_DUPLICATE_ERROR,message:l.translate("Duplicate file error."),file:t}),i(!1),void 0;i(!0)}),l.addFileFilter("prevent_empty",function(e,t,n){e&&!t.size&&t.size!==i?(this.trigger("Error",{code:l.FILE_SIZE_ERROR,message:l.translate("File size error."),file:t}),n(!1)):n(!0)}),l.Uploader=function(e){function a(){var e,t,i=0;if(this.state==l.STARTED){for(t=0;t<D.length;t++)e||D[t].status!=l.QUEUED?i++:(e=D[t],this.trigger("BeforeUpload",e)&&(e.status=l.UPLOADING,this.trigger("UploadFile",e)));i==D.length&&(this.state!==l.STOPPED&&(this.state=l.STOPPED,this.trigger("StateChanged")),this.trigger("UploadComplete",D))}}function u(e){e.percent=e.size>0?Math.ceil(100*(e.loaded/e.size)):100,d()}function d(){var e,t,n,r=0;for(I.reset(),e=0;e<D.length;e++)t=D[e],t.size!==i?(I.size+=t.origSize,n=t.loaded*t.origSize/t.size,(!t.completeTimestamp||t.completeTimestamp>S)&&(r+=n),I.loaded+=n):I.size=i,t.status==l.DONE?I.uploaded++:t.status==l.FAILED?I.failed++:I.queued++;I.size===i?I.percent=D.length>0?Math.ceil(100*(I.uploaded/D.length)):0:(I.bytesPerSec=Math.ceil(r/((+new Date-S||1)/1e3)),I.percent=I.size>0?Math.ceil(100*(I.loaded/I.size)):0)}function c(){var e=F[0]||P[0];return e?e.getRuntime().uid:!1}function f(){this.bind("FilesAdded FilesRemoved",function(e){e.trigger("QueueChanged"),e.refresh()}),this.bind("CancelUpload",b),this.bind("BeforeUpload",m),this.bind("UploadFile",_),this.bind("UploadProgress",E),this.bind("StateChanged",v),this.bind("QueueChanged",d),this.bind("Error",R),this.bind("FileUploaded",y),this.bind("Destroy",z)}function p(e,i){var n=this,r=0,s=[],a={runtime_order:e.runtimes,required_caps:e.required_features,preferred_caps:x,swf_url:e.flash_swf_url,xap_url:e.silverlight_xap_url};l.each(e.runtimes.split(/\s*,\s*/),function(t){e[t]&&(a[t]=e[t])}),e.browse_button&&l.each(e.browse_button,function(i){s.push(function(s){var u=new t.file.FileInput(l.extend({},a,{accept:e.filters.mime_types,name:e.file_data_name,multiple:e.multi_selection,container:e.container,browse_button:i}));u.onready=function(){var e=o.getInfo(this.ruid);l.extend(n.features,{chunks:e.can("slice_blob"),multipart:e.can("send_multipart"),multi_selection:e.can("select_multiple")}),r++,F.push(this),s()},u.onchange=function(){n.addFile(this.files)},u.bind("mouseenter mouseleave mousedown mouseup",function(t){U||(e.browse_button_hover&&("mouseenter"===t.type?l.addClass(i,e.browse_button_hover):"mouseleave"===t.type&&l.removeClass(i,e.browse_button_hover)),e.browse_button_active&&("mousedown"===t.type?l.addClass(i,e.browse_button_active):"mouseup"===t.type&&l.removeClass(i,e.browse_button_active)))}),u.bind("mousedown",function(){n.trigger("Browse")}),u.bind("error runtimeerror",function(){u=null,s()}),u.init()})}),e.drop_element&&l.each(e.drop_element,function(e){s.push(function(i){var s=new t.file.FileDrop(l.extend({},a,{drop_zone:e}));s.onready=function(){var e=o.getInfo(this.ruid);l.extend(n.features,{chunks:e.can("slice_blob"),multipart:e.can("send_multipart"),dragdrop:e.can("drag_and_drop")}),r++,P.push(this),i()},s.ondrop=function(){n.addFile(this.files)},s.bind("error runtimeerror",function(){s=null,i()}),s.init()})}),l.inSeries(s,function(){"function"==typeof i&&i(r)})}function g(e,n,r,s){var a=new t.image.Image;try{a.onload=function(){n.width>this.width&&n.height>this.height&&n.quality===i&&n.preserve_headers&&!n.crop?(this.destroy(),s(e)):a.downsize(n.width,n.height,n.crop,n.preserve_headers)},a.onresize=function(){var t=this.getAsBlob(e.type,n.quality);this.destroy(),s(t)},a.bind("error runtimeerror",function(){this.destroy(),s(e)}),a.load(e,r)}catch(o){s(e)}}function h(e,i,r){function s(e,i,n){var r=O[e];switch(e){case"max_file_size":"max_file_size"===e&&(O.max_file_size=O.filters.max_file_size=i);break;case"chunk_size":(i=l.parseSize(i))&&(O[e]=i,O.send_file_name=!0);break;case"multipart":O[e]=i,i||(O.send_file_name=!0);break;case"http_method":O[e]="PUT"===i.toUpperCase()?"PUT":"POST";break;case"unique_names":O[e]=i,i&&(O.send_file_name=!0);break;case"filters":"array"===l.typeOf(i)&&(i={mime_types:i}),n?l.extend(O.filters,i):O.filters=i,i.mime_types&&("string"===l.typeOf(i.mime_types)&&(i.mime_types=t.core.utils.Mime.mimes2extList(i.mime_types)),i.mime_types.regexp=function(e){var t=[];return l.each(e,function(e){l.each(e.extensions.split(/,/),function(e){/^\s*\*\s*$/.test(e)?t.push("\\.*"):t.push("\\."+e.replace(new RegExp("["+"/^$.*+?|()[]{}\\".replace(/./g,"\\$&")+"]","g"),"\\$&"))})}),new RegExp("("+t.join("|")+")$","i")}(i.mime_types),O.filters.mime_types=i.mime_types);break;case"resize":O.resize=i?l.extend({preserve_headers:!0,crop:!1},i):!1;break;case"prevent_duplicates":O.prevent_duplicates=O.filters.prevent_duplicates=!!i;break;case"container":case"browse_button":case"drop_element":i="container"===e?l.get(i):l.getAll(i);case"runtimes":case"multi_selection":case"flash_swf_url":case"silverlight_xap_url":O[e]=i,n||(u=!0);break;default:O[e]=i}n||a.trigger("OptionChanged",e,i,r)}var a=this,u=!1;"object"==typeof e?l.each(e,function(e,t){s(t,e,r)}):s(e,i,r),r?(O.required_features=n(l.extend({},O)),x=n(l.extend({},O,{required_features:!0}))):u&&(a.trigger("Destroy"),p.call(a,O,function(e){e?(a.runtime=o.getInfo(c()).type,a.trigger("Init",{runtime:a.runtime}),a.trigger("PostInit")):a.trigger("Error",{code:l.INIT_ERROR,message:l.translate("Init error.")})}))}function m(e,t){if(e.settings.unique_names){var i=t.name.match(/\.([^.]+)$/),n="part";i&&(n=i[1]),t.target_name=t.id+"."+n}}function _(e,i){function n(){c-->0?r(s,1e3):(i.loaded=p,e.trigger("Error",{code:l.HTTP_ERROR,message:l.translate("HTTP Error."),file:i,response:T.responseText,status:T.status,responseHeaders:T.getAllResponseHeaders()}))}function s(){var t,n,r={};i.status===l.UPLOADING&&e.state!==l.STOPPED&&(e.settings.send_file_name&&(r.name=i.target_name||i.name),d&&f.chunks&&o.size>d?(n=Math.min(d,o.size-p),t=o.slice(p,p+n)):(n=o.size,t=o),d&&f.chunks&&(e.settings.send_chunk_number?(r.chunk=Math.ceil(p/d),r.chunks=Math.ceil(o.size/d)):(r.offset=p,r.total=o.size)),e.trigger("BeforeChunkUpload",i,r,t,p)&&a(r,t,n))}function a(a,d,g){var m;T=new t.xhr.XMLHttpRequest,T.upload&&(T.upload.onprogress=function(t){i.loaded=Math.min(i.size,p+t.loaded),e.trigger("UploadProgress",i)}),T.onload=function(){return T.status<200||T.status>=400?(n(),void 0):(c=e.settings.max_retries,g<o.size?(d.destroy(),p+=g,i.loaded=Math.min(p,o.size),e.trigger("ChunkUploaded",i,{offset:i.loaded,total:o.size,response:T.responseText,status:T.status,responseHeaders:T.getAllResponseHeaders()}),"Android Browser"===l.ua.browser&&e.trigger("UploadProgress",i)):i.loaded=i.size,d=m=null,!p||p>=o.size?(i.size!=i.origSize&&(o.destroy(),o=null),e.trigger("UploadProgress",i),i.status=l.DONE,i.completeTimestamp=+new Date,e.trigger("FileUploaded",i,{response:T.responseText,status:T.status,responseHeaders:T.getAllResponseHeaders()})):r(s,1),void 0)},T.onerror=function(){n()},T.onloadend=function(){this.destroy()},e.settings.multipart&&f.multipart?(T.open(e.settings.http_method,u,!0),l.each(e.settings.headers,function(e,t){T.setRequestHeader(t,e)}),m=new t.xhr.FormData,l.each(l.extend(a,e.settings.multipart_params),function(e,t){m.append(t,e)}),m.append(e.settings.file_data_name,d),T.send(m,h)):(u=l.buildUrl(e.settings.url,l.extend(a,e.settings.multipart_params)),T.open(e.settings.http_method,u,!0),l.each(e.settings.headers,function(e,t){T.setRequestHeader(t,e)}),T.hasRequestHeader("Content-Type")||T.setRequestHeader("Content-Type","application/octet-stream"),T.send(d,h))}var o,u=e.settings.url,d=e.settings.chunk_size,c=e.settings.max_retries,f=e.features,p=0,h={runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:x,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url};i.loaded&&(p=i.loaded=d?d*Math.floor(i.loaded/d):0),o=i.getSource(),l.isEmptyObj(e.settings.resize)||-1===l.inArray(o.type,["image/jpeg","image/png"])?s():g(o,e.settings.resize,h,function(e){o=e,i.size=e.size,s()})}function E(e,t){u(t)}function v(e){if(e.state==l.STARTED)S=+new Date;else if(e.state==l.STOPPED)for(var t=e.files.length-1;t>=0;t--)e.files[t].status==l.UPLOADING&&(e.files[t].status=l.QUEUED,d())}function b(){T&&T.abort()}function y(e){d(),r(function(){a.call(e)},1)}function R(e,t){t.code===l.INIT_ERROR?e.destroy():t.code===l.HTTP_ERROR&&(t.file.status=l.FAILED,t.file.completeTimestamp=+new Date,u(t.file),e.state==l.STARTED&&(e.trigger("CancelUpload"),r(function(){a.call(e)},1)))}function z(e){e.stop(),l.each(D,function(e){e.destroy()}),D=[],F.length&&(l.each(F,function(e){e.destroy()}),F=[]),P.length&&(l.each(P,function(e){e.destroy()}),P=[]),x={},U=!1,S=T=null,I.reset()}var O,S,I,T,w=l.guid(),D=[],x={},F=[],P=[],U=!1;O={chunk_size:0,file_data_name:"file",filters:{mime_types:[],max_file_size:0,prevent_duplicates:!1,prevent_empty:!0},flash_swf_url:"js/Moxie.swf",http_method:"POST",max_retries:0,multipart:!0,multi_selection:!0,resize:!1,runtimes:o.order,send_file_name:!0,send_chunk_number:!0,silverlight_xap_url:"js/Moxie.xap"},h.call(this,e,null,!0),I=new l.QueueProgress,l.extend(this,{id:w,uid:w,state:l.STOPPED,features:{},runtime:null,files:D,settings:O,total:I,init:function(){var e,t,i=this;return e=i.getOption("preinit"),"function"==typeof e?e(i):l.each(e,function(e,t){i.bind(t,e)}),f.call(i),l.each(["container","browse_button","drop_element"],function(e){return null===i.getOption(e)?(t={code:l.INIT_ERROR,message:l.sprintf(l.translate("%s specified, but cannot be found."),e)},!1):void 0}),t?i.trigger("Error",t):O.browse_button||O.drop_element?(p.call(i,O,function(e){var t=i.getOption("init");"function"==typeof t?t(i):l.each(t,function(e,t){i.bind(t,e)}),e?(i.runtime=o.getInfo(c()).type,i.trigger("Init",{runtime:i.runtime}),i.trigger("PostInit")):i.trigger("Error",{code:l.INIT_ERROR,message:l.translate("Init error.")})}),void 0):i.trigger("Error",{code:l.INIT_ERROR,message:l.translate("You must specify either browse_button or drop_element.")})},setOption:function(e,t){h.call(this,e,t,!this.runtime)},getOption:function(e){return e?O[e]:O},refresh:function(){F.length&&l.each(F,function(e){e.trigger("Refresh")}),this.trigger("Refresh")},start:function(){this.state!=l.STARTED&&(this.state=l.STARTED,this.trigger("StateChanged"),a.call(this))},stop:function(){this.state!=l.STOPPED&&(this.state=l.STOPPED,this.trigger("StateChanged"),this.trigger("CancelUpload"))},disableBrowse:function(){U=arguments[0]!==i?arguments[0]:!0,F.length&&l.each(F,function(e){e.disable(U)}),this.trigger("DisableBrowse",U)},getFile:function(e){var t;for(t=D.length-1;t>=0;t--)if(D[t].id===e)return D[t]},addFile:function(e,i){function n(e,t){var i=[];l.each(u.settings.filters,function(t,n){s[n]&&i.push(function(i){s[n].call(u,t,e,function(e){i(!e)})})}),l.inSeries(i,t)}function a(e){var s=l.typeOf(e);if(e instanceof t.file.File){if(!e.ruid&&!e.isDetached()){if(!o)return!1;e.ruid=o,e.connectRuntime(o)}a(new l.File(e))}else e instanceof t.file.Blob?(a(e.getSource()),e.destroy()):e instanceof l.File?(i&&(e.name=i),d.push(function(t){n(e,function(i){i||(D.push(e),f.push(e),u.trigger("FileFiltered",e)),r(t,1)})})):-1!==l.inArray(s,["file","blob"])?a(new t.file.File(null,e)):"node"===s&&"filelist"===l.typeOf(e.files)?l.each(e.files,a):"array"===s&&(i=null,l.each(e,a))}var o,u=this,d=[],f=[];o=c(),a(e),d.length&&l.inSeries(d,function(){f.length&&u.trigger("FilesAdded",f)})},removeFile:function(e){for(var t="string"==typeof e?e:e.id,i=D.length-1;i>=0;i--)if(D[i].id===t)return this.splice(i,1)[0]},splice:function(e,t){var n=D.splice(e===i?0:e,t===i?D.length:t),r=!1;return this.state==l.STARTED&&(l.each(n,function(e){return e.status===l.UPLOADING?(r=!0,!1):void 0}),r&&this.stop()),this.trigger("FilesRemoved",n),l.each(n,function(e){e.destroy()}),r&&this.start(),n},dispatchEvent:function(e){var t,i;if(e=e.toLowerCase(),t=this.hasEventListener(e)){t.sort(function(e,t){return t.priority-e.priority}),i=[].slice.call(arguments),i.shift(),i.unshift(this);for(var n=0;n<t.length;n++)if(t[n].fn.apply(t[n].scope,i)===!1)return!1}return!0},bind:function(e,t,i,n){l.Uploader.prototype.bind.call(this,e,t,n,i)},destroy:function(){this.trigger("Destroy"),O=I=null,this.unbindAll()}})},l.Uploader.prototype=t.core.EventTarget.instance,l.File=function(){function e(e){l.extend(this,{id:l.guid(),name:e.name||e.fileName,type:e.type||"",relativePath:e.relativePath||"",size:e.fileSize||e.size,origSize:e.fileSize||e.size,loaded:0,percent:0,status:l.QUEUED,lastModifiedDate:e.lastModifiedDate||(new Date).toLocaleString(),completeTimestamp:0,getNative:function(){var e=this.getSource().getSource();return-1!==l.inArray(l.typeOf(e),["blob","file"])?e:null},getSource:function(){return t[this.id]?t[this.id]:null},destroy:function(){var e=this.getSource();e&&(e.destroy(),delete t[this.id])}}),t[this.id]=e}var t={};return e}(),l.QueueProgress=function(){var e=this;e.size=0,e.loaded=0,e.uploaded=0,e.failed=0,e.queued=0,e.percent=0,e.bytesPerSec=0,e.reset=function(){e.size=e.loaded=e.uploaded=e.failed=e.queued=e.percent=e.bytesPerSec=0}},e.plupload=l}(this,e)}); \ No newline at end of file
diff --git a/phpBB/bin/phpbbcli.php b/phpBB/bin/phpbbcli.php
index 239dd3932b..5ae18334d9 100755
--- a/phpBB/bin/phpbbcli.php
+++ b/phpBB/bin/phpbbcli.php
@@ -21,6 +21,7 @@ if (php_sapi_name() != 'cli')
}
define('IN_PHPBB', true);
+
$phpbb_root_path = __DIR__ . '/../';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
require($phpbb_root_path . 'includes/startup.' . $phpEx);
@@ -32,38 +33,58 @@ $phpbb_class_loader->register();
$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
extract($phpbb_config_php_file->get_all());
+if (!defined('PHPBB_ENVIRONMENT'))
+{
+ @define('PHPBB_ENVIRONMENT', 'production');
+}
+
require($phpbb_root_path . 'includes/constants.' . $phpEx);
require($phpbb_root_path . 'includes/functions.' . $phpEx);
require($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
+require($phpbb_root_path . 'includes/functions_compatibility.' . $phpEx);
-$phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
-$phpbb_container_builder->set_dump_container(false);
+$phpbb_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+$phpbb_container = $phpbb_container_builder->with_config($phpbb_config_php_file);
$input = new ArgvInput();
+if ($input->hasParameterOption(array('--env')))
+{
+ $phpbb_container_builder->with_environment($input->getParameterOption('--env'));
+}
+
if ($input->hasParameterOption(array('--safe-mode')))
{
- $phpbb_container_builder->set_use_extensions(false);
- $phpbb_container_builder->set_dump_container(false);
+ $phpbb_container_builder->without_extensions();
+ $phpbb_container_builder->without_cache();
}
else
{
$phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx);
$phpbb_class_loader_ext->register();
- phpbb_load_extensions_autoloaders($phpbb_root_path);
}
$phpbb_container = $phpbb_container_builder->get_container();
$phpbb_container->get('request')->enable_super_globals();
require($phpbb_root_path . 'includes/compatibility_globals.' . $phpEx);
+register_compatibility_globals();
+
+/** @var \phpbb\config\config $config */
+$config = $phpbb_container->get('config');
+
+/** @var \phpbb\language\language $language */
+$language = $phpbb_container->get('language');
+$language->set_default_language($config['default_lang']);
+$language->add_lang(array('common', 'acp/common', 'cli'));
+
+/* @var $user \phpbb\user */
$user = $phpbb_container->get('user');
$user->data['user_id'] = ANONYMOUS;
$user->ip = '127.0.0.1';
-$user->add_lang('acp/common');
-$user->add_lang('cli');
-$application = new \phpbb\console\application('phpBB Console', PHPBB_VERSION, $user);
+$application = new \phpbb\console\application('phpBB Console', PHPBB_VERSION, $language);
+$application->setDispatcher($phpbb_container->get('dispatcher'));
$application->register_container_commands($phpbb_container->get('console.command_collection'));
$application->run($input);
diff --git a/phpBB/common.php b/phpBB/common.php
index 71d501e926..172503f078 100644
--- a/phpBB/common.php
+++ b/phpBB/common.php
@@ -12,7 +12,7 @@
*/
/**
-* Minimum Requirement: PHP 5.3.3
+* Minimum Requirement: PHP 5.4.0
*/
if (!defined('IN_PHPBB'))
@@ -29,6 +29,11 @@ $phpbb_class_loader->register();
$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
extract($phpbb_config_php_file->get_all());
+if (!defined('PHPBB_ENVIRONMENT'))
+{
+ @define('PHPBB_ENVIRONMENT', 'production');
+}
+
if (!defined('PHPBB_INSTALLED'))
{
// Redirect the user to the installer
@@ -53,14 +58,14 @@ if (!defined('PHPBB_INSTALLED'))
}
// $phpbb_root_path accounts for redirects from e.g. /adm
- $script_path = trim(dirname($script_name)) . '/' . $phpbb_root_path . 'install/index.' . $phpEx;
+ $script_path = trim(dirname($script_name)) . '/' . $phpbb_root_path . 'install/app.' . $phpEx;
// Replace any number of consecutive backslashes and/or slashes with a single slash
// (could happen on some proxy setups and/or Windows servers)
$script_path = preg_replace('#[\\\\/]{2,}#', '/', $script_path);
// Eliminate . and .. from the path
require($phpbb_root_path . 'phpbb/filesystem.' . $phpEx);
- $phpbb_filesystem = new phpbb\filesystem();
+ $phpbb_filesystem = new phpbb\filesystem\filesystem();
$script_path = $phpbb_filesystem->clean_path($script_path);
$url = (($secure) ? 'https://' : 'http://') . $server_name;
@@ -91,26 +96,51 @@ include($phpbb_root_path . 'includes/functions_compatibility.' . $phpEx);
require($phpbb_root_path . 'includes/constants.' . $phpEx);
require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
-// Set PHP error handler to ours
-set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
+if (PHPBB_ENVIRONMENT === 'development')
+{
+ \phpbb\debug\debug::enable();
+}
+else
+{
+ set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
+}
$phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx);
$phpbb_class_loader_ext->register();
-phpbb_load_extensions_autoloaders($phpbb_root_path);
-
// Set up container
-$phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
-$phpbb_container = $phpbb_container_builder->get_container();
+try
+{
+ $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+ $phpbb_container = $phpbb_container_builder->with_config($phpbb_config_php_file)->get_container();
+}
+catch (InvalidArgumentException $e)
+{
+ if (PHPBB_ENVIRONMENT !== 'development')
+ {
+ trigger_error(
+ 'The requested environment ' . PHPBB_ENVIRONMENT . ' is not available.',
+ E_USER_ERROR
+ );
+ }
+ else
+ {
+ throw $e;
+ }
+}
$phpbb_class_loader->set_cache($phpbb_container->get('cache.driver'));
$phpbb_class_loader_ext->set_cache($phpbb_container->get('cache.driver'));
require($phpbb_root_path . 'includes/compatibility_globals.' . $phpEx);
+register_compatibility_globals();
+
// Add own hook handler
require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
$phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));
+
+/* @var $phpbb_hook_finder \phpbb\hook\finder */
$phpbb_hook_finder = $phpbb_container->get('hook_finder');
foreach ($phpbb_hook_finder->find() as $hook)
diff --git a/phpBB/composer.json b/phpBB/composer.json
index e6cb2f40ae..e97407bf7f 100644
--- a/phpBB/composer.json
+++ b/phpBB/composer.json
@@ -4,7 +4,7 @@
"type": "project",
"keywords": ["phpbb", "forum"],
"homepage": "https://www.phpbb.com",
- "license": "GPL-2.0",
+ "license": "GPL-2.0-only",
"authors": [
{
"name": "phpBB Limited",
@@ -25,36 +25,51 @@
"phpbb/phpbb-core": "self.version"
},
"require": {
- "php": ">=5.3.3,<=7.3",
- "lusitanian/oauth": "0.2.*",
- "symfony/config": "2.3.*",
- "symfony/console": "2.3.*",
- "symfony/dependency-injection": "2.3.*",
- "symfony/event-dispatcher": "2.3.*",
- "symfony/http-kernel": "2.3.*",
- "symfony/routing": "2.3.*",
- "symfony/yaml": "2.3.*",
- "twig/twig": "^1.0,<1.25"
+ "php": ">=5.4",
+ "bantu/ini-get-wrapper": "1.0.*",
+ "google/recaptcha": "~1.1",
+ "guzzlehttp/guzzle": "~5.3",
+ "lusitanian/oauth": "^0.8.1",
+ "marc1706/fast-image-size": "^1.1",
+ "paragonie/random_compat": "^2.0",
+ "patchwork/utf8": "^1.1",
+ "s9e/text-formatter": "^1.3",
+ "symfony/config": "^2.8",
+ "symfony/console": "^2.8",
+ "symfony/debug": "^2.8",
+ "symfony/dependency-injection": "^2.8",
+ "symfony/event-dispatcher": "^2.8",
+ "symfony/filesystem": "^2.8",
+ "symfony/finder": "^2.8",
+ "symfony/http-foundation": "^2.8",
+ "symfony/http-kernel": "^2.8",
+ "symfony/proxy-manager-bridge": "^2.8",
+ "symfony/routing": "^2.8",
+ "symfony/twig-bridge": "^2.8",
+ "symfony/yaml": "^2.8",
+ "twig/twig": "^1.0"
},
"require-dev": {
- "fabpot/goutte": "1.0.*",
+ "fabpot/goutte": "~2.0",
+ "facebook/webdriver": "~1.1",
+ "laravel/homestead": "~2.2",
"phing/phing": "2.4.*",
"phpunit/dbunit": "1.3.*",
- "phpunit/phpunit": "4.1.*",
+ "phpunit/phpunit": "^4.1",
"sami/sami": "1.*",
"squizlabs/php_codesniffer": "2.*",
- "symfony/browser-kit": "2.3.*",
- "symfony/css-selector": "2.3.*",
- "symfony/debug": "2.3.*",
- "symfony/dom-crawler": "2.3.*",
- "symfony/filesystem": "2.3.*",
- "symfony/finder": "2.3.*",
- "symfony/http-foundation": "2.3.*",
- "symfony/process": "2.3.*"
+ "symfony/browser-kit": "^2.8",
+ "symfony/css-selector": "^2.8",
+ "symfony/dom-crawler": "^2.8"
},
"extra": {
"branch-alias": {
- "dev-master": "3.1.x-dev"
+ "dev-master": "3.2.x-dev"
+ }
+ },
+ "config": {
+ "platform": {
+ "php": ">=5.4.7"
}
}
}
diff --git a/phpBB/composer.lock b/phpBB/composer.lock
index edd6f7dc07..735de476c1 100644
--- a/phpBB/composer.lock
+++ b/phpBB/composer.lock
@@ -1,24 +1,294 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "hash": "ab3d7f33388bce90e6032110a537e61f",
- "content-hash": "9c138398f4bc789098b020ed37f6ae20",
+ "content-hash": "cd42964227d699a6923798e33eab3dd5",
"packages": [
{
+ "name": "bantu/ini-get-wrapper",
+ "version": "v1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/bantuXorg/php-ini-get-wrapper.git",
+ "reference": "4770c7feab370c62e23db4f31c112b7c6d90aee2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/bantuXorg/php-ini-get-wrapper/zipball/4770c7feab370c62e23db4f31c112b7c6d90aee2",
+ "reference": "4770c7feab370c62e23db4f31c112b7c6d90aee2",
+ "shasum": ""
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "bantu\\IniGetWrapper\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Convenience wrapper around ini_get()",
+ "time": "2014-09-15T13:12:35+00:00"
+ },
+ {
+ "name": "google/recaptcha",
+ "version": "1.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/google/recaptcha.git",
+ "reference": "2b7e00566afca82a38a1d3adb8e42c118006296e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/google/recaptcha/zipball/2b7e00566afca82a38a1d3adb8e42c118006296e",
+ "reference": "2b7e00566afca82a38a1d3adb8e42c118006296e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.5.*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "ReCaptcha\\": "src/ReCaptcha"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Client library for reCAPTCHA, a free service that protect websites from spam and abuse.",
+ "homepage": "http://www.google.com/recaptcha/",
+ "keywords": [
+ "Abuse",
+ "captcha",
+ "recaptcha",
+ "spam"
+ ],
+ "time": "2015-09-02T17:23:59+00:00"
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "5.3.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "b87eda7a7162f95574032da17e9323c9899cb6b2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b87eda7a7162f95574032da17e9323c9899cb6b2",
+ "reference": "b87eda7a7162f95574032da17e9323c9899cb6b2",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/ringphp": "^1.1",
+ "php": ">=5.4.0",
+ "react/promise": "^2.2"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ],
+ "time": "2019-10-30T09:32:00+00:00"
+ },
+ {
+ "name": "guzzlehttp/ringphp",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/RingPHP.git",
+ "reference": "5e2a174052995663dd68e6b5ad838afd47dd615b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/5e2a174052995663dd68e6b5ad838afd47dd615b",
+ "reference": "5e2a174052995663dd68e6b5ad838afd47dd615b",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/streams": "~3.0",
+ "php": ">=5.4.0",
+ "react/promise": "~2.0"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "~4.0"
+ },
+ "suggest": {
+ "ext-curl": "Guzzle will use specific adapters if cURL is present"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Ring\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.",
+ "time": "2018-07-31T13:22:33+00:00"
+ },
+ {
+ "name": "guzzlehttp/streams",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/streams.git",
+ "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
+ "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Stream\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Provides a simple abstraction over streams of data",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "Guzzle",
+ "stream"
+ ],
+ "time": "2014-10-12T19:18:40+00:00"
+ },
+ {
+ "name": "ircmaxell/password-compat",
+ "version": "v1.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ircmaxell/password_compat.git",
+ "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c",
+ "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c",
+ "shasum": ""
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/password.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Anthony Ferrara",
+ "email": "ircmaxell@php.net",
+ "homepage": "http://blog.ircmaxell.com"
+ }
+ ],
+ "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash",
+ "homepage": "https://github.com/ircmaxell/password_compat",
+ "keywords": [
+ "hashing",
+ "password"
+ ],
+ "time": "2014-11-20T16:49:30+00:00"
+ },
+ {
"name": "lusitanian/oauth",
- "version": "v0.2.5",
+ "version": "v0.8.11",
"source": {
"type": "git",
"url": "https://github.com/Lusitanian/PHPoAuthLib.git",
- "reference": "27e375e13e1badcd6dca7fb47b154b3c48fdec0c"
+ "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/27e375e13e1badcd6dca7fb47b154b3c48fdec0c",
- "reference": "27e375e13e1badcd6dca7fb47b154b3c48fdec0c",
+ "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/fc11a53db4b66da555a6a11fce294f574a8374f9",
+ "reference": "fc11a53db4b66da555a6a11fce294f574a8374f9",
"shasum": ""
},
"require": {
@@ -27,9 +297,11 @@
"require-dev": {
"phpunit/phpunit": "3.7.*",
"predis/predis": "0.8.*@dev",
+ "squizlabs/php_codesniffer": "2.*",
"symfony/http-foundation": "~2.1"
},
"suggest": {
+ "ext-openssl": "Allows for usage of secure connections with the stream-based HTTP client.",
"predis/predis": "Allows using the Redis storage backend.",
"symfony/http-foundation": "Allows using the Symfony Session storage backend."
},
@@ -55,10 +327,12 @@
"email": "david@daviddesberg.com"
},
{
+ "name": "Elliot Chance",
+ "email": "elliotchance@gmail.com"
+ },
+ {
"name": "Pieter Hordijk",
- "email": "info@pieterhordijk.com",
- "homepage": "https://pieterhordijk.com",
- "role": "developer"
+ "email": "info@pieterhordijk.com"
}
],
"description": "PHP 5.3+ oAuth 1/2 Library",
@@ -68,20 +342,251 @@
"oauth",
"security"
],
- "time": "2013-12-25 20:05:42"
+ "time": "2016-07-12T22:15:00+00:00"
},
{
- "name": "psr/log",
+ "name": "marc1706/fast-image-size",
+ "version": "v1.1.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/marc1706/fast-image-size.git",
+ "reference": "3a3a2b036be20f43fa06ce00dfa754df503e6684"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/marc1706/fast-image-size/zipball/3a3a2b036be20f43fa06ce00dfa754df503e6684",
+ "reference": "3a3a2b036be20f43fa06ce00dfa754df503e6684",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "FastImageSize\\": "lib",
+ "FastImageSize\\tests\\": "tests"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marc Alexander",
+ "email": "admin@m-a-styles.de",
+ "homepage": "https://www.m-a-styles.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "fast-image-size is a PHP library that does almost everything PHP's getimagesize() does but without the large overhead of downloading the complete file.",
+ "homepage": "https://www.m-a-styles.de",
+ "keywords": [
+ "fast",
+ "getimagesize",
+ "image",
+ "imagesize",
+ "php",
+ "size"
+ ],
+ "time": "2019-12-07T08:02:07+00:00"
+ },
+ {
+ "name": "ocramius/proxy-manager",
"version": "1.0.2",
"source": {
"type": "git",
+ "url": "https://github.com/Ocramius/ProxyManager.git",
+ "reference": "57e9272ec0e8deccf09421596e0e2252df440e11"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/57e9272ec0e8deccf09421596e0e2252df440e11",
+ "reference": "57e9272ec0e8deccf09421596e0e2252df440e11",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "zendframework/zend-code": ">2.2.5,<3.0"
+ },
+ "require-dev": {
+ "ext-phar": "*",
+ "phpunit/phpunit": "~4.0",
+ "squizlabs/php_codesniffer": "1.5.*"
+ },
+ "suggest": {
+ "ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects",
+ "zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)",
+ "zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)",
+ "zendframework/zend-stdlib": "To use the hydrator proxy",
+ "zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "ProxyManager\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "http://ocramius.github.com/"
+ }
+ ],
+ "description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies",
+ "homepage": "https://github.com/Ocramius/ProxyManager",
+ "keywords": [
+ "aop",
+ "lazy loading",
+ "proxy",
+ "proxy pattern",
+ "service proxies"
+ ],
+ "time": "2015-08-09T04:28:19+00:00"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v2.0.18",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0a58ef6e3146256cc3dc7cc393927bcc7d1b72db",
+ "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "lib/random.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "time": "2019-01-03T20:59:08+00:00"
+ },
+ {
+ "name": "patchwork/utf8",
+ "version": "v1.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/tchwork/utf8.git",
+ "reference": "d296e0026e7ce10b2a9fe594feca9628ef00e9e8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/tchwork/utf8/zipball/d296e0026e7ce10b2a9fe594feca9628ef00e9e8",
+ "reference": "d296e0026e7ce10b2a9fe594feca9628ef00e9e8",
+ "shasum": ""
+ },
+ "require": {
+ "lib-pcre": ">=7.3",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^3.4|^4.4"
+ },
+ "suggest": {
+ "ext-iconv": "Use iconv for best performance",
+ "ext-intl": "Use Intl for best performance",
+ "ext-mbstring": "Use Mbstring for best performance",
+ "ext-wfio": "Use WFIO for UTF-8 filesystem access on Windows"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Patchwork\\": "src/Patchwork/"
+ },
+ "classmap": [
+ "src/Normalizer.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "(Apache-2.0 or GPL-2.0)"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ }
+ ],
+ "description": "Portable and performant UTF-8, Unicode and Grapheme Clusters for PHP",
+ "homepage": "https://github.com/tchwork/utf8",
+ "keywords": [
+ "grapheme",
+ "i18n",
+ "unicode",
+ "utf-8",
+ "utf8"
+ ],
+ "time": "2019-12-03T14:44:12+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "1.1.2",
+ "source": {
+ "type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
- "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
"shasum": ""
},
"require": {
@@ -90,7 +595,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0.x-dev"
+ "dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -115,35 +620,153 @@
"psr",
"psr-3"
],
- "time": "2016-10-10 12:19:37"
+ "time": "2019-11-01T11:05:21+00:00"
+ },
+ {
+ "name": "react/promise",
+ "version": "v2.7.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "31ffa96f8d2ed0341a57848cbb84d88b89dd664d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/31ffa96f8d2ed0341a57848cbb84d88b89dd664d",
+ "reference": "31ffa96f8d2ed0341a57848cbb84d88b89dd664d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "time": "2019-01-07T21:25:54+00:00"
+ },
+ {
+ "name": "s9e/text-formatter",
+ "version": "1.4.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/s9e/TextFormatter.git",
+ "reference": "6857c53658929b66dc0d92daece17f211c64ea61"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/s9e/TextFormatter/zipball/6857c53658929b66dc0d92daece17f211c64ea61",
+ "reference": "6857c53658929b66dc0d92daece17f211c64ea61",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-filter": "*",
+ "lib-pcre": ">=7.2",
+ "php": ">=5.4.7"
+ },
+ "require-dev": {
+ "matthiasmullie/minify": "*",
+ "php-coveralls/php-coveralls": "*",
+ "phpunit/phpunit": "<6",
+ "s9e/regexp-builder": "1.*"
+ },
+ "suggest": {
+ "ext-curl": "Improves the performance of the MediaEmbed plugin and some JavaScript minifiers",
+ "ext-intl": "Allows international URLs to be accepted by the URL filter",
+ "ext-json": "Enables the generation of a JavaScript parser",
+ "ext-mbstring": "Improves the performance of the PHP renderer",
+ "ext-tokenizer": "Improves the performance of the PHP renderer",
+ "ext-xsl": "Enables the XSLT renderer",
+ "ext-zlib": "Enables gzip compression when scraping content via the MediaEmbed plugin"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "s9e\\TextFormatter\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Multi-purpose text formatting and markup library. Plugins offer support for BBCodes, Markdown, emoticons, HTML, embedding media (YouTube, etc...), enhanced typography and more.",
+ "homepage": "https://github.com/s9e/TextFormatter/",
+ "keywords": [
+ "bbcode",
+ "bbcodes",
+ "blog",
+ "censor",
+ "embed",
+ "emoji",
+ "emoticons",
+ "engine",
+ "forum",
+ "html",
+ "markdown",
+ "markup",
+ "media",
+ "parser",
+ "shortcodes"
+ ],
+ "time": "2019-06-04T15:47:55+00:00"
},
{
"name": "symfony/config",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Config",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
- "reference": "16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b"
+ "reference": "7dd5f5040dc04c118d057fb5886563963eb70011"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/config/zipball/16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b",
- "reference": "16a645cef1c09ebfc907d3c9b3e9f5836a7d4d3b",
+ "url": "https://api.github.com/repos/symfony/config/zipball/7dd5f5040dc04c118d057fb5886563963eb70011",
+ "reference": "7dd5f5040dc04c118d057fb5886563963eb70011",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "symfony/filesystem": "~2.3"
+ "php": ">=5.3.9",
+ "symfony/filesystem": "~2.3|~3.0.0",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "require-dev": {
+ "symfony/yaml": "~2.7|~3.0.0"
+ },
+ "suggest": {
+ "symfony/yaml": "To use the yaml reference dumper"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
@@ -166,40 +789,45 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
- "time": "2016-05-30 08:14:41"
+ "time": "2018-11-26T09:38:12+00:00"
},
{
"name": "symfony/console",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Console",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "20c12c6d6c5a087a66d4e77999451713a92a3507"
+ "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/20c12c6d6c5a087a66d4e77999451713a92a3507",
- "reference": "20c12c6d6c5a087a66d4e77999451713a92a3507",
+ "url": "https://api.github.com/repos/symfony/console/zipball/cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12",
+ "reference": "cbcf4b5e233af15cd2bbd50dee1ccc9b7927dc12",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9",
+ "symfony/debug": "^2.7.2|~3.0.0",
+ "symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
- "symfony/event-dispatcher": "~2.1"
+ "psr/log": "~1.0",
+ "symfony/event-dispatcher": "~2.1|~3.0.0",
+ "symfony/process": "~2.1|~3.0.0"
},
"suggest": {
- "symfony/event-dispatcher": ""
+ "psr/log-implementation": "For using the console logger",
+ "symfony/event-dispatcher": "",
+ "symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
@@ -222,46 +850,41 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
- "time": "2016-05-26 08:04:58"
+ "time": "2018-11-20T15:55:20+00:00"
},
{
"name": "symfony/debug",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Debug",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
- "reference": "863d29c31a1ddfcf1faedf5f8362f392e3261632"
+ "reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/debug/zipball/863d29c31a1ddfcf1faedf5f8362f392e3261632",
- "reference": "863d29c31a1ddfcf1faedf5f8362f392e3261632",
+ "url": "https://api.github.com/repos/symfony/debug/zipball/74251c8d50dd3be7c4ce0c7b862497cdc641a5d0",
+ "reference": "74251c8d50dd3be7c4ce0c7b862497cdc641a5d0",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9",
+ "psr/log": "~1.0"
},
"conflict": {
"symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
},
"require-dev": {
- "symfony/http-foundation": "~2.1",
- "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2"
- },
- "suggest": {
- "symfony/class-loader": "",
- "symfony/http-foundation": "",
- "symfony/http-kernel": ""
+ "symfony/class-loader": "~2.2|~3.0.0",
+ "symfony/http-kernel": "~2.3.24|~2.5.9|^2.6.2|~3.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
@@ -284,43 +907,47 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
- "time": "2016-03-30 09:02:35"
+ "time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/dependency-injection",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/DependencyInjection",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
- "reference": "06265ee128644eb70356bd72ab28c9ded6618d19"
+ "reference": "c306198fee8f872a8f5f031e6e4f6f83086992d8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/06265ee128644eb70356bd72ab28c9ded6618d19",
- "reference": "06265ee128644eb70356bd72ab28c9ded6618d19",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c306198fee8f872a8f5f031e6e4f6f83086992d8",
+ "reference": "c306198fee8f872a8f5f031e6e4f6f83086992d8",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9"
+ },
+ "conflict": {
+ "symfony/expression-language": "<2.6"
},
"require-dev": {
- "symfony/config": "~2.2",
- "symfony/yaml": "~2.1"
+ "symfony/config": "~2.2|~3.0.0",
+ "symfony/expression-language": "~2.6|~3.0.0",
+ "symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7"
},
"suggest": {
"symfony/config": "",
+ "symfony/expression-language": "For using expressions in service container configuration",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\DependencyInjection\\": ""
},
"exclude-from-classmap": [
@@ -343,28 +970,31 @@
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
- "time": "2016-05-30 08:31:06"
+ "time": "2019-04-16T11:33:46+00:00"
},
{
"name": "symfony/event-dispatcher",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/EventDispatcher",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "fd6d162d97bf3e6060622e5c015af39ca72e33bc"
+ "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fd6d162d97bf3e6060622e5c015af39ca72e33bc",
- "reference": "fd6d162d97bf3e6060622e5c015af39ca72e33bc",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a77e974a5fecb4398833b0709210e3d5e334ffb0",
+ "reference": "a77e974a5fecb4398833b0709210e3d5e334ffb0",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9"
},
"require-dev": {
- "symfony/dependency-injection": "~2.0,>=2.0.5"
+ "psr/log": "~1.0",
+ "symfony/config": "^2.0.5|~3.0.0",
+ "symfony/dependency-injection": "~2.6|~3.0.0",
+ "symfony/expression-language": "~2.6|~3.0.0",
+ "symfony/stopwatch": "~2.3|~3.0.0"
},
"suggest": {
"symfony/dependency-injection": "",
@@ -373,11 +1003,11 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
},
"exclude-from-classmap": [
@@ -400,34 +1030,34 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
- "time": "2016-04-04 09:22:54"
+ "time": "2018-11-21T14:20:20+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Filesystem",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3"
+ "reference": "7ae46872dad09dffb7fe1e93a0937097339d0080"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3",
- "reference": "8fd9cd1da0afe63f0d9d4f27875782a2b7d590d3",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/7ae46872dad09dffb7fe1e93a0937097339d0080",
+ "reference": "7ae46872dad09dffb7fe1e93a0937097339d0080",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9",
+ "symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
@@ -450,40 +1080,90 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
- "time": "2016-04-12 15:20:10"
+ "time": "2018-11-11T11:18:13+00:00"
+ },
+ {
+ "name": "symfony/finder",
+ "version": "v2.8.52",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "1444eac52273e345d9b95129bf914639305a9ba4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/1444eac52273e345d9b95129bf914639305a9ba4",
+ "reference": "1444eac52273e345d9b95129bf914639305a9ba4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.8-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Finder Component",
+ "homepage": "https://symfony.com",
+ "time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/http-foundation",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/HttpFoundation",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "9f4dbb1f3e3cad22d9462e0306c9c71212458f61"
+ "reference": "3929d9fe8148d17819ad0178c748b8d339420709"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9f4dbb1f3e3cad22d9462e0306c9c71212458f61",
- "reference": "9f4dbb1f3e3cad22d9462e0306c9c71212458f61",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3929d9fe8148d17819ad0178c748b8d339420709",
+ "reference": "3929d9fe8148d17819ad0178c748b8d339420709",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "symfony/polyfill-mbstring": "~1.1"
+ "php": ">=5.3.9",
+ "symfony/polyfill-mbstring": "~1.1",
+ "symfony/polyfill-php54": "~1.0",
+ "symfony/polyfill-php55": "~1.0"
+ },
+ "require-dev": {
+ "symfony/expression-language": "~2.4|~3.0.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\HttpFoundation\\": ""
},
- "classmap": [
- "Symfony/Component/HttpFoundation/Resources/stubs"
- ],
"exclude-from-classmap": [
"/Tests/"
]
@@ -504,43 +1184,51 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
- "time": "2016-05-13 15:22:39"
+ "time": "2019-11-12T12:34:41+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/HttpKernel",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "57e0329236e8edf2b0e683043c604f7c9aba9398"
+ "reference": "c3be27b8627cd5ee8dfa8d1b923982f618ec521c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/57e0329236e8edf2b0e683043c604f7c9aba9398",
- "reference": "57e0329236e8edf2b0e683043c604f7c9aba9398",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/c3be27b8627cd5ee8dfa8d1b923982f618ec521c",
+ "reference": "c3be27b8627cd5ee8dfa8d1b923982f618ec521c",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
+ "php": ">=5.3.9",
"psr/log": "~1.0",
- "symfony/debug": "~2.3.24|~2.5.9|~2.6,>=2.6.2",
- "symfony/event-dispatcher": "~2.1",
- "symfony/http-foundation": "~2.3,>=2.3.4"
+ "symfony/debug": "^2.6.2",
+ "symfony/event-dispatcher": "^2.6.7|~3.0.0",
+ "symfony/http-foundation": "~2.7.36|~2.8.29|~3.1.6",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-php56": "~1.8"
+ },
+ "conflict": {
+ "symfony/config": "<2.7",
+ "twig/twig": "<1.34|<2.4,>=2"
},
"require-dev": {
- "symfony/browser-kit": "~2.3",
- "symfony/class-loader": "~2.1",
- "symfony/config": "~2.0,>=2.0.5",
- "symfony/console": "~2.2",
- "symfony/css-selector": "~2.0,>=2.0.5",
- "symfony/dependency-injection": "~2.2",
- "symfony/dom-crawler": "~2.0,>=2.0.5",
- "symfony/finder": "~2.0,>=2.0.5",
- "symfony/process": "~2.0,>=2.0.5",
- "symfony/routing": "~2.2",
- "symfony/stopwatch": "~2.3",
- "symfony/templating": "~2.2"
+ "symfony/browser-kit": "~2.3|~3.0.0",
+ "symfony/class-loader": "~2.1|~3.0.0",
+ "symfony/config": "~2.8",
+ "symfony/console": "~2.3|~3.0.0",
+ "symfony/css-selector": "^2.0.5|~3.0.0",
+ "symfony/dependency-injection": "~2.8|~3.0.0",
+ "symfony/dom-crawler": "^2.0.5|~3.0.0",
+ "symfony/expression-language": "~2.4|~3.0.0",
+ "symfony/finder": "^2.0.5|~3.0.0",
+ "symfony/process": "^2.0.5|~3.0.0",
+ "symfony/routing": "~2.8|~3.0.0",
+ "symfony/stopwatch": "~2.3|~3.0.0",
+ "symfony/templating": "~2.2|~3.0.0",
+ "symfony/translation": "^2.0.5|~3.0.0",
+ "symfony/var-dumper": "~2.6|~3.0.0"
},
"suggest": {
"symfony/browser-kit": "",
@@ -548,16 +1236,17 @@
"symfony/config": "",
"symfony/console": "",
"symfony/dependency-injection": "",
- "symfony/finder": ""
+ "symfony/finder": "",
+ "symfony/var-dumper": ""
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\HttpKernel\\": ""
},
"exclude-from-classmap": [
@@ -580,20 +1269,78 @@
],
"description": "Symfony HttpKernel Component",
"homepage": "https://symfony.com",
- "time": "2016-05-30 08:41:10"
+ "time": "2019-11-13T08:36:16+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
+ "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.13-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "time": "2019-11-27T13:56:44+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.3.0",
+ "version": "v1.13.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
+ "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
- "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f",
+ "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f",
"shasum": ""
},
"require": {
@@ -605,7 +1352,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.3-dev"
+ "dev-master": "1.13-dev"
}
},
"autoload": {
@@ -639,46 +1386,328 @@
"portable",
"shim"
],
- "time": "2016-11-14 01:06:16"
+ "time": "2019-11-27T14:18:11+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php54",
+ "version": "v1.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php54.git",
+ "reference": "dd1618047426412036e98d159940d58a81fc392c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/dd1618047426412036e98d159940d58a81fc392c",
+ "reference": "dd1618047426412036e98d159940d58a81fc392c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.13-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php54\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ],
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2019-11-27T13:56:44+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php55",
+ "version": "v1.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php55.git",
+ "reference": "b0d838f225725e2951af1aafc784d2e5ea7b656e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/b0d838f225725e2951af1aafc784d2e5ea7b656e",
+ "reference": "b0d838f225725e2951af1aafc784d2e5ea7b656e",
+ "shasum": ""
+ },
+ "require": {
+ "ircmaxell/password-compat": "~1.0",
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.13-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php55\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2019-11-27T13:56:44+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php56",
+ "version": "v1.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php56.git",
+ "reference": "53dd1cdf3cb986893ccf2b96665b25b3abb384f4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/53dd1cdf3cb986893ccf2b96665b25b3abb384f4",
+ "reference": "53dd1cdf3cb986893ccf2b96665b25b3abb384f4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/polyfill-util": "~1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.13-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Php56\\": ""
+ },
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "time": "2019-11-27T13:56:44+00:00"
+ },
+ {
+ "name": "symfony/polyfill-util",
+ "version": "v1.13.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-util.git",
+ "reference": "964a67f293b66b95883a5ed918a65354fcd2258f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/964a67f293b66b95883a5ed918a65354fcd2258f",
+ "reference": "964a67f293b66b95883a5ed918a65354fcd2258f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.13-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Polyfill\\Util\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony utilities for portability of PHP codes",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compat",
+ "compatibility",
+ "polyfill",
+ "shim"
+ ],
+ "time": "2019-11-27T13:56:44+00:00"
+ },
+ {
+ "name": "symfony/proxy-manager-bridge",
+ "version": "v2.8.52",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/proxy-manager-bridge.git",
+ "reference": "40802595fea26ada845ed58124d8000a13dd4c6f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/proxy-manager-bridge/zipball/40802595fea26ada845ed58124d8000a13dd4c6f",
+ "reference": "40802595fea26ada845ed58124d8000a13dd4c6f",
+ "shasum": ""
+ },
+ "require": {
+ "ocramius/proxy-manager": "~0.4|~1.0|~2.0",
+ "php": ">=5.3.9",
+ "symfony/dependency-injection": "~2.8|~3.0.0"
+ },
+ "require-dev": {
+ "symfony/config": "~2.3|~3.0.0"
+ },
+ "type": "symfony-bridge",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.8-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bridge\\ProxyManager\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony ProxyManager Bridge",
+ "homepage": "https://symfony.com",
+ "time": "2019-04-16T11:33:46+00:00"
},
{
"name": "symfony/routing",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Routing",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "5b8a2bb7569df81401171829498809e90d6e446c"
+ "reference": "8b0df6869d1997baafff6a1541826eac5a03d067"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/5b8a2bb7569df81401171829498809e90d6e446c",
- "reference": "5b8a2bb7569df81401171829498809e90d6e446c",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/8b0df6869d1997baafff6a1541826eac5a03d067",
+ "reference": "8b0df6869d1997baafff6a1541826eac5a03d067",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9"
+ },
+ "conflict": {
+ "symfony/config": "<2.7"
},
"require-dev": {
- "doctrine/common": "~2.2",
+ "doctrine/annotations": "~1.0",
"psr/log": "~1.0",
- "symfony/config": "~2.2",
- "symfony/http-foundation": "~2.3",
- "symfony/yaml": "~2.0,>=2.0.5"
+ "symfony/config": "~2.7|~3.0.0",
+ "symfony/expression-language": "~2.4|~3.0.0",
+ "symfony/http-foundation": "~2.3|~3.0.0",
+ "symfony/yaml": "^2.0.5|~3.0.0"
},
"suggest": {
- "doctrine/common": "",
- "symfony/config": "",
- "symfony/yaml": ""
+ "doctrine/annotations": "For using the annotation loader",
+ "symfony/config": "For using the all-in-one router or any loader",
+ "symfony/dependency-injection": "For loading routes from a service",
+ "symfony/expression-language": "For using expression matching",
+ "symfony/http-foundation": "For using a Symfony Request object",
+ "symfony/yaml": "For using the YAML loader"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\Routing\\": ""
},
"exclude-from-classmap": [
@@ -701,34 +1730,125 @@
],
"description": "Symfony Routing Component",
"homepage": "https://symfony.com",
- "time": "2016-05-29 10:13:06"
+ "keywords": [
+ "router",
+ "routing",
+ "uri",
+ "url"
+ ],
+ "time": "2018-11-20T15:55:20+00:00"
+ },
+ {
+ "name": "symfony/twig-bridge",
+ "version": "v2.8.52",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/twig-bridge.git",
+ "reference": "ecc1e30d05fa99f25b504e2d6a8684555ae39f7c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/ecc1e30d05fa99f25b504e2d6a8684555ae39f7c",
+ "reference": "ecc1e30d05fa99f25b504e2d6a8684555ae39f7c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9",
+ "twig/twig": "~1.34|~2.4"
+ },
+ "conflict": {
+ "symfony/form": "<2.8.23"
+ },
+ "require-dev": {
+ "symfony/asset": "~2.7|~3.0.0",
+ "symfony/console": "~2.8|~3.0.0",
+ "symfony/expression-language": "~2.4|~3.0.0",
+ "symfony/finder": "~2.3|~3.0.0",
+ "symfony/form": "^2.8.23",
+ "symfony/http-foundation": "^2.8.29|~3.0.0",
+ "symfony/http-kernel": "~2.8|~3.0.0",
+ "symfony/polyfill-intl-icu": "~1.0",
+ "symfony/routing": "~2.2|~3.0.0",
+ "symfony/security": "^2.8.31|^3.3.13",
+ "symfony/security-acl": "~2.6|~3.0.0",
+ "symfony/stopwatch": "~2.2|~3.0.0",
+ "symfony/templating": "~2.1|~3.0.0",
+ "symfony/translation": "~2.7|~3.0.0",
+ "symfony/var-dumper": "~2.7.16|~2.8.9|~3.0.9",
+ "symfony/yaml": "^2.0.5|~3.0.0"
+ },
+ "suggest": {
+ "symfony/asset": "For using the AssetExtension",
+ "symfony/expression-language": "For using the ExpressionExtension",
+ "symfony/finder": "",
+ "symfony/form": "For using the FormExtension",
+ "symfony/http-kernel": "For using the HttpKernelExtension",
+ "symfony/routing": "For using the RoutingExtension",
+ "symfony/security": "For using the SecurityExtension",
+ "symfony/stopwatch": "For using the StopwatchExtension",
+ "symfony/templating": "For using the TwigEngine",
+ "symfony/translation": "For using the TranslationExtension",
+ "symfony/var-dumper": "For using the DumpExtension",
+ "symfony/yaml": "For using the YamlExtension"
+ },
+ "type": "symfony-bridge",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.8-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bridge\\Twig\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Twig Bridge",
+ "homepage": "https://symfony.com",
+ "time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/yaml",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Yaml",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
- "reference": "2cb5f366f9e0df014fc93de46cc416ba0a3055f8"
+ "reference": "02c1859112aa779d9ab394ae4f3381911d84052b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/2cb5f366f9e0df014fc93de46cc416ba0a3055f8",
- "reference": "2cb5f366f9e0df014fc93de46cc416ba0a3055f8",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b",
+ "reference": "02c1859112aa779d9ab394ae4f3381911d84052b",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9",
+ "symfony/polyfill-ctype": "~1.8"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
@@ -751,38 +1871,43 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2016-05-30 08:10:17"
+ "time": "2018-11-11T11:18:13+00:00"
},
{
"name": "twig/twig",
- "version": "v1.24.2",
+ "version": "v1.42.2",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
- "reference": "33093f6e310e6976baeac7b14f3a6ec02f2d79b7"
+ "reference": "21707d6ebd05476854805e4f91b836531941bcd4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/twigphp/Twig/zipball/33093f6e310e6976baeac7b14f3a6ec02f2d79b7",
- "reference": "33093f6e310e6976baeac7b14f3a6ec02f2d79b7",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/21707d6ebd05476854805e4f91b836531941bcd4",
+ "reference": "21707d6ebd05476854805e4f91b836531941bcd4",
"shasum": ""
},
"require": {
- "php": ">=5.2.7"
+ "php": ">=5.4.0",
+ "symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
- "symfony/debug": "~2.7",
- "symfony/phpunit-bridge": "~2.7"
+ "psr/container": "^1.0",
+ "symfony/debug": "^2.7",
+ "symfony/phpunit-bridge": "^3.4.19|^4.1.8|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.24-dev"
+ "dev-master": "1.42-dev"
}
},
"autoload": {
"psr-0": {
"Twig_": "lib/"
+ },
+ "psr-4": {
+ "Twig\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -803,153 +1928,206 @@
},
{
"name": "Twig Team",
- "homepage": "http://twig.sensiolabs.org/contributors",
+ "homepage": "https://twig.symfony.com/contributors",
"role": "Contributors"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
- "homepage": "http://twig.sensiolabs.org",
+ "homepage": "https://twig.symfony.com",
"keywords": [
"templating"
],
- "time": "2016-09-01 17:50:53"
- }
- ],
- "packages-dev": [
+ "time": "2019-06-18T15:35:16+00:00"
+ },
{
- "name": "fabpot/goutte",
- "version": "v1.0.7",
+ "name": "zendframework/zend-code",
+ "version": "2.5.1",
"source": {
"type": "git",
- "url": "https://github.com/FriendsOfPHP/Goutte.git",
- "reference": "794b196e76bdd37b5155cdecbad311f0a3b07625"
+ "url": "https://github.com/zendframework/zend-code.git",
+ "reference": "5d998f261ec2a55171c71da57a11622745680153"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/794b196e76bdd37b5155cdecbad311f0a3b07625",
- "reference": "794b196e76bdd37b5155cdecbad311f0a3b07625",
+ "url": "https://api.github.com/repos/zendframework/zend-code/zipball/5d998f261ec2a55171c71da57a11622745680153",
+ "reference": "5d998f261ec2a55171c71da57a11622745680153",
"shasum": ""
},
"require": {
- "ext-curl": "*",
- "guzzle/http": "~3.1",
- "php": ">=5.3.0",
- "symfony/browser-kit": "~2.1",
- "symfony/css-selector": "~2.1",
- "symfony/dom-crawler": "~2.1",
- "symfony/finder": "~2.1",
- "symfony/process": "~2.1"
+ "php": ">=5.3.23",
+ "zendframework/zend-eventmanager": "~2.5"
},
"require-dev": {
- "guzzle/plugin-history": "~3.1",
- "guzzle/plugin-mock": "~3.1"
+ "doctrine/common": ">=2.1",
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "zendframework/zend-stdlib": "~2.5",
+ "zendframework/zend-version": "~2.5"
},
- "type": "application",
+ "suggest": {
+ "doctrine/common": "Doctrine\\Common >=2.1 for annotation features",
+ "zendframework/zend-stdlib": "Zend\\Stdlib component"
+ },
+ "type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-master": "2.5-dev",
+ "dev-develop": "2.6-dev"
}
},
"autoload": {
- "psr-0": {
- "Goutte": "."
+ "psr-4": {
+ "Zend\\Code\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- }
+ "BSD-3-Clause"
],
- "description": "A simple PHP Web Scraper",
- "homepage": "https://github.com/fabpot/Goutte",
+ "description": "provides facilities to generate arbitrary code using an object oriented interface",
+ "homepage": "https://github.com/zendframework/zend-code",
"keywords": [
- "scraper"
+ "code",
+ "zf2"
],
- "time": "2014-10-09 15:52:51"
+ "time": "2015-06-03T15:31:59+00:00"
},
{
- "name": "guzzle/common",
- "version": "v3.9.2",
- "target-dir": "Guzzle/Common",
+ "name": "zendframework/zend-eventmanager",
+ "version": "2.5.1",
"source": {
"type": "git",
- "url": "https://github.com/Guzzle3/common.git",
- "reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc"
+ "url": "https://github.com/zendframework/zend-eventmanager.git",
+ "reference": "d94a16039144936f107f906896349900fd634443"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Guzzle3/common/zipball/2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc",
- "reference": "2e36af7cf2ce3ea1f2d7c2831843b883a8e7b7dc",
+ "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/d94a16039144936f107f906896349900fd634443",
+ "reference": "d94a16039144936f107f906896349900fd634443",
"shasum": ""
},
"require": {
- "php": ">=5.3.2",
- "symfony/event-dispatcher": ">=2.1"
+ "php": ">=5.3.23",
+ "zendframework/zend-stdlib": "~2.5"
+ },
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.7-dev"
+ "dev-master": "2.5-dev",
+ "dev-develop": "2.6-dev"
}
},
"autoload": {
- "psr-0": {
- "Guzzle\\Common": ""
+ "psr-4": {
+ "Zend\\EventManager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "MIT"
+ "BSD-3-Clause"
],
- "description": "Common libraries used by Guzzle",
- "homepage": "http://guzzlephp.org/",
+ "homepage": "https://github.com/zendframework/zend-eventmanager",
"keywords": [
- "collection",
- "common",
- "event",
- "exception"
+ "eventmanager",
+ "zf2"
],
- "abandoned": "guzzle/guzzle",
- "time": "2014-08-11 04:32:36"
+ "time": "2015-06-03T15:32:01+00:00"
},
{
- "name": "guzzle/http",
- "version": "v3.9.2",
- "target-dir": "Guzzle/Http",
+ "name": "zendframework/zend-stdlib",
+ "version": "2.5.1",
"source": {
"type": "git",
- "url": "https://github.com/Guzzle3/http.git",
- "reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5"
+ "url": "https://github.com/zendframework/zend-stdlib.git",
+ "reference": "cc8e90a60dd5d44b9730b77d07b97550091da1ae"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Guzzle3/http/zipball/1e8dd1e2ba9dc42332396f39fbfab950b2301dc5",
- "reference": "1e8dd1e2ba9dc42332396f39fbfab950b2301dc5",
+ "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/cc8e90a60dd5d44b9730b77d07b97550091da1ae",
+ "reference": "cc8e90a60dd5d44b9730b77d07b97550091da1ae",
"shasum": ""
},
"require": {
- "guzzle/common": "self.version",
- "guzzle/parser": "self.version",
- "guzzle/stream": "self.version",
- "php": ">=5.3.2"
+ "php": ">=5.3.23"
+ },
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "zendframework/zend-config": "~2.5",
+ "zendframework/zend-eventmanager": "~2.5",
+ "zendframework/zend-filter": "~2.5",
+ "zendframework/zend-inputfilter": "~2.5",
+ "zendframework/zend-serializer": "~2.5",
+ "zendframework/zend-servicemanager": "~2.5"
},
"suggest": {
- "ext-curl": "*"
+ "zendframework/zend-eventmanager": "To support aggregate hydrator usage",
+ "zendframework/zend-filter": "To support naming strategy hydrator usage",
+ "zendframework/zend-serializer": "Zend\\Serializer component",
+ "zendframework/zend-servicemanager": "To support hydrator plugin manager usage"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.7-dev"
+ "dev-master": "2.5-dev",
+ "dev-develop": "2.6-dev"
}
},
"autoload": {
- "psr-0": {
- "Guzzle\\Http": ""
+ "psr-4": {
+ "Zend\\Stdlib\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "homepage": "https://github.com/zendframework/zend-stdlib",
+ "keywords": [
+ "stdlib",
+ "zf2"
+ ],
+ "time": "2015-06-03T15:32:03+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "doctrine/instantiator",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/doctrine/instantiator.git",
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
+ "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3,<8.0-DEV"
+ },
+ "require-dev": {
+ "athletic/athletic": "~0.1.8",
+ "ext-pdo": "*",
+ "ext-phar": "*",
+ "phpunit/phpunit": "~4.0",
+ "squizlabs/php_codesniffer": "~2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -958,99 +2136,140 @@
],
"authors": [
{
- "name": "Michael Dowling",
- "email": "mtdowling@gmail.com",
- "homepage": "https://github.com/mtdowling"
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com",
+ "homepage": "http://ocramius.github.com/"
}
],
- "description": "HTTP libraries used by Guzzle",
- "homepage": "http://guzzlephp.org/",
+ "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
+ "homepage": "https://github.com/doctrine/instantiator",
"keywords": [
- "Guzzle",
- "client",
- "curl",
- "http",
- "http client"
+ "constructor",
+ "instantiate"
],
- "abandoned": "guzzle/guzzle",
- "time": "2014-08-11 04:32:36"
+ "time": "2015-06-14T21:17:01+00:00"
},
{
- "name": "guzzle/parser",
- "version": "v3.9.2",
- "target-dir": "Guzzle/Parser",
+ "name": "fabpot/goutte",
+ "version": "v2.0.4",
"source": {
"type": "git",
- "url": "https://github.com/Guzzle3/parser.git",
- "reference": "6874d171318a8e93eb6d224cf85e4678490b625c"
+ "url": "https://github.com/FriendsOfPHP/Goutte.git",
+ "reference": "0ad3ee6dc2d0aaa832a80041a1e09bf394e99802"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Guzzle3/parser/zipball/6874d171318a8e93eb6d224cf85e4678490b625c",
- "reference": "6874d171318a8e93eb6d224cf85e4678490b625c",
+ "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/0ad3ee6dc2d0aaa832a80041a1e09bf394e99802",
+ "reference": "0ad3ee6dc2d0aaa832a80041a1e09bf394e99802",
"shasum": ""
},
"require": {
- "php": ">=5.3.2"
+ "guzzlehttp/guzzle": ">=4,<6",
+ "php": ">=5.4.0",
+ "symfony/browser-kit": "~2.1",
+ "symfony/css-selector": "~2.1",
+ "symfony/dom-crawler": "~2.1"
},
- "type": "library",
+ "type": "application",
"extra": {
"branch-alias": {
- "dev-master": "3.7-dev"
+ "dev-master": "2.0-dev"
}
},
"autoload": {
- "psr-0": {
- "Guzzle\\Parser": ""
+ "psr-4": {
+ "Goutte\\": "Goutte"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
- "description": "Interchangeable parsers used by Guzzle",
- "homepage": "http://guzzlephp.org/",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "description": "A simple PHP Web Scraper",
+ "homepage": "https://github.com/FriendsOfPHP/Goutte",
"keywords": [
- "URI Template",
- "cookie",
- "http",
- "message",
- "url"
+ "scraper"
],
- "abandoned": "guzzle/guzzle",
- "time": "2014-02-05 18:29:46"
+ "time": "2015-05-05T21:14:57+00:00"
},
{
- "name": "guzzle/stream",
- "version": "v3.9.2",
- "target-dir": "Guzzle/Stream",
+ "name": "facebook/webdriver",
+ "version": "1.1.3",
"source": {
"type": "git",
- "url": "https://github.com/Guzzle3/stream.git",
- "reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0"
+ "url": "https://github.com/facebook/php-webdriver.git",
+ "reference": "b7186fb1bcfda956d237f59face250d06ef47253"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Guzzle3/stream/zipball/60c7fed02e98d2c518dae8f97874c8f4622100f0",
- "reference": "60c7fed02e98d2c518dae8f97874c8f4622100f0",
+ "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/b7186fb1bcfda956d237f59face250d06ef47253",
+ "reference": "b7186fb1bcfda956d237f59face250d06ef47253",
"shasum": ""
},
"require": {
- "guzzle/common": "self.version",
- "php": ">=5.3.2"
+ "ext-curl": "*",
+ "php": ">=5.3.19"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^1.11",
+ "phpunit/phpunit": "4.6.* || ~5.0",
+ "squizlabs/php_codesniffer": "^2.6"
},
"suggest": {
- "guzzle/http": "To convert Guzzle request objects to PHP streams"
+ "phpdocumentor/phpdocumentor": "2.*"
},
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "3.7-dev"
+ "autoload": {
+ "psr-4": {
+ "Facebook\\WebDriver\\": "lib/"
}
},
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "description": "A PHP client for WebDriver",
+ "homepage": "https://github.com/facebook/php-webdriver",
+ "keywords": [
+ "facebook",
+ "php",
+ "selenium",
+ "webdriver"
+ ],
+ "time": "2016-08-10T00:44:08+00:00"
+ },
+ {
+ "name": "laravel/homestead",
+ "version": "v2.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laravel/homestead.git",
+ "reference": "f4e45f895d8707042c2d0698627d33c484e7c6ba"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laravel/homestead/zipball/f4e45f895d8707042c2d0698627d33c484e7c6ba",
+ "reference": "f4e45f895d8707042c2d0698627d33c484e7c6ba",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4",
+ "symfony/console": "~2.0 || ~3.0",
+ "symfony/process": "~2.0 || ~3.0"
+ },
+ "bin": [
+ "homestead"
+ ],
+ "type": "library",
"autoload": {
- "psr-0": {
- "Guzzle\\Stream": ""
+ "psr-4": {
+ "Laravel\\Homestead\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1059,47 +2278,37 @@
],
"authors": [
{
- "name": "Michael Dowling",
- "email": "mtdowling@gmail.com",
- "homepage": "https://github.com/mtdowling"
+ "name": "Taylor Otwell",
+ "email": "taylorotwell@gmail.com"
}
],
- "description": "Guzzle stream wrapper component",
- "homepage": "http://guzzlephp.org/",
- "keywords": [
- "Guzzle",
- "component",
- "stream"
- ],
- "abandoned": "guzzle/guzzle",
- "time": "2014-05-01 21:36:02"
+ "description": "A virtual machine for web artisans.",
+ "time": "2016-09-17T04:42:33+00:00"
},
{
"name": "michelf/php-markdown",
- "version": "1.7.0",
+ "version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/michelf/php-markdown.git",
- "reference": "1f51cc520948f66cd2af8cbc45a5ee175e774220"
+ "reference": "c83178d49e372ca967d1a8c77ae4e051b3a3c75c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/michelf/php-markdown/zipball/1f51cc520948f66cd2af8cbc45a5ee175e774220",
- "reference": "1f51cc520948f66cd2af8cbc45a5ee175e774220",
+ "url": "https://api.github.com/repos/michelf/php-markdown/zipball/c83178d49e372ca967d1a8c77ae4e051b3a3c75c",
+ "reference": "c83178d49e372ca967d1a8c77ae4e051b3a3c75c",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-lib": "1.4.x-dev"
- }
+ "require-dev": {
+ "phpunit/phpunit": ">=4.3 <5.8"
},
+ "type": "library",
"autoload": {
- "psr-0": {
- "Michelf": ""
+ "psr-4": {
+ "Michelf\\": "Michelf/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1123,7 +2332,7 @@
"keywords": [
"markdown"
],
- "time": "2016-10-29 18:58:20"
+ "time": "2019-12-02T02:32:27+00:00"
},
{
"name": "nikic/php-parser",
@@ -1168,7 +2377,7 @@
"parser",
"php"
],
- "time": "2014-07-23 18:24:17"
+ "time": "2014-07-23T18:24:17+00:00"
},
{
"name": "phing/phing",
@@ -1206,7 +2415,8 @@
"authors": [
{
"name": "Michiel Rook",
- "email": "mrook@php.net"
+ "email": "mrook@php.net",
+ "role": "Lead"
},
{
"name": "Phing Community",
@@ -1220,7 +2430,119 @@
"task",
"tool"
],
- "time": "2012-11-29 21:23:47"
+ "time": "2012-11-29T21:23:47+00:00"
+ },
+ {
+ "name": "phpdocumentor/reflection-docblock",
+ "version": "2.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
+ "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b",
+ "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0"
+ },
+ "suggest": {
+ "dflydev/markdown": "~1.0",
+ "erusev/parsedown": "~1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "phpDocumentor": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Mike van Riel",
+ "email": "mike.vanriel@naenius.com"
+ }
+ ],
+ "time": "2016-01-25T08:17:30+00:00"
+ },
+ {
+ "name": "phpspec/prophecy",
+ "version": "1.10.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/prophecy.git",
+ "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
+ "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc",
+ "shasum": ""
+ },
+ "require": {
+ "doctrine/instantiator": "^1.0.2",
+ "php": "^5.3|^7.0",
+ "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
+ "sebastian/comparator": "^1.2.3|^2.0|^3.0",
+ "sebastian/recursion-context": "^1.0|^2.0|^3.0"
+ },
+ "require-dev": {
+ "phpspec/phpspec": "^2.5 || ^3.2",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Prophecy\\": "src/Prophecy"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Konstantin Kudryashov",
+ "email": "ever.zet@gmail.com",
+ "homepage": "http://everzet.com"
+ },
+ {
+ "name": "Marcello Duarte",
+ "email": "marcello.duarte@gmail.com"
+ }
+ ],
+ "description": "Highly opinionated mocking framework for PHP 5.3+",
+ "homepage": "https://github.com/phpspec/prophecy",
+ "keywords": [
+ "Double",
+ "Dummy",
+ "fake",
+ "mock",
+ "spy",
+ "stub"
+ ],
+ "time": "2019-12-22T21:05:45+00:00"
},
{
"name": "phpunit/dbunit",
@@ -1279,7 +2601,8 @@
"testing",
"xunit"
],
- "time": "2015-03-29 14:23:04"
+ "abandoned": true,
+ "time": "2015-03-29T14:23:04+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -1341,35 +2664,37 @@
"testing",
"xunit"
],
- "time": "2015-10-06 15:47:00"
+ "time": "2015-10-06T15:47:00+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "1.3.4",
+ "version": "1.4.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
- "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+ "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4.x-dev"
+ }
+ },
"autoload": {
"classmap": [
- "File/"
+ "src/"
]
},
"notification-url": "https://packagist.org/downloads/",
- "include-path": [
- ""
- ],
"license": [
"BSD-3-Clause"
],
@@ -1386,7 +2711,7 @@
"filesystem",
"iterator"
],
- "time": "2013-10-10 15:34:57"
+ "time": "2017-11-27T13:52:08+00:00"
},
{
"name": "phpunit/php-text-template",
@@ -1427,7 +2752,7 @@
"keywords": [
"template"
],
- "time": "2015-06-21 13:50:34"
+ "time": "2015-06-21T13:50:34+00:00"
},
{
"name": "phpunit/php-timer",
@@ -1444,7 +2769,7 @@
"shasum": ""
},
"require": {
- "php": "^5.3.3 || ^7.3.17"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
@@ -1476,20 +2801,20 @@
"keywords": [
"timer"
],
- "time": "2017-02-26 11:10:40"
+ "time": "2017-02-26T11:10:40+00:00"
},
{
"name": "phpunit/php-token-stream",
- "version": "1.4.11",
+ "version": "1.4.12",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
- "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
+ "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
- "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
+ "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
"shasum": ""
},
"require": {
@@ -1525,20 +2850,20 @@
"keywords": [
"tokenizer"
],
- "time": "2017-02-27 10:12:30"
+ "time": "2017-12-04T08:55:13+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "4.1.6",
+ "version": "4.8.36",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "241116219bb7e3b8111a36ffd8f37546888738d6"
+ "reference": "46023de9a91eec7dfb06cc56cb4e260017298517"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/241116219bb7e3b8111a36ffd8f37546888738d6",
- "reference": "241116219bb7e3b8111a36ffd8f37546888738d6",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517",
+ "reference": "46023de9a91eec7dfb06cc56cb4e260017298517",
"shasum": ""
},
"require": {
@@ -1548,17 +2873,19 @@
"ext-reflection": "*",
"ext-spl": "*",
"php": ">=5.3.3",
- "phpunit/php-code-coverage": "~2.0",
- "phpunit/php-file-iterator": "~1.3.1",
+ "phpspec/prophecy": "^1.3.1",
+ "phpunit/php-code-coverage": "~2.1",
+ "phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
- "phpunit/php-timer": "~1.0.2",
- "phpunit/phpunit-mock-objects": "2.1.5",
- "sebastian/comparator": "~1.0",
- "sebastian/diff": "~1.1",
- "sebastian/environment": "~1.0",
- "sebastian/exporter": "~1.0",
+ "phpunit/php-timer": "^1.0.6",
+ "phpunit/phpunit-mock-objects": "~2.3",
+ "sebastian/comparator": "~1.2.2",
+ "sebastian/diff": "~1.2",
+ "sebastian/environment": "~1.3",
+ "sebastian/exporter": "~1.2",
+ "sebastian/global-state": "~1.0",
"sebastian/version": "~1.0",
- "symfony/yaml": "~2.0"
+ "symfony/yaml": "~2.1|~3.0"
},
"suggest": {
"phpunit/php-invoker": "~1.1"
@@ -1569,7 +2896,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.1.x-dev"
+ "dev-master": "4.8.x-dev"
}
},
"autoload": {
@@ -1578,10 +2905,6 @@
]
},
"notification-url": "https://packagist.org/downloads/",
- "include-path": [
- "",
- "../../symfony/yaml/"
- ],
"license": [
"BSD-3-Clause"
],
@@ -1593,34 +2916,36 @@
}
],
"description": "The PHP Unit Testing framework.",
- "homepage": "http://www.phpunit.de/",
+ "homepage": "https://phpunit.de/",
"keywords": [
"phpunit",
"testing",
"xunit"
],
- "time": "2014-08-17 08:07:02"
+ "time": "2017-06-21T08:07:12+00:00"
},
{
"name": "phpunit/phpunit-mock-objects",
- "version": "2.1.5",
+ "version": "2.3.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
- "reference": "7878b9c41edb3afab92b85edf5f0981014a2713a"
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/7878b9c41edb3afab92b85edf5f0981014a2713a",
- "reference": "7878b9c41edb3afab92b85edf5f0981014a2713a",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+ "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
"shasum": ""
},
"require": {
+ "doctrine/instantiator": "^1.0.2",
"php": ">=5.3.3",
- "phpunit/php-text-template": "~1.2"
+ "phpunit/php-text-template": "~1.2",
+ "sebastian/exporter": "~1.2"
},
"require-dev": {
- "phpunit/phpunit": "~4.1"
+ "phpunit/phpunit": "~4.4"
},
"suggest": {
"ext-soap": "*"
@@ -1628,7 +2953,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1.x-dev"
+ "dev-master": "2.3.x-dev"
}
},
"autoload": {
@@ -1637,9 +2962,6 @@
]
},
"notification-url": "https://packagist.org/downloads/",
- "include-path": [
- ""
- ],
"license": [
"BSD-3-Clause"
],
@@ -1656,7 +2978,8 @@
"mock",
"xunit"
],
- "time": "2014-06-12 07:22:15"
+ "abandoned": true,
+ "time": "2015-10-02T06:51:40+00:00"
},
{
"name": "pimple/pimple",
@@ -1693,9 +3016,7 @@
"authors": [
{
"name": "Fabien Potencier",
- "email": "fabien@symfony.com",
- "homepage": "http://fabien.potencier.org",
- "role": "Lead Developer"
+ "email": "fabien@symfony.com"
}
],
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
@@ -1704,7 +3025,7 @@
"container",
"dependency injection"
],
- "time": "2013-03-08 08:21:40"
+ "time": "2013-03-08T08:21:40+00:00"
},
{
"name": "sami/sami",
@@ -1761,7 +3082,8 @@
"keywords": [
"phpdoc"
],
- "time": "2015-06-05 03:36:34"
+ "abandoned": true,
+ "time": "2015-06-05T03:36:34+00:00"
},
{
"name": "sebastian/comparator",
@@ -1825,7 +3147,7 @@
"compare",
"equality"
],
- "time": "2017-01-29 09:50:25"
+ "time": "2017-01-29T09:50:25+00:00"
},
{
"name": "sebastian/diff",
@@ -1842,7 +3164,7 @@
"shasum": ""
},
"require": {
- "php": "^5.3.3 || ^7.3.17"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
@@ -1877,7 +3199,7 @@
"keywords": [
"diff"
],
- "time": "2017-05-22 07:24:03"
+ "time": "2017-05-22T07:24:03+00:00"
},
{
"name": "sebastian/environment",
@@ -1894,7 +3216,7 @@
"shasum": ""
},
"require": {
- "php": "^5.3.3 || ^7.3.17"
+ "php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8 || ^5.0"
@@ -1927,7 +3249,7 @@
"environment",
"hhvm"
],
- "time": "2016-08-18 05:49:44"
+ "time": "2016-08-18T05:49:44+00:00"
},
{
"name": "sebastian/exporter",
@@ -1994,7 +3316,58 @@
"export",
"exporter"
],
- "time": "2016-06-17 09:04:28"
+ "time": "2016-06-17T09:04:28+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.2"
+ },
+ "suggest": {
+ "ext-uopz": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "time": "2015-10-12T03:26:01+00:00"
},
{
"name": "sebastian/recursion-context",
@@ -2047,7 +3420,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
- "time": "2016-10-03 07:41:43"
+ "time": "2016-10-03T07:41:43+00:00"
},
{
"name": "sebastian/version",
@@ -2082,20 +3455,20 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
- "time": "2015-06-21 13:59:46"
+ "time": "2015-06-21T13:59:46+00:00"
},
{
"name": "squizlabs/php_codesniffer",
- "version": "2.9.1",
+ "version": "2.9.2",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
- "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62"
+ "reference": "2acf168de78487db620ab4bc524135a13cfe6745"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62",
- "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62",
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745",
+ "reference": "2acf168de78487db620ab4bc524135a13cfe6745",
"shasum": ""
},
"require": {
@@ -2160,30 +3533,29 @@
"phpcs",
"standards"
],
- "time": "2017-05-22 02:43:20"
+ "time": "2018-11-07T22:31:41+00:00"
},
{
"name": "symfony/browser-kit",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/BrowserKit",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
- "reference": "0fca8e3490f003262258dcf67c329691913642e5"
+ "reference": "b507697225f32a76a9d333d0766fb46353e9d00d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/browser-kit/zipball/0fca8e3490f003262258dcf67c329691913642e5",
- "reference": "0fca8e3490f003262258dcf67c329691913642e5",
+ "url": "https://api.github.com/repos/symfony/browser-kit/zipball/b507697225f32a76a9d333d0766fb46353e9d00d",
+ "reference": "b507697225f32a76a9d333d0766fb46353e9d00d",
"shasum": ""
},
"require": {
- "php": ">=5.3.3",
- "symfony/dom-crawler": "~2.0,>=2.0.5"
+ "php": ">=5.3.9",
+ "symfony/dom-crawler": "~2.1|~3.0.0"
},
"require-dev": {
- "symfony/css-selector": "~2.0,>=2.0.5",
- "symfony/process": "~2.3.34|~2.7,>=2.7.6"
+ "symfony/css-selector": "^2.0.5|~3.0.0",
+ "symfony/process": "~2.3.34|^2.7.6|~3.0.0"
},
"suggest": {
"symfony/process": ""
@@ -2191,11 +3563,11 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\BrowserKit\\": ""
},
"exclude-from-classmap": [
@@ -2218,34 +3590,33 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
- "time": "2016-03-04 07:12:06"
+ "time": "2018-11-26T06:55:10+00:00"
},
{
"name": "symfony/css-selector",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/CssSelector",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
- "reference": "e750fff4bd738e54414fbfdd48ede6b0e99ab808"
+ "reference": "7b1692e418d7ccac24c373528453bc90e42797de"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/css-selector/zipball/e750fff4bd738e54414fbfdd48ede6b0e99ab808",
- "reference": "e750fff4bd738e54414fbfdd48ede6b0e99ab808",
+ "url": "https://api.github.com/repos/symfony/css-selector/zipball/7b1692e418d7ccac24c373528453bc90e42797de",
+ "reference": "7b1692e418d7ccac24c373528453bc90e42797de",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\CssSelector\\": ""
},
"exclude-from-classmap": [
@@ -2258,42 +3629,43 @@
],
"authors": [
{
- "name": "Jean-François Simon",
- "email": "jeanfrancois.simon@sensiolabs.com"
- },
- {
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
+ "name": "Jean-François Simon",
+ "email": "jeanfrancois.simon@sensiolabs.com"
+ },
+ {
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
- "time": "2016-03-04 07:12:06"
+ "time": "2018-11-11T11:18:13+00:00"
},
{
"name": "symfony/dom-crawler",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/DomCrawler",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
- "reference": "b1a52aeafe4dd31914c75e72fc9b9ca3a3e5981d"
+ "reference": "2cdc7d3909eea6f982a6298d2e9ab7db01b6403c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b1a52aeafe4dd31914c75e72fc9b9ca3a3e5981d",
- "reference": "b1a52aeafe4dd31914c75e72fc9b9ca3a3e5981d",
+ "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2cdc7d3909eea6f982a6298d2e9ab7db01b6403c",
+ "reference": "2cdc7d3909eea6f982a6298d2e9ab7db01b6403c",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
- "symfony/css-selector": "~2.0,>=2.0.5"
+ "symfony/css-selector": "~2.8|~3.0.0"
},
"suggest": {
"symfony/css-selector": ""
@@ -2301,11 +3673,11 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\DomCrawler\\": ""
},
"exclude-from-classmap": [
@@ -2328,84 +3700,33 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
- "time": "2016-04-06 13:13:46"
- },
- {
- "name": "symfony/finder",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Finder",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/finder.git",
- "reference": "dce4b58434fc1cbd66e3006e539bb53074dfea82"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/dce4b58434fc1cbd66e3006e539bb53074dfea82",
- "reference": "dce4b58434fc1cbd66e3006e539bb53074dfea82",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.3"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.3-dev"
- }
- },
- "autoload": {
- "psr-0": {
- "Symfony\\Component\\Finder\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony Finder Component",
- "homepage": "https://symfony.com",
- "time": "2016-05-13 14:58:35"
+ "time": "2018-11-24T22:30:19+00:00"
},
{
"name": "symfony/process",
- "version": "v2.3.42",
- "target-dir": "Symfony/Component/Process",
+ "version": "v2.8.52",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "89aced1438655ad81fc828c2e2e555e9b88fef3b"
+ "reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/89aced1438655ad81fc828c2e2e555e9b88fef3b",
- "reference": "89aced1438655ad81fc828c2e2e555e9b88fef3b",
+ "url": "https://api.github.com/repos/symfony/process/zipball/c3591a09c78639822b0b290d44edb69bf9f05dc8",
+ "reference": "c3591a09c78639822b0b290d44edb69bf9f05dc8",
"shasum": ""
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.3.9"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.3-dev"
+ "dev-master": "2.8-dev"
}
},
"autoload": {
- "psr-0": {
+ "psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
@@ -2428,7 +3749,7 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2016-03-31 08:39:43"
+ "time": "2018-11-11T11:18:13+00:00"
}
],
"aliases": [],
@@ -2437,7 +3758,10 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=5.3.3,<=7.3.17"
+ "php": ">=5.4"
},
- "platform-dev": []
+ "platform-dev": [],
+ "platform-overrides": {
+ "php": "5.4.7"
+ }
}
diff --git a/phpBB/config/auth.yml b/phpBB/config/auth.yml
deleted file mode 100644
index ef06080d38..0000000000
--- a/phpBB/config/auth.yml
+++ /dev/null
@@ -1,101 +0,0 @@
-services:
-# ----- Auth management -----
- auth:
- class: phpbb\auth\auth
-
-# ----- Auth providers -----
- auth.provider_collection:
- class: phpbb\auth\provider_collection
- arguments:
- - @service_container
- - @config
- tags:
- - { name: service_collection, tag: auth.provider }
-
- auth.provider.db:
- class: phpbb\auth\provider\db
- arguments:
- - @dbal.conn
- - @config
- - @passwords.manager
- - @request
- - @user
- - @service_container
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: auth.provider }
-
- auth.provider.apache:
- class: phpbb\auth\provider\apache
- arguments:
- - @dbal.conn
- - @config
- - @passwords.manager
- - @request
- - @user
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: auth.provider }
-
- auth.provider.ldap:
- class: phpbb\auth\provider\ldap
- arguments:
- - @dbal.conn
- - @config
- - @passwords.manager
- - @user
- tags:
- - { name: auth.provider }
-
- auth.provider.oauth:
- class: phpbb\auth\provider\oauth\oauth
- arguments:
- - @dbal.conn
- - @config
- - @passwords.manager
- - @request
- - @user
- - %tables.auth_provider_oauth_token_storage%
- - %tables.auth_provider_oauth_account_assoc%
- - @auth.provider.oauth.service_collection
- - %tables.users%
- - @service_container
- - @dispatcher
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: auth.provider }
-
-# ----- OAuth services providers -----
- auth.provider.oauth.service_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: auth.provider.oauth.service }
-
- auth.provider.oauth.service.bitly:
- class: phpbb\auth\provider\oauth\service\bitly
- arguments:
- - @config
- - @request
- tags:
- - { name: auth.provider.oauth.service }
-
- auth.provider.oauth.service.facebook:
- class: phpbb\auth\provider\oauth\service\facebook
- arguments:
- - @config
- - @request
- tags:
- - { name: auth.provider.oauth.service }
-
- auth.provider.oauth.service.google:
- class: phpbb\auth\provider\oauth\service\google
- arguments:
- - @config
- - @request
- tags:
- - { name: auth.provider.oauth.service }
diff --git a/phpBB/config/avatar.yml b/phpBB/config/avatar.yml
deleted file mode 100644
index b0dca137b0..0000000000
--- a/phpBB/config/avatar.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-services:
- avatar.manager:
- class: phpbb\avatar\manager
- arguments:
- - @config
- - @avatar.driver_collection
-
-# ----- Avatar drivers -----
- avatar.driver_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: avatar.driver }
-
- avatar.driver.gravatar:
- class: phpbb\avatar\driver\gravatar
- arguments:
- - @config
- - %core.root_path%
- - %core.php_ext%
- - @path_helper
- - @cache.driver
- calls:
- - [set_name, [avatar.driver.gravatar]]
- tags:
- - { name: avatar.driver }
-
- avatar.driver.local:
- class: phpbb\avatar\driver\local
- arguments:
- - @config
- - %core.root_path%
- - %core.php_ext%
- - @path_helper
- - @cache.driver
- calls:
- - [set_name, [avatar.driver.local]]
- tags:
- - { name: avatar.driver }
-
- avatar.driver.remote:
- class: phpbb\avatar\driver\remote
- arguments:
- - @config
- - %core.root_path%
- - %core.php_ext%
- - @path_helper
- - @cache.driver
- calls:
- - [set_name, [avatar.driver.remote]]
- tags:
- - { name: avatar.driver }
-
- avatar.driver.upload:
- class: phpbb\avatar\driver\upload
- arguments:
- - @config
- - %core.root_path%
- - %core.php_ext%
- - @path_helper
- - @mimetype.guesser
- - @dispatcher
- - @cache.driver
- calls:
- - [set_name, [avatar.driver.upload]]
- tags:
- - { name: avatar.driver }
diff --git a/phpBB/config/captcha.yml b/phpBB/config/captcha.yml
deleted file mode 100644
index e3f617e909..0000000000
--- a/phpBB/config/captcha.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-services:
- captcha.factory:
- class: phpbb\captcha\factory
- arguments:
- - @service_container
- - @captcha.plugins.service_collection
-
-# ----- Captcha plugins -----
-# Scope MUST be prototype for all the plugins to work.
- captcha.plugins.service_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: captcha.plugins }
-
- core.captcha.plugins.gd:
- class: phpbb\captcha\plugins\gd
- scope: prototype
- calls:
- - [set_name, [core.captcha.plugins.gd]]
- tags:
- - { name: captcha.plugins }
-
- core.captcha.plugins.gd_wave:
- class: phpbb\captcha\plugins\gd_wave
- scope: prototype
- calls:
- - [set_name, [core.captcha.plugins.gd_wave]]
- tags:
- - { name: captcha.plugins }
-
- core.captcha.plugins.nogd:
- class: phpbb\captcha\plugins\nogd
- scope: prototype
- calls:
- - [set_name, [core.captcha.plugins.nogd]]
- tags:
- - { name: captcha.plugins }
-
- core.captcha.plugins.qa:
- class: phpbb\captcha\plugins\qa
- scope: prototype
- arguments:
- - %tables.captcha_qa_questions%
- - %tables.captcha_qa_answers%
- - %tables.captcha_qa_confirm%
- calls:
- - [set_name, [core.captcha.plugins.qa]]
- tags:
- - { name: captcha.plugins }
-
- core.captcha.plugins.recaptcha:
- class: phpbb\captcha\plugins\recaptcha
- scope: prototype
- calls:
- - [set_name, [core.captcha.plugins.recaptcha]]
- tags:
- - { name: captcha.plugins }
diff --git a/phpBB/config/console.yml b/phpBB/config/console.yml
deleted file mode 100644
index 55ffd358e4..0000000000
--- a/phpBB/config/console.yml
+++ /dev/null
@@ -1,162 +0,0 @@
-services:
- console.command_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: console.command }
-
- console.command.cache.purge:
- class: phpbb\console\command\cache\purge
- arguments:
- - @user
- - @cache.driver
- - @dbal.conn
- - @auth
- - @log
- - @config
- tags:
- - { name: console.command }
-
- console.command.config.delete:
- class: phpbb\console\command\config\delete
- arguments:
- - @user
- - @config
- tags:
- - { name: console.command }
-
- console.command.config.increment:
- class: phpbb\console\command\config\increment
- arguments:
- - @user
- - @config
- tags:
- - { name: console.command }
-
- console.command.config.get:
- class: phpbb\console\command\config\get
- arguments:
- - @user
- - @config
- tags:
- - { name: console.command }
-
- console.command.config.set:
- class: phpbb\console\command\config\set
- arguments:
- - @user
- - @config
- tags:
- - { name: console.command }
-
- console.command.config.set_atomic:
- class: phpbb\console\command\config\set_atomic
- arguments:
- - @user
- - @config
- tags:
- - { name: console.command }
-
- console.command.cron.list:
- class: phpbb\console\command\cron\cron_list
- arguments:
- - @user
- - @cron.manager
- tags:
- - { name: console.command }
-
- console.command.cron.run:
- class: phpbb\console\command\cron\run
- arguments:
- - @user
- - @cron.manager
- - @cron.lock_db
- tags:
- - { name: console.command }
-
- console.command.db.migrate:
- class: phpbb\console\command\db\migrate
- arguments:
- - @user
- - @migrator
- - @ext.manager
- - @config
- - @cache
- - @log
- - %core.root_path%
- tags:
- - { name: console.command }
-
- console.command.dev.migration_tips:
- class: phpbb\console\command\dev\migration_tips
- arguments:
- - @user
- - @ext.manager
- tags:
- - { name: console.command }
-
- console.command.extension.disable:
- class: phpbb\console\command\extension\disable
- arguments:
- - @user
- - @ext.manager
- - @log
- tags:
- - { name: console.command }
-
- console.command.extension.enable:
- class: phpbb\console\command\extension\enable
- arguments:
- - @user
- - @ext.manager
- - @log
- tags:
- - { name: console.command }
-
- console.command.extension.purge:
- class: phpbb\console\command\extension\purge
- arguments:
- - @user
- - @ext.manager
- - @log
- tags:
- - { name: console.command }
-
- console.command.extension.show:
- class: phpbb\console\command\extension\show
- arguments:
- - @user
- - @ext.manager
- - @log
- tags:
- - { name: console.command }
-
- console.command.fixup.recalculate_email_hash:
- class: phpbb\console\command\fixup\recalculate_email_hash
- arguments:
- - @user
- - @dbal.conn
- tags:
- - { name: console.command }
-
- console.command.fixup.update_hashes:
- class: phpbb\console\command\fixup\update_hashes
- arguments:
- - @config
- - @user
- - @dbal.conn
- - @passwords.manager
- - @passwords.driver_collection
- - %passwords.algorithms%
- tags:
- - { name: console.command }
-
- console.command.fixup.fix_left_right_ids:
- class: phpbb\console\command\fixup\fix_left_right_ids
- arguments:
- - @user
- - @dbal.conn
- - @cache.driver
- tags:
- - { name: console.command }
diff --git a/phpBB/config/content.yml b/phpBB/config/content.yml
deleted file mode 100644
index 4d9ee31335..0000000000
--- a/phpBB/config/content.yml
+++ /dev/null
@@ -1,72 +0,0 @@
-services:
- content.visibility:
- class: phpbb\content_visibility
- arguments:
- - @auth
- - @config
- - @dispatcher
- - @dbal.conn
- - @user
- - %core.root_path%
- - %core.php_ext%
- - %tables.forums%
- - %tables.posts%
- - %tables.topics%
- - %tables.users%
-
- groupposition.legend:
- class: phpbb\groupposition\legend
- arguments:
- - @dbal.conn
- - @user
-
- groupposition.teampage:
- class: phpbb\groupposition\teampage
- arguments:
- - @dbal.conn
- - @user
- - @cache.driver
-
- message.form.admin:
- class: phpbb\message\admin_form
- arguments:
- - @auth
- - @config
- - @config_text
- - @dbal.conn
- - @user
- - %core.root_path%
- - %core.php_ext%
-
- message.form.topic:
- class: phpbb\message\topic_form
- arguments:
- - @auth
- - @config
- - @dbal.conn
- - @user
- - %core.root_path%
- - %core.php_ext%
-
- message.form.user:
- class: phpbb\message\user_form
- arguments:
- - @auth
- - @config
- - @dbal.conn
- - @user
- - %core.root_path%
- - %core.php_ext%
-
- pagination:
- class: phpbb\pagination
- arguments:
- - @template
- - @user
- - @controller.helper
- - @dispatcher
-
- viewonline_helper:
- class: phpbb\viewonline_helper
- arguments:
- - @filesystem
diff --git a/phpBB/config/cron.yml b/phpBB/config/cron.yml
deleted file mode 100644
index dc628b43ff..0000000000
--- a/phpBB/config/cron.yml
+++ /dev/null
@@ -1,162 +0,0 @@
-services:
- cron.manager:
- class: phpbb\cron\manager
- arguments:
- - @cron.task_collection
- - %core.root_path%
- - %core.php_ext%
-
- cron.lock_db:
- class: phpbb\lock\db
- arguments:
- - cron_lock
- - @config
- - @dbal.conn
-
-# ----- Cron tasks -----
- cron.task_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: cron.task }
-
- cron.task.core.prune_all_forums:
- class: phpbb\cron\task\core\prune_all_forums
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @config
- - @dbal.conn
- calls:
- - [set_name, [cron.task.core.prune_all_forums]]
- tags:
- - { name: cron.task }
-
- cron.task.core.prune_forum:
- class: phpbb\cron\task\core\prune_forum
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @config
- - @dbal.conn
- calls:
- - [set_name, [cron.task.core.prune_forum]]
- tags:
- - { name: cron.task }
-
- cron.task.core.prune_shadow_topics:
- class: phpbb\cron\task\core\prune_shadow_topics
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @config
- - @dbal.conn
- - @log
- - @user
- calls:
- - [set_name, [cron.task.core.prune_shadow_topics]]
- tags:
- - { name: cron.task }
-
- cron.task.core.prune_notifications:
- class: phpbb\cron\task\core\prune_notifications
- arguments:
- - @config
- - @notification_manager
- calls:
- - [set_name, [cron.task.core.prune_notifications]]
- tags:
- - { name: cron.task }
-
- cron.task.core.queue:
- class: phpbb\cron\task\core\queue
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @config
- calls:
- - [set_name, [cron.task.core.queue]]
- tags:
- - { name: cron.task }
-
- cron.task.core.tidy_cache:
- class: phpbb\cron\task\core\tidy_cache
- arguments:
- - @config
- - @cache.driver
- calls:
- - [set_name, [cron.task.core.tidy_cache]]
- tags:
- - { name: cron.task }
-
- cron.task.core.tidy_database:
- class: phpbb\cron\task\core\tidy_database
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @config
- calls:
- - [set_name, [cron.task.core.tidy_database]]
- tags:
- - { name: cron.task }
-
- cron.task.core.tidy_plupload:
- class: phpbb\cron\task\core\tidy_plupload
- arguments:
- - %core.root_path%
- - @config
- calls:
- - [set_name, [cron.task.core.tidy_plupload]]
- tags:
- - { name: cron.task }
-
- cron.task.core.tidy_search:
- class: phpbb\cron\task\core\tidy_search
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @auth
- - @config
- - @dbal.conn
- - @user
- - @dispatcher
- calls:
- - [set_name, [cron.task.core.tidy_search]]
- tags:
- - { name: cron.task }
-
- cron.task.core.tidy_sessions:
- class: phpbb\cron\task\core\tidy_sessions
- arguments:
- - @config
- - @user
- calls:
- - [set_name, [cron.task.core.tidy_sessions]]
- tags:
- - { name: cron.task }
-
- cron.task.core.tidy_warnings:
- class: phpbb\cron\task\core\tidy_warnings
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @config
- calls:
- - [set_name, [cron.task.core.tidy_warnings]]
- tags:
- - { name: cron.task }
-
- cron.task.core.update_hashes:
- class: phpbb\cron\task\core\update_hashes
- arguments:
- - @config
- - @dbal.conn
- - @passwords.update.lock
- - @passwords.manager
- - @passwords.driver_collection
- - %passwords.algorithms%
- calls:
- - [set_name, [cron.task.core.update_hashes]]
- tags:
- - { name: cron.task }
diff --git a/phpBB/config/db.yml b/phpBB/config/db.yml
deleted file mode 100644
index 4ab4401bbd..0000000000
--- a/phpBB/config/db.yml
+++ /dev/null
@@ -1,76 +0,0 @@
-services:
- dbal.conn:
- class: phpbb\db\driver\factory
- arguments:
- - @service_container
-
- dbal.conn.driver:
- synthetic: true
-
- dbal.tools:
- class: phpbb\db\tools
- arguments:
- - @dbal.conn
-
-# ----- Migrator -----
- migrator:
- class: phpbb\db\migrator
- arguments:
- - @service_container
- - @config
- - @dbal.conn
- - @dbal.tools
- - %tables.migrations%
- - %core.root_path%
- - %core.php_ext%
- - %core.table_prefix%
- - @migrator.tool_collection
- - @migrator.helper
-
- migrator.helper:
- class: phpbb\db\migration\helper
-
-# ----- Migrator's tools -----
- migrator.tool_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: migrator.tool }
-
- migrator.tool.config:
- class: phpbb\db\migration\tool\config
- arguments:
- - @config
- tags:
- - { name: migrator.tool }
-
- migrator.tool.config_text:
- class: phpbb\db\migration\tool\config_text
- arguments:
- - @config_text
- tags:
- - { name: migrator.tool }
-
- migrator.tool.module:
- class: phpbb\db\migration\tool\module
- arguments:
- - @dbal.conn
- - @cache
- - @user
- - %core.root_path%
- - %core.php_ext%
- - %tables.modules%
- tags:
- - { name: migrator.tool }
-
- migrator.tool.permission:
- class: phpbb\db\migration\tool\permission
- arguments:
- - @dbal.conn
- - @cache
- - @auth
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: migrator.tool }
diff --git a/phpBB/config/default/config.yml b/phpBB/config/default/config.yml
new file mode 100644
index 0000000000..e8d0536287
--- /dev/null
+++ b/phpBB/config/default/config.yml
@@ -0,0 +1 @@
+# phpBB's config file (This line is needed because of the packager)
diff --git a/phpBB/config/parameters.yml b/phpBB/config/default/container/parameters.yml
index 8ecc1428f4..8ecc1428f4 100644
--- a/phpBB/config/parameters.yml
+++ b/phpBB/config/default/container/parameters.yml
diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml
new file mode 100644
index 0000000000..3ead1e6181
--- /dev/null
+++ b/phpBB/config/default/container/services.yml
@@ -0,0 +1,175 @@
+imports:
+ - { resource: services_attachment.yml }
+ - { resource: services_auth.yml }
+ - { resource: services_avatar.yml }
+ - { resource: services_captcha.yml }
+ - { resource: services_console.yml }
+ - { resource: services_content.yml }
+ - { resource: services_cron.yml }
+ - { resource: services_db.yml }
+ - { resource: services_event.yml }
+ - { resource: services_feed.yml }
+ - { resource: services_files.yml }
+ - { resource: services_filesystem.yml }
+ - { resource: services_help.yml }
+ - { resource: services_hook.yml }
+ - { resource: services_http.yml }
+ - { resource: services_language.yml }
+ - { resource: services_migrator.yml }
+ - { resource: services_mimetype_guesser.yml }
+ - { resource: services_module.yml }
+ - { resource: services_notification.yml }
+ - { resource: services_password.yml }
+ - { resource: services_php.yml }
+ - { resource: services_profilefield.yml }
+ - { resource: services_report.yml }
+ - { resource: services_routing.yml }
+ - { resource: services_text_formatter.yml }
+ - { resource: services_text_reparser.yml }
+ - { resource: services_twig.yml }
+ - { resource: services_user.yml }
+
+ - { resource: tables.yml }
+ - { resource: parameters.yml }
+
+services:
+ cache:
+ class: phpbb\cache\service
+ arguments:
+ - '@cache.driver'
+ - '@config'
+ - '@dbal.conn'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ cache.driver:
+ class: '%cache.driver.class%'
+
+ class_loader:
+ class: phpbb\class_loader
+ arguments:
+ - phpbb\
+ - '%core.root_path%includes/'
+ - '%core.php_ext%'
+ calls:
+ - [register, []]
+ - [set_cache, ['@cache.driver']]
+
+ class_loader.ext:
+ class: phpbb\class_loader
+ arguments:
+ - \
+ - '%core.root_path%ext/'
+ - '%core.php_ext%'
+ calls:
+ - [register, []]
+ - [set_cache, ['@cache.driver']]
+
+ config:
+ class: phpbb\config\db
+ arguments:
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '%tables.config%'
+
+ config.php:
+ synthetic: true
+
+ config_text:
+ class: phpbb\config\db_text
+ arguments:
+ - '@dbal.conn'
+ - '%tables.config_text%'
+
+ controller.helper:
+ class: phpbb\controller\helper
+ arguments:
+ - '@template'
+ - '@user'
+ - '@config'
+ - '@symfony_request'
+ - '@request'
+ - '@routing.helper'
+
+ controller.resolver:
+ class: phpbb\controller\resolver
+ arguments:
+ - '@service_container'
+ - '%core.root_path%'
+ - '@template'
+
+ ext.manager:
+ class: phpbb\extension\manager
+ arguments:
+ - '@service_container'
+ - '@dbal.conn'
+ - '@config'
+ - '@filesystem'
+ - '%tables.ext%'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@cache'
+
+ file_downloader:
+ class: phpbb\file_downloader
+
+ file_locator:
+ class: phpbb\routing\file_locator
+ arguments:
+ - '@filesystem'
+ - '%core.root_path%'
+
+ group_helper:
+ class: phpbb\group\helper
+ arguments:
+ - '@auth'
+ - '@cache'
+ - '@config'
+ - '@language'
+ - '@dispatcher'
+ - '@path_helper'
+ - '@user'
+
+ log:
+ class: phpbb\log\log
+ arguments:
+ - '@dbal.conn'
+ - '@user'
+ - '@auth'
+ - '@dispatcher'
+ - '%core.root_path%'
+ - '%core.adm_relative_path%'
+ - '%core.php_ext%'
+ - '%tables.log%'
+
+ path_helper:
+ class: phpbb\path_helper
+ arguments:
+ - '@symfony_request'
+ - '@filesystem'
+ - '@request'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '%core.adm_relative_path%'
+
+ plupload:
+ class: phpbb\plupload\plupload
+ arguments:
+ - '%core.root_path%'
+ - '@config'
+ - '@request'
+ - '@user'
+ - '@php_ini'
+ - '@mimetype.guesser'
+
+ upload_imagesize:
+ class: FastImageSize\FastImageSize
+
+ version_helper:
+ class: phpbb\version_helper
+ shared: false
+ arguments:
+ - '@cache'
+ - '@config'
+ - '@file_downloader'
+ - '@user'
diff --git a/phpBB/config/default/container/services_attachment.yml b/phpBB/config/default/container/services_attachment.yml
new file mode 100644
index 0000000000..c56ced21f4
--- /dev/null
+++ b/phpBB/config/default/container/services_attachment.yml
@@ -0,0 +1,40 @@
+services:
+ attachment.delete:
+ class: phpbb\attachment\delete
+ shared: false
+ arguments:
+ - '@config'
+ - '@dbal.conn'
+ - '@dispatcher'
+ - '@filesystem'
+ - '@attachment.resync'
+ - '%core.root_path%'
+
+ attachment.manager:
+ class: phpbb\attachment\manager
+ shared: false
+ arguments:
+ - '@attachment.delete'
+ - '@attachment.resync'
+ - '@attachment.upload'
+
+ attachment.resync:
+ class: phpbb\attachment\resync
+ shared: false
+ arguments:
+ - '@dbal.conn'
+
+ attachment.upload:
+ class: phpbb\attachment\upload
+ shared: false
+ arguments:
+ - '@auth'
+ - '@cache'
+ - '@config'
+ - '@files.upload'
+ - '@language'
+ - '@mimetype.guesser'
+ - '@dispatcher'
+ - '@plupload'
+ - '@user'
+ - '%core.root_path%'
diff --git a/phpBB/config/default/container/services_auth.yml b/phpBB/config/default/container/services_auth.yml
new file mode 100644
index 0000000000..ed8dc90a74
--- /dev/null
+++ b/phpBB/config/default/container/services_auth.yml
@@ -0,0 +1,110 @@
+services:
+# ----- Auth management -----
+ auth:
+ class: phpbb\auth\auth
+
+# ----- Auth providers -----
+ auth.provider_collection:
+ class: phpbb\auth\provider_collection
+ arguments:
+ - '@service_container'
+ - '@config'
+ tags:
+ - { name: service_collection, tag: auth.provider }
+
+ auth.provider.db:
+ class: phpbb\auth\provider\db
+ arguments:
+ - '@dbal.conn'
+ - '@config'
+ - '@passwords.manager'
+ - '@request'
+ - '@user'
+ - '@service_container'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: auth.provider }
+
+ auth.provider.apache:
+ class: phpbb\auth\provider\apache
+ arguments:
+ - '@dbal.conn'
+ - '@config'
+ - '@passwords.manager'
+ - '@request'
+ - '@user'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: auth.provider }
+
+ auth.provider.ldap:
+ class: phpbb\auth\provider\ldap
+ arguments:
+ - '@dbal.conn'
+ - '@config'
+ - '@passwords.manager'
+ - '@user'
+ tags:
+ - { name: auth.provider }
+
+ auth.provider.oauth:
+ class: phpbb\auth\provider\oauth\oauth
+ arguments:
+ - '@dbal.conn'
+ - '@config'
+ - '@passwords.manager'
+ - '@request'
+ - '@user'
+ - '%tables.auth_provider_oauth_token_storage%'
+ - '%tables.auth_provider_oauth_states%'
+ - '%tables.auth_provider_oauth_account_assoc%'
+ - '@auth.provider.oauth.service_collection'
+ - '%tables.users%'
+ - '@service_container'
+ - '@dispatcher'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: auth.provider }
+
+# ----- OAuth services providers -----
+ auth.provider.oauth.service_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: auth.provider.oauth.service }
+
+ auth.provider.oauth.service.bitly:
+ class: phpbb\auth\provider\oauth\service\bitly
+ arguments:
+ - '@config'
+ - '@request'
+ tags:
+ - { name: auth.provider.oauth.service }
+
+ auth.provider.oauth.service.facebook:
+ class: phpbb\auth\provider\oauth\service\facebook
+ arguments:
+ - '@config'
+ - '@request'
+ tags:
+ - { name: auth.provider.oauth.service }
+
+ auth.provider.oauth.service.google:
+ class: phpbb\auth\provider\oauth\service\google
+ arguments:
+ - '@config'
+ - '@request'
+ tags:
+ - { name: auth.provider.oauth.service }
+
+ auth.provider.oauth.service.twitter:
+ class: phpbb\auth\provider\oauth\service\twitter
+ arguments:
+ - '@config'
+ - '@request'
+ tags:
+ - { name: auth.provider.oauth.service }
diff --git a/phpBB/config/default/container/services_avatar.yml b/phpBB/config/default/container/services_avatar.yml
new file mode 100644
index 0000000000..d96aa6239a
--- /dev/null
+++ b/phpBB/config/default/container/services_avatar.yml
@@ -0,0 +1,73 @@
+services:
+ avatar.manager:
+ class: phpbb\avatar\manager
+ arguments:
+ - '@config'
+ - '@dispatcher'
+ - '@avatar.driver_collection'
+
+# ----- Avatar drivers -----
+ avatar.driver_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: avatar.driver }
+
+ avatar.driver.gravatar:
+ class: phpbb\avatar\driver\gravatar
+ arguments:
+ - '@config'
+ - '@upload_imagesize'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@path_helper'
+ - '@cache.driver'
+ calls:
+ - [set_name, [avatar.driver.gravatar]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.local:
+ class: phpbb\avatar\driver\local
+ arguments:
+ - '@config'
+ - '@upload_imagesize'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@path_helper'
+ - '@cache.driver'
+ calls:
+ - [set_name, [avatar.driver.local]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.remote:
+ class: phpbb\avatar\driver\remote
+ arguments:
+ - '@config'
+ - '@upload_imagesize'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@path_helper'
+ - '@cache.driver'
+ calls:
+ - [set_name, [avatar.driver.remote]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.upload:
+ class: phpbb\avatar\driver\upload
+ arguments:
+ - '@config'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@filesystem'
+ - '@path_helper'
+ - '@dispatcher'
+ - '@files.factory'
+ - '@cache.driver'
+ calls:
+ - [set_name, [avatar.driver.upload]]
+ tags:
+ - { name: avatar.driver }
diff --git a/phpBB/config/default/container/services_captcha.yml b/phpBB/config/default/container/services_captcha.yml
new file mode 100644
index 0000000000..e462c43bb8
--- /dev/null
+++ b/phpBB/config/default/container/services_captcha.yml
@@ -0,0 +1,59 @@
+services:
+ captcha.factory:
+ class: phpbb\captcha\factory
+ arguments:
+ - '@service_container'
+ - '@captcha.plugins.service_collection'
+
+# ----- Captcha plugins -----
+# Service MUST NOT be shared for all the plugins to work.
+ captcha.plugins.service_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: captcha.plugins }
+
+ core.captcha.plugins.gd:
+ class: phpbb\captcha\plugins\gd
+ shared: false
+ calls:
+ - [set_name, [core.captcha.plugins.gd]]
+ tags:
+ - { name: captcha.plugins }
+
+ core.captcha.plugins.gd_wave:
+ class: phpbb\captcha\plugins\gd_wave
+ shared: false
+ calls:
+ - [set_name, [core.captcha.plugins.gd_wave]]
+ tags:
+ - { name: captcha.plugins }
+
+ core.captcha.plugins.nogd:
+ class: phpbb\captcha\plugins\nogd
+ shared: false
+ calls:
+ - [set_name, [core.captcha.plugins.nogd]]
+ tags:
+ - { name: captcha.plugins }
+
+ core.captcha.plugins.qa:
+ class: phpbb\captcha\plugins\qa
+ shared: false
+ arguments:
+ - '%tables.captcha_qa_questions%'
+ - '%tables.captcha_qa_answers%'
+ - '%tables.captcha_qa_confirm%'
+ calls:
+ - [set_name, [core.captcha.plugins.qa]]
+ tags:
+ - { name: captcha.plugins }
+
+ core.captcha.plugins.recaptcha:
+ class: phpbb\captcha\plugins\recaptcha
+ shared: false
+ calls:
+ - [set_name, [core.captcha.plugins.recaptcha]]
+ tags:
+ - { name: captcha.plugins }
diff --git a/phpBB/config/default/container/services_console.yml b/phpBB/config/default/container/services_console.yml
new file mode 100644
index 0000000000..05e467ff8d
--- /dev/null
+++ b/phpBB/config/default/container/services_console.yml
@@ -0,0 +1,295 @@
+services:
+ console.exception_subscriber:
+ class: phpbb\console\exception_subscriber
+ arguments:
+ - '@language'
+ tags:
+ - { name: kernel.event_subscriber }
+
+ console.command_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: console.command }
+
+ console.command.cache.purge:
+ class: phpbb\console\command\cache\purge
+ arguments:
+ - '@user'
+ - '@cache.driver'
+ - '@dbal.conn'
+ - '@auth'
+ - '@log'
+ - '@config'
+ tags:
+ - { name: console.command }
+
+ console.command.config.delete:
+ class: phpbb\console\command\config\delete
+ arguments:
+ - '@user'
+ - '@config'
+ tags:
+ - { name: console.command }
+
+ console.command.config.increment:
+ class: phpbb\console\command\config\increment
+ arguments:
+ - '@user'
+ - '@config'
+ tags:
+ - { name: console.command }
+
+ console.command.config.get:
+ class: phpbb\console\command\config\get
+ arguments:
+ - '@user'
+ - '@config'
+ tags:
+ - { name: console.command }
+
+ console.command.config.set:
+ class: phpbb\console\command\config\set
+ arguments:
+ - '@user'
+ - '@config'
+ tags:
+ - { name: console.command }
+
+ console.command.config.set_atomic:
+ class: phpbb\console\command\config\set_atomic
+ arguments:
+ - '@user'
+ - '@config'
+ tags:
+ - { name: console.command }
+
+ console.command.cron.list:
+ class: phpbb\console\command\cron\cron_list
+ arguments:
+ - '@user'
+ - '@cron.manager'
+ tags:
+ - { name: console.command }
+
+ console.command.cron.run:
+ class: phpbb\console\command\cron\run
+ arguments:
+ - '@user'
+ - '@cron.manager'
+ - '@cron.lock_db'
+ tags:
+ - { name: console.command }
+
+ console.command.db.list:
+ class: phpbb\console\command\db\list_command
+ arguments:
+ - '@user'
+ - '@migrator'
+ - '@ext.manager'
+ - '@config'
+ - '@cache'
+ tags:
+ - { name: console.command }
+
+ console.command.db.migrate:
+ class: phpbb\console\command\db\migrate
+ arguments:
+ - '@user'
+ - '@language'
+ - '@migrator'
+ - '@ext.manager'
+ - '@config'
+ - '@cache'
+ - '@log'
+ - '@filesystem'
+ - '%core.root_path%'
+ tags:
+ - { name: console.command }
+
+ console.command.db.revert:
+ class: phpbb\console\command\db\revert
+ parent: console.command.db.migrate
+ tags:
+ - { name: console.command }
+
+ console.command.dev.migration_tips:
+ class: phpbb\console\command\dev\migration_tips
+ arguments:
+ - '@user'
+ - '@ext.manager'
+ tags:
+ - { name: console.command }
+
+ console.command.extension.disable:
+ class: phpbb\console\command\extension\disable
+ arguments:
+ - '@user'
+ - '@ext.manager'
+ - '@log'
+ tags:
+ - { name: console.command }
+
+ console.command.extension.enable:
+ class: phpbb\console\command\extension\enable
+ arguments:
+ - '@user'
+ - '@ext.manager'
+ - '@log'
+ tags:
+ - { name: console.command }
+
+ console.command.extension.purge:
+ class: phpbb\console\command\extension\purge
+ arguments:
+ - '@user'
+ - '@ext.manager'
+ - '@log'
+ tags:
+ - { name: console.command }
+
+ console.command.extension.show:
+ class: phpbb\console\command\extension\show
+ arguments:
+ - '@user'
+ - '@ext.manager'
+ - '@log'
+ tags:
+ - { name: console.command }
+
+ console.command.fixup.recalculate_email_hash:
+ class: phpbb\console\command\fixup\recalculate_email_hash
+ arguments:
+ - '@user'
+ - '@dbal.conn'
+ tags:
+ - { name: console.command }
+
+ console.command.fixup.update_hashes:
+ class: phpbb\console\command\fixup\update_hashes
+ arguments:
+ - '@config'
+ - '@user'
+ - '@dbal.conn'
+ - '@passwords.manager'
+ - '@passwords.driver_collection'
+ - '%passwords.algorithms%'
+ tags:
+ - { name: console.command }
+
+ console.command.fixup.fix_left_right_ids:
+ class: phpbb\console\command\fixup\fix_left_right_ids
+ arguments:
+ - '@user'
+ - '@dbal.conn'
+ - '@cache.driver'
+ tags:
+ - { name: console.command }
+
+ console.command.reparser.list:
+ class: phpbb\console\command\reparser\list_all
+ arguments:
+ - '@user'
+ - '@text_reparser_collection'
+ tags:
+ - { name: console.command }
+
+ console.command.reparser.reparse:
+ class: phpbb\console\command\reparser\reparse
+ arguments:
+ - '@user'
+ - '@text_reparser.lock'
+ - '@text_reparser.manager'
+ - '@text_reparser_collection'
+ tags:
+ - { name: console.command }
+
+ console.command.thumbnail.delete:
+ class: phpbb\console\command\thumbnail\delete
+ arguments:
+ - '@config'
+ - '@user'
+ - '@dbal.conn'
+ - '%core.root_path%'
+ tags:
+ - { name: console.command }
+
+ console.command.thumbnail.generate:
+ class: phpbb\console\command\thumbnail\generate
+ arguments:
+ - '@config'
+ - '@user'
+ - '@dbal.conn'
+ - '@cache'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: console.command }
+
+ console.command.thumbnail.recreate:
+ class: phpbb\console\command\thumbnail\recreate
+ arguments:
+ - '@user'
+ tags:
+ - { name: console.command }
+
+ console.command.update.check:
+ class: phpbb\console\command\update\check
+ arguments:
+ - '@user'
+ - '@config'
+ - '@service_container'
+ - '@language'
+ tags:
+ - { name: console.command }
+
+ console.command.user.activate:
+ class: phpbb\console\command\user\activate
+ arguments:
+ - '@user'
+ - '@dbal.conn'
+ - '@config'
+ - '@language'
+ - '@log'
+ - '@notification_manager'
+ - '@user_loader'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: console.command }
+
+ console.command.user.add:
+ class: phpbb\console\command\user\add
+ arguments:
+ - '@user'
+ - '@dbal.conn'
+ - '@config'
+ - '@language'
+ - '@passwords.manager'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: console.command }
+
+ console.command.user.delete:
+ class: phpbb\console\command\user\delete
+ arguments:
+ - '@user'
+ - '@dbal.conn'
+ - '@language'
+ - '@log'
+ - '@user_loader'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: console.command }
+
+ console.command.user.reclean:
+ class: phpbb\console\command\user\reclean
+ arguments:
+ - '@user'
+ - '@dbal.conn'
+ - '@language'
+ tags:
+ - { name: console.command }
diff --git a/phpBB/config/default/container/services_content.yml b/phpBB/config/default/container/services_content.yml
new file mode 100644
index 0000000000..6717c20337
--- /dev/null
+++ b/phpBB/config/default/container/services_content.yml
@@ -0,0 +1,73 @@
+services:
+ content.visibility:
+ class: phpbb\content_visibility
+ arguments:
+ - '@auth'
+ - '@config'
+ - '@dispatcher'
+ - '@dbal.conn'
+ - '@user'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '%tables.forums%'
+ - '%tables.posts%'
+ - '%tables.topics%'
+ - '%tables.users%'
+
+ groupposition.legend:
+ class: phpbb\groupposition\legend
+ arguments:
+ - '@dbal.conn'
+ - '@user'
+
+ groupposition.teampage:
+ class: phpbb\groupposition\teampage
+ arguments:
+ - '@dbal.conn'
+ - '@user'
+ - '@cache.driver'
+
+ message.form.admin:
+ class: phpbb\message\admin_form
+ arguments:
+ - '@auth'
+ - '@config'
+ - '@config_text'
+ - '@dbal.conn'
+ - '@user'
+ - '@dispatcher'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ message.form.topic:
+ class: phpbb\message\topic_form
+ arguments:
+ - '@auth'
+ - '@config'
+ - '@dbal.conn'
+ - '@user'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ message.form.user:
+ class: phpbb\message\user_form
+ arguments:
+ - '@auth'
+ - '@config'
+ - '@dbal.conn'
+ - '@user'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ pagination:
+ class: phpbb\pagination
+ arguments:
+ - '@template'
+ - '@user'
+ - '@controller.helper'
+ - '@dispatcher'
+
+ viewonline_helper:
+ class: phpbb\viewonline_helper
+ arguments:
+ - '@filesystem'
diff --git a/phpBB/config/default/container/services_cron.yml b/phpBB/config/default/container/services_cron.yml
new file mode 100644
index 0000000000..d7f6388536
--- /dev/null
+++ b/phpBB/config/default/container/services_cron.yml
@@ -0,0 +1,235 @@
+services:
+ cron.manager:
+ class: phpbb\cron\manager
+ arguments:
+ - '@cron.task_collection'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ cron.lock_db:
+ class: phpbb\lock\db
+ arguments:
+ - cron_lock
+ - '@config'
+ - '@dbal.conn'
+
+# ----- Cron tasks -----
+ cron.task_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: cron.task }
+
+ cron.task.core.prune_all_forums:
+ class: phpbb\cron\task\core\prune_all_forums
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@config'
+ - '@dbal.conn'
+ calls:
+ - [set_name, [cron.task.core.prune_all_forums]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.prune_forum:
+ class: phpbb\cron\task\core\prune_forum
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@config'
+ - '@dbal.conn'
+ calls:
+ - [set_name, [cron.task.core.prune_forum]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.prune_shadow_topics:
+ class: phpbb\cron\task\core\prune_shadow_topics
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@config'
+ - '@dbal.conn'
+ - '@log'
+ - '@user'
+ calls:
+ - [set_name, [cron.task.core.prune_shadow_topics]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.prune_notifications:
+ class: phpbb\cron\task\core\prune_notifications
+ arguments:
+ - '@config'
+ - '@notification_manager'
+ calls:
+ - [set_name, [cron.task.core.prune_notifications]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.queue:
+ class: phpbb\cron\task\core\queue
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@config'
+ - '%core.cache_dir%'
+ calls:
+ - [set_name, [cron.task.core.queue]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.tidy_cache:
+ class: phpbb\cron\task\core\tidy_cache
+ arguments:
+ - '@config'
+ - '@cache.driver'
+ calls:
+ - [set_name, [cron.task.core.tidy_cache]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.tidy_database:
+ class: phpbb\cron\task\core\tidy_database
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@config'
+ calls:
+ - [set_name, [cron.task.core.tidy_database]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.tidy_plupload:
+ class: phpbb\cron\task\core\tidy_plupload
+ arguments:
+ - '%core.root_path%'
+ - '@config'
+ - '@log'
+ - '@user'
+ calls:
+ - [set_name, [cron.task.core.tidy_plupload]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.tidy_search:
+ class: phpbb\cron\task\core\tidy_search
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@auth'
+ - '@config'
+ - '@dbal.conn'
+ - '@user'
+ - '@dispatcher'
+ calls:
+ - [set_name, [cron.task.core.tidy_search]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.tidy_sessions:
+ class: phpbb\cron\task\core\tidy_sessions
+ arguments:
+ - '@config'
+ - '@user'
+ calls:
+ - [set_name, [cron.task.core.tidy_sessions]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.tidy_warnings:
+ class: phpbb\cron\task\core\tidy_warnings
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@config'
+ calls:
+ - [set_name, [cron.task.core.tidy_warnings]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.text_reparser.pm_text:
+ class: phpbb\cron\task\text_reparser\reparser
+ arguments:
+ - '@config'
+ - '@config_text'
+ - '@text_reparser.lock'
+ - '@text_reparser.manager'
+ - '@text_reparser_collection'
+ calls:
+ - [set_name, [cron.task.text_reparser.pm_text]]
+ - [set_reparser, [text_reparser.pm_text]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.text_reparser.poll_option:
+ class: phpbb\cron\task\text_reparser\reparser
+ arguments:
+ - '@config'
+ - '@config_text'
+ - '@text_reparser.lock'
+ - '@text_reparser.manager'
+ - '@text_reparser_collection'
+ calls:
+ - [set_name, [cron.task.text_reparser.poll_option]]
+ - [set_reparser, [text_reparser.poll_option]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.text_reparser.poll_title:
+ class: phpbb\cron\task\text_reparser\reparser
+ arguments:
+ - '@config'
+ - '@config_text'
+ - '@text_reparser.lock'
+ - '@text_reparser.manager'
+ - '@text_reparser_collection'
+ calls:
+ - [set_name, [cron.task.text_reparser.poll_title]]
+ - [set_reparser, [text_reparser.poll_title]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.text_reparser.post_text:
+ class: phpbb\cron\task\text_reparser\reparser
+ arguments:
+ - '@config'
+ - '@config_text'
+ - '@text_reparser.lock'
+ - '@text_reparser.manager'
+ - '@text_reparser_collection'
+ calls:
+ - [set_name, [cron.task.text_reparser.post_text]]
+ - [set_reparser, [text_reparser.post_text]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.text_reparser.user_signature:
+ class: phpbb\cron\task\text_reparser\reparser
+ arguments:
+ - '@config'
+ - '@config_text'
+ - '@text_reparser.lock'
+ - '@text_reparser.manager'
+ - '@text_reparser_collection'
+ calls:
+ - [set_name, [cron.task.text_reparser.user_signature]]
+ - [set_reparser, [text_reparser.user_signature]]
+ tags:
+ - { name: cron.task }
+
+ cron.task.core.update_hashes:
+ class: phpbb\cron\task\core\update_hashes
+ arguments:
+ - '@config'
+ - '@dbal.conn'
+ - '@passwords.update.lock'
+ - '@passwords.manager'
+ - '@passwords.driver_collection'
+ - '%passwords.algorithms%'
+ calls:
+ - [set_name, [cron.task.core.update_hashes]]
+ tags:
+ - { name: cron.task }
diff --git a/phpBB/config/default/container/services_db.yml b/phpBB/config/default/container/services_db.yml
new file mode 100644
index 0000000000..d538177603
--- /dev/null
+++ b/phpBB/config/default/container/services_db.yml
@@ -0,0 +1,71 @@
+services:
+ dbal.conn:
+ class: phpbb\db\driver\factory
+ arguments:
+ - '@service_container'
+
+ dbal.conn.driver:
+ synthetic: true
+
+# ----- DB Tools -----
+ dbal.tools.factory:
+ class: phpbb\db\tools\factory
+
+ dbal.tools:
+ class: phpbb\db\tools\tools_interface
+ factory: ['@dbal.tools.factory', get]
+ arguments:
+ - '@dbal.conn.driver'
+
+# ----- DB Extractor -----
+ dbal.extractor.factory:
+ class: phpbb\db\extractor\factory
+ arguments:
+ - '@dbal.conn.driver'
+ - '@service_container'
+
+ dbal.extractor:
+ class: phpbb\db\extractor\extractor_interface
+ factory: ['@dbal.extractor.factory', get]
+
+# ----- DB Extractors for different drivers -----
+# Service MUST NOT be shared for all the handlers to work correctly.
+ dbal.extractor.extractors.mssql_extractor:
+ class: phpbb\db\extractor\mssql_extractor
+ shared: false
+ arguments:
+ - '%core.root_path%'
+ - '@request'
+ - '@dbal.conn.driver'
+
+ dbal.extractor.extractors.mysql_extractor:
+ class: phpbb\db\extractor\mysql_extractor
+ shared: false
+ arguments:
+ - '%core.root_path%'
+ - '@request'
+ - '@dbal.conn.driver'
+
+ dbal.extractor.extractors.oracle_extractor:
+ class: phpbb\db\extractor\oracle_extractor
+ shared: false
+ arguments:
+ - '%core.root_path%'
+ - '@request'
+ - '@dbal.conn.driver'
+
+ dbal.extractor.extractors.postgres_extractor:
+ class: phpbb\db\extractor\postgres_extractor
+ shared: false
+ arguments:
+ - '%core.root_path%'
+ - '@request'
+ - '@dbal.conn.driver'
+
+ dbal.extractor.extractors.sqlite3_extractor:
+ class: phpbb\db\extractor\sqlite3_extractor
+ shared: false
+ arguments:
+ - '%core.root_path%'
+ - '@request'
+ - '@dbal.conn.driver'
diff --git a/phpBB/config/default/container/services_event.yml b/phpBB/config/default/container/services_event.yml
new file mode 100644
index 0000000000..5696275e64
--- /dev/null
+++ b/phpBB/config/default/container/services_event.yml
@@ -0,0 +1,26 @@
+services:
+ dispatcher:
+ class: phpbb\event\dispatcher
+ arguments:
+ - '@service_container'
+
+ kernel_exception_subscriber:
+ class: phpbb\event\kernel_exception_subscriber
+ arguments:
+ - '@template'
+ - '@language'
+ - '%debug.exceptions%'
+ tags:
+ - { name: kernel.event_subscriber }
+
+ kernel_terminate_subscriber:
+ class: phpbb\event\kernel_terminate_subscriber
+ tags:
+ - { name: kernel.event_subscriber }
+
+ symfony_response_listener:
+ class: Symfony\Component\HttpKernel\EventListener\ResponseListener
+ arguments:
+ - UTF-8
+ tags:
+ - { name: kernel.event_subscriber }
diff --git a/phpBB/config/default/container/services_feed.yml b/phpBB/config/default/container/services_feed.yml
new file mode 100644
index 0000000000..e8bac4b5ce
--- /dev/null
+++ b/phpBB/config/default/container/services_feed.yml
@@ -0,0 +1,126 @@
+services:
+ phpbb.feed.controller:
+ class: phpbb\feed\controller\feed
+ arguments:
+ - '@template.twig.environment'
+ - '@symfony_request'
+ - '@controller.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@service_container'
+ - '@feed.helper'
+ - '@user'
+ - '@auth'
+ - '@dispatcher'
+ - '%core.php_ext%'
+
+ feed.helper:
+ class: phpbb\feed\helper
+ arguments:
+ - '@config'
+ - '@service_container'
+ - '@path_helper'
+ - '@text_formatter.renderer'
+ - '@user'
+
+ feed.forum:
+ class: phpbb\feed\forum
+ shared: false
+ arguments:
+ - '@feed.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@auth'
+ - '@content.visibility'
+ - '@dispatcher'
+ - '%core.php_ext%'
+
+ feed.forums:
+ class: phpbb\feed\forums
+ shared: false
+ arguments:
+ - '@feed.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@auth'
+ - '@content.visibility'
+ - '@dispatcher'
+ - '%core.php_ext%'
+
+ feed.news:
+ class: phpbb\feed\news
+ shared: false
+ arguments:
+ - '@feed.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@auth'
+ - '@content.visibility'
+ - '@dispatcher'
+ - '%core.php_ext%'
+
+ feed.overall:
+ class: phpbb\feed\overall
+ shared: false
+ arguments:
+ - '@feed.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@auth'
+ - '@content.visibility'
+ - '@dispatcher'
+ - '%core.php_ext%'
+
+ feed.quote_helper:
+ class: phpbb\feed\quote_helper
+ parent: text_formatter.s9e.quote_helper
+
+ feed.topic:
+ class: phpbb\feed\topic
+ shared: false
+ arguments:
+ - '@feed.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@auth'
+ - '@content.visibility'
+ - '@dispatcher'
+ - '%core.php_ext%'
+
+ feed.topics:
+ class: phpbb\feed\topics
+ shared: false
+ arguments:
+ - '@feed.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@auth'
+ - '@content.visibility'
+ - '@dispatcher'
+ - '%core.php_ext%'
+
+ feed.topics_active:
+ class: phpbb\feed\topics_active
+ shared: false
+ arguments:
+ - '@feed.helper'
+ - '@config'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@auth'
+ - '@content.visibility'
+ - '@dispatcher'
+ - '%core.php_ext%'
diff --git a/phpBB/config/default/container/services_files.yml b/phpBB/config/default/container/services_files.yml
new file mode 100644
index 0000000000..ba1fdb4c9a
--- /dev/null
+++ b/phpBB/config/default/container/services_files.yml
@@ -0,0 +1,57 @@
+services:
+ files.factory:
+ class: phpbb\files\factory
+ arguments:
+ - '@service_container'
+
+ files.filespec:
+ class: phpbb\files\filespec
+ shared: false
+ arguments:
+ - '@filesystem'
+ - '@language'
+ - '@php_ini'
+ - '@upload_imagesize'
+ - '%core.root_path%'
+ - '@mimetype.guesser'
+ - '@plupload'
+
+ files.upload:
+ class: phpbb\files\upload
+ shared: false
+ arguments:
+ - '@filesystem'
+ - '@files.factory'
+ - '@language'
+ - '@php_ini'
+ - '@request'
+
+ files.types.form:
+ class: phpbb\files\types\form
+ shared: false
+ arguments:
+ - '@files.factory'
+ - '@language'
+ - '@php_ini'
+ - '@plupload'
+ - '@request'
+
+ files.types.local:
+ class: phpbb\files\types\local
+ shared: false
+ arguments:
+ - '@files.factory'
+ - '@language'
+ - '@php_ini'
+ - '@request'
+
+ files.types.remote:
+ class: phpbb\files\types\remote
+ shared: false
+ arguments:
+ - '@config'
+ - '@files.factory'
+ - '@language'
+ - '@php_ini'
+ - '@request'
+ - '%core.root_path%'
diff --git a/phpBB/config/default/container/services_filesystem.yml b/phpBB/config/default/container/services_filesystem.yml
new file mode 100644
index 0000000000..828f9076dd
--- /dev/null
+++ b/phpBB/config/default/container/services_filesystem.yml
@@ -0,0 +1,3 @@
+services:
+ filesystem:
+ class: phpbb\filesystem\filesystem
diff --git a/phpBB/config/default/container/services_help.yml b/phpBB/config/default/container/services_help.yml
new file mode 100644
index 0000000000..1bff001523
--- /dev/null
+++ b/phpBB/config/default/container/services_help.yml
@@ -0,0 +1,27 @@
+services:
+ phpbb.help.manager:
+ class: phpbb\help\manager
+ arguments:
+ - '@dispatcher'
+ - '@language'
+ - '@template'
+
+ phpbb.help.controller.bbcode:
+ class: phpbb\help\controller\bbcode
+ arguments:
+ - '@controller.helper'
+ - '@phpbb.help.manager'
+ - '@template'
+ - '@language'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ phpbb.help.controller.faq:
+ class: phpbb\help\controller\faq
+ arguments:
+ - '@controller.helper'
+ - '@phpbb.help.manager'
+ - '@template'
+ - '@language'
+ - '%core.root_path%'
+ - '%core.php_ext%'
diff --git a/phpBB/config/default/container/services_hook.yml b/phpBB/config/default/container/services_hook.yml
new file mode 100644
index 0000000000..10a84184a0
--- /dev/null
+++ b/phpBB/config/default/container/services_hook.yml
@@ -0,0 +1,7 @@
+services:
+ hook_finder:
+ class: phpbb\hook\finder
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '@cache.driver'
diff --git a/phpBB/config/default/container/services_http.yml b/phpBB/config/default/container/services_http.yml
new file mode 100644
index 0000000000..49cfbf5b84
--- /dev/null
+++ b/phpBB/config/default/container/services_http.yml
@@ -0,0 +1,23 @@
+services:
+ http_kernel:
+ class: Symfony\Component\HttpKernel\HttpKernel
+ arguments:
+ - '@dispatcher'
+ - '@controller.resolver'
+ - '@request_stack'
+
+ # WARNING: The Symfony request does not escape the input and should be used very carefully
+ # prefer the phpbb request (service @request) as possible
+ symfony_request:
+ class: phpbb\symfony_request
+ arguments:
+ - '@request'
+
+ request_stack:
+ class: Symfony\Component\HttpFoundation\RequestStack
+
+ request:
+ class: phpbb\request\request
+ arguments:
+ - null
+ - '%core.disable_super_globals%'
diff --git a/phpBB/config/default/container/services_language.yml b/phpBB/config/default/container/services_language.yml
new file mode 100644
index 0000000000..8201fbf9b6
--- /dev/null
+++ b/phpBB/config/default/container/services_language.yml
@@ -0,0 +1,22 @@
+services:
+ language.helper.language_file:
+ class: phpbb\language\language_file_helper
+ arguments:
+ - '%core.root_path%'
+
+ language:
+ class: phpbb\language\language
+ arguments:
+ - '@language.loader'
+
+ language.loader_abstract:
+ abstract: true
+ class: phpbb\language\language_file_loader
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ language.loader:
+ parent: language.loader_abstract
+ calls:
+ - [set_extension_manager, ['@ext.manager']]
diff --git a/phpBB/config/default/container/services_migrator.yml b/phpBB/config/default/container/services_migrator.yml
new file mode 100644
index 0000000000..c63b087adb
--- /dev/null
+++ b/phpBB/config/default/container/services_migrator.yml
@@ -0,0 +1,64 @@
+services:
+# ----- Migrator -----
+ migrator:
+ class: phpbb\db\migrator
+ arguments:
+ - '@service_container'
+ - '@config'
+ - '@dbal.conn'
+ - '@dbal.tools'
+ - '%tables.migrations%'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '%core.table_prefix%'
+ - '@migrator.tool_collection'
+ - '@migrator.helper'
+
+ migrator.helper:
+ class: phpbb\db\migration\helper
+
+# ----- Migrator's tools -----
+ migrator.tool_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: migrator.tool }
+
+ migrator.tool.config:
+ class: phpbb\db\migration\tool\config
+ arguments:
+ - '@config'
+ tags:
+ - { name: migrator.tool }
+
+ migrator.tool.config_text:
+ class: phpbb\db\migration\tool\config_text
+ arguments:
+ - '@config_text'
+ tags:
+ - { name: migrator.tool }
+
+ migrator.tool.module:
+ class: phpbb\db\migration\tool\module
+ arguments:
+ - '@dbal.conn'
+ - '@cache'
+ - '@user'
+ - '@module.manager'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '%tables.modules%'
+ tags:
+ - { name: migrator.tool }
+
+ migrator.tool.permission:
+ class: phpbb\db\migration\tool\permission
+ arguments:
+ - '@dbal.conn'
+ - '@cache'
+ - '@auth'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: migrator.tool }
diff --git a/phpBB/config/default/container/services_mimetype_guesser.yml b/phpBB/config/default/container/services_mimetype_guesser.yml
new file mode 100644
index 0000000000..432470d40c
--- /dev/null
+++ b/phpBB/config/default/container/services_mimetype_guesser.yml
@@ -0,0 +1,36 @@
+services:
+ mimetype.guesser_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: mimetype.guessers }
+
+ mimetype.fileinfo_mimetype_guesser:
+ class: Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser
+ tags:
+ - { name: mimetype.guessers }
+
+ mimetype.filebinary_mimetype_guesser:
+ class: Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser
+ tags:
+ - { name: mimetype.guessers }
+
+ mimetype.content_guesser:
+ class: phpbb\mimetype\content_guesser
+ calls:
+ - [set_priority, ['%mimetype.guesser.priority.low%']]
+ tags:
+ - { name: mimetype.guessers }
+
+ mimetype.extension_guesser:
+ class: phpbb\mimetype\extension_guesser
+ calls:
+ - [set_priority, ['%mimetype.guesser.priority.lowest%']]
+ tags:
+ - { name: mimetype.guessers }
+
+ mimetype.guesser:
+ class: phpbb\mimetype\guesser
+ arguments:
+ - '@mimetype.guesser_collection'
diff --git a/phpBB/config/default/container/services_module.yml b/phpBB/config/default/container/services_module.yml
new file mode 100644
index 0000000000..a057e55239
--- /dev/null
+++ b/phpBB/config/default/container/services_module.yml
@@ -0,0 +1,10 @@
+services:
+ module.manager:
+ class: phpbb\module\module_manager
+ arguments:
+ - '@cache.driver'
+ - '@dbal.conn'
+ - '@ext.manager'
+ - '%tables.modules%'
+ - '%core.root_path%'
+ - '%core.php_ext%'
diff --git a/phpBB/config/default/container/services_notification.yml b/phpBB/config/default/container/services_notification.yml
new file mode 100644
index 0000000000..6c3cea3dbc
--- /dev/null
+++ b/phpBB/config/default/container/services_notification.yml
@@ -0,0 +1,224 @@
+services:
+ notification_manager:
+ class: phpbb\notification\manager
+ arguments:
+ - '@notification.type_collection'
+ - '@notification.method_collection'
+ - '@service_container'
+ - '@user_loader'
+ - '@dispatcher'
+ - '@dbal.conn'
+ - '@cache'
+ - '@language'
+ - '@user'
+ - '%tables.notification_types%'
+ - '%tables.user_notifications%'
+
+# ----- Notification's types -----
+# Service MUST NOT be shared for all the plugins to work.
+ notification.type_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: notification.type }
+
+ notification.type.base:
+ abstract: true
+ arguments:
+ - '@dbal.conn'
+ - '@language'
+ - '@user'
+ - '@auth'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '%tables.user_notifications%'
+
+ notification.type.admin_activate_user:
+ class: phpbb\notification\type\admin_activate_user
+ shared: false
+ parent: notification.type.base
+ calls:
+ - [set_user_loader, ['@user_loader']]
+ - [set_config, ['@config']]
+ tags:
+ - { name: notification.type }
+
+ notification.type.approve_post:
+ class: phpbb\notification\type\approve_post
+ shared: false
+ parent: notification.type.post
+ tags:
+ - { name: notification.type }
+
+ notification.type.approve_topic:
+ class: phpbb\notification\type\approve_topic
+ shared: false
+ parent: notification.type.topic
+ tags:
+ - { name: notification.type }
+
+ notification.type.bookmark:
+ class: phpbb\notification\type\bookmark
+ shared: false
+ parent: notification.type.post
+ tags:
+ - { name: notification.type }
+
+ notification.type.disapprove_post:
+ class: phpbb\notification\type\disapprove_post
+ shared: false
+ parent: notification.type.post
+ tags:
+ - { name: notification.type }
+
+ notification.type.disapprove_topic:
+ class: phpbb\notification\type\disapprove_topic
+ shared: false
+ parent: notification.type.topic
+ tags:
+ - { name: notification.type }
+
+ notification.type.group_request:
+ class: phpbb\notification\type\group_request
+ shared: false
+ parent: notification.type.base
+ calls:
+ - [set_user_loader, ['@user_loader']]
+ tags:
+ - { name: notification.type }
+
+ notification.type.group_request_approved:
+ class: phpbb\notification\type\group_request_approved
+ shared: false
+ parent: notification.type.base
+ tags:
+ - { name: notification.type }
+
+ notification.type.pm:
+ class: phpbb\notification\type\pm
+ shared: false
+ parent: notification.type.base
+ calls:
+ - [set_user_loader, ['@user_loader']]
+ - [set_config, ['@config']]
+ tags:
+ - { name: notification.type }
+
+ notification.type.post:
+ class: phpbb\notification\type\post
+ shared: false
+ parent: notification.type.base
+ calls:
+ - [set_user_loader, ['@user_loader']]
+ - [set_config, ['@config']]
+ tags:
+ - { name: notification.type }
+
+ notification.type.post_in_queue:
+ class: phpbb\notification\type\post_in_queue
+ shared: false
+ parent: notification.type.post
+ tags:
+ - { name: notification.type }
+
+ notification.type.quote:
+ class: phpbb\notification\type\quote
+ shared: false
+ parent: notification.type.post
+ calls:
+ - [set_utils, ['@text_formatter.utils']]
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_pm:
+ class: phpbb\notification\type\report_pm
+ shared: false
+ parent: notification.type.pm
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_pm_closed:
+ class: phpbb\notification\type\report_pm_closed
+ shared: false
+ parent: notification.type.pm
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_post:
+ class: phpbb\notification\type\report_post
+ shared: false
+ parent: notification.type.post
+ tags:
+ - { name: notification.type }
+
+ notification.type.report_post_closed:
+ class: phpbb\notification\type\report_post_closed
+ shared: false
+ parent: notification.type.post
+ tags:
+ - { name: notification.type }
+
+ notification.type.topic:
+ class: phpbb\notification\type\topic
+ shared: false
+ parent: notification.type.base
+ calls:
+ - [set_user_loader, ['@user_loader']]
+ - [set_config, ['@config']]
+ tags:
+ - { name: notification.type }
+
+ notification.type.topic_in_queue:
+ class: phpbb\notification\type\topic_in_queue
+ shared: false
+ parent: notification.type.topic
+ tags:
+ - { name: notification.type }
+
+# ----- Notification's methods -----
+# Service MUST NOT be shared for all the plugins to work.
+ notification.method_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: notification.method }
+
+ notification.method.board:
+ class: phpbb\notification\method\board
+ shared: false
+ arguments:
+ - '@user_loader'
+ - '@dbal.conn'
+ - '@cache.driver'
+ - '@user'
+ - '@config'
+ - '%tables.notification_types%'
+ - '%tables.notifications%'
+ tags:
+ - { name: notification.method }
+
+ notification.method.email:
+ class: phpbb\notification\method\email
+ shared: false
+ arguments:
+ - '@user_loader'
+ - '@user'
+ - '@config'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: notification.method }
+
+ notification.method.jabber:
+ class: phpbb\notification\method\jabber
+ shared: false
+ arguments:
+ - '@user_loader'
+ - '@user'
+ - '@config'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: notification.method }
diff --git a/phpBB/config/default/container/services_password.yml b/phpBB/config/default/container/services_password.yml
new file mode 100644
index 0000000000..d5f5fe287b
--- /dev/null
+++ b/phpBB/config/default/container/services_password.yml
@@ -0,0 +1,136 @@
+parameters:
+ passwords.driver.bcrypt_cost: 10
+
+services:
+# ----- Password management -----
+ passwords.manager:
+ class: phpbb\passwords\manager
+ arguments:
+ - '@config'
+ - '@passwords.driver_collection'
+ - '@passwords.helper'
+ - '%passwords.algorithms%'
+
+ passwords.helper:
+ class: phpbb\passwords\helper
+
+ passwords.driver_helper:
+ class: phpbb\passwords\driver\helper
+ arguments:
+ - '@config'
+
+# ----- Password's drivers -----
+ passwords.driver_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: passwords.driver }
+
+ passwords.driver.bcrypt:
+ class: phpbb\passwords\driver\bcrypt
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ - '%passwords.driver.bcrypt_cost%'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.bcrypt_2y:
+ class: phpbb\passwords\driver\bcrypt_2y
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ - '%passwords.driver.bcrypt_cost%'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.bcrypt_wcf2:
+ class: phpbb\passwords\driver\bcrypt_wcf2
+ arguments:
+ - '@passwords.driver.bcrypt'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.salted_md5:
+ class: phpbb\passwords\driver\salted_md5
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.phpass:
+ class: phpbb\passwords\driver\phpass
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.convert_password:
+ class: phpbb\passwords\driver\convert_password
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.sha1_smf:
+ class: phpbb\passwords\driver\sha1_smf
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.sha1_wcf1:
+ class: phpbb\passwords\driver\sha1_wcf1
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.sha1:
+ class: phpbb\passwords\driver\sha1
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.md5_phpbb2:
+ class: phpbb\passwords\driver\md5_phpbb2
+ arguments:
+ - '@request'
+ - '@passwords.driver.salted_md5'
+ - '@passwords.driver_helper'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.md5_mybb:
+ class: phpbb\passwords\driver\md5_mybb
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.driver.md5_vb:
+ class: phpbb\passwords\driver\md5_vb
+ arguments:
+ - '@config'
+ - '@passwords.driver_helper'
+ tags:
+ - { name: passwords.driver }
+
+ passwords.update.lock:
+ class: phpbb\lock\db
+ arguments:
+ - update_hashes_lock
+ - '@config'
+ - '@dbal.conn'
diff --git a/phpBB/config/default/container/services_php.yml b/phpBB/config/default/container/services_php.yml
new file mode 100644
index 0000000000..29349960f3
--- /dev/null
+++ b/phpBB/config/default/container/services_php.yml
@@ -0,0 +1,3 @@
+services:
+ php_ini:
+ class: bantu\IniGetWrapper\IniGetWrapper
diff --git a/phpBB/config/default/container/services_profilefield.yml b/phpBB/config/default/container/services_profilefield.yml
new file mode 100644
index 0000000000..90b22836e5
--- /dev/null
+++ b/phpBB/config/default/container/services_profilefield.yml
@@ -0,0 +1,102 @@
+services:
+ profilefields.manager:
+ class: phpbb\profilefields\manager
+ arguments:
+ - '@auth'
+ - '@dbal.conn'
+ - '@dispatcher'
+ - '@request'
+ - '@template'
+ - '@profilefields.type_collection'
+ - '@user'
+ - '%tables.profile_fields%'
+ - '%tables.profile_fields_language%'
+ - '%tables.profile_fields_data%'
+
+ profilefields.lang_helper:
+ class: phpbb\profilefields\lang_helper
+ arguments:
+ - '@dbal.conn'
+ - '%tables.profile_fields_options_language%'
+
+# ----- Profile fields types -----
+ profilefields.type_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: profilefield.type }
+
+ profilefields.type.bool:
+ class: phpbb\profilefields\type\type_bool
+ arguments:
+ - '@profilefields.lang_helper'
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
+
+ profilefields.type.date:
+ class: phpbb\profilefields\type\type_date
+ arguments:
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
+
+ profilefields.type.dropdown:
+ class: phpbb\profilefields\type\type_dropdown
+ arguments:
+ - '@profilefields.lang_helper'
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
+
+ profilefields.type.googleplus:
+ class: phpbb\profilefields\type\type_googleplus
+ arguments:
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
+
+ profilefields.type.int:
+ class: phpbb\profilefields\type\type_int
+ arguments:
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
+
+ profilefields.type.string:
+ class: phpbb\profilefields\type\type_string
+ arguments:
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
+
+ profilefields.type.text:
+ class: phpbb\profilefields\type\type_text
+ arguments:
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
+
+ profilefields.type.url:
+ class: phpbb\profilefields\type\type_url
+ arguments:
+ - '@request'
+ - '@template'
+ - '@user'
+ tags:
+ - { name: profilefield.type }
diff --git a/phpBB/config/default/container/services_report.yml b/phpBB/config/default/container/services_report.yml
new file mode 100644
index 0000000000..2c5b3bf3d5
--- /dev/null
+++ b/phpBB/config/default/container/services_report.yml
@@ -0,0 +1,53 @@
+services:
+# ----- Report controller -----
+ phpbb.report.controller:
+ class: phpbb\report\controller\report
+ arguments:
+ - '@config'
+ - '@user'
+ - '@template'
+ - '@controller.helper'
+ - '@request'
+ - '@captcha.factory'
+ - '@phpbb.report.handler_factory'
+ - '@phpbb.report.report_reason_list_provider'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+# ----- Report handler factory -----
+ phpbb.report.handler_factory:
+ class: phpbb\report\handler_factory
+ arguments:
+ - '@service_container'
+
+# ----- Report UI provider -----
+ phpbb.report.report_reason_list_provider:
+ class: phpbb\report\report_reason_list_provider
+ arguments:
+ - '@dbal.conn.driver'
+ - '@template'
+ - '@user'
+
+# ----- Report handlers -----
+# Service MUST NOT be shared for all the handlers to work correctly.
+ phpbb.report.handlers.report_handler_pm:
+ class: phpbb\report\report_handler_pm
+ shared: false
+ arguments:
+ - '@dbal.conn.driver'
+ - '@dispatcher'
+ - '@config'
+ - '@auth'
+ - '@user'
+ - '@notification_manager'
+
+ phpbb.report.handlers.report_handler_post:
+ class: phpbb\report\report_handler_post
+ shared: false
+ arguments:
+ - '@dbal.conn.driver'
+ - '@dispatcher'
+ - '@config'
+ - '@auth'
+ - '@user'
+ - '@notification_manager'
diff --git a/phpBB/config/default/container/services_routing.yml b/phpBB/config/default/container/services_routing.yml
new file mode 100644
index 0000000000..3048145a2f
--- /dev/null
+++ b/phpBB/config/default/container/services_routing.yml
@@ -0,0 +1,79 @@
+services:
+ router:
+ class: phpbb\routing\router
+ arguments:
+ - '@service_container'
+ - '@routing.chained_resources_locator'
+ - '@routing.delegated_loader'
+ - '%core.php_ext%'
+ - '%core.cache_dir%'
+
+ router.listener:
+ class: Symfony\Component\HttpKernel\EventListener\RouterListener
+ arguments:
+ - '@router'
+ - null
+ - null
+ - '@request_stack'
+ tags:
+ - { name: kernel.event_subscriber }
+
+ routing.helper:
+ class: phpbb\routing\helper
+ arguments:
+ - '@config'
+ - '@router'
+ - '@symfony_request'
+ - '@request'
+ - '@filesystem'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+# ---- Route loaders ----
+
+ routing.delegated_loader:
+ class: Symfony\Component\Config\Loader\DelegatingLoader
+ arguments:
+ - '@routing.resolver'
+
+ routing.resolver:
+ class: phpbb\routing\loader_resolver
+ arguments:
+ - '@routing.loader.collection'
+
+ routing.loader.collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: routing.loader }
+
+ routing.loader.yaml:
+ class: Symfony\Component\Routing\Loader\YamlFileLoader
+ arguments:
+ - '@file_locator'
+ tags:
+ - { name: routing.loader }
+
+# ---- Resources Locators ----
+
+ routing.chained_resources_locator:
+ class: phpbb\routing\resources_locator\chained_resources_locator
+ arguments:
+ - '@routing.resources_locator.collection'
+
+ routing.resources_locator.collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: routing.resources_locator }
+
+ routing.resources_locator.default:
+ class: phpbb\routing\resources_locator\default_resources_locator
+ arguments:
+ - '%core.root_path%'
+ - '%core.environment%'
+ - '@ext.manager'
+ tags:
+ - { name: routing.resources_locator }
diff --git a/phpBB/config/default/container/services_text_formatter.yml b/phpBB/config/default/container/services_text_formatter.yml
new file mode 100644
index 0000000000..07087cd4a9
--- /dev/null
+++ b/phpBB/config/default/container/services_text_formatter.yml
@@ -0,0 +1,79 @@
+parameters:
+ text_formatter.cache.dir: '%core.cache_dir%'
+ text_formatter.cache.parser.key: _text_formatter_parser
+ text_formatter.cache.renderer.key: _text_formatter_renderer
+
+services:
+ text_formatter.cache:
+ alias: text_formatter.s9e.factory
+
+ text_formatter.data_access:
+ class: phpbb\textformatter\data_access
+ arguments:
+ - '@dbal.conn'
+ - '%tables.bbcodes%'
+ - '%tables.smilies%'
+ - '%tables.styles%'
+ - '%tables.words%'
+ - '%core.root_path%styles/'
+
+ text_formatter.parser:
+ alias: text_formatter.s9e.parser
+
+ text_formatter.renderer:
+ alias: text_formatter.s9e.renderer
+
+ text_formatter.utils:
+ alias: text_formatter.s9e.utils
+
+ text_formatter.s9e.bbcode_merger:
+ class: phpbb\textformatter\s9e\bbcode_merger
+ arguments:
+ - '@text_formatter.s9e.factory'
+
+ text_formatter.s9e.factory:
+ class: phpbb\textformatter\s9e\factory
+ arguments:
+ - '@text_formatter.data_access'
+ - '@cache.driver'
+ - '@dispatcher'
+ - '@config'
+ - '@text_formatter.s9e.link_helper'
+ - '@log'
+ - '%text_formatter.cache.dir%'
+ - '%text_formatter.cache.parser.key%'
+ - '%text_formatter.cache.renderer.key%'
+
+ text_formatter.s9e.link_helper:
+ class: phpbb\textformatter\s9e\link_helper
+
+ text_formatter.s9e.parser:
+ class: phpbb\textformatter\s9e\parser
+ arguments:
+ - '@cache.driver'
+ - '%text_formatter.cache.parser.key%'
+ - '@text_formatter.s9e.factory'
+ - '@dispatcher'
+
+ text_formatter.s9e.quote_helper:
+ class: phpbb\textformatter\s9e\quote_helper
+ arguments:
+ - '@user'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ text_formatter.s9e.renderer:
+ class: phpbb\textformatter\s9e\renderer
+ arguments:
+ - '@cache.driver'
+ - '%text_formatter.cache.dir%'
+ - '%text_formatter.cache.renderer.key%'
+ - '@text_formatter.s9e.factory'
+ - '@dispatcher'
+ calls:
+ - [configure_quote_helper, ['@text_formatter.s9e.quote_helper']]
+ - [configure_smilies_path, ['@config', '@path_helper']]
+ - [configure_user, ['@user', '@config', '@auth']]
+
+ text_formatter.s9e.utils:
+ class: phpbb\textformatter\s9e\utils
diff --git a/phpBB/config/default/container/services_text_reparser.yml b/phpBB/config/default/container/services_text_reparser.yml
new file mode 100644
index 0000000000..4bc49f5765
--- /dev/null
+++ b/phpBB/config/default/container/services_text_reparser.yml
@@ -0,0 +1,109 @@
+services:
+ text_reparser.manager:
+ class: phpbb\textreparser\manager
+ arguments:
+ - '@config'
+ - '@config_text'
+ - '@text_reparser_collection'
+
+ text_reparser.lock:
+ class: phpbb\lock\db
+ arguments:
+ - reparse_lock
+ - '@config'
+ - '@dbal.conn'
+
+ text_reparser_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: text_reparser.plugin }
+
+ text_reparser.contact_admin_info:
+ class: phpbb\textreparser\plugins\contact_admin_info
+ arguments:
+ - '@config_text'
+ calls:
+ - [set_name, [contact_admin_info]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.forum_description:
+ class: phpbb\textreparser\plugins\forum_description
+ arguments:
+ - '@dbal.conn'
+ - '%tables.forums%'
+ calls:
+ - [set_name, [forum_description]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.forum_rules:
+ class: phpbb\textreparser\plugins\forum_rules
+ arguments:
+ - '@dbal.conn'
+ - '%tables.forums%'
+ calls:
+ - [set_name, [forum_rules]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.group_description:
+ class: phpbb\textreparser\plugins\group_description
+ arguments:
+ - '@dbal.conn'
+ - '%tables.groups%'
+ calls:
+ - [set_name, [group_description]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.pm_text:
+ class: phpbb\textreparser\plugins\pm_text
+ arguments:
+ - '@dbal.conn'
+ - '%tables.privmsgs%'
+ calls:
+ - [set_name, [pm_text]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.poll_option:
+ class: phpbb\textreparser\plugins\poll_option
+ arguments:
+ - '@dbal.conn'
+ calls:
+ - [set_name, [poll_option]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.poll_title:
+ class: phpbb\textreparser\plugins\poll_title
+ arguments:
+ - '@dbal.conn'
+ - '%tables.topics%'
+ calls:
+ - [set_name, [poll_title]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.post_text:
+ class: phpbb\textreparser\plugins\post_text
+ arguments:
+ - '@dbal.conn'
+ - '%tables.posts%'
+ calls:
+ - [set_name, [post_text]]
+ tags:
+ - { name: text_reparser.plugin }
+
+ text_reparser.user_signature:
+ class: phpbb\textreparser\plugins\user_signature
+ arguments:
+ - '@dbal.conn'
+ - '%tables.users%'
+ calls:
+ - [set_name, [user_signature]]
+ tags:
+ - { name: text_reparser.plugin }
diff --git a/phpBB/config/default/container/services_twig.yml b/phpBB/config/default/container/services_twig.yml
new file mode 100644
index 0000000000..a9b5b6d4cd
--- /dev/null
+++ b/phpBB/config/default/container/services_twig.yml
@@ -0,0 +1,68 @@
+parameters:
+ core.template.cache_path: '%core.cache_dir%twig/'
+
+services:
+ template.twig.environment:
+ class: phpbb\template\twig\environment
+ arguments:
+ - '@config'
+ - '@filesystem'
+ - '@path_helper'
+ - '%core.template.cache_path%'
+ - '@ext.manager'
+ - '@template.twig.loader'
+ - '@dispatcher'
+ - []
+ calls:
+ - [setLexer, ['@template.twig.lexer']]
+
+ template.twig.lexer:
+ class: phpbb\template\twig\lexer
+ lazy: true
+ arguments:
+ - '@template.twig.environment'
+
+ template.twig.loader:
+ class: phpbb\template\twig\loader
+ arguments:
+ - '@filesystem'
+
+ template.twig.extensions.collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: twig.extension }
+
+ template.twig.extensions.phpbb:
+ class: phpbb\template\twig\extension
+ arguments:
+ - '@template_context'
+ - '@language'
+ tags:
+ - { name: twig.extension }
+
+ template.twig.extensions.routing:
+ class: phpbb\template\twig\extension\routing
+ arguments:
+ - '@routing.helper'
+ tags:
+ - { name: twig.extension }
+
+ template.twig.extensions.debug:
+ class: Twig_Extension_Debug
+
+ template:
+ class: phpbb\template\twig\twig
+ arguments:
+ - '@path_helper'
+ - '@config'
+ - '@template_context'
+ - '@template.twig.environment'
+ - '%core.template.cache_path%'
+ - '@user'
+ - '@template.twig.extensions.collection'
+ - '@ext.manager'
+
+ template_context:
+ class: phpbb\template\context
diff --git a/phpBB/config/default/container/services_user.yml b/phpBB/config/default/container/services_user.yml
new file mode 100644
index 0000000000..7e634c60c3
--- /dev/null
+++ b/phpBB/config/default/container/services_user.yml
@@ -0,0 +1,20 @@
+services:
+ acl.permissions:
+ class: phpbb\permissions
+ arguments:
+ - '@dispatcher'
+ - '@user'
+
+ user:
+ class: phpbb\user
+ arguments:
+ - '@language'
+ - '%datetime.class%'
+
+ user_loader:
+ class: phpbb\user_loader
+ arguments:
+ - '@dbal.conn'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '%tables.users%'
diff --git a/phpBB/config/default/container/tables.yml b/phpBB/config/default/container/tables.yml
new file mode 100644
index 0000000000..4aed35710b
--- /dev/null
+++ b/phpBB/config/default/container/tables.yml
@@ -0,0 +1,78 @@
+parameters:
+ tables.acl_groups: '%core.table_prefix%acl_groups'
+ tables.acl_options: '%core.table_prefix%acl_options'
+ tables.acl_roles: '%core.table_prefix%acl_roles'
+ tables.acl_roles_data: '%core.table_prefix%acl_roles_data'
+ tables.acl_users: '%core.table_prefix%acl_users'
+ tables.attachments: '%core.table_prefix%attachments'
+ tables.auth_provider_oauth_token_storage: '%core.table_prefix%oauth_tokens'
+ tables.auth_provider_oauth_states: '%core.table_prefix%oauth_states'
+ tables.auth_provider_oauth_account_assoc: '%core.table_prefix%oauth_accounts'
+ tables.banlist: '%core.table_prefix%banlist'
+ tables.bbcodes: '%core.table_prefix%bbcodes'
+ tables.bookmarks: '%core.table_prefix%bookmarks'
+ tables.bots: '%core.table_prefix%bots'
+ tables.captcha_qa_questions: '%core.table_prefix%captcha_questions'
+ tables.captcha_qa_answers: '%core.table_prefix%captcha_answers'
+ tables.captcha_qa_confirm: '%core.table_prefix%qa_confirm'
+ tables.config: '%core.table_prefix%config'
+ tables.config_text: '%core.table_prefix%config_text'
+ tables.confirm: '%core.table_prefix%confirm'
+ tables.disallow: '%core.table_prefix%disallow'
+ tables.drafts: '%core.table_prefix%drafts'
+ tables.ext: '%core.table_prefix%ext'
+ tables.extensions: '%core.table_prefix%extensions'
+ tables.extension_groups: '%core.table_prefix%extension_groups'
+ tables.forums: '%core.table_prefix%forums'
+ tables.forums_access: '%core.table_prefix%forums_access'
+ tables.forums_track: '%core.table_prefix%forums_track'
+ tables.forums_watch: '%core.table_prefix%forums_watch'
+ tables.groups: '%core.table_prefix%groups'
+ tables.icons: '%core.table_prefix%icons'
+ tables.lang: '%core.table_prefix%lang'
+ tables.log: '%core.table_prefix%log'
+ tables.login_attempts: '%core.table_prefix%login_attempts'
+ tables.migrations: '%core.table_prefix%migrations'
+ tables.moderator_cache: '%core.table_prefix%moderator_cache'
+ tables.modules: '%core.table_prefix%modules'
+ tables.notification_types: '%core.table_prefix%notification_types'
+ tables.notifications: '%core.table_prefix%notifications'
+ tables.poll_options: '%core.table_prefix%poll_options'
+ tables.poll_votes: '%core.table_prefix%poll_votes'
+ tables.posts: '%core.table_prefix%posts'
+ tables.privmsgs: '%core.table_prefix%privmsgs'
+ tables.privmsgs_folder: '%core.table_prefix%privmsgs_folder'
+ tables.privmsgs_rules: '%core.table_prefix%privmsgs_rules'
+ tables.privmsgs_to: '%core.table_prefix%privmsgs_to'
+ tables.profile_fields: '%core.table_prefix%profile_fields'
+ tables.profile_fields_data: '%core.table_prefix%profile_fields_data'
+ tables.profile_fields_options_language: '%core.table_prefix%profile_fields_lang'
+ tables.profile_fields_language: '%core.table_prefix%profile_lang'
+ tables.ranks: '%core.table_prefix%ranks'
+ tables.reports: '%core.table_prefix%reports'
+ tables.reports_reasons: '%core.table_prefix%reports_reasons'
+ tables.search_results: '%core.table_prefix%search_results'
+ tables.search_wordlist: '%core.table_prefix%search_wordlist'
+ tables.search_wordmatch: '%core.table_prefix%search_wordmatch'
+ tables.sessions: '%core.table_prefix%sessions'
+ tables.sessions_keys: '%core.table_prefix%sessions_keys'
+ tables.sitelist: '%core.table_prefix%sitelist'
+ tables.smilies: '%core.table_prefix%smilies'
+ tables.sphinx: '%core.table_prefix%sphinx'
+ tables.styles: '%core.table_prefix%styles'
+ tables.styles_template: '%core.table_prefix%styles_template'
+ tables.styles_template_data: '%core.table_prefix%styles_template_data'
+ tables.styles_theme: '%core.table_prefix%styles_theme'
+ tables.styles_imageset: '%core.table_prefix%styles_imageset'
+ tables.styles_imageset_data: '%core.table_prefix%styles_imageset_data'
+ tables.teampage: '%core.table_prefix%teampage'
+ tables.topics: '%core.table_prefix%topics'
+ tables.topics_posted: '%core.table_prefix%topics_posted'
+ tables.topics_track: '%core.table_prefix%topics_track'
+ tables.topics_watch: '%core.table_prefix%topics_watch'
+ tables.user_group: '%core.table_prefix%user_group'
+ tables.user_notifications: '%core.table_prefix%user_notifications'
+ tables.users: '%core.table_prefix%users'
+ tables.warnings: '%core.table_prefix%warnings'
+ tables.words: '%core.table_prefix%words'
+ tables.zebra: '%core.table_prefix%zebra'
diff --git a/phpBB/config/default/routing/feed.yml b/phpBB/config/default/routing/feed.yml
new file mode 100644
index 0000000000..22c9ea5755
--- /dev/null
+++ b/phpBB/config/default/routing/feed.yml
@@ -0,0 +1,35 @@
+phpbb_feed_forums:
+ path: /forums
+ defaults: { _controller: phpbb.feed.controller:forums }
+
+phpbb_feed_news:
+ path: /news
+ defaults: { _controller: phpbb.feed.controller:news }
+
+phpbb_feed_topics:
+ path: /topics
+ defaults: { _controller: phpbb.feed.controller:topics }
+
+phpbb_feed_topics_active:
+ path: /topics_active
+ defaults: { _controller: phpbb.feed.controller:topics_active }
+
+phpbb_feed_topics_new:
+ path: /topics_new
+ defaults: { _controller: phpbb.feed.controller:topics_new }
+
+phpbb_feed_forum:
+ path: /forum/{forum_id}
+ defaults: { _controller: phpbb.feed.controller:forum }
+ requirements:
+ forum_id: \d+
+
+phpbb_feed_topic:
+ path: /topic/{topic_id}
+ defaults: { _controller: phpbb.feed.controller:topic }
+ requirements:
+ topic_id: \d+
+
+phpbb_feed_overall:
+ path: /{mode}
+ defaults: { _controller: phpbb.feed.controller:overall }
diff --git a/phpBB/config/default/routing/help.yml b/phpBB/config/default/routing/help.yml
new file mode 100644
index 0000000000..8d43839d1e
--- /dev/null
+++ b/phpBB/config/default/routing/help.yml
@@ -0,0 +1,7 @@
+phpbb_help_bbcode_controller:
+ path: /bbcode
+ defaults: { _controller: phpbb.help.controller.bbcode:handle }
+
+phpbb_help_faq_controller:
+ path: /faq
+ defaults: { _controller: phpbb.help.controller.faq:handle }
diff --git a/phpBB/config/default/routing/report.yml b/phpBB/config/default/routing/report.yml
new file mode 100644
index 0000000000..c386770e42
--- /dev/null
+++ b/phpBB/config/default/routing/report.yml
@@ -0,0 +1,17 @@
+phpbb_report_pm_controller:
+ path: /pm/{id}/report
+ methods: [GET, POST]
+ defaults:
+ _controller: phpbb.report.controller:handle
+ mode: 'pm'
+ requirements:
+ id: \d+
+
+phpbb_report_post_controller:
+ path: /post/{id}/report
+ methods: [GET, POST]
+ defaults:
+ _controller: phpbb.report.controller:handle
+ mode: 'post'
+ requirements:
+ id: \d+
diff --git a/phpBB/config/default/routing/routing.yml b/phpBB/config/default/routing/routing.yml
new file mode 100644
index 0000000000..f381f024ad
--- /dev/null
+++ b/phpBB/config/default/routing/routing.yml
@@ -0,0 +1,24 @@
+# Structure:
+#
+# foo_controller:
+# path: /foo
+# defaults: { _controller: foo_sevice:method }
+#
+# The above will be accessed via app.php?controller=foo and it will
+# instantiate the 'foo_service' service and call the 'method' method.
+#
+
+phpbb_feed_routing:
+ resource: feed.yml
+ prefix: /feed
+
+phpbb_feed_index:
+ path: /feed
+ defaults: { _controller: phpbb.feed.controller:overall }
+
+phpbb_help_routing:
+ resource: help.yml
+ prefix: /help
+
+phpbb_report_routing:
+ resource: report.yml
diff --git a/phpBB/config/development/config.yml b/phpBB/config/development/config.yml
new file mode 100644
index 0000000000..f39eb52e73
--- /dev/null
+++ b/phpBB/config/development/config.yml
@@ -0,0 +1,13 @@
+imports:
+ - { resource: ../default/config.yml }
+
+core:
+ require_dev_dependencies: true
+
+ debug:
+ exceptions: true
+
+ twig:
+ debug: true
+ auto_reload: true
+ enable_debug_extension: true
diff --git a/phpBB/config/development/container/environment.yml b/phpBB/config/development/container/environment.yml
new file mode 100644
index 0000000000..40a3c7a683
--- /dev/null
+++ b/phpBB/config/development/container/environment.yml
@@ -0,0 +1,3 @@
+imports:
+ - { resource: services.yml }
+ - { resource: parameters.yml }
diff --git a/phpBB/config/development/container/parameters.yml b/phpBB/config/development/container/parameters.yml
new file mode 100644
index 0000000000..0447646806
--- /dev/null
+++ b/phpBB/config/development/container/parameters.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../../default/container/parameters.yml }
diff --git a/phpBB/config/development/container/services.yml b/phpBB/config/development/container/services.yml
new file mode 100644
index 0000000000..b302f0f966
--- /dev/null
+++ b/phpBB/config/development/container/services.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../../default/container/services.yml }
diff --git a/phpBB/config/development/routing/environment.yml b/phpBB/config/development/routing/environment.yml
new file mode 100644
index 0000000000..301183bbae
--- /dev/null
+++ b/phpBB/config/development/routing/environment.yml
@@ -0,0 +1,2 @@
+core.default:
+ resource: ../../default/routing/routing.yml
diff --git a/phpBB/config/event.yml b/phpBB/config/event.yml
deleted file mode 100644
index 7bc4cb0042..0000000000
--- a/phpBB/config/event.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-services:
- dispatcher:
- class: phpbb\event\dispatcher
- arguments:
- - @service_container
-
- hook_finder:
- class: phpbb\hook\finder
- arguments:
- - %core.root_path%
- - %core.php_ext%
- - @cache.driver
-
- kernel_request_subscriber:
- class: phpbb\event\kernel_request_subscriber
- arguments:
- - @ext.manager
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: kernel.event_subscriber }
-
- kernel_exception_subscriber:
- class: phpbb\event\kernel_exception_subscriber
- arguments:
- - @template
- - @user
- tags:
- - { name: kernel.event_subscriber }
-
- kernel_terminate_subscriber:
- class: phpbb\event\kernel_terminate_subscriber
- tags:
- - { name: kernel.event_subscriber }
-
- symfony_response_listener:
- class: Symfony\Component\HttpKernel\EventListener\ResponseListener
- arguments:
- - UTF-8
- tags:
- - { name: kernel.event_subscriber }
diff --git a/phpBB/config/feed.yml b/phpBB/config/feed.yml
deleted file mode 100644
index b69f80b2c5..0000000000
--- a/phpBB/config/feed.yml
+++ /dev/null
@@ -1,113 +0,0 @@
-services:
- feed.helper:
- class: phpbb\feed\helper
- arguments:
- - @config
- - @user
- - %core.root_path%
- - %core.php_ext%
-
- feed.factory:
- class: phpbb\feed\factory
- arguments:
- - @service_container
- - @config
- - @dbal.conn
-
- feed.forum:
- class: phpbb\feed\forum
- scope: prototype
- arguments:
- - @feed.helper
- - @config
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @content.visibility
- - @dispatcher
- - %core.php_ext%
-
- feed.forums:
- class: phpbb\feed\forums
- scope: prototype
- arguments:
- - @feed.helper
- - @config
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @content.visibility
- - @dispatcher
- - %core.php_ext%
-
- feed.news:
- class: phpbb\feed\news
- scope: prototype
- arguments:
- - @feed.helper
- - @config
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @content.visibility
- - @dispatcher
- - %core.php_ext%
-
- feed.overall:
- class: phpbb\feed\overall
- scope: prototype
- arguments:
- - @feed.helper
- - @config
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @content.visibility
- - @dispatcher
- - %core.php_ext%
-
- feed.topic:
- class: phpbb\feed\topic
- scope: prototype
- arguments:
- - @feed.helper
- - @config
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @content.visibility
- - @dispatcher
- - %core.php_ext%
-
- feed.topics:
- class: phpbb\feed\topics
- scope: prototype
- arguments:
- - @feed.helper
- - @config
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @content.visibility
- - @dispatcher
- - %core.php_ext%
-
- feed.topics_active:
- class: phpbb\feed\topics_active
- scope: prototype
- arguments:
- - @feed.helper
- - @config
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @content.visibility
- - @dispatcher
- - %core.php_ext%
diff --git a/phpBB/config/installer/config.yml b/phpBB/config/installer/config.yml
new file mode 100644
index 0000000000..979dbbcdd9
--- /dev/null
+++ b/phpBB/config/installer/config.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../default/config.yml }
diff --git a/phpBB/config/installer/container/environment.yml b/phpBB/config/installer/container/environment.yml
new file mode 100644
index 0000000000..40a3c7a683
--- /dev/null
+++ b/phpBB/config/installer/container/environment.yml
@@ -0,0 +1,3 @@
+imports:
+ - { resource: services.yml }
+ - { resource: parameters.yml }
diff --git a/phpBB/config/installer/container/parameters.yml b/phpBB/config/installer/container/parameters.yml
new file mode 100644
index 0000000000..f11f7e2d84
--- /dev/null
+++ b/phpBB/config/installer/container/parameters.yml
@@ -0,0 +1,5 @@
+imports:
+ - { resource: ../../default/container/parameters.yml }
+
+parameters:
+ installer.create_config_file.options: []
diff --git a/phpBB/config/installer/container/services.yml b/phpBB/config/installer/container/services.yml
new file mode 100644
index 0000000000..7203c0ab10
--- /dev/null
+++ b/phpBB/config/installer/container/services.yml
@@ -0,0 +1,104 @@
+imports:
+ - { resource: services_installer.yml }
+ - { resource: ../../default/container/services_event.yml }
+ - { resource: ../../default/container/services_filesystem.yml }
+ - { resource: ../../default/container/services_http.yml }
+ - { resource: ../../default/container/services_language.yml }
+ - { resource: ../../default/container/services_php.yml }
+ - { resource: ../../default/container/services_routing.yml }
+ - { resource: ../../default/container/services_twig.yml }
+
+services:
+ cache.driver:
+ class: '%cache.driver.class%'
+ arguments:
+ - '%core.cache_dir%'
+
+ config:
+ class: phpbb\config\config
+ arguments:
+ -
+ rand_seed: 'installer_seed'
+ rand_seed_last_update: 0
+
+ controller.resolver:
+ class: phpbb\controller\resolver
+ arguments:
+ - '@service_container'
+ - '%core.root_path%'
+ - '@template'
+
+ file_locator:
+ class: phpbb\routing\file_locator
+ arguments:
+ - '@filesystem'
+ - '%core.root_path%'
+
+ kernel_exception_subscriber:
+ class: phpbb\install\event\kernel_exception_subscriber
+ arguments:
+ - '@phpbb.installer.controller.helper'
+ - '@language'
+ - '@template'
+ tags:
+ - { name: kernel.event_subscriber }
+
+ language.loader:
+ parent: language.loader_abstract
+
+ path_helper:
+ class: phpbb\path_helper
+ arguments:
+ - '@symfony_request'
+ - '@filesystem'
+ - '@request'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ routing.resources_locator.default:
+ class: phpbb\routing\resources_locator\installer_resources_locator
+ arguments:
+ - '@filesystem'
+ - '%core.root_path%'
+ - '%core.environment%'
+ tags:
+ - { name: routing.resources_locator }
+
+ template:
+ class: phpbb\template\twig\twig
+ arguments:
+ - '@path_helper'
+ - '@config'
+ - '@template_context'
+ - '@template.twig.environment'
+ - '%core.template.cache_path%'
+ - null
+ - '@template.twig.extensions.collection'
+
+ template.twig.environment:
+ class: phpbb\template\twig\environment
+ arguments:
+ - '@config'
+ - '@filesystem'
+ - '@path_helper'
+ - '%core.template.cache_path%'
+ - null
+ - '@template.twig.loader'
+ - null
+ - []
+ calls:
+ - [setLexer, ['@template.twig.lexer']]
+
+ user:
+ class: phpbb\user
+ arguments:
+ - '@language'
+ - '%datetime.class%'
+
+ console.exception_subscriber:
+ class: phpbb\console\exception_subscriber
+ arguments:
+ - '@language'
+ - '%debug.exceptions%'
+ tags:
+ - { name: kernel.event_subscriber }
diff --git a/phpBB/config/installer/container/services_file_updater.yml b/phpBB/config/installer/container/services_file_updater.yml
new file mode 100644
index 0000000000..9d39bb8b89
--- /dev/null
+++ b/phpBB/config/installer/container/services_file_updater.yml
@@ -0,0 +1,38 @@
+services:
+ installer.file_updater.factory:
+ class: phpbb\install\helper\file_updater\factory
+ arguments:
+ - '@installer.file_updater.collection'
+
+ installer.file_updater.collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: file_updater }
+
+ installer.file_updater.compress:
+ class: phpbb\install\helper\file_updater\compression_file_updater
+ arguments:
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: file_updater }
+
+ installer.file_updater.ftp:
+ class: phpbb\install\helper\file_updater\ftp_file_updater
+ arguments:
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: file_updater }
+
+ installer.file_updater.file:
+ class: phpbb\install\helper\file_updater\file_updater
+ arguments:
+ - '@filesystem'
+ - '%core.root_path%'
+ tags:
+ - { name: file_updater }
diff --git a/phpBB/config/installer/container/services_install_console.yml b/phpBB/config/installer/container/services_install_console.yml
new file mode 100644
index 0000000000..41d3aa4c1b
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_console.yml
@@ -0,0 +1,61 @@
+services:
+ console.installer.command_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: console.installer.command }
+
+ console.installer.command.install:
+ class: phpbb\install\console\command\install\install
+ arguments:
+ - '@language'
+ - '@installer.helper.iohandler_factory'
+ - '@installer.installer.install'
+ - '@installer.helper.install_helper'
+ tags:
+ - { name: console.installer.command }
+
+ console.installer.command.config.show:
+ class: phpbb\install\console\command\install\config\show
+ arguments:
+ - '@language'
+ - '@installer.helper.iohandler_factory'
+ tags:
+ - { name: console.installer.command }
+
+
+ console.installer.command.config.validate:
+ class: phpbb\install\console\command\install\config\validate
+ arguments:
+ - '@language'
+ - '@installer.helper.iohandler_factory'
+ tags:
+ - { name: console.installer.command }
+
+ console.updater.command.update:
+ class: phpbb\install\console\command\update\update
+ arguments:
+ - '@language'
+ - '@installer.helper.iohandler_factory'
+ - '@installer.installer.update'
+ - '@installer.helper.install_helper'
+ tags:
+ - { name: console.installer.command }
+
+ console.updater.command.config.show:
+ class: phpbb\install\console\command\update\config\show
+ arguments:
+ - '@language'
+ - '@installer.helper.iohandler_factory'
+ tags:
+ - { name: console.installer.command }
+
+
+ console.updater.command.config.validate:
+ class: phpbb\install\console\command\update\config\validate
+ arguments:
+ - '@language'
+ - '@installer.helper.iohandler_factory'
+ tags:
+ - { name: console.installer.command }
diff --git a/phpBB/config/installer/container/services_install_controller.yml b/phpBB/config/installer/container/services_install_controller.yml
new file mode 100644
index 0000000000..5aaba0f47f
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_controller.yml
@@ -0,0 +1,73 @@
+services:
+ phpbb.installer.controller.welcome:
+ class: phpbb\install\controller\installer_index
+ arguments:
+ - '@phpbb.installer.controller.helper'
+ - '@language'
+ - '@template'
+ - '%core.root_path%'
+
+ phpbb.installer.controller.helper:
+ class: phpbb\install\controller\helper
+ arguments:
+ - '@installer.helper.config'
+ - '@language'
+ - '@language.helper.language_file'
+ - '@installer.navigation.provider'
+ - '@template'
+ - '@path_helper'
+ - '@request'
+ - '@symfony_request'
+ - '@router'
+ - '%core.root_path%'
+
+ phpbb.installer.controller.install:
+ class: phpbb\install\controller\install
+ arguments:
+ - '@phpbb.installer.controller.helper'
+ - '@installer.helper.iohandler_factory'
+ - '@installer.navigation.provider'
+ - '@language'
+ - '@template'
+ - '@request'
+ - '@installer.installer.install'
+ - '@installer.helper.install_helper'
+
+ phpbb.installer.controller.update:
+ class: phpbb\install\controller\update
+ arguments:
+ - '@phpbb.installer.controller.helper'
+ - '@installer.installer.update'
+ - '@installer.helper.install_helper'
+ - '@installer.helper.iohandler_factory'
+ - '@language'
+ - '@installer.navigation.provider'
+ - '@request'
+ - '@template'
+
+ phpbb.installer.controller.file_downloader:
+ class: phpbb\install\controller\archive_download
+ arguments:
+ - '@installer.helper.config'
+
+ phpbb.installer.controller.convert:
+ class: phpbb\convert\controller\convertor
+ arguments:
+ - '@cache.driver'
+ - '@installer.helper.container_factory'
+ - '@installer.helper.database'
+ - '@phpbb.installer.controller.helper'
+ - '@installer.helper.install_helper'
+ - '@installer.helper.iohandler_factory'
+ - '@language'
+ - '@installer.navigation.provider'
+ - '@request'
+ - '@template'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ phpbb.installer.controller.status:
+ class: phpbb\install\controller\timeout_check
+ arguments:
+ - '@phpbb.installer.controller.helper'
+ - '%core.root_path%'
diff --git a/phpBB/config/installer/container/services_install_data.yml b/phpBB/config/installer/container/services_install_data.yml
new file mode 100644
index 0000000000..5de00170e9
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_data.yml
@@ -0,0 +1,55 @@
+services:
+ installer.install_data.add_bots:
+ class: phpbb\install\module\install_data\task\add_bots
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.container_factory'
+ - '@language'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: install_data_install, order: 20 }
+
+ installer.install_data.add_languages:
+ class: phpbb\install\module\install_data\task\add_languages
+ arguments:
+ - '@installer.helper.iohandler'
+ - '@installer.helper.container_factory'
+ - '@language.helper.language_file'
+ tags:
+ - { name: install_data_install, order: 10 }
+
+ installer.install_data.add_modules:
+ class: phpbb\install\module\install_data\task\add_modules
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.container_factory'
+ tags:
+ - { name: install_data_install, order: 30 }
+
+ installer.install_data.create_search_index:
+ class: phpbb\install\module\install_data\task\create_search_index
+ arguments:
+ - '@config'
+ - '@installer.helper.container_factory'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: install_data_install, order: 40 }
+
+ installer.module.data_install_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: install_data_install, class_name_aware: true }
+
+ installer.module.data_install:
+ class: phpbb\install\module\install_data\module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.data_install_collection'
+ tags:
+ - { name: installer_install_module, order: 50 }
diff --git a/phpBB/config/installer/container/services_install_database.yml b/phpBB/config/installer/container/services_install_database.yml
new file mode 100644
index 0000000000..33f596506d
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_database.yml
@@ -0,0 +1,71 @@
+services:
+ installer.install_database.create_schema_file:
+ class: phpbb\install\module\install_database\task\create_schema_file
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.database'
+ - '@filesystem'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: install_database_install, order: 10 }
+
+ installer.install_database.set_up_database:
+ class: phpbb\install\module\install_database\task\set_up_database
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.database'
+ - '@filesystem'
+ - '@installer.helper.iohandler'
+ - '%core.root_path%'
+ tags:
+ - { name: install_database_install, order: 20 }
+
+ installer.install_database.add_tables:
+ class: phpbb\install\module\install_database\task\add_tables
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.database'
+ - '@filesystem'
+ - '%core.root_path%'
+ tags:
+ - { name: install_database_install, order: 30 }
+
+ installer.install_database.add_default_data:
+ class: phpbb\install\module\install_database\task\add_default_data
+ arguments:
+ - '@installer.helper.database'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.container_factory'
+ - '@language'
+ - '%core.root_path%'
+ tags:
+ - { name: install_database_install, order: 40 }
+
+ installer.install_database.add_config_settings:
+ class: phpbb\install\module\install_database\task\add_config_settings
+ arguments:
+ - '@filesystem'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.container_factory'
+ - '@language'
+ - '%core.root_path%'
+ tags:
+ - { name: install_database_install, order: 50 }
+
+ installer.module.install_database_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: install_database_install, class_name_aware: true }
+
+ installer.module.database_install:
+ class: phpbb\install\module\install_database\module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.install_database_collection'
+ tags:
+ - { name: installer_install_module, order: 40 }
diff --git a/phpBB/config/installer/container/services_install_filesystem.yml b/phpBB/config/installer/container/services_install_filesystem.yml
new file mode 100644
index 0000000000..65b2a6eddd
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_filesystem.yml
@@ -0,0 +1,28 @@
+services:
+ installer.install_filesystem.create_config_file:
+ class: phpbb\install\module\install_filesystem\task\create_config_file
+ arguments:
+ - '@filesystem'
+ - '@installer.helper.config'
+ - '@installer.helper.database'
+ - '@installer.helper.iohandler'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - '%installer.create_config_file.options%'
+ tags:
+ - { name: install_filesystem_install, order: 10 }
+
+ installer.module.install_filesystem_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: install_filesystem_install, class_name_aware: true }
+
+ installer.module.filesystem_install:
+ class: phpbb\install\module\install_filesystem\module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.install_filesystem_collection'
+ tags:
+ - { name: installer_install_module, order: 30 }
diff --git a/phpBB/config/installer/container/services_install_finish.yml b/phpBB/config/installer/container/services_install_finish.yml
new file mode 100644
index 0000000000..6a46d8f9d9
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_finish.yml
@@ -0,0 +1,44 @@
+services:
+ installer.install_finish.populate_migrations:
+ class: phpbb\install\module\install_finish\task\populate_migrations
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.container_factory'
+ tags:
+ - { name: install_finish, order: 10 }
+
+ installer.install_finish.install_extensions:
+ class: phpbb\install\module\install_finish\task\install_extensions
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '%core.root_path%'
+ tags:
+ - { name: install_finish, order: 20 }
+
+ installer.install_finish.notify_user:
+ class: phpbb\install\module\install_finish\task\notify_user
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: install_finish, order: 30 }
+
+ installer.module.install_finish_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: install_finish, class_name_aware: true }
+
+ installer.module.finish_install:
+ class: phpbb\install\module\install_finish\module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.install_finish_collection'
+ tags:
+ - { name: installer_install_module, order: 60 }
diff --git a/phpBB/config/installer/container/services_install_navigation.yml b/phpBB/config/installer/container/services_install_navigation.yml
new file mode 100644
index 0000000000..d7151eb1c6
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_navigation.yml
@@ -0,0 +1,42 @@
+services:
+ installer.navigation.provider:
+ class: phpbb\install\helper\navigation\navigation_provider
+ arguments:
+ - '@installer.navigation.service_collection'
+
+ installer.navigation.service_collection:
+ class: phpbb\di\service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: installer.navigation }
+
+ installer.navigation.main_navigation:
+ class: phpbb\install\helper\navigation\main_navigation
+ shared: false
+ tags:
+ - { name: installer.navigation }
+
+ installer.navigation.install_navigation:
+ class: phpbb\install\helper\navigation\install_navigation
+ arguments:
+ - '@installer.helper.install_helper'
+ shared: false
+ tags:
+ - { name: installer.navigation }
+
+ installer.navigation.update_navigation:
+ class: phpbb\install\helper\navigation\update_navigation
+ arguments:
+ - '@installer.helper.install_helper'
+ shared: false
+ tags:
+ - { name: installer.navigation }
+
+ installer.navigation.convertor_navigation:
+ class: phpbb\install\helper\navigation\convertor_navigation
+ arguments:
+ - '@installer.helper.install_helper'
+ shared: false
+ tags:
+ - { name: installer.navigation }
diff --git a/phpBB/config/installer/container/services_install_obtain_data.yml b/phpBB/config/installer/container/services_install_obtain_data.yml
new file mode 100644
index 0000000000..010aba829d
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_obtain_data.yml
@@ -0,0 +1,59 @@
+services:
+ installer.obtain_data.obtain_admin_data:
+ class: phpbb\install\module\obtain_data\task\obtain_admin_data
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ tags:
+ - { name: install_obtain_data, order: 10 }
+
+ installer.obtain_data.obtain_board_data:
+ class: phpbb\install\module\obtain_data\task\obtain_board_data
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@language.helper.language_file'
+ tags:
+ - { name: install_obtain_data, order: 50 }
+
+ installer.obtain_data.obtain_database_data:
+ class: phpbb\install\module\obtain_data\task\obtain_database_data
+ arguments:
+ - '@installer.helper.database'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ tags:
+ - { name: install_obtain_data, order: 20 }
+
+ installer.obtain_data.obtain_email_data:
+ class: phpbb\install\module\obtain_data\task\obtain_email_data
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ tags:
+ - { name: install_obtain_data, order: 40 }
+
+ installer.obtain_data.obtain_server_data:
+ class: phpbb\install\module\obtain_data\task\obtain_server_data
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ tags:
+ - { name: install_obtain_data, order: 30 }
+
+ installer.module.install_obtain_data_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: install_obtain_data, class_name_aware: true }
+
+ installer.module.obtain_data_install:
+ class: phpbb\install\module\obtain_data\install_module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.install_obtain_data_collection'
+ - true
+ - false
+ tags:
+ - { name: installer_install_module, order: 20 }
diff --git a/phpBB/config/installer/container/services_install_requirements.yml b/phpBB/config/installer/container/services_install_requirements.yml
new file mode 100644
index 0000000000..c03eb1fb93
--- /dev/null
+++ b/phpBB/config/installer/container/services_install_requirements.yml
@@ -0,0 +1,37 @@
+services:
+ installer.requirements.check_filesystem:
+ class: phpbb\install\module\requirements\task\check_filesystem
+ arguments:
+ - '@filesystem'
+ - '@installer.helper.iohandler'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: installer_requirements, order: 10 }
+
+ installer.requirements.check_server_environment:
+ class: phpbb\install\module\requirements\task\check_server_environment
+ arguments:
+ - '@installer.helper.database'
+ - '@installer.helper.iohandler'
+ tags:
+ - { name: installer_requirements, order: 20 }
+ - { name: update_requirements, order: 20 }
+
+ installer.module.install_requirements_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: installer_requirements, class_name_aware: true }
+
+# Please note, that the name of this module is hard coded in the installer service
+ installer.module.requirements_install:
+ class: phpbb\install\module\requirements\install_module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.install_requirements_collection'
+ - true
+ - false
+ tags:
+ - { name: installer_install_module, order: 10 }
diff --git a/phpBB/config/installer/container/services_installer.yml b/phpBB/config/installer/container/services_installer.yml
new file mode 100644
index 0000000000..57181b21d4
--- /dev/null
+++ b/phpBB/config/installer/container/services_installer.yml
@@ -0,0 +1,119 @@
+imports:
+ - { resource: services_file_updater.yml }
+ - { resource: services_install_console.yml }
+ - { resource: services_install_controller.yml }
+ - { resource: services_install_data.yml }
+ - { resource: services_install_database.yml }
+ - { resource: services_install_filesystem.yml }
+ - { resource: services_install_finish.yml }
+ - { resource: services_install_navigation.yml }
+ - { resource: services_install_obtain_data.yml }
+ - { resource: services_install_requirements.yml }
+ - { resource: services_update_database.yml }
+ - { resource: services_update_filesystem.yml }
+ - { resource: services_update_obtain_data.yml }
+ - { resource: services_update_requirements.yml }
+
+services:
+# -------- Installer helpers ------------------------
+ installer.helper.config:
+ class: phpbb\install\helper\config
+ arguments:
+ - '@filesystem'
+ - '@php_ini'
+ - '%core.root_path%'
+
+ installer.helper.database:
+ class: phpbb\install\helper\database
+ arguments:
+ - '@filesystem'
+ - '%core.root_path%'
+
+ installer.helper.iohandler_factory:
+ class: phpbb\install\helper\iohandler\factory
+ arguments:
+ - '@service_container'
+
+ installer.helper.iohandler_abstract:
+ abstract: true
+ calls:
+ - [set_language, ['@language']]
+
+ installer.helper.iohandler_ajax:
+ class: phpbb\install\helper\iohandler\ajax_iohandler
+ parent: installer.helper.iohandler_abstract
+ arguments:
+ - '@path_helper'
+ - '@request'
+ - '@template'
+ - '@router'
+ - '%core.root_path%'
+
+ installer.helper.iohandler_cli:
+ class: phpbb\install\helper\iohandler\cli_iohandler
+ parent: installer.helper.iohandler_abstract
+
+ installer.helper.iohandler:
+ class: phpbb\install\helper\iohandler\iohandler_interface
+ factory: ['@installer.helper.iohandler_factory', get]
+
+ installer.helper.container_factory:
+ class: phpbb\install\helper\container_factory
+ arguments:
+ - '@language'
+ - '@request'
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ installer.helper.install_helper:
+ class: phpbb\install\helper\install_helper
+ arguments:
+ - '%core.root_path%'
+ - '%core.php_ext%'
+
+ installer.helper.update_helper:
+ class: phpbb\install\helper\update_helper
+ arguments:
+ - '%core.root_path%'
+
+# -------- Installer --------------------------------
+ installer.module_base:
+ abstract: true
+ calls:
+ - [setup, ['@installer.helper.config', '@installer.helper.iohandler']]
+
+ installer.installer.abstract:
+ class: phpbb\install\installer
+ abstract: true
+ arguments:
+ - '@cache.driver'
+ - '@installer.helper.config'
+ - '@path_helper'
+ - '@installer.helper.container_factory'
+
+ installer.install.module_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: installer_install_module }
+
+ installer.update.module_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: installer_update_module }
+
+ installer.installer.install:
+ parent: installer.installer.abstract
+ calls:
+ - [set_modules, ['@installer.install.module_collection']]
+ - [set_purge_cache_before, [false]]
+
+ installer.installer.update:
+ parent: installer.installer.abstract
+ calls:
+ - [set_modules, ['@installer.update.module_collection']]
+ - [set_purge_cache_before, [true]]
diff --git a/phpBB/config/installer/container/services_update_database.yml b/phpBB/config/installer/container/services_update_database.yml
new file mode 100644
index 0000000000..bb97cff489
--- /dev/null
+++ b/phpBB/config/installer/container/services_update_database.yml
@@ -0,0 +1,40 @@
+services:
+ installer.update_database.update_task:
+ class: phpbb\install\module\update_database\task\update
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@filesystem'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@language'
+ - '%core.root_path%'
+ tags:
+ - { name: update_database_task, order: 10 }
+
+ installer.update_database.update_extensions:
+ class: phpbb\install\module\update_database\task\update_extensions
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ tags:
+ - { name: update_database_task, order: 20 }
+
+ installer.module.update_database_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: update_database_task, class_name_aware: true }
+
+ installer.module.update_database:
+ class: phpbb\install\module\update_database\module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.update_database_collection'
+ - true
+ - false
+ tags:
+ - { name: installer_update_module, order: 40 }
diff --git a/phpBB/config/installer/container/services_update_filesystem.yml b/phpBB/config/installer/container/services_update_filesystem.yml
new file mode 100644
index 0000000000..c0a04676f6
--- /dev/null
+++ b/phpBB/config/installer/container/services_update_filesystem.yml
@@ -0,0 +1,72 @@
+services:
+ installer.update_filesystem.check_task:
+ class: phpbb\install\module\update_filesystem\task\file_check
+ arguments:
+ - '@filesystem'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ tags:
+ - { name: update_filesystem, order: 10 }
+
+ installer.update_filesystem.diff_files:
+ class: phpbb\install\module\update_filesystem\task\diff_files
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: update_filesystem, order: 20 }
+
+ installer.update_filesystem.show_file_status:
+ class: phpbb\install\module\update_filesystem\task\show_file_status
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@filesystem'
+ - '@installer.file_updater.factory'
+ tags:
+ - { name: update_filesystem, order: 30 }
+
+ installer.update_filesystem.update_files:
+ class: phpbb\install\module\update_filesystem\task\update_files
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.file_updater.factory'
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ tags:
+ - { name: update_filesystem, order: 40 }
+
+ installer.update_filesystem.download_updated_files:
+ class: phpbb\install\module\update_filesystem\task\download_updated_files
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@filesystem'
+ tags:
+ - { name: update_filesystem, order: 50 }
+
+ installer.module.update_filesystem_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: update_filesystem, class_name_aware: true }
+
+ installer.module.filesystem_update:
+ class: phpbb\install\module\update_filesystem\module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.update_filesystem_collection'
+ - true
+ - false
+ tags:
+ - { name: installer_update_module, order: 30 }
diff --git a/phpBB/config/installer/container/services_update_obtain_data.yml b/phpBB/config/installer/container/services_update_obtain_data.yml
new file mode 100644
index 0000000000..999976aed0
--- /dev/null
+++ b/phpBB/config/installer/container/services_update_obtain_data.yml
@@ -0,0 +1,53 @@
+services:
+ installer.obtain_data.update_options:
+ class: phpbb\install\module\obtain_data\task\obtain_update_settings
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ tags:
+ - { name: update_obtain_data, order: 10 }
+
+ installer.obtain_data.file_updater_method:
+ class: phpbb\install\module\obtain_data\task\obtain_file_updater_method
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ tags:
+ - { name: update_obtain_data, order: 20 }
+
+ installer.obtain_data.update_files:
+ class: phpbb\install\module\obtain_data\task\obtain_update_files
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: update_obtain_data, order: 30 }
+
+ installer.obtain_data.update_ftp_settings:
+ class: phpbb\install\module\obtain_data\task\obtain_update_ftp_data
+ arguments:
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.update_helper'
+ - '%core.php_ext%'
+ tags:
+ - { name: update_obtain_data, order: 40 }
+
+ installer.module.update_obtain_data_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: update_obtain_data, class_name_aware: true }
+
+ installer.module.obtain_data_update:
+ class: phpbb\install\module\obtain_data\update_module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.update_obtain_data_collection'
+ - true
+ - false
+ tags:
+ - { name: installer_update_module, order: 20 }
diff --git a/phpBB/config/installer/container/services_update_requirements.yml b/phpBB/config/installer/container/services_update_requirements.yml
new file mode 100644
index 0000000000..6b851de78b
--- /dev/null
+++ b/phpBB/config/installer/container/services_update_requirements.yml
@@ -0,0 +1,41 @@
+services:
+ installer.requirements.check_filesystem_update:
+ class: phpbb\install\module\requirements\task\check_filesystem
+ arguments:
+ - '@filesystem'
+ - '@installer.helper.iohandler'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ - false
+ tags:
+ - { name: update_requirements, order: 10 }
+
+ installer.requirements.update_requirements:
+ class: phpbb\install\module\requirements\task\check_update
+ arguments:
+ - '@installer.helper.container_factory'
+ - '@filesystem'
+ - '@installer.helper.config'
+ - '@installer.helper.iohandler'
+ - '@installer.helper.update_helper'
+ - '%core.root_path%'
+ - '%core.php_ext%'
+ tags:
+ - { name: update_requirements, order: 30 }
+
+ installer.module.update_requirements_collection:
+ class: phpbb\di\ordered_service_collection
+ arguments:
+ - '@service_container'
+ tags:
+ - { name: service_collection, tag: update_requirements, class_name_aware: true }
+
+ installer.module.requirements_update:
+ class: phpbb\install\module\requirements\update_module
+ parent: installer.module_base
+ arguments:
+ - '@installer.module.update_requirements_collection'
+ - true
+ - false
+ tags:
+ - { name: installer_update_module, order: 10 }
diff --git a/phpBB/config/installer/routing/environment.yml b/phpBB/config/installer/routing/environment.yml
new file mode 100644
index 0000000000..7a1f588fa1
--- /dev/null
+++ b/phpBB/config/installer/routing/environment.yml
@@ -0,0 +1,2 @@
+core.default:
+ resource: installer.yml
diff --git a/phpBB/config/installer/routing/installer.yml b/phpBB/config/installer/routing/installer.yml
new file mode 100644
index 0000000000..66b8893ad9
--- /dev/null
+++ b/phpBB/config/installer/routing/installer.yml
@@ -0,0 +1,67 @@
+phpbb_installer_index:
+ path: /
+ defaults:
+ _controller: phpbb.installer.controller.welcome:handle
+ mode: 'intro'
+
+phpbb_installer_license:
+ path: /license
+ defaults:
+ _controller: phpbb.installer.controller.welcome:handle
+ mode: 'license'
+
+phpbb_installer_support:
+ path: /support
+ defaults:
+ _controller: phpbb.installer.controller.welcome:handle
+ mode: 'support'
+
+phpbb_installer_install:
+ path: /install
+ defaults:
+ _controller: phpbb.installer.controller.install:handle
+
+phpbb_installer_update:
+ path: /update
+ defaults:
+ _controller: phpbb.installer.controller.update:handle
+
+phpbb_installer_update_file_download:
+ path: /download/updated
+ defaults:
+ _controller: phpbb.installer.controller.file_downloader:update_archive
+
+phpbb_installer_update_conflict_download:
+ path: /download/conflict
+ defaults:
+ _controller: phpbb.installer.controller.file_downloader:conflict_archive
+
+phpbb_convert_intro:
+ path: /convert/{start_new}
+ defaults:
+ _controller: phpbb.installer.controller.convert:intro
+ start_new: 0
+
+phpbb_convert_settings:
+ path: /convert/settings/{converter}
+ defaults:
+ _controller: phpbb.installer.controller.convert:settings
+ requirements:
+ converter: "[a-zA-Z0-9_]+"
+
+phpbb_convert_convert:
+ path: /convert/in_progress/{converter}
+ defaults:
+ _controller: phpbb.installer.controller.convert:convert
+ requirements:
+ converter: "[a-zA-Z0-9_]+"
+
+phpbb_convert_finish:
+ path: /convert/finished
+ defaults:
+ _controller: phpbb.installer.controller.convert:finish
+
+phpbb_installer_status:
+ path: /installer/status
+ defaults:
+ _controller: phpbb.installer.controller.status:status
diff --git a/phpBB/config/mimetype_guesser.yml b/phpBB/config/mimetype_guesser.yml
deleted file mode 100644
index 2e89ed3c1f..0000000000
--- a/phpBB/config/mimetype_guesser.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-services:
- mimetype.guesser_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: mimetype.guessers }
-
- mimetype.fileinfo_mimetype_guesser:
- class: Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser
- tags:
- - { name: mimetype.guessers }
-
- mimetype.filebinary_mimetype_guesser:
- class: Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser
- tags:
- - { name: mimetype.guessers }
-
- mimetype.content_guesser:
- class: phpbb\mimetype\content_guesser
- calls:
- - [set_priority, [%mimetype.guesser.priority.low%]]
- tags:
- - { name: mimetype.guessers }
-
- mimetype.extension_guesser:
- class: phpbb\mimetype\extension_guesser
- calls:
- - [set_priority, [%mimetype.guesser.priority.lowest%]]
- tags:
- - { name: mimetype.guessers }
-
- mimetype.guesser:
- class: phpbb\mimetype\guesser
- arguments:
- - @mimetype.guesser_collection
diff --git a/phpBB/config/notification.yml b/phpBB/config/notification.yml
deleted file mode 100644
index b17a172fb5..0000000000
--- a/phpBB/config/notification.yml
+++ /dev/null
@@ -1,390 +0,0 @@
-services:
- notification_manager:
- class: phpbb\notification\manager
- arguments:
- - @notification.type_collection
- - @notification.method_collection
- - @service_container
- - @user_loader
- - @config
- - @dispatcher
- - @dbal.conn
- - @cache
- - @user
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
-
-# ----- Notification's types -----
-# Scope MUST be prototype for all the plugins to work.
- notification.type_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: notification.type }
-
- notification.type.approve_post:
- class: phpbb\notification\type\approve_post
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.approve_topic:
- class: phpbb\notification\type\approve_topic
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.bookmark:
- class: phpbb\notification\type\bookmark
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.disapprove_post:
- class: phpbb\notification\type\disapprove_post
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.disapprove_topic:
- class: phpbb\notification\type\disapprove_topic
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.group_request:
- class: phpbb\notification\type\group_request
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.group_request_approved:
- class: phpbb\notification\type\group_request_approved
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.pm:
- class: phpbb\notification\type\pm
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.post:
- class: phpbb\notification\type\post
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.post_in_queue:
- class: phpbb\notification\type\post_in_queue
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.quote:
- class: phpbb\notification\type\quote
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.report_pm:
- class: phpbb\notification\type\report_pm
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.report_pm_closed:
- class: phpbb\notification\type\report_pm_closed
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.report_post:
- class: phpbb\notification\type\report_post
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.report_post_closed:
- class: phpbb\notification\type\report_post_closed
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.topic:
- class: phpbb\notification\type\topic
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.topic_in_queue:
- class: phpbb\notification\type\topic_in_queue
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
- notification.type.admin_activate_user:
- class: phpbb\notification\type\admin_activate_user
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- - %tables.notification_types%
- - %tables.notifications%
- - %tables.user_notifications%
- tags:
- - { name: notification.type }
-
-# ----- Notification's methods -----
-# Scope MUST be prototype for all the plugins to work.
- notification.method_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: notification.method }
-
- notification.method.email:
- class: phpbb\notification\method\email
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: notification.method }
-
- notification.method.jabber:
- class: phpbb\notification\method\jabber
- scope: prototype
- arguments:
- - @user_loader
- - @dbal.conn
- - @cache.driver
- - @user
- - @auth
- - @config
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: notification.method }
diff --git a/phpBB/config/password.yml b/phpBB/config/password.yml
deleted file mode 100644
index 938cef7e16..0000000000
--- a/phpBB/config/password.yml
+++ /dev/null
@@ -1,131 +0,0 @@
-services:
-# ----- Password management -----
- passwords.manager:
- class: phpbb\passwords\manager
- arguments:
- - @config
- - @passwords.driver_collection
- - @passwords.helper
- - %passwords.algorithms%
-
- passwords.helper:
- class: phpbb\passwords\helper
-
- passwords.driver_helper:
- class: phpbb\passwords\driver\helper
- arguments:
- - @config
-
-# ----- Password's drivers -----
- passwords.driver_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: passwords.driver }
-
- passwords.driver.bcrypt:
- class: phpbb\passwords\driver\bcrypt
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.bcrypt_2y:
- class: phpbb\passwords\driver\bcrypt_2y
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.bcrypt_wcf2:
- class: phpbb\passwords\driver\bcrypt_wcf2
- arguments:
- - @passwords.driver.bcrypt
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.salted_md5:
- class: phpbb\passwords\driver\salted_md5
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.phpass:
- class: phpbb\passwords\driver\phpass
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.convert_password:
- class: phpbb\passwords\driver\convert_password
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.sha1_smf:
- class: phpbb\passwords\driver\sha1_smf
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.sha1_wcf1:
- class: phpbb\passwords\driver\sha1_wcf1
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.sha1:
- class: phpbb\passwords\driver\sha1
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.md5_phpbb2:
- class: phpbb\passwords\driver\md5_phpbb2
- arguments:
- - @request
- - @passwords.driver.salted_md5
- - @passwords.driver_helper
- - %core.root_path%
- - %core.php_ext%
- tags:
- - { name: passwords.driver }
-
- passwords.driver.md5_mybb:
- class: phpbb\passwords\driver\md5_mybb
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.driver.md5_vb:
- class: phpbb\passwords\driver\md5_vb
- arguments:
- - @config
- - @passwords.driver_helper
- tags:
- - { name: passwords.driver }
-
- passwords.update.lock:
- class: phpbb\lock\db
- arguments:
- - update_hashes_lock
- - '@config'
- - '@dbal.conn'
diff --git a/phpBB/config/production/config.yml b/phpBB/config/production/config.yml
new file mode 100644
index 0000000000..979dbbcdd9
--- /dev/null
+++ b/phpBB/config/production/config.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../default/config.yml }
diff --git a/phpBB/config/production/container/environment.yml b/phpBB/config/production/container/environment.yml
new file mode 100644
index 0000000000..40a3c7a683
--- /dev/null
+++ b/phpBB/config/production/container/environment.yml
@@ -0,0 +1,3 @@
+imports:
+ - { resource: services.yml }
+ - { resource: parameters.yml }
diff --git a/phpBB/config/production/container/parameters.yml b/phpBB/config/production/container/parameters.yml
new file mode 100644
index 0000000000..0447646806
--- /dev/null
+++ b/phpBB/config/production/container/parameters.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../../default/container/parameters.yml }
diff --git a/phpBB/config/production/container/services.yml b/phpBB/config/production/container/services.yml
new file mode 100644
index 0000000000..b302f0f966
--- /dev/null
+++ b/phpBB/config/production/container/services.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../../default/container/services.yml }
diff --git a/phpBB/config/production/routing/environment.yml b/phpBB/config/production/routing/environment.yml
new file mode 100644
index 0000000000..301183bbae
--- /dev/null
+++ b/phpBB/config/production/routing/environment.yml
@@ -0,0 +1,2 @@
+core.default:
+ resource: ../../default/routing/routing.yml
diff --git a/phpBB/config/profilefield.yml b/phpBB/config/profilefield.yml
deleted file mode 100644
index 5ccfef9148..0000000000
--- a/phpBB/config/profilefield.yml
+++ /dev/null
@@ -1,102 +0,0 @@
-services:
- profilefields.manager:
- class: phpbb\profilefields\manager
- arguments:
- - @auth
- - @dbal.conn
- - @dispatcher
- - @request
- - @template
- - @profilefields.type_collection
- - @user
- - %tables.profile_fields%
- - %tables.profile_fields_language%
- - %tables.profile_fields_data%
-
- profilefields.lang_helper:
- class: phpbb\profilefields\lang_helper
- arguments:
- - @dbal.conn
- - %tables.profile_fields_options_language%
-
-# ----- Profile fields types -----
- profilefields.type_collection:
- class: phpbb\di\service_collection
- arguments:
- - @service_container
- tags:
- - { name: service_collection, tag: profilefield.type }
-
- profilefields.type.bool:
- class: phpbb\profilefields\type\type_bool
- arguments:
- - @profilefields.lang_helper
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
-
- profilefields.type.date:
- class: phpbb\profilefields\type\type_date
- arguments:
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
-
- profilefields.type.dropdown:
- class: phpbb\profilefields\type\type_dropdown
- arguments:
- - @profilefields.lang_helper
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
-
- profilefields.type.googleplus:
- class: phpbb\profilefields\type\type_googleplus
- arguments:
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
-
- profilefields.type.int:
- class: phpbb\profilefields\type\type_int
- arguments:
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
-
- profilefields.type.string:
- class: phpbb\profilefields\type\type_string
- arguments:
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
-
- profilefields.type.text:
- class: phpbb\profilefields\type\type_text
- arguments:
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
-
- profilefields.type.url:
- class: phpbb\profilefields\type\type_url
- arguments:
- - @request
- - @template
- - @user
- tags:
- - { name: profilefield.type }
diff --git a/phpBB/config/routing.yml b/phpBB/config/routing.yml
deleted file mode 100644
index 94146e1ec2..0000000000
--- a/phpBB/config/routing.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-# Structure:
-#
-# foo_controller:
-# path: /foo
-# defaults: { _controller: foo_sevice:method }
-#
-# The above will be accessed via app.php?controller=foo and it will
-# instantiate the "foo_service" service and call the "method" method.
-#
diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml
deleted file mode 100644
index 8667cbbf84..0000000000
--- a/phpBB/config/services.yml
+++ /dev/null
@@ -1,188 +0,0 @@
-imports:
- - { resource: auth.yml }
- - { resource: avatar.yml }
- - { resource: captcha.yml }
- - { resource: console.yml }
- - { resource: content.yml }
- - { resource: cron.yml }
- - { resource: db.yml }
- - { resource: event.yml }
- - { resource: feed.yml }
- - { resource: mimetype_guesser.yml }
- - { resource: notification.yml }
- - { resource: password.yml }
- - { resource: profilefield.yml }
- - { resource: user.yml }
-
- - { resource: tables.yml }
- - { resource: parameters.yml }
-
-services:
- cache:
- class: phpbb\cache\service
- arguments:
- - @cache.driver
- - @config
- - @dbal.conn
- - %core.root_path%
- - %core.php_ext%
-
- cache.driver:
- class: %cache.driver.class%
-
- class_loader:
- class: phpbb\class_loader
- arguments:
- - phpbb\
- - %core.root_path%includes/
- - %core.php_ext%
- calls:
- - [register, []]
- - [set_cache, [@cache.driver]]
-
- class_loader.ext:
- class: phpbb\class_loader
- arguments:
- - \
- - %core.root_path%ext/
- - %core.php_ext%
- calls:
- - [register, []]
- - [set_cache, [@cache.driver]]
-
- config:
- class: phpbb\config\db
- arguments:
- - @dbal.conn
- - @cache.driver
- - %tables.config%
-
- config.php:
- synthetic: true
-
- config_text:
- class: phpbb\config\db_text
- arguments:
- - @dbal.conn
- - %tables.config_text%
-
- controller.helper:
- class: phpbb\controller\helper
- arguments:
- - @template
- - @user
- - @config
- - @controller.provider
- - @ext.manager
- - @symfony_request
- - @request
- - @filesystem
- - %core.root_path%
- - %core.php_ext%
-
- controller.resolver:
- class: phpbb\controller\resolver
- arguments:
- - @user
- - @service_container
- - %core.root_path%
- - @template
-
- controller.provider:
- class: phpbb\controller\provider
- calls:
- - [find, [%core.root_path%]]
-
- ext.manager:
- class: phpbb\extension\manager
- arguments:
- - @service_container
- - @dbal.conn
- - @config
- - @filesystem
- - @user
- - %tables.ext%
- - %core.root_path%
- - %core.php_ext%
- - @cache.driver
-
- filesystem:
- class: phpbb\filesystem
-
- file_downloader:
- class: phpbb\file_downloader
-
- http_kernel:
- class: Symfony\Component\HttpKernel\HttpKernel
- arguments:
- - @dispatcher
- - @controller.resolver
-
- log:
- class: phpbb\log\log
- arguments:
- - @dbal.conn
- - @user
- - @auth
- - @dispatcher
- - %core.root_path%
- - %core.adm_relative_path%
- - %core.php_ext%
- - %tables.log%
-
- path_helper:
- class: phpbb\path_helper
- arguments:
- - @symfony_request
- - @filesystem
- - @request
- - %core.root_path%
- - %core.php_ext%
- - %core.adm_relative_path%
-
- php_ini:
- class: phpbb\php\ini
-
- plupload:
- class: phpbb\plupload\plupload
- arguments:
- - %core.root_path%
- - @config
- - @request
- - @user
- - @php_ini
- - @mimetype.guesser
-
- request:
- class: phpbb\request\request
- arguments:
- - null
- - %core.disable_super_globals%
-
- # WARNING: The Symfony request does not escape the input and should be used very carefully
- # prefer the phpbb request (service @request) as possible
- symfony_request:
- class: phpbb\symfony_request
- arguments:
- - @request
-
- template:
- class: phpbb\template\twig\twig
- arguments:
- - @path_helper
- - @config
- - @user
- - @template_context
- - @ext.manager
-
- template_context:
- class: phpbb\template\context
-
- version_helper:
- class: phpbb\version_helper
- scope: prototype
- arguments:
- - @cache
- - @config
- - @file_downloader
- - @user
diff --git a/phpBB/config/tables.yml b/phpBB/config/tables.yml
deleted file mode 100644
index 2fe2a33be8..0000000000
--- a/phpBB/config/tables.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-parameters:
- tables.auth_provider_oauth_token_storage: %core.table_prefix%oauth_tokens
- tables.auth_provider_oauth_account_assoc: %core.table_prefix%oauth_accounts
- tables.captcha_qa_questions: %core.table_prefix%captcha_questions
- tables.captcha_qa_answers: %core.table_prefix%captcha_answers
- tables.captcha_qa_confirm: %core.table_prefix%qa_confirm
- tables.config: %core.table_prefix%config
- tables.config_text: %core.table_prefix%config_text
- tables.ext: %core.table_prefix%ext
- tables.forums: %core.table_prefix%forums
- tables.log: %core.table_prefix%log
- tables.migrations: %core.table_prefix%migrations
- tables.modules: %core.table_prefix%modules
- tables.notification_types: %core.table_prefix%notification_types
- tables.notifications: %core.table_prefix%notifications
- tables.profile_fields: %core.table_prefix%profile_fields
- tables.profile_fields_data: %core.table_prefix%profile_fields_data
- tables.profile_fields_options_language: %core.table_prefix%profile_fields_lang
- tables.profile_fields_language: %core.table_prefix%profile_lang
- tables.posts: %core.table_prefix%posts
- tables.topics: %core.table_prefix%topics
- tables.user_notifications: %core.table_prefix%user_notifications
- tables.users: %core.table_prefix%users
diff --git a/phpBB/config/test/config.yml b/phpBB/config/test/config.yml
new file mode 100644
index 0000000000..1c17b08931
--- /dev/null
+++ b/phpBB/config/test/config.yml
@@ -0,0 +1,5 @@
+imports:
+ - { resource: ../default/config.yml }
+
+core:
+ require_dev_dependencies: true
diff --git a/phpBB/config/test/container/environment.yml b/phpBB/config/test/container/environment.yml
new file mode 100644
index 0000000000..40a3c7a683
--- /dev/null
+++ b/phpBB/config/test/container/environment.yml
@@ -0,0 +1,3 @@
+imports:
+ - { resource: services.yml }
+ - { resource: parameters.yml }
diff --git a/phpBB/config/test/container/parameters.yml b/phpBB/config/test/container/parameters.yml
new file mode 100644
index 0000000000..0447646806
--- /dev/null
+++ b/phpBB/config/test/container/parameters.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../../default/container/parameters.yml }
diff --git a/phpBB/config/test/container/services.yml b/phpBB/config/test/container/services.yml
new file mode 100644
index 0000000000..b302f0f966
--- /dev/null
+++ b/phpBB/config/test/container/services.yml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: ../../default/container/services.yml }
diff --git a/phpBB/config/test/routing/environment.yml b/phpBB/config/test/routing/environment.yml
new file mode 100644
index 0000000000..301183bbae
--- /dev/null
+++ b/phpBB/config/test/routing/environment.yml
@@ -0,0 +1,2 @@
+core.default:
+ resource: ../../default/routing/routing.yml
diff --git a/phpBB/config/user.yml b/phpBB/config/user.yml
deleted file mode 100644
index 1ca853ea45..0000000000
--- a/phpBB/config/user.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-services:
- acl.permissions:
- class: phpbb\permissions
- arguments:
- - @dispatcher
- - @user
-
- user:
- class: phpbb\user
- arguments:
- - %datetime.class%
-
- user_loader:
- class: phpbb\user_loader
- arguments:
- - @dbal.conn
- - %core.root_path%
- - %core.php_ext%
- - %tables.users%
diff --git a/phpBB/cron.php b/phpBB/cron.php
index aed68f6aeb..2f519947aa 100644
--- a/phpBB/cron.php
+++ b/phpBB/cron.php
@@ -42,14 +42,16 @@ function output_image()
//
// Attempt to alleviate the problem by doing setup outside of the lock as much as possible.
-$cron_type = request_var('cron_type', '');
+$cron_type = $request->variable('cron_type', '');
// Comment this line out for debugging so the page does not return an image.
output_image();
+/* @var $cron_lock \phpbb\lock\db */
$cron_lock = $phpbb_container->get('cron.lock_db');
if ($cron_lock->acquire())
{
+ /* @var $cron \phpbb\cron\manager */
$cron = $phpbb_container->get('cron.manager');
$task = $cron->find_task($cron_type);
diff --git a/phpBB/develop/add_permissions.php b/phpBB/develop/add_permissions.php
index a5279f8f13..ee5e116d91 100644
--- a/phpBB/develop/add_permissions.php
+++ b/phpBB/develop/add_permissions.php
@@ -64,6 +64,7 @@ $f_permissions = array(
'f_vote' => array(1, 0),
'f_votechg' => array(1, 0),
'f_announce'=> array(1, 0),
+ 'f_announce_global' => array(1, 0),
'f_sticky' => array(1, 0),
'f_attach' => array(1, 0),
'f_download'=> array(1, 0),
@@ -155,6 +156,7 @@ $u_permissions = array(
'u_download' => array(0, 1),
'u_attach' => array(0, 1),
'u_sig' => array(0, 1),
+ 'u_emoji' => array(0, 1),
'u_pm_attach' => array(0, 1),
'u_pm_bbcode' => array(0, 1),
'u_pm_smilies' => array(0, 1),
@@ -184,7 +186,7 @@ while ($row = $db->sql_fetchrow($result))
}
$db->sql_freeresult($result);
-if (sizeof($remove_auth_options))
+if (count($remove_auth_options))
{
$db->sql_query('DELETE FROM ' . ACL_USERS_TABLE . ' WHERE auth_option_id IN (' . implode(', ', $remove_auth_options) . ')');
$db->sql_query('DELETE FROM ' . ACL_GROUPS_TABLE . ' WHERE auth_option_id IN (' . implode(', ', $remove_auth_options) . ')');
@@ -198,7 +200,7 @@ $prefixes = array('f_', 'a_', 'm_', 'u_');
foreach ($prefixes as $prefix)
{
$var = $prefix . 'permissions';
- if (sizeof(${$var}))
+ if (count(${$var}))
{
foreach (${$var} as $auth_option => $l_ary)
{
@@ -378,8 +380,6 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting)
$sql = 'VALUES ' . implode(', ', preg_replace('#^(.*?)$#', '(\1)', $sql_subary));
break;
- case 'mssql':
- case 'sqlite':
case 'sqlite3':
$sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary));
break;
@@ -388,7 +388,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting)
foreach ($sql_subary as $sql)
{
$sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) VALUES ($sql)";
- $result = $db->sql_query($sql);
+ $db->sql_query($sql);
$sql = '';
}
}
@@ -396,7 +396,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting)
if ($sql != '')
{
$sql = "INSERT INTO $table ($id_field, forum_id, auth_option_id, auth_setting) $sql";
- $result = $db->sql_query($sql);
+ $db->sql_query($sql);
}
break;
@@ -404,7 +404,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting)
case 'delete':
foreach ($sql_subary as $sql)
{
- $result = $db->sql_query($sql);
+ $db->sql_query($sql);
$sql = '';
}
break;
diff --git a/phpBB/develop/benchmark.php b/phpBB/develop/benchmark.php
index c3cf90773e..631b7d05ca 100644
--- a/phpBB/develop/benchmark.php
+++ b/phpBB/develop/benchmark.php
@@ -143,7 +143,7 @@ function filldb($newposts)
if ((rand(0,30) < 1) || ($forum_topic_count[$forum] == 0))
{
// create a new topic 1 in 30 times (or when there are none);
- $topic = make_topic($userid, "Testing topic $i", $forum);
+ make_topic($userid, "Testing topic $i", $forum);
$forum_topic_count[$forum]++;
}
else
diff --git a/phpBB/develop/check_flash_bbcodes.php b/phpBB/develop/check_flash_bbcodes.php
index 6e1b415bb6..282adad229 100644
--- a/phpBB/develop/check_flash_bbcodes.php
+++ b/phpBB/develop/check_flash_bbcodes.php
@@ -51,7 +51,7 @@ function check_table_flash_bbcodes($table_name, $id_field, $content_field, $uid_
$ids = get_table_flash_bbcode_pkids($table_name, $id_field, $content_field, $uid_field, $bitfield_field);
- $size = sizeof($ids);
+ $size = count($ids);
if ($size)
{
echo "Found $size potentially dangerous flash bbcodes.\n";
@@ -140,8 +140,12 @@ function html_entity_decode_utf8($string)
static $trans_tbl;
// replace numeric entities
- $string = preg_replace('~&#x([0-9a-f]+);~ei', 'code2utf8(hexdec("\\1"))', $string);
- $string = preg_replace('~&#([0-9]+);~e', 'code2utf8(\\1)', $string);
+ $string = preg_replace_callback('~&#x([0-9a-f]+);~i', function ($match) {
+ return code2utf8(hexdec($match[1]));
+ }, $string);
+ $string = preg_replace_callback('~&#([0-9]+);~', function ($match) {
+ return code2utf8($match[1]);
+ }, $string);
// replace literal entities
if (!isset($trans_tbl))
diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php
index 60ffe04330..6e0a082045 100644
--- a/phpBB/develop/create_schema_files.php
+++ b/phpBB/develop/create_schema_files.php
@@ -38,18 +38,22 @@ define('IN_PHPBB', true);
$phpbb_root_path = dirname(__FILE__) . '/../';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
+include($phpbb_root_path . 'vendor/autoload.php');
include($phpbb_root_path . 'includes/constants.' . $phpEx);
require($phpbb_root_path . 'phpbb/class_loader.' . $phpEx);
$phpbb_class_loader = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}phpbb/", $phpEx);
$phpbb_class_loader->register();
-$finder = new \phpbb\finder(new \phpbb\filesystem(), $phpbb_root_path);
+$finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), $phpbb_root_path);
$classes = $finder->core_path('phpbb/')
->directory('/db/migration/data')
->get_classes();
-$db = new \phpbb\db\driver\sqlite();
-$schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, new \phpbb\db\tools($db, true), $phpbb_root_path, $phpEx, $table_prefix);
+$db = new \phpbb\db\driver\sqlite3();
+$factory = new \phpbb\db\tools\factory();
+$db_tools = $factory->get($db, true);
+
+$schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, $db_tools, $phpbb_root_path, $phpEx, $table_prefix);
$schema_data = $schema_generator->get_schema();
$fp = fopen($schema_path . 'schema.json', 'wb');
diff --git a/phpBB/develop/create_search_index.php b/phpBB/develop/create_search_index.php
index 9b79a35a84..6ef200699c 100644
--- a/phpBB/develop/create_search_index.php
+++ b/phpBB/develop/create_search_index.php
@@ -132,7 +132,7 @@ else
$search->tidy();
-add_log('admin', 'LOG_SEARCH_INDEX_CREATED', $search_name);
+$phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_SEARCH_INDEX_CREATED', false, array($search_name));
echo $user->lang['SEARCH_INDEX_CREATED'] . "\n";
echo 'Peak Memory Usage: ' . get_formatted_filesize(memory_get_peak_usage()) . "\n";
diff --git a/phpBB/develop/create_variable_overview.php b/phpBB/develop/create_variable_overview.php
index ace2e4d953..da9a4fe683 100644
--- a/phpBB/develop/create_variable_overview.php
+++ b/phpBB/develop/create_variable_overview.php
@@ -489,12 +489,12 @@ foreach ($lang_references as $lang_var => $filenames)
$html_data .= '<b>' . $lang_var . '</b><ul>';
- if (sizeof($filenames) != 1)
+ if (count($filenames) != 1)
{
fwrite($common_fp, (($entry['common']) ? ",\n" : '') . "\t'$var' => '" . $lang[$var] . "'");
$entry['common'] = true;
}
- else if (sizeof($filenames) == 1)
+ else if (count($filenames) == 1)
{
// Merge logical - hardcoded
$fname = (preg_match('#^(' . implode('|', $merge) . ')#', $filenames[0], $match)) ? $match[0] . '.php' : str_replace($ext, 'php', $filenames[0]);
diff --git a/phpBB/develop/fill.php b/phpBB/develop/fill.php
index 6d08e9c206..2aaafe1e38 100644
--- a/phpBB/develop/fill.php
+++ b/phpBB/develop/fill.php
@@ -42,8 +42,8 @@ $posts_per_topic = 500;
// general vars
-$mode = request_var('mode', 'generate');
-$start = request_var('start', 0);
+$mode = $request->variable('mode', 'generate');
+$start = $request->variable('start', 0);
switch ($mode)
{
diff --git a/phpBB/develop/generate_utf_tables.php b/phpBB/develop/generate_utf_tables.php
index 16a449679b..888c07676d 100644
--- a/phpBB/develop/generate_utf_tables.php
+++ b/phpBB/develop/generate_utf_tables.php
@@ -32,262 +32,11 @@ $phpbb_root_path = '../';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
echo "Checking for required files\n";
-download('http://www.unicode.org/Public/UNIDATA/CompositionExclusions.txt');
-download('http://www.unicode.org/Public/UNIDATA/DerivedNormalizationProps.txt');
download('http://www.unicode.org/Public/UNIDATA/UnicodeData.txt');
echo "\n";
-require_once($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx);
-$file_contents = array();
-
-/**
-* Generate some Hangul/Jamo stuff
-*/
-echo "\nGenerating Hangul and Jamo tables\n";
-for ($i = 0; $i < UNICODE_HANGUL_LCOUNT; ++$i)
-{
- $utf_char = cp_to_utf(UNICODE_HANGUL_LBASE + $i);
- $file_contents['utf_normalizer_common']['utf_jamo_index'][$utf_char] = $i * UNICODE_HANGUL_VCOUNT * UNICODE_HANGUL_TCOUNT + UNICODE_HANGUL_SBASE;
- $file_contents['utf_normalizer_common']['utf_jamo_type'][$utf_char] = UNICODE_JAMO_L;
-}
-
-for ($i = 0; $i < UNICODE_HANGUL_VCOUNT; ++$i)
-{
- $utf_char = cp_to_utf(UNICODE_HANGUL_VBASE + $i);
- $file_contents['utf_normalizer_common']['utf_jamo_index'][$utf_char] = $i * UNICODE_HANGUL_TCOUNT;
- $file_contents['utf_normalizer_common']['utf_jamo_type'][$utf_char] = UNICODE_JAMO_V;
-}
-
-for ($i = 0; $i < UNICODE_HANGUL_TCOUNT; ++$i)
-{
- $utf_char = cp_to_utf(UNICODE_HANGUL_TBASE + $i);
- $file_contents['utf_normalizer_common']['utf_jamo_index'][$utf_char] = $i;
- $file_contents['utf_normalizer_common']['utf_jamo_type'][$utf_char] = UNICODE_JAMO_T;
-}
-
-/**
-* Load the CompositionExclusions table
-*/
-echo "Loading CompositionExclusion\n";
-$fp = fopen('CompositionExclusions.txt', 'rt');
-
-$exclude = array();
-while (!feof($fp))
-{
- $line = fgets($fp, 1024);
-
- if (!strpos(' 0123456789ABCDEFabcdef', $line[0]))
- {
- continue;
- }
-
- $cp = strtok($line, ' ');
-
- if ($pos = strpos($cp, '..'))
- {
- $start = hexdec(substr($cp, 0, $pos));
- $end = hexdec(substr($cp, $pos + 2));
-
- for ($i = $start; $i < $end; ++$i)
- {
- $exclude[$i] = 1;
- }
- }
- else
- {
- $exclude[hexdec($cp)] = 1;
- }
-}
-fclose($fp);
-
-/**
-* Load QuickCheck tables
-*/
-echo "Generating QuickCheck tables\n";
-$fp = fopen('DerivedNormalizationProps.txt', 'rt');
-
-while (!feof($fp))
-{
- $line = fgets($fp, 1024);
-
- if (!strpos(' 0123456789ABCDEFabcdef', $line[0]))
- {
- continue;
- }
-
- $p = array_map('trim', explode(';', strtok($line, '#')));
-
- /**
- * Capture only NFC_QC, NFKC_QC
- */
- if (!preg_match('#^NFK?C_QC$#', $p[1]))
- {
- continue;
- }
-
- if ($pos = strpos($p[0], '..'))
- {
- $start = hexdec(substr($p[0], 0, $pos));
- $end = hexdec(substr($p[0], $pos + 2));
- }
- else
- {
- $start = $end = hexdec($p[0]);
- }
-
- if ($start >= UTF8_HANGUL_FIRST && $end <= UTF8_HANGUL_LAST)
- {
- /**
- * We do not store Hangul syllables in the array
- */
- continue;
- }
-
- if ($p[2] == 'M')
- {
- $val = UNICODE_QC_MAYBE;
- }
- else
- {
- $val = UNICODE_QC_NO;
- }
-
- if ($p[1] == 'NFKC_QC')
- {
- $file = 'utf_nfkc_qc';
- }
- else
- {
- $file = 'utf_nfc_qc';
- }
-
- for ($i = $start; $i <= $end; ++$i)
- {
- /**
- * The vars have the same name as the file: $utf_nfc_qc is in utf_nfc_qc.php
- */
- $file_contents[$file][$file][cp_to_utf($i)] = $val;
- }
-}
-fclose($fp);
-
/**
-* Do mappings
-*/
-echo "Loading Unicode decomposition mappings\n";
-$fp = fopen($phpbb_root_path . 'develop/UnicodeData.txt', 'rt');
-
-$map = array();
-while (!feof($fp))
-{
- $p = explode(';', fgets($fp, 1024));
- $cp = hexdec($p[0]);
-
- if (!empty($p[3]))
- {
- /**
- * Store combining class > 0
- */
- $file_contents['utf_normalizer_common']['utf_combining_class'][cp_to_utf($cp)] = (int) $p[3];
- }
-
- if (!isset($p[5]) || !preg_match_all('#[0-9A-F]+#', strip_tags($p[5]), $m))
- {
- continue;
- }
-
- if (strpos($p[5], '>'))
- {
- $map['NFKD'][$cp] = implode(' ', array_map('hexdec', $m[0]));
- }
- else
- {
- $map['NFD'][$cp] = $map['NFKD'][$cp] = implode(' ', array_map('hexdec', $m[0]));
- }
-}
-fclose($fp);
-
-/**
-* Build the canonical composition table
-*/
-echo "Generating the Canonical Composition table\n";
-foreach ($map['NFD'] as $cp => $decomp_seq)
-{
- if (!strpos($decomp_seq, ' ') || isset($exclude[$cp]))
- {
- /**
- * Singletons are excluded from canonical composition
- */
- continue;
- }
-
- $utf_seq = implode('', array_map('cp_to_utf', explode(' ', $decomp_seq)));
-
- if (!isset($file_contents['utf_canonical_comp']['utf_canonical_comp'][$utf_seq]))
- {
- $file_contents['utf_canonical_comp']['utf_canonical_comp'][$utf_seq] = cp_to_utf($cp);
- }
-}
-
-/**
-* Decompose the NF[K]D mappings recursively and prepare the file contents
-*/
-echo "Generating the Canonical and Compatibility Decomposition tables\n\n";
-foreach ($map as $type => $decomp_map)
-{
- foreach ($decomp_map as $cp => $decomp_seq)
- {
- $decomp_map[$cp] = decompose($decomp_map, $decomp_seq);
- }
- unset($decomp_seq);
-
- if ($type == 'NFKD')
- {
- $file = 'utf_compatibility_decomp';
- $var = 'utf_compatibility_decomp';
- }
- else
- {
- $file = 'utf_canonical_decomp';
- $var = 'utf_canonical_decomp';
- }
-
- /**
- * Generate the corresponding file
- */
- foreach ($decomp_map as $cp => $decomp_seq)
- {
- $file_contents[$file][$var][cp_to_utf($cp)] = implode('', array_map('cp_to_utf', explode(' ', $decomp_seq)));
- }
-}
-
-/**
-* Generate and/or alter the files
-*/
-foreach ($file_contents as $file => $contents)
-{
- /**
- * Generate a new file
- */
- echo "Writing to $file.$phpEx\n";
-
- if (!$fp = fopen($phpbb_root_path . 'includes/utf/data/' . $file . '.' . $phpEx, 'wb'))
- {
- trigger_error('Cannot open ' . $file . ' for write');
- }
-
- fwrite($fp, '<?php');
- foreach ($contents as $var => $val)
- {
- fwrite($fp, "\n\$GLOBALS[" . my_var_export($var) . ']=' . my_var_export($val) . ";");
- }
- fclose($fp);
-}
-
-echo "\n*** UTF-8 normalization tables done\n\n";
-
-/**
-* Now we'll generate the files needed by the search indexer
+* Generate the files needed by the search indexer
*/
echo "Generating search indexer tables\n";
@@ -425,32 +174,6 @@ die("\nAll done!\n");
////////////////////////////////////////////////////////////////////////////////
/**
-* Decompose a sequence recusively
-*
-* @param array $decomp_map Decomposition mapping, passed by reference
-* @param string $decomp_seq Decomposition sequence as decimal codepoints separated with a space
-* @return string Decomposition sequence, fully decomposed
-*/
-function decompose(&$decomp_map, $decomp_seq)
-{
- $ret = array();
- foreach (explode(' ', $decomp_seq) as $cp)
- {
- if (isset($decomp_map[$cp]))
- {
- $ret[] = decompose($decomp_map, $decomp_map[$cp]);
- }
- else
- {
- $ret[] = $cp;
- }
- }
-
- return implode(' ', $ret);
-}
-
-
-/**
* Return a parsable string representation of a variable
*
* This is function is limited to array/strings/integers
@@ -538,17 +261,6 @@ function hex_to_utf($hex)
}
/**
-* Return a UTF string formed from a sequence of codepoints in hexadecimal
-*
-* @param string $seq Sequence of codepoints, separated with a space
-* @return string UTF-8 string
-*/
-function hexseq_to_utf($seq)
-{
- return implode('', array_map('hex_to_utf', explode(' ', $seq)));
-}
-
-/**
* Convert a codepoint to a UTF-8 char
*
* @param integer $cp Unicode codepoint
diff --git a/phpBB/develop/imageset_to_css.php b/phpBB/develop/imageset_to_css.php
index d49fe9c741..bbe7c31c83 100644
--- a/phpBB/develop/imageset_to_css.php
+++ b/phpBB/develop/imageset_to_css.php
@@ -7,7 +7,7 @@
*/
$phpbb_root_path = '../';
-$style = 'subsilver2';
+$style = 'prosilver';
$imageset_path = $phpbb_root_path . 'styles/' . $style . '/imageset';
$theme_path = $phpbb_root_path . 'styles/' . $style . '/theme';
diff --git a/phpBB/develop/lang_duplicates.php b/phpBB/develop/lang_duplicates.php
index 5981882292..7a74b1088a 100644
--- a/phpBB/develop/lang_duplicates.php
+++ b/phpBB/develop/lang_duplicates.php
@@ -29,7 +29,7 @@ $phpEx = substr(strrchr(__FILE__, '.'), 1);
$phpbb_root_path='./../';
include($phpbb_root_path . 'common.'.$phpEx);
-$mode = request_var('mode', '');
+$mode = $request->variable('mode', '');
$modules = find_modules($phpbb_root_path . 'language/en');
diff --git a/phpBB/develop/lang_migrate_help_lang.php b/phpBB/develop/lang_migrate_help_lang.php
new file mode 100644
index 0000000000..81b71398e1
--- /dev/null
+++ b/phpBB/develop/lang_migrate_help_lang.php
@@ -0,0 +1,307 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+define('LANGUAGE_TO_MIGRATE', 'en');
+
+# NO CHANGES BELOW THIS LINE
+
+define('IN_PHPBB', true);
+$phpEx = substr(strrchr(__FILE__, '.'), 1);
+$phpbb_root_path = './../';
+include($phpbb_root_path . 'common.'.$phpEx);
+
+$help_bbcode = load_help('bbcode');
+$lang_bbcode = array(
+ 'HELP_BBCODE_BLOCK_INTRO' => $help_bbcode[0][1],
+ 'HELP_BBCODE_INTRO_BBCODE_QUESTION' => $help_bbcode[1][0],
+ 'HELP_BBCODE_INTRO_BBCODE_ANSWER' => $help_bbcode[1][1],
+
+ 'HELP_BBCODE_BLOCK_TEXT' => $help_bbcode[2][1],
+ 'HELP_BBCODE_TEXT_BASIC_QUESTION' => $help_bbcode[3][0],
+ 'HELP_BBCODE_TEXT_BASIC_ANSWER' => $help_bbcode[3][1],
+ 'HELP_BBCODE_TEXT_COLOR_QUESTION' => $help_bbcode[4][0],
+ 'HELP_BBCODE_TEXT_COLOR_ANSWER' => $help_bbcode[4][1],
+ 'HELP_BBCODE_TEXT_COMBINE_QUESTION' => $help_bbcode[5][0],
+ 'HELP_BBCODE_TEXT_COMBINE_ANSWER' => $help_bbcode[5][1],
+
+ 'HELP_BBCODE_BLOCK_QUOTES' => $help_bbcode[6][1],
+ 'HELP_BBCODE_QUOTES_TEXT_QUESTION' => $help_bbcode[7][0],
+ 'HELP_BBCODE_QUOTES_TEXT_ANSWER' => $help_bbcode[7][1],
+ 'HELP_BBCODE_QUOTES_CODE_QUESTION' => $help_bbcode[8][0],
+ 'HELP_BBCODE_QUOTES_CODE_ANSWER' => $help_bbcode[8][1],
+
+ 'HELP_BBCODE_BLOCK_LISTS' => $help_bbcode[9][1],
+ 'HELP_BBCODE_LISTS_UNORDERER_QUESTION' => $help_bbcode[10][0],
+ 'HELP_BBCODE_LISTS_UNORDERER_ANSWER' => $help_bbcode[10][1],
+ 'HELP_BBCODE_LISTS_ORDERER_QUESTION' => $help_bbcode[11][0],
+ 'HELP_BBCODE_LISTS_ORDERER_ANSWER' => $help_bbcode[11][1],
+
+ 'HELP_BBCODE_BLOCK_LINKS' => $help_bbcode[13][1],
+ 'HELP_BBCODE_LINKS_BASIC_QUESTION' => $help_bbcode[14][0],
+ 'HELP_BBCODE_LINKS_BASIC_ANSWER' => $help_bbcode[14][1],
+
+ 'HELP_BBCODE_BLOCK_IMAGES' => $help_bbcode[15][1],
+ 'HELP_BBCODE_IMAGES_BASIC_QUESTION' => $help_bbcode[16][0],
+ 'HELP_BBCODE_IMAGES_BASIC_ANSWER' => $help_bbcode[16][1],
+ 'HELP_BBCODE_IMAGES_ATTACHMENT_QUESTION' => $help_bbcode[17][0],
+ 'HELP_BBCODE_IMAGES_ATTACHMENT_ANSWER' => $help_bbcode[17][1],
+
+ 'HELP_BBCODE_BLOCK_OTHERS' => $help_bbcode[18][1],
+ 'HELP_BBCODE_OTHERS_CUSTOM_QUESTION' => $help_bbcode[19][0],
+ 'HELP_BBCODE_OTHERS_CUSTOM_ANSWER' => $help_bbcode[19][1],
+);
+write_help('bbcode', $lang_bbcode);
+
+$help_phpbb = load_help('faq');
+$lang_phpbb = array(
+ 'HELP_FAQ_BLOCK_LOGIN' => $help_phpbb[0][1],
+ 'HELP_FAQ_LOGIN_REGISTER_QUESTION' => $help_phpbb[1][0],
+ 'HELP_FAQ_LOGIN_REGISTER_ANSWER' => $help_phpbb[1][1],
+ 'HELP_FAQ_LOGIN_COPPA_QUESTION' => $help_phpbb[2][0],
+ 'HELP_FAQ_LOGIN_COPPA_ANSWER' => $help_phpbb[2][1],
+ 'HELP_FAQ_LOGIN_CANNOT_REGISTER_QUESTION' => $help_phpbb[3][0],
+ 'HELP_FAQ_LOGIN_CANNOT_REGISTER_ANSWER' => $help_phpbb[3][1],
+ 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_QUESTION' => $help_phpbb[4][0],
+ 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_ANSWER' => $help_phpbb[4][1],
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_QUESTION' => $help_phpbb[5][0],
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANSWER' => $help_phpbb[5][1],
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_QUESTION' => $help_phpbb[6][0],
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_ANSWER' => $help_phpbb[6][1],
+ 'HELP_FAQ_LOGIN_LOST_PASSWORD_QUESTION' => $help_phpbb[7][0],
+ 'HELP_FAQ_LOGIN_LOST_PASSWORD_ANSWER' => $help_phpbb[7][1],
+ 'HELP_FAQ_LOGIN_AUTO_LOGOUT_QUESTION' => $help_phpbb[8][0],
+ 'HELP_FAQ_LOGIN_AUTO_LOGOUT_ANSWER' => $help_phpbb[8][1],
+ 'HELP_FAQ_LOGIN_DELETE_COOKIES_QUESTION' => $help_phpbb[9][0],
+ 'HELP_FAQ_LOGIN_DELETE_COOKIES_ANSWER' => $help_phpbb[9][1],
+
+ 'HELP_FAQ_BLOCK_USERSETTINGS' => $help_phpbb[10][1],
+ 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_QUESTION' => $help_phpbb[11][0],
+ 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_ANSWER' => $help_phpbb[11][1],
+ 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_QUESTION' => $help_phpbb[12][0],
+ 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_ANSWER' => $help_phpbb[12][1],
+ 'HELP_FAQ_USERSETTINGS_TIMEZONE_QUESTION' => $help_phpbb[13][0],
+ 'HELP_FAQ_USERSETTINGS_TIMEZONE_ANSWER' => $help_phpbb[13][1],
+ 'HELP_FAQ_USERSETTINGS_SERVERTIME_QUESTION' => $help_phpbb[14][0],
+ 'HELP_FAQ_USERSETTINGS_SERVERTIME_ANSWER' => $help_phpbb[14][1],
+ 'HELP_FAQ_USERSETTINGS_LANGUAGE_QUESTION' => $help_phpbb[15][0],
+ 'HELP_FAQ_USERSETTINGS_LANGUAGE_ANSWER' => $help_phpbb[15][1],
+ 'HELP_FAQ_USERSETTINGS_AVATAR_QUESTION' => $help_phpbb[16][0],
+ 'HELP_FAQ_USERSETTINGS_AVATAR_ANSWER' => $help_phpbb[16][1],
+ 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_QUESTION' => $help_phpbb[17][0],
+ 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_ANSWER' => $help_phpbb[17][1],
+ 'HELP_FAQ_USERSETTINGS_RANK_QUESTION' => $help_phpbb[18][0],
+ 'HELP_FAQ_USERSETTINGS_RANK_ANSWER' => $help_phpbb[18][1],
+ 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_QUESTION' => $help_phpbb[19][0],
+ 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_ANSWER' => $help_phpbb[19][1],
+
+ 'HELP_FAQ_BLOCK_POSTING' => $help_phpbb[20][1],
+ 'HELP_FAQ_POSTING_CREATE_QUESTION' => $help_phpbb[21][0],
+ 'HELP_FAQ_POSTING_CREATE_ANSWER' => $help_phpbb[21][1],
+ 'HELP_FAQ_POSTING_EDIT_DELETE_QUESTION' => $help_phpbb[22][0],
+ 'HELP_FAQ_POSTING_EDIT_DELETE_ANSWER' => $help_phpbb[22][1],
+ 'HELP_FAQ_POSTING_SIGNATURE_QUESTION' => $help_phpbb[23][0],
+ 'HELP_FAQ_POSTING_SIGNATURE_ANSWER' => $help_phpbb[23][1],
+ 'HELP_FAQ_POSTING_POLL_CREATE_QUESTION' => $help_phpbb[24][0],
+ 'HELP_FAQ_POSTING_POLL_CREATE_ANSWER' => $help_phpbb[24][1],
+ 'HELP_FAQ_POSTING_POLL_ADD_QUESTION' => $help_phpbb[25][0],
+ 'HELP_FAQ_POSTING_POLL_ADD_ANSWER' => $help_phpbb[25][1],
+ 'HELP_FAQ_POSTING_POLL_EDIT_QUESTION' => $help_phpbb[26][0],
+ 'HELP_FAQ_POSTING_POLL_EDIT_ANSWER' => $help_phpbb[26][1],
+ 'HELP_FAQ_POSTING_FORUM_RESTRICTED_QUESTION' => $help_phpbb[27][0],
+ 'HELP_FAQ_POSTING_FORUM_RESTRICTED_ANSWER' => $help_phpbb[27][1],
+ 'HELP_FAQ_POSTING_NO_ATTACHMENTS_QUESTION' => $help_phpbb[28][0],
+ 'HELP_FAQ_POSTING_NO_ATTACHMENTS_ANSWER' => $help_phpbb[28][1],
+ 'HELP_FAQ_POSTING_WARNING_QUESTION' => $help_phpbb[29][0],
+ 'HELP_FAQ_POSTING_WARNING_ANSWER' => $help_phpbb[29][1],
+ 'HELP_FAQ_POSTING_REPORT_QUESTION' => $help_phpbb[30][0],
+ 'HELP_FAQ_POSTING_REPORT_ANSWER' => $help_phpbb[30][1],
+ 'HELP_FAQ_POSTING_DRAFT_QUESTION' => $help_phpbb[31][0],
+ 'HELP_FAQ_POSTING_DRAFT_ANSWER' => $help_phpbb[31][1],
+ 'HELP_FAQ_POSTING_QUEUE_QUESTION' => $help_phpbb[32][0],
+ 'HELP_FAQ_POSTING_QUEUE_ANSWER' => $help_phpbb[32][1],
+ 'HELP_FAQ_POSTING_BUMP_QUESTION' => $help_phpbb[33][0],
+ 'HELP_FAQ_POSTING_BUMP_ANSWER' => $help_phpbb[33][1],
+
+ 'HELP_FAQ_BLOCK_FORMATTING' => $help_phpbb[34][1],
+ 'HELP_FAQ_FORMATTING_BBOCDE_QUESTION' => $help_phpbb[35][0],
+ 'HELP_FAQ_FORMATTING_BBOCDE_ANSWER' => $help_phpbb[35][1],
+ 'HELP_FAQ_FORMATTING_HTML_QUESTION' => $help_phpbb[36][0],
+ 'HELP_FAQ_FORMATTING_HTML_ANSWER' => $help_phpbb[36][1],
+ 'HELP_FAQ_FORMATTING_SMILIES_QUESTION' => $help_phpbb[37][0],
+ 'HELP_FAQ_FORMATTING_SMILIES_ANSWER' => $help_phpbb[37][1],
+ 'HELP_FAQ_FORMATTING_IMAGES_QUESTION' => $help_phpbb[38][0],
+ 'HELP_FAQ_FORMATTING_IMAGES_ANSWER' => $help_phpbb[38][1],
+ 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_QUESTION' => $help_phpbb[39][0],
+ 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_ANSWER' => $help_phpbb[39][1],
+ 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_QUESTION' => $help_phpbb[40][0],
+ 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_ANSWER' => $help_phpbb[40][1],
+ 'HELP_FAQ_FORMATTING_STICKIES_QUESTION' => $help_phpbb[41][0],
+ 'HELP_FAQ_FORMATTING_STICKIES_ANSWER' => $help_phpbb[41][1],
+ 'HELP_FAQ_FORMATTING_LOCKED_QUESTION' => $help_phpbb[42][0],
+ 'HELP_FAQ_FORMATTING_LOCKED_ANSWER' => $help_phpbb[42][1],
+ 'HELP_FAQ_FORMATTING_ICONS_QUESTION' => $help_phpbb[43][0],
+ 'HELP_FAQ_FORMATTING_ICONS_ANSWER' => $help_phpbb[43][1],
+
+ 'HELP_FAQ_BLOCK_GROUPS' => $help_phpbb[45][1],
+ 'HELP_FAQ_GROUPS_ADMINISTRATORS_QUESTION' => $help_phpbb[46][0],
+ 'HELP_FAQ_GROUPS_ADMINISTRATORS_ANSWER' => $help_phpbb[46][1],
+ 'HELP_FAQ_GROUPS_MODERATORS_QUESTION' => $help_phpbb[47][0],
+ 'HELP_FAQ_GROUPS_MODERATORS_ANSWER' => $help_phpbb[47][1],
+ 'HELP_FAQ_GROUPS_USERGROUPS_QUESTION' => $help_phpbb[48][0],
+ 'HELP_FAQ_GROUPS_USERGROUPS_ANSWER' => $help_phpbb[48][1],
+ 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_QUESTION' => $help_phpbb[49][0],
+ 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_ANSWER' => $help_phpbb[49][1],
+ 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_QUESTION' => $help_phpbb[50][0],
+ 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_ANSWER' => $help_phpbb[50][1],
+ 'HELP_FAQ_GROUPS_COLORS_QUESTION' => $help_phpbb[51][0],
+ 'HELP_FAQ_GROUPS_COLORS_ANSWER' => $help_phpbb[51][1],
+ 'HELP_FAQ_GROUPS_DEFAULT_QUESTION' => $help_phpbb[52][0],
+ 'HELP_FAQ_GROUPS_DEFAULT_ANSWER' => $help_phpbb[52][1],
+ 'HELP_FAQ_GROUPS_TEAM_QUESTION' => $help_phpbb[53][0],
+ 'HELP_FAQ_GROUPS_TEAM_ANSWER' => $help_phpbb[53][1],
+
+ 'HELP_FAQ_BLOCK_PMS' => $help_phpbb[54][1],
+ 'HELP_FAQ_PMS_CANNOT_SEND_QUESTION' => $help_phpbb[55][0],
+ 'HELP_FAQ_PMS_CANNOT_SEND_ANSWER' => $help_phpbb[55][1],
+ 'HELP_FAQ_PMS_UNWANTED_QUESTION' => $help_phpbb[56][0],
+ 'HELP_FAQ_PMS_UNWANTED_ANSWER' => $help_phpbb[56][1],
+ 'HELP_FAQ_PMS_SPAM_QUESTION' => $help_phpbb[57][0],
+ 'HELP_FAQ_PMS_SPAM_ANSWER' => $help_phpbb[57][1],
+
+ 'HELP_FAQ_BLOCK_FRIENDS' => $help_phpbb[58][1],
+ 'HELP_FAQ_FRIENDS_BASIC_QUESTION' => $help_phpbb[59][0],
+ 'HELP_FAQ_FRIENDS_BASIC_ANSWER' => $help_phpbb[59][1],
+ 'HELP_FAQ_FRIENDS_MANAGE_QUESTION' => $help_phpbb[60][0],
+ 'HELP_FAQ_FRIENDS_MANAGE_ANSWER' => $help_phpbb[60][1],
+
+ 'HELP_FAQ_BLOCK_SEARCH' => $help_phpbb[61][1],
+ 'HELP_FAQ_SEARCH_FORUM_QUESTION' => $help_phpbb[62][0],
+ 'HELP_FAQ_SEARCH_FORUM_ANSWER' => $help_phpbb[62][1],
+ 'HELP_FAQ_SEARCH_NO_RESULT_QUESTION' => $help_phpbb[63][0],
+ 'HELP_FAQ_SEARCH_NO_RESULT_ANSWER' => $help_phpbb[63][1],
+ 'HELP_FAQ_SEARCH_BLANK_QUESTION' => $help_phpbb[64][0],
+ 'HELP_FAQ_SEARCH_BLANK_ANSWER' => $help_phpbb[64][1],
+ 'HELP_FAQ_SEARCH_MEMBERS_QUESTION' => $help_phpbb[65][0],
+ 'HELP_FAQ_SEARCH_MEMBERS_ANSWER' => $help_phpbb[65][1],
+ 'HELP_FAQ_SEARCH_OWN_QUESTION' => $help_phpbb[66][0],
+ 'HELP_FAQ_SEARCH_OWN_ANSWER' => $help_phpbb[66][1],
+
+ 'HELP_FAQ_BLOCK_BOOKMARKS' => $help_phpbb[67][1],
+ 'HELP_FAQ_BOOKMARKS_DIFFERENCE_QUESTION' => $help_phpbb[68][0],
+ 'HELP_FAQ_BOOKMARKS_DIFFERENCE_ANSWER' => $help_phpbb[68][1],
+ 'HELP_FAQ_BOOKMARKS_TOPIC_QUESTION' => $help_phpbb[69][0],
+ 'HELP_FAQ_BOOKMARKS_TOPIC_ANSWER' => $help_phpbb[69][1],
+ 'HELP_FAQ_BOOKMARKS_FORUM_QUESTION' => $help_phpbb[70][0],
+ 'HELP_FAQ_BOOKMARKS_FORUM_ANSWER' => $help_phpbb[70][1],
+ 'HELP_FAQ_BOOKMARKS_REMOVE_QUESTION' => $help_phpbb[71][0],
+ 'HELP_FAQ_BOOKMARKS_REMOVE_ANSWER' => $help_phpbb[71][1],
+
+ 'HELP_FAQ_BLOCK_ATTACHMENTS' => $help_phpbb[72][1],
+ 'HELP_FAQ_ATTACHMENTS_ALLOWED_QUESTION' => $help_phpbb[73][0],
+ 'HELP_FAQ_ATTACHMENTS_ALLOWED_ANSWER' => $help_phpbb[73][1],
+ 'HELP_FAQ_ATTACHMENTS_OWN_QUESTION' => $help_phpbb[74][0],
+ 'HELP_FAQ_ATTACHMENTS_OWN_ANSWER' => $help_phpbb[74][1],
+
+ 'HELP_FAQ_BLOCK_ISSUES' => $help_phpbb[75][1],
+ 'HELP_FAQ_ISSUES_WHOIS_PHPBB_QUESTION' => $help_phpbb[76][0],
+ 'HELP_FAQ_ISSUES_WHOIS_PHPBB_ANSWER' => $help_phpbb[76][1],
+ 'HELP_FAQ_ISSUES_FEATURE_QUESTION' => $help_phpbb[77][0],
+ 'HELP_FAQ_ISSUES_FEATURE_ANSWER' => $help_phpbb[77][1],
+ 'HELP_FAQ_ISSUES_LEGAL_QUESTION' => $help_phpbb[78][0],
+ 'HELP_FAQ_ISSUES_LEGAL_ANSWER' => $help_phpbb[78][1],
+ 'HELP_FAQ_ISSUES_ADMIN_QUESTION' => $help_phpbb[79][0],
+ 'HELP_FAQ_ISSUES_ADMIN_ANSWER' => $help_phpbb[79][1],
+
+);
+write_help('faq', $lang_phpbb);
+
+trigger_error('Successfully migrated help_bbcode and help_faq to help/bbcode and help/phpbb');
+
+/**
+ * @param string $help
+ * @return array
+ */
+function load_help($help)
+{
+ global $phpbb_root_path;
+ include($phpbb_root_path . 'language/' . LANGUAGE_TO_MIGRATE . '/help_' . $help . '.php');
+ return $help;
+}
+
+/**
+ * @param string $help
+ * @param array $lang
+ */
+function write_help($help, array $lang)
+{
+ global $phpbb_root_path;
+ $fp = fopen($phpbb_root_path . 'language/' . LANGUAGE_TO_MIGRATE . '/help/' . $help . '.php', 'wb');
+ fwrite($fp, get_language_file_header());
+ fwrite($fp, '$lang = array_merge($lang, array(' . "\n");
+
+ $last_key = '';
+ ksort($lang);
+ foreach ($lang as $key => $translation)
+ {
+ $key_sections = explode('_', $key, 4);
+ unset($key_sections[3]);
+ $key_start = implode('_', $key_sections);
+
+ if ($last_key !== '' && $key_start !== $last_key)
+ {
+ fwrite($fp, "\n");
+ }
+ fwrite($fp, "\t'" . $key . "'\t=> '" . $translation . "',\n");
+ $last_key = $key_start;
+ }
+
+ fwrite($fp, '));' . "\n");
+ #fwrite($fp, $lang);
+ fclose($fp);
+}
+
+/**
+ * @return string
+ */
+function get_language_file_header()
+{
+ return <<<EOT
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * DO NOT CHANGE
+ */
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+if (empty(\$lang) || !is_array(\$lang))
+{
+ \$lang = array();
+}
+
+
+EOT;
+}
diff --git a/phpBB/develop/mysql_upgrader.php b/phpBB/develop/mysql_upgrader.php
index 698be9d303..276c010e84 100644
--- a/phpBB/develop/mysql_upgrader.php
+++ b/phpBB/develop/mysql_upgrader.php
@@ -62,14 +62,17 @@ echo "USE $dbname;$newline$newline";
@set_time_limit(0);
-$finder = new \phpbb\finder(new \phpbb\filesystem(), $phpbb_root_path);
+$finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), $phpbb_root_path);
$classes = $finder->core_path('phpbb/')
->directory('/db/migration/data')
->get_classes();
-$schema_generator = new \phpbb\db\migration\schema_generator($classes, $config, $db, new \phpbb\db\tools($db, true), $phpbb_root_path, $phpEx, $table_prefix);
+$factory = new \phpbb\db\tools\factory();
+$db_tools = $factory->get($db, true);
+
+$schema_generator = new \phpbb\db\migration\schema_generator($classes, $config, $db, $db_tools, $phpbb_root_path, $phpEx, $table_prefix);
$schema_data = $schema_generator->get_schema();
-$dbms_type_map = \phpbb\db\tools::get_dbms_type_map();
+$dbms_type_map = \phpbb\db\tools\tools::get_dbms_type_map();
foreach ($schema_data as $table_name => $table_data)
{
diff --git a/phpBB/develop/regex_idn.php b/phpBB/develop/regex_idn.php
index d871695c50..30373f8de3 100644
--- a/phpBB/develop/regex_idn.php
+++ b/phpBB/develop/regex_idn.php
@@ -120,7 +120,7 @@ do
$pct_encoded = "%[\dA-F]{2}";
$unreserved = "$add_chars\pL0-9\-._~";
$sub_delims = ($inline) ? '!$&\'(*+,;=' : '!$&\'()*+,;=';
- $scheme = ($inline) ? '[a-z][a-z\d+]*': '[a-z][a-z\d+\-.]*' ; // avoid automatic parsing of "word" in "last word.http://..."
+ $scheme = ($inline) ? '[a-z][a-z\d+]*(?<!javascript)': '[a-z][a-z\d+\-.]*(?<!javascript)' ; // avoid automatic parsing of "word" in "last word.http://..."
$pchar = "(?:[^$remove_chars]*[$unreserved$sub_delims:@|]+|$pct_encoded)"; // rfc: no "|"
$reg_name = "(?:[^$remove_chars]*[$unreserved$sub_delims:@|]+|$pct_encoded)+"; // rfc: * instead of + and no "|" and no "@" and no ":" (included instead of userinfo)
diff --git a/phpBB/develop/search_fill.php b/phpBB/develop/search_fill.php
index 07c4024b2f..4f684b5b27 100644
--- a/phpBB/develop/search_fill.php
+++ b/phpBB/develop/search_fill.php
@@ -89,7 +89,7 @@ for(;$postcounter <= $max_post_id; $postcounter += $batchsize)
$rowset = $db->sql_fetchrowset($result);
$db->sql_freeresult($result);
- $post_rows = sizeof($rowset);
+ $post_rows = count($rowset);
if( $post_rows )
{
diff --git a/phpBB/develop/test.gif b/phpBB/develop/test.gif
new file mode 100644
index 0000000000..0dbc9b0459
--- /dev/null
+++ b/phpBB/develop/test.gif
Binary files differ
diff --git a/phpBB/develop/unicode_testing.php b/phpBB/develop/unicode_testing.php
index ec3c71d078..01586ca09b 100644
--- a/phpBB/develop/unicode_testing.php
+++ b/phpBB/develop/unicode_testing.php
@@ -19,7 +19,7 @@ if (!headers_sent())
function unicode_to_utf8($string)
{
$utf8 = '';
- $chars = array();
+
for ($i = 0; $i < strlen($string); $i++)
{
if (isset($string[$i + 5]) && substr($string, $i, 2) == '\\u' && ctype_xdigit(substr($string, $i + 2, 4)))
@@ -81,38 +81,3 @@ function utf8_to_unicode_callback($m)
{
return '\u' . str_pad(base_convert(utf8_ord($m[0]), 10, 16), 4, '0', STR_PAD_LEFT) . '';
}
-
-/**
-* A wrapper function for the normalizer which takes care of including the class if required and modifies the passed strings
-* to be in NFKC
-*
-* @param mixed $strings a string or an array of strings to normalize
-* @return mixed the normalized content, preserving array keys if array given.
-*/
-function utf8_normalize_nfkc($strings)
-{
- if (empty($strings))
- {
- return $strings;
- }
-
- if (!class_exists('utf_normalizer'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx);
- }
-
- if (!is_array($strings))
- {
- utf_normalizer::nfkc($strings);
- }
- else if (is_array($strings))
- {
- foreach ($strings as $key => $string)
- {
- utf_normalizer::nfkc($strings[$key]);
- }
- }
-
- return $strings;
-}
diff --git a/phpBB/develop/update_email_hash.php b/phpBB/develop/update_email_hash.php
index 57aebe3ca0..c149900d64 100644
--- a/phpBB/develop/update_email_hash.php
+++ b/phpBB/develop/update_email_hash.php
@@ -19,7 +19,7 @@ $user->session_begin();
$auth->acl($user->data);
$user->setup();
-$start = request_var('start', 0);
+$start = $request->variable('start', 0);
$num_items = 1000;
echo '<br />Updating user email hashes' . "\n";
diff --git a/phpBB/develop/utf_normalizer_test.php b/phpBB/develop/utf_normalizer_test.php
deleted file mode 100644
index 27ff786db7..0000000000
--- a/phpBB/develop/utf_normalizer_test.php
+++ /dev/null
@@ -1,394 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-if (php_sapi_name() != 'cli')
-{
- die("This program must be run from the command line.\n");
-}
-
-//
-// Security message:
-//
-// This script is potentially dangerous.
-// Remove or comment the next line (die(".... ) to enable this script.
-// Do NOT FORGET to either remove this script or disable it after you have used it.
-//
-die("Please read the first lines of this script for instructions on how to enable it");
-
-set_time_limit(0);
-error_reporting(E_ALL);
-
-define('IN_PHPBB', true);
-$phpbb_root_path = '../';
-$phpEx = substr(strrchr(__FILE__, '.'), 1);
-
-
-/**
-* Let's download some files we need
-*/
-download('http://www.unicode.org/Public/UNIDATA/NormalizationTest.txt');
-download('http://www.unicode.org/Public/UNIDATA/UnicodeData.txt');
-
-/**
-* Those are the tests we run
-*/
-$test_suite = array(
- /**
- * NFC
- * c2 == NFC(c1) == NFC(c2) == NFC(c3)
- * c4 == NFC(c4) == NFC(c5)
- */
- 'NFC' => array(
- 'c2' => array('c1', 'c2', 'c3'),
- 'c4' => array('c4', 'c5')
- ),
-
- /**
- * NFD
- * c3 == NFD(c1) == NFD(c2) == NFD(c3)
- * c5 == NFD(c4) == NFD(c5)
- */
- 'NFD' => array(
- 'c3' => array('c1', 'c2', 'c3'),
- 'c5' => array('c4', 'c5')
- ),
-
- /**
- * NFKC
- * c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
- */
- 'NFKC' => array(
- 'c4' => array('c1', 'c2', 'c3', 'c4', 'c5')
- ),
-
- /**
- * NFKD
- * c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
- */
- 'NFKD' => array(
- 'c5' => array('c1', 'c2', 'c3', 'c4', 'c5')
- )
-);
-
-require_once($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx);
-
-$i = $n = 0;
-$failed = false;
-$tested_chars = array();
-
-$fp = fopen($phpbb_root_path . 'develop/NormalizationTest.txt', 'rb');
-while (!feof($fp))
-{
- $line = fgets($fp);
- ++$n;
-
- if ($line[0] == '@')
- {
- if ($i)
- {
- echo "done\n";
- }
-
- $i = 0;
- echo "\n", substr($line, 1), "\n\n";
- continue;
- }
-
- if (!strpos(' 0123456789ABCDEF', $line[0]))
- {
- continue;
- }
-
- if (++$i % 100 == 0)
- {
- echo $i, ' ';
- }
-
- list($c1, $c2, $c3, $c4, $c5) = explode(';', $line);
-
- if (!strpos($c1, ' '))
- {
- /**
- * We are currently testing a single character, we add it to the list of
- * characters we have processed so that we can exclude it when testing
- * for invariants
- */
- $tested_chars[$c1] = 1;
- }
-
- foreach ($test_suite as $form => $serie)
- {
- foreach ($serie as $expected => $tests)
- {
- $hex_expected = ${$expected};
- $utf_expected = hexseq_to_utf($hex_expected);
-
- foreach ($tests as $test)
- {
- $utf_result = $utf_expected;
- call_user_func(array('utf_normalizer', $form), $utf_result);
-
- if (strcmp($utf_expected, $utf_result))
- {
- $failed = true;
- $hex_result = utf_to_hexseq($utf_result);
-
- echo "\nFAILED $expected == $form($test) ($hex_expected != $hex_result)";
- }
- }
- }
-
- if ($failed)
- {
- die("\n\nFailed at line $n\n");
- }
- }
-}
-fclose($fp);
-
-/**
-* Test for invariants
-*/
-echo "\n\nTesting for invariants...\n\n";
-
-$fp = fopen($phpbb_root_path . 'develop/UnicodeData.txt', 'rt');
-
-$n = 0;
-while (!feof($fp))
-{
- if (++$n % 100 == 0)
- {
- echo $n, ' ';
- }
-
- $line = fgets($fp, 1024);
-
- if (!$pos = strpos($line, ';'))
- {
- continue;
- }
-
- $hex_tested = $hex_expected = substr($line, 0, $pos);
-
- if (isset($tested_chars[$hex_tested]))
- {
- continue;
- }
-
- $utf_expected = hex_to_utf($hex_expected);
-
- if ($utf_expected >= UTF8_SURROGATE_FIRST
- && $utf_expected <= UTF8_SURROGATE_LAST)
- {
- /**
- * Surrogates are illegal on their own, we expect the normalizer
- * to return a replacement char
- */
- $utf_expected = UTF8_REPLACEMENT;
- $hex_expected = utf_to_hexseq($utf_expected);
- }
-
- foreach (array('nfc', 'nfkc', 'nfd', 'nfkd') as $form)
- {
- $utf_result = $utf_expected;
- utf_normalizer::$form($utf_result);
- $hex_result = utf_to_hexseq($utf_result);
-// echo "$form($utf_expected) == $utf_result\n";
-
- if (strcmp($utf_expected, $utf_result))
- {
- $failed = 1;
-
- echo "\nFAILED $hex_expected == $form($hex_tested) ($hex_expected != $hex_result)";
- }
- }
-
- if ($failed)
- {
- die("\n\nFailed at line $n\n");
- }
-}
-fclose($fp);
-
-die("\n\nALL TESTS PASSED SUCCESSFULLY\n");
-
-/**
-* Download a file to the develop/ dir
-*
-* @param string $url URL of the file to download
-* @return null
-*/
-function download($url)
-{
- global $phpbb_root_path;
-
- if (file_exists($phpbb_root_path . 'develop/' . basename($url)))
- {
- return;
- }
-
- echo 'Downloading from ', $url, ' ';
-
- if (!$fpr = fopen($url, 'rb'))
- {
- die("Can't download from $url\nPlease download it yourself and put it in the develop/ dir, kthxbai");
- }
-
- if (!$fpw = fopen($phpbb_root_path . 'develop/' . basename($url), 'wb'))
- {
- die("Can't open develop/" . basename($url) . " for output... please check your permissions or something");
- }
-
- $i = 0;
- $chunk = 32768;
- $done = '';
-
- while (!feof($fpr))
- {
- $i += fwrite($fpw, fread($fpr, $chunk));
- echo str_repeat("\x08", strlen($done));
-
- $done = ($i >> 10) . ' KiB';
- echo $done;
- }
- fclose($fpr);
- fclose($fpw);
-
- echo "\n";
-}
-
-/**
-* Convert a UTF string to a sequence of codepoints in hexadecimal
-*
-* @param string $utf UTF string
-* @return integer Unicode codepoints in hex
-*/
-function utf_to_hexseq($str)
-{
- $pos = 0;
- $len = strlen($str);
- $ret = array();
-
- while ($pos < $len)
- {
- $c = $str[$pos];
- switch ($c & "\xF0")
- {
- case "\xC0":
- case "\xD0":
- $utf_char = substr($str, $pos, 2);
- $pos += 2;
- break;
-
- case "\xE0":
- $utf_char = substr($str, $pos, 3);
- $pos += 3;
- break;
-
- case "\xF0":
- $utf_char = substr($str, $pos, 4);
- $pos += 4;
- break;
-
- default:
- $utf_char = $c;
- ++$pos;
- }
-
- $hex = dechex(utf_to_cp($utf_char));
-
- if (!isset($hex[3]))
- {
- $hex = substr('000' . $hex, -4);
- }
-
- $ret[] = $hex;
- }
-
- return strtr(implode(' ', $ret), 'abcdef', 'ABCDEF');
-}
-
-/**
-* Convert a UTF-8 char to its codepoint
-*
-* @param string $utf_char UTF-8 char
-* @return integer Unicode codepoint
-*/
-function utf_to_cp($utf_char)
-{
- switch (strlen($utf_char))
- {
- case 1:
- return ord($utf_char);
-
- case 2:
- return ((ord($utf_char[0]) & 0x1F) << 6) | (ord($utf_char[1]) & 0x3F);
-
- case 3:
- return ((ord($utf_char[0]) & 0x0F) << 12) | ((ord($utf_char[1]) & 0x3F) << 6) | (ord($utf_char[2]) & 0x3F);
-
- case 4:
- return ((ord($utf_char[0]) & 0x07) << 18) | ((ord($utf_char[1]) & 0x3F) << 12) | ((ord($utf_char[2]) & 0x3F) << 6) | (ord($utf_char[3]) & 0x3F);
-
- default:
- die('UTF-8 chars can only be 1-4 bytes long');
- }
-}
-
-/**
-* Return a UTF string formed from a sequence of codepoints in hexadecimal
-*
-* @param string $seq Sequence of codepoints, separated with a space
-* @return string UTF-8 string
-*/
-function hexseq_to_utf($seq)
-{
- return implode('', array_map('hex_to_utf', explode(' ', $seq)));
-}
-
-/**
-* Convert a codepoint in hexadecimal to a UTF-8 char
-*
-* @param string $hex Codepoint, in hexadecimal
-* @return string UTF-8 char
-*/
-function hex_to_utf($hex)
-{
- return cp_to_utf(hexdec($hex));
-}
-
-/**
-* Convert a codepoint to a UTF-8 char
-*
-* @param integer $cp Unicode codepoint
-* @return string UTF-8 string
-*/
-function cp_to_utf($cp)
-{
- if ($cp > 0xFFFF)
- {
- return chr(0xF0 | ($cp >> 18)) . chr(0x80 | (($cp >> 12) & 0x3F)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
- }
- else if ($cp > 0x7FF)
- {
- return chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
- }
- else if ($cp > 0x7F)
- {
- return chr(0xC0 | ($cp >> 6)) . chr(0x80 | ($cp & 0x3F));
- }
- else
- {
- return chr($cp);
- }
-}
diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html
index a149e3d6c5..45300c4986 100644
--- a/phpBB/docs/CHANGELOG.html
+++ b/phpBB/docs/CHANGELOG.html
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="" />
-<meta name="description" content="phpBB 3.1.x Changelog" />
+<meta name="description" content="phpBB 3.2.x Changelog" />
<title>phpBB &bull; Changelog</title>
<link href="assets/css/stylesheet.css" rel="stylesheet" type="text/css" media="screen" />
@@ -21,7 +21,7 @@
<div id="doc-description">
<a href="../index.php" id="logo"><img src="assets/images/site_logo.gif" alt="" /></a>
- <h1>phpBB 3.1.x Changelog</h1>
+ <h1>phpBB 3.2.x Changelog</h1>
<p style="display: none;"><a href="#start_here">Skip</a></p>
</div>
@@ -36,7 +36,7 @@
<!-- BEGIN DOCUMENT -->
<p class="paragraph main-description">
- This is a non-exhaustive (but still near complete) changelog for phpBB 3.1.x including release candidate versions.
+ This is a non-exhaustive (but still near complete) changelog for phpBB 3.2.x including release candidate versions.
Our thanks to all those people who've contributed bug reports and code fixes.
</p>
@@ -50,6 +50,29 @@
<ol>
<li><a href="#changelog">Changelog</a>
<ul>
+ <li><a href="#v329rc1">Changes since 3.2.9-RC1</a></li>
+ <li><a href="#v328">Changes since 3.2.8</a></li>
+ <li><a href="#v328rc1">Changes since 3.2.8-RC1</a></li>
+ <li><a href="#v327">Changes since 3.2.7</a></li>
+ <li><a href="#v326">Changes since 3.2.6</a></li>
+ <li><a href="#v326rc1">Changes since 3.2.6-RC1</a></li>
+ <li><a href="#v325">Changes since 3.2.5</a></li>
+ <li><a href="#v325rc1">Changes since 3.2.5-RC1</a></li>
+ <li><a href="#v324">Changes since 3.2.4</a></li>
+ <li><a href="#v324rc1">Changes since 3.2.4-RC1</a></li>
+ <li><a href="#v323">Changes since 3.2.3</a></li>
+ <li><a href="#v323rc2">Changes since 3.2.3-RC2</a></li>
+ <li><a href="#v323rc1">Changes since 3.2.3-RC1</a></li>
+ <li><a href="#v322">Changes since 3.2.2</a></li>
+ <li><a href="#v321">Changes since 3.2.1</a></li>
+ <li><a href="#v320">Changes since 3.2.0</a></li>
+ <li><a href="#v320rc1">Changes since 3.2.0-RC1</a></li>
+ <li><a href="#v320b2">Changes since 3.2.0-b2</a></li>
+ <li><a href="#v320b1">Changes since 3.2.0-b1</a></li>
+ <li><a href="#v320a2">Changes since 3.2.0-a2</a></li>
+ <li><a href="#v320a1">Changes since 3.2.0-a1</a></li>
+ <li><a href="#v31x">Changes since 3.1.x</a></li>
+ <li><a href="#v3111">Changes since 3.1.11</a></li>
<li><a href="#v3110">Changes since 3.1.10</a></li>
<li><a href="#v319">Changes since 3.1.9</a></li>
<li><a href="#v318">Changes since 3.1.8</a></li>
@@ -118,7 +141,1301 @@
<div class="paragraph">
<div class="inner">
-<div class="content">
+ <div class="content">
+ <a name="v329rc1"></a><h3>Changes since 3.2.9-RC1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15592">PHPBB3-15592</a>] - &quot;Place inline&quot; button appears when BBcode is disabled (Post settings)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16269">PHPBB3-16269</a>] - Sphinx backend indexes HTML markup as keywords</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16282">PHPBB3-16282</a>] - Default jQuery CDN URL is outdated on new installs</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16271">PHPBB3-16271</a>] - Add support for 3.3.x API documentation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16279">PHPBB3-16279</a>] - Add permission for Emojii in topic title</li>
+ </ul>
+ <h4>Security</h4>
+ <ul>
+ <li>[SECURITY-249] - Group avatar overwrite on invalid submit</li>
+ <li>[SECURITY-250] - Group leader can be tricked into approving user</li>
+ </ul>
+ <h4>Hardening</h4>
+ <ul>
+ <li>[SECURITY-251] - Unwanted move of PMs to folders</li>
+ <li>[SECURITY-252] - PMs of unsuspecting users can be marked as important</li>
+ <li>[SECURITY-253] - PM export without proper validation</li>
+ </ul>
+
+ <a name="v328"></a><h3>Changes since 3.2.8</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14815">PHPBB3-14815</a>] - The facebook page link is not displayed properly in memberlist.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15643">PHPBB3-15643</a>] - $phpbb_filesystem-&gt;resolve_path() may trigger open_basedir restriction</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15902">PHPBB3-15902</a>] - Out of range error with Sphinx search</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16056">PHPBB3-16056</a>] - JPEG dimensions undetectable for some kind of jpeg files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16076">PHPBB3-16076</a>] - Limit attachment size by extension group</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16141">PHPBB3-16141</a>] - plupload chunk_size calculation incorrect when one or more settings are 'unlimited'</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16150">PHPBB3-16150</a>] - Post title link urls not reliable when shared</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16156">PHPBB3-16156</a>] - Bots see both register and logout links in the navbar</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16157">PHPBB3-16157</a>] - Incorrect FORM_INVALID error message while sending email form</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16181">PHPBB3-16181</a>] - OAuth provider id needs to be quoted</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16184">PHPBB3-16184</a>] - Mark read button only works once</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16199">PHPBB3-16199</a>] - Guest posting CAPTCHA is being generated with no guest posting auth</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16209">PHPBB3-16209</a>] - Nginx example configuration file blocks an image in the ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16210">PHPBB3-16210</a>] - Terms of use should not be skippable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16211">PHPBB3-16211</a>] - COPPA should not be skippable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16216">PHPBB3-16216</a>] - Disable xdebug in travis builds</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16217">PHPBB3-16217</a>] - Enable opcache in travis CI builds</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16228">PHPBB3-16228</a>] - BBCode definitions with an optional attribute and a non-TEXT content are not merged correctly</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16242">PHPBB3-16242</a>] - Redirect loop when install folder doesn't exist</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16252">PHPBB3-16252</a>] - Ignore non-BBCodes when looking for unauthorized markup</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16257">PHPBB3-16257</a>] - Typo in Email Settings section</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16258">PHPBB3-16258</a>] - Sample Sphinx configuration file causes delta index to only include the most recent post</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16084">PHPBB3-16084</a>] - Pointless radio button for database backup in 3.2.7 </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16139">PHPBB3-16139</a>] - Add core.viewtopic_modify_quick_reply_template_vars</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16140">PHPBB3-16140</a>] - Add new event to UCP Edit Profile Page</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16143">PHPBB3-16143</a>] - Add core events for move topics</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16144">PHPBB3-16144</a>] - NO_STYLE_DATA - Provide extra fallback to board's default style for $user.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16146">PHPBB3-16146</a>] - Add core event for after move the forum</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16148">PHPBB3-16148</a>] - Add template events to acp_groups.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16151">PHPBB3-16151</a>] - Enable Emojis and rich text in forum name</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16153">PHPBB3-16153</a>] - Enable Emojis and rich text in topic title</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16159">PHPBB3-16159</a>] - Wrap post times in html time tag</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16174">PHPBB3-16174</a>] - Event for disabling cookie creation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16182">PHPBB3-16182</a>] - Add core.generate_smilies_modify_rowset</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16183">PHPBB3-16183</a>] - Add core.generate_smilies_count_sql_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16203">PHPBB3-16203</a>] - Enable Emojis and rich text in sent Emails</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16247">PHPBB3-16247</a>] - Quote PM has no identifier</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16251">PHPBB3-16251</a>] - Shortened link text shouldn't override custom plugins</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15422">PHPBB3-15422</a>] - Remove the unnecessary helpline function and help_line variable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16147">PHPBB3-16147</a>] - Updated tokens legend in BBCodes ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16160">PHPBB3-16160</a>] - Add script for generating package json file</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16172">PHPBB3-16172</a>] - Add &quot;Rank:&quot; or &quot;Group rank:&quot; in the memberlist</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16224">PHPBB3-16224</a>] - Update composer dependencies</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16246">PHPBB3-16246</a>] - Prettify and update README Automated Testing section</li>
+ </ul>
+
+ <a name="v328rc1"></a><h3>Changes since 3.2.8-RC1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15467">PHPBB3-15467</a>] - Permission settings do not take affect when set using All YES/NO/NEVER</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16123">PHPBB3-16123</a>] - PHP error (Array to string conversion) on new user registration if email address is banned and &quot; Reason shown to the banned&quot; is empty</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16136">PHPBB3-16136</a>] - Missing word in 'AUTH_PROVIDER_OAUTH_ERROR_ALREADY_LINKED' </li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16134">PHPBB3-16134</a>] - Exclude group leaders on group member purge</li>
+ </ul>
+ <h4>Security Issue</h4>
+ <ul>
+ <li>[SECURITY-243] - CSS injection via BBCode tag</li>
+ <li>[SECURITY-244] - Missing form token check when handling attachments</li>
+ <li>[SECURITY-246] - Missing form token check when managing BBCodes</li>
+ </ul>
+ <h4>Hardening</h4>
+ <ul>
+ <li>[SECURITY-247] - Disable MySQLi local infile to prevent local file inclusion</li>
+ </ul>
+
+ <a name="v327"></a><h3>Changes since 3.2.7</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13175">PHPBB3-13175</a>] - External accounts can be linked to more than one local account</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14459">PHPBB3-14459</a>] - Check language input for group</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15211">PHPBB3-15211</a>] - Emoji characters in forum name causing SQL errors</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15885">PHPBB3-15885</a>] - Group rank not displaying on memberlist_body</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15897">PHPBB3-15897</a>] - Unicode Characters in Attachment Comment Causes mySQL Error </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15932">PHPBB3-15932</a>] - Users can delete their attachments in the UCP, even if the post is locked</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15961">PHPBB3-15961</a>] - SMTP support for TLS is forcing use of deprecated TLS 1.0</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15974">PHPBB3-15974</a>] - The link &quot;Back to previous page&quot; can redirect to another page, not the previous one</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15976">PHPBB3-15976</a>] - Changing account settings without changing password resets user_passchg</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15982">PHPBB3-15982</a>] - Q&amp;A captcha plug-in still throws PHP 7.2.x countable warning</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16003">PHPBB3-16003</a>] - Post count not updated when deleting only post in topic</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16021">PHPBB3-16021</a>] - Recognize number of Template Event instances in events.md file</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16040">PHPBB3-16040</a>] - Topic Icon with space in filename isn't displayed by viewforum_body.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16048">PHPBB3-16048</a>] - Unable to restore any backup from ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16050">PHPBB3-16050</a>] - PHP warning in MCP banning tab on PHP 7.2+</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16053">PHPBB3-16053</a>] - BBCodes using {TEXT} in HTML tags no longer work</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16054">PHPBB3-16054</a>] - Style templates no longer able to login &quot;from any page.&quot;</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16055">PHPBB3-16055</a>] - Unable to login using Oauth via Forums, topics or posts</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16061">PHPBB3-16061</a>] - Migrator never drops unique indexes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16063">PHPBB3-16063</a>] - board_dst config value is not removed from config table after conversion</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16066">PHPBB3-16066</a>] - Banned or suspended user receives &quot;The submitted form was invalid. Try submitting again.&quot;</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16071">PHPBB3-16071</a>] - Undefined index for custom attachments groups</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16073">PHPBB3-16073</a>] - Fix warning in ACP version check</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16074">PHPBB3-16074</a>] - Twemoji -fe0f sequence not rendering</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16075">PHPBB3-16075</a>] - PM filter “sent to my default usergroup†triggers array to string conversion warning</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16080">PHPBB3-16080</a>] - Warnings When a Style exists on database but not on FTP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16093">PHPBB3-16093</a>] - Attach row template always gets displayed with JS disabled</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16096">PHPBB3-16096</a>] - MySQL full text search always uses MyISAM limits</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16124">PHPBB3-16124</a>] - Incorrect users search by last visit time in memberlist.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16126">PHPBB3-16126</a>] - AppVeyor builds fail due to chocolatey being unable to install PHP</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15745">PHPBB3-15745</a>] - Hardcoded lang in credit line</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15886">PHPBB3-15886</a>] - Group helper functions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15946">PHPBB3-15946</a>] - Add event - core.posting_modify_row_data</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15967">PHPBB3-15967</a>] - Unambiguous wording in user activation request email to Admin/Moderator</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15984">PHPBB3-15984</a>] - Use of 'Cache-Control: public' for serving files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16000">PHPBB3-16000</a>] - Provide link to PHP Date Function in both ACP and UCP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16013">PHPBB3-16013</a>] - Do not prevent username changes in ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16019">PHPBB3-16019</a>] - Deny prosilver's uninstallation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16024">PHPBB3-16024</a>] - Add core.topic_review_modify_sql_ary</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16025">PHPBB3-16025</a>] - Add 2 template events *_author_username_{append/prepend}</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16047">PHPBB3-16047</a>] - ACP Private Messages: Wording could be better</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16058">PHPBB3-16058</a>] - Remove sudo required from travis config</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16065">PHPBB3-16065</a>] - Undefined index: user_ip in oauth.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16068">PHPBB3-16068</a>] - Incorrect docblock parameter types</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16070">PHPBB3-16070</a>] - Remove support for WebSTAR and Xitami</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16078">PHPBB3-16078</a>] - Use chrome webdriver for UI tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16089">PHPBB3-16089</a>] - Add core.confirm_box_ajax_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16097">PHPBB3-16097</a>] - Add core.viewtopic_gen_sort_selects_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16102">PHPBB3-16102</a>] - Add core.posting_modify_post_subject</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16103">PHPBB3-16103</a>] - Add core.pm_modify_message_subject</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16106">PHPBB3-16106</a>] - Add core.mcp_main_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16107">PHPBB3-16107</a>] - Add mcp_move_destination_forum_before|after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16108">PHPBB3-16108</a>] - Add topiclist_row_topic_by_author_before|after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16109">PHPBB3-16109</a>] - Custom Profile Field visibility is incorrectly explained</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16111">PHPBB3-16111</a>] - Add core.message_history_modify_sql_ary</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16113">PHPBB3-16113</a>] - Add core.mcp_topic_modify_sql_ary</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16114">PHPBB3-16114</a>] - Add 2 mcp_topic_post_author_full_{append/prepend}</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16127">PHPBB3-16127</a>] - Add UI for Mass email $max_chunk_size</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16129">PHPBB3-16129</a>] - The attachment's ALT tag is supposed to describe the image, not the file.</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16067">PHPBB3-16067</a>] - Define trusty build environment for travis builds</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16112">PHPBB3-16112</a>] - Update composer dependencies to latest</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16119">PHPBB3-16119</a>] - The text input for poll question has a too high maxlength attribute</li>
+ </ul>
+ <h4>Hardening</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16101">PHPBB3-16101</a>] - Add Referrer-Policy header</li>
+ </ul>
+
+ <a name="v326"></a><h3>Changes since 3.2.6</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16034">PHPBB3-16034</a>] - Links created with [url=] - are sometimes incorrectly shortened</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16036">PHPBB3-16036</a>] - Cannot login with 3.2.6</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16037">PHPBB3-16037</a>] - Private message ViewFolder Broken</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16039">PHPBB3-16039</a>] - Unable to change announcement to standard topic due to missing global</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16042">PHPBB3-16042</a>] - Use S_LOGIN_REDIRECT to output login form token</li>
+ </ul>
+
+ <a name="v326rc1"></a><h3>Changes since 3.2.6-RC1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16027">PHPBB3-16027</a>] - Appveyor builds fail on PHP 7.0</li>
+ </ul>
+ <h4>Security Issue</h4>
+ <ul>
+ <li>[SECURITY-231] - Remote avatar functionality allows checking for files and ports on local network</li>
+ <li>[SECURITY-235] - Fulltext native search can be used to cause long execution times</li>
+ </ul>
+ <h4>Hardening</h4>
+ <ul>
+ <li>[SECURITY-228] - Require form token in login_box</li>
+ <li>[SECURITY-233] - SMTP auth data shouldn't be cached</li>
+ <li>[SECURITY-234] - Main website URL in Admin Control Panel should not support JS URLs</li>
+ </ul>
+
+ <a name="v325"></a><h3>Changes since 3.2.5</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15509">PHPBB3-15509</a>] - Update database: info message is to scary</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15869">PHPBB3-15869</a>] - Cookies Problem with domains with special chars</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15876">PHPBB3-15876</a>] - Mysql 5.7 support Q&amp;A plugin</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15883">PHPBB3-15883</a>] - No error for invalid usernames on bulk add to usergroup</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15904">PHPBB3-15904</a>] - PHP warning when accessing modules in ACP System tab</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15917">PHPBB3-15917</a>] - Unapproved posts count towards forum post count</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15918">PHPBB3-15918</a>] - Ban reason messages show backslash (\) before apostrophe -- ex. (don\'t).</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15919">PHPBB3-15919</a>] - Lint test throws PHP warnings due to node modules folder</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15931">PHPBB3-15931</a>] - Issues in PM report emails</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15954">PHPBB3-15954</a>] - Some calls to include() don't have a safeguard</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15957">PHPBB3-15957</a>] - User preferences show notification method &quot;both&quot; with disabled Jabber in ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15959">PHPBB3-15959</a>] - Travis Network Test is Failing for news.cnet.com</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15965">PHPBB3-15965</a>] - Console command to handle thumbnails have files directory hardcoded</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15975">PHPBB3-15975</a>] - Delete or prune an user doesn't remove its entries in the user_notifications table</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15986">PHPBB3-15986</a>] - Add missing language key for posting.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15996">PHPBB3-15996</a>] - Invalid data provider function name in migrator_tool_permission_test</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16006">PHPBB3-16006</a>] - Duplicate form IDs in UCP oauth form</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15884">PHPBB3-15884</a>] - Add memberlist_body_* events</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15889">PHPBB3-15889</a>] - Add core.memberlist_modify_memberrow_sql</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15890">PHPBB3-15890</a>] - Add core.memberlist_modify_viewprofile_sql</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15891">PHPBB3-15891</a>] - Add core.memberlist_modify_view_profile_template_vars</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15898">PHPBB3-15898</a>] - Add core.ucp_pm_compose_template</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15899">PHPBB3-15899</a>] - Add core.modify_attachment_sql_ary_on_* events</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15901">PHPBB3-15901</a>] - Add mcp_post_* template events</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15910">PHPBB3-15910</a>] - Pass object arguments by reference implicitly</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15914">PHPBB3-15914</a>] - Add core.modify_memberlist_viewprofile_group_sql and core.modify_memberlist_viewprofile_group_data</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15915">PHPBB3-15915</a>] - Add template events to posting_attach_body.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15924">PHPBB3-15924</a>] - Move from precise to trusty builds</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15926">PHPBB3-15926</a>] - Deny installs on PHP &gt;= 7.3@dev - Increase min. req. to 5.4.7</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15928">PHPBB3-15928</a>] - Remove support for backup download</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15939">PHPBB3-15939</a>] - Pagination docblocks</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15941">PHPBB3-15941</a>] - Replace MAX SQL in functions_posting.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15942">PHPBB3-15942</a>] - Array to string conversion when permanently deleting a post</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15948">PHPBB3-15948</a>] - Add core.mcp_change_topic_type_after/before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15949">PHPBB3-15949</a>] - [Template] - ucp_profile_signature_posting_editor_options_prepend</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15950">PHPBB3-15950</a>] - Add SQL transactions to mcp_main.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15960">PHPBB3-15960</a>] - Add SQL transactions to functions_admin.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15970">PHPBB3-15970</a>] - Add core.message_admin_form_submit_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15972">PHPBB3-15972</a>] - Add core.markread_after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15992">PHPBB3-15992</a>] - Fix breadcrumb schema</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15995">PHPBB3-15995</a>] - Add core.memberlist_modify_sort_pagination_params</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15997">PHPBB3-15997</a>] - Increase webdriver timeout for UI tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16001">PHPBB3-16001</a>] - Append data to the OAuth's redirect URL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16009">PHPBB3-16009</a>] - Display OAuth login's buttons in a row.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16010">PHPBB3-16010</a>] - Automatically check order of events in events.md file</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16018">PHPBB3-16018</a>] - Update composer and dependencies for 3.2.6</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-16020">PHPBB3-16020</a>] - Fix placement of event viewforum_body_topic_author_username_append</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15944">PHPBB3-15944</a>] - Add core.posting_modify_quote_attributes</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15921">PHPBB3-15921</a>] - Update TextFormatter to 1.3.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15953">PHPBB3-15953</a>] - pm reported missing border color</li>
+ </ul>
+
+ <a name="v325rc1"></a><h3>Changes since 3.2.5-RC1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15888">PHPBB3-15888</a>] - Update link to user guide</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15893">PHPBB3-15893</a>] - Call to undefined $user in phpbb_format_quote() when BBCodes are disabled</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15911">PHPBB3-15911</a>] - SQL general error on DB update from 3.0 branch</li>
+ </ul>
+ <h4>Hardening</h4>
+ <ul>
+ <li>[SECURITY-229] - Update to latest version of jQuery 1.x and add ajax prefilter</li>
+ </ul>
+
+ <a name="v324"></a><h3>Changes since 3.2.4</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15665">PHPBB3-15665</a>] - MSSQL implementation crashes when upload directory &gt; 2GB</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15858">PHPBB3-15858</a>] - Unapproved User(s) appearing as Guest in Team Page.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15867">PHPBB3-15867</a>] - Contact form without class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15871">PHPBB3-15871</a>] - PHP 7.1+ warning in ACP extensions module</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15875">PHPBB3-15875</a>] - BBCode parsing error (PHP fatal error)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15881">PHPBB3-15881</a>] - Login keys are not reset after password update in some cases</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15542">PHPBB3-15542</a>] - Some JS files being called without assets version</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15859">PHPBB3-15859</a>] - Modify the topic ordering if needed</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15863">PHPBB3-15863</a>] - Modify the topic sort ordering from the beginning</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15870">PHPBB3-15870</a>] - Modify the forum ID to handle the correct display of viewtopic if needed</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15872">PHPBB3-15872</a>] - Add show_user_activity to display_user_activity_modify_actives</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15873">PHPBB3-15873</a>] - Event to add/modify MCP report details template data.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15878">PHPBB3-15878</a>] - Add attachment to core.ucp_pm_view_message</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15879">PHPBB3-15879</a>] - Modify attachment's poster_id for get_submitted_attachment_data</li>
+ </ul>
+
+ <a name="v324rc1"></a><h3>Changes since 3.2.4-RC1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15860">PHPBB3-15860</a>] - Backups filenames arent saved in the expected format</li>
+ </ul>
+ <h4>Security Issue</h4>
+ <ul>
+ <li>[SECURITY-227] - Phar deserialization in ACP leads to Remote Code Execution</li>
+ </ul>
+
+ <a name="v323"></a><h3>Changes since 3.2.3</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11453">PHPBB3-11453</a>] - phpbb_notification_method_email unnecessarily loads data of banned users.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12430">PHPBB3-12430</a>] - hilit not removed from URL after search</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13043">PHPBB3-13043</a>] - Fixing HTML5 conformance</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13128">PHPBB3-13128</a>] - sql_query_info, max_matches and charset_type removed from sphinxsearch 2.2.2-beta</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14812">PHPBB3-14812</a>] - No shadow pruning with system cron enabled</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15329">PHPBB3-15329</a>] - View/Edit drafts contain underlying HTML coding</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15420">PHPBB3-15420</a>] - Quote Notification Sent for Edited Posts by Non Author</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15494">PHPBB3-15494</a>] - Users can only be removed once from newly registered users</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15507">PHPBB3-15507</a>] - PHP 7.2 Warning</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15544">PHPBB3-15544</a>] - Migrations don't delete modules in every case</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15552">PHPBB3-15552</a>] - Private Message (PM) &quot;find a member&quot; button &quot;select marked&quot; not working</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15557">PHPBB3-15557</a>] - Used composer version has bug with PHP 7.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15583">PHPBB3-15583</a>] - Updating session time in AJAX request ignores 60 seconds check</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15593">PHPBB3-15593</a>] - Disabling &quot;print view&quot; (permission or private messages settings) actually doesn't block the feature</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15600">PHPBB3-15600</a>] - Ban reasons are not escaped in mcp_ban.html template</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15604">PHPBB3-15604</a>] - Appveyor builds unable to download and unpack MSSQL drivers</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15606">PHPBB3-15606</a>] - Hide/Reveal 'Profile' Link According to Permission Setting</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15607">PHPBB3-15607</a>] - Board's cookies not deleted on disabled board</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15611">PHPBB3-15611</a>] - Prosilver mobile layout: Misaligned text in user profile</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15612">PHPBB3-15612</a>] - PHP warning with MSSQL on PHP 7.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15616">PHPBB3-15616</a>] - Jumpbox doesn't display in the login forum page (access to forum with password)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15618">PHPBB3-15618</a>] - Team page link always appears when you are logout (anonymous), even if you don't have the permission (unlike memberlist link)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15619">PHPBB3-15619</a>] - Legends of custom profile fields could be hidden in memberlist, when viewing an user group</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15620">PHPBB3-15620</a>] - Avatar gallery can be unusable on multilingual boards, unless people use the board default language</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15622">PHPBB3-15622</a>] - Quoting messages (while viewing one, not inside post editor) can return a wrong chain</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15637">PHPBB3-15637</a>] - Event list only has first line of PHP event description</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15651">PHPBB3-15651</a>] - Migration 'if' conditions only support booleans</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15659">PHPBB3-15659</a>] - retrieve_block_vars generates warnings in PHP 7.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15666">PHPBB3-15666</a>] - Language system is not fully supported in Twig</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15670">PHPBB3-15670</a>] - Group forum permission: Can see forum gives NO SQL ERROR</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15673">PHPBB3-15673</a>] - Duplicated links for (ACP,MCP,FAQ) in QuickLinks and main nav bar</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15680">PHPBB3-15680</a>] - INSTALL.html should point to 3.2 documentation instead of 3.1</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15693">PHPBB3-15693</a>] - gen_rand_string() don't return a string with the expected length</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15695">PHPBB3-15695</a>] - gen_rand_string can return less characters than expected</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15700">PHPBB3-15700</a>] - {T_THEME_LANG_NAME} template variable could be wrong when log off</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15705">PHPBB3-15705</a>] - phpbbcli language parse error in PHP &lt;= 5.5.38</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15716">PHPBB3-15716</a>] - OAuth link information remains after deleting a user, causes fatal exception</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15717">PHPBB3-15717</a>] - Old email address missing from log when user changes email address</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15723">PHPBB3-15723</a>] - gen_rand_string() return wrong number or characters sometimes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15733">PHPBB3-15733</a>] - Remove unused variables related to deprecated flood control</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15742">PHPBB3-15742</a>] - Remove get_magic_quotes_gpc from type_cast_helper</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15751">PHPBB3-15751</a>] - Warning when update with CLI</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15755">PHPBB3-15755</a>] - Broken events in /phpbb/attachment/delete.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15758">PHPBB3-15758</a>] - String INSECURE_REDIRECT is not shown translated</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15770">PHPBB3-15770</a>] - Sphinx assertion fails on unread posts when exceeding an offset of 999</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15788">PHPBB3-15788</a>] - Return button from privacy policy shows wrong text</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15817">PHPBB3-15817</a>] - Unable to install in Oracle 11R2 Express</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15824">PHPBB3-15824</a>] - UI test framework Broken for extensions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15830">PHPBB3-15830</a>] - 'core.modify_notification_message' event is useless</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15849">PHPBB3-15849</a>] - PHP 7.2 compat for bitfield class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15852">PHPBB3-15852</a>] - IPv6 address not working in Whois</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10432">PHPBB3-10432</a>] - Don't require username when user forgets password</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11500">PHPBB3-11500</a>] - on Custom profile fields the field_ident field lacks name</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12739">PHPBB3-12739</a>] - Make the font color palette in ACP same as Prosilver</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14656">PHPBB3-14656</a>] - Add a list-unsubscribe header with the unsubscribe URL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14990">PHPBB3-14990</a>] - Add core event to the Twig environment</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15554">PHPBB3-15554</a>] - Simple footer after load js</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15579">PHPBB3-15579</a>] - Add core.ucp_main_front_modify_sql and core.ucp_main_front_modify_template_vars</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15590">PHPBB3-15590</a>] - Add PHP events after adding, updating and deleting BBCodes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15628">PHPBB3-15628</a>] - newtopic_notify.txt does not have directly link to the new topic</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15638">PHPBB3-15638</a>] - Add word-break for overflowing.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15642">PHPBB3-15642</a>] - String to be used in HTML element contains &quot;&gt;&quot;</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15656">PHPBB3-15656</a>] - Add &quot;View post&quot; link in the mod logs on the ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15661">PHPBB3-15661</a>] - Add core.viewtopic_modify_poll_ajax_data</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15662">PHPBB3-15662</a>] - Add $this-&gt;template to core.modify_notification_message</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15668">PHPBB3-15668</a>] - Change JQuery .load(fn) event to .on('load',fn)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15674">PHPBB3-15674</a>] - Edit language lines in file en\acp\profile.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15683">PHPBB3-15683</a>] - Better error message when commit message has CRLF</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15696">PHPBB3-15696</a>] - 'if' module tool should support calling other tools</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15706">PHPBB3-15706</a>] - [Template] - mcp_post_report_buttons_top_*</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15719">PHPBB3-15719</a>] - Add core event on viewtopic post_list query for query modification</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15726">PHPBB3-15726</a>] - Implement selective purge in APCu cache driver</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15735">PHPBB3-15735</a>] - [Template] - *_content_after (for posts)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15737">PHPBB3-15737</a>] - [PHP] - Add $user_rows to core.delete_user_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15762">PHPBB3-15762</a>] - Topics per page Conformity</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15768">PHPBB3-15768</a>] - Add a license to a repository</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15771">PHPBB3-15771</a>] - Q&amp;A configuration instructions not optilmal</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15799">PHPBB3-15799</a>] - Find correct poll for voting animation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15803">PHPBB3-15803</a>] - Add core events on ucp_pm_compose for additional message list actions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15819">PHPBB3-15819</a>] - Add core event to functions_posting to modify notifications</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15825">PHPBB3-15825</a>] - Add core.acp_manage_forums_move_content_sql_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15826">PHPBB3-15826</a>] - Add core.mcp_main_fork_sql_after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15827">PHPBB3-15827</a>] - [Template] - Add *_username_{prepend/append} template events</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15831">PHPBB3-15831</a>] - ACP signature update should trigger event</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15832">PHPBB3-15832</a>] - ACP avatar update event</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15833">PHPBB3-15833</a>] - ACP and UCP avatar delete events</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15837">PHPBB3-15837</a>] - Add core.ucp_register_welcome_email_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15838">PHPBB3-15838</a>] - Add core.ucp_register_register_after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15839">PHPBB3-15839</a>] - Add core.ucp_login_link_template_after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15841">PHPBB3-15841</a>] - Allow postrow pm link to be modified by event</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15848">PHPBB3-15848</a>] - Up-version plupload to v2.3.6 to fix image rotation issues</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15850">PHPBB3-15850</a>] - Use standard SQL cache for notification types</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15792">PHPBB3-15792</a>] - [Template] - confirm_delete_body_delete_reason_before</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15596">PHPBB3-15596</a>] - Migrate from data-vocabulary.org to schema.org</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15621">PHPBB3-15621</a>] - Some graphical inconsistencies with colored users groups in posting, UCP and MCP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15701">PHPBB3-15701</a>] - {SIGNATURE} variable is added in mcp_post.html but not defined in MCP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15809">PHPBB3-15809</a>] - Allow events with twig syntax</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15857">PHPBB3-15857</a>] - Add rubencm to CREDITS.txt</li>
+ </ul>
+
+ <a name="v323rc2"></a><h3>Changes since 3.2.3-RC2</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15504">PHPBB3-15504</a>] - phpBB Debug warning in 3.2.2</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15740">PHPBB3-15740</a>] - Terms &amp; Privavy hardcoded</li>
+ </ul>
+
+ <a name="v323rc1"></a><h3>Changes since 3.2.3-RC1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11847">PHPBB3-11847</a>] - auth_provider_oauth migration must depend on at least one migration that ensures the module tables exist as expected</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15548">PHPBB3-15548</a>] - Dead link in ACP_COOKIE_SETTINGS_EXPLAIN language entry</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15586">PHPBB3-15586</a>] - When creating a module without the modes array a missing 'module_langname' index is accessed</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15613">PHPBB3-15613</a>] - Notification dropdown said to be not RTL compliant</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15627">PHPBB3-15627</a>] - Improve wording of YES_ACCURATE_PM_BUTTON + EXPLAIN</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15678">PHPBB3-15678</a>] - PHP warning in filesystem.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15731">PHPBB3-15731</a>] - Fix acp_search language parameters when deleting index</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15630">PHPBB3-15630</a>] - Change &lt;b&gt; to &lt;strong&gt; </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15633">PHPBB3-15633</a>] - Remove extra space in GROUP_MAX_RECIPIENTS_EXPLAIN</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15657">PHPBB3-15657</a>] - Add core.mcp_queue_get_posts_for_posts_query_before and core.mcp_queue_get_posts_modify_post_row</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15676">PHPBB3-15676</a>] - Display privacy policy &amp; terms of use more prominently</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15677">PHPBB3-15677</a>] - Updated dependencies for 3.2.3-RC2</li>
+ </ul>
+
+ <a name="v322"></a><h3>Changes since 3.2.2</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14936">PHPBB3-14936</a>] - Missing language variable INST_ERR_DB</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15491">PHPBB3-15491</a>] - Outdated linkes in installer support page</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15492">PHPBB3-15492</a>] - Permissions role combobox does not work in RTL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15500">PHPBB3-15500</a>] - Docs outdated for new PHP 5.4.7 requirement</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15502">PHPBB3-15502</a>] - Errors in migrations in 3.2.2 release</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15506">PHPBB3-15506</a>] - Previewing new post empties attachment list of all but first attachment</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15512">PHPBB3-15512</a>] - Avoid reparsing non-existent polls</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15513">PHPBB3-15513</a>] - Signature edit in acp gives error</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15520">PHPBB3-15520</a>] - DbDriver-&gt;sql_build_query cant cope with sub-selects</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15522">PHPBB3-15522</a>] - Allow multiple color palettes per page</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15523">PHPBB3-15523</a>] - AdBlocker may cause JS error when using CookieConsent</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15525">PHPBB3-15525</a>] - composer.json License is Invalid/Deprecated</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15526">PHPBB3-15526</a>] - Cast bbcode ID to integer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15527">PHPBB3-15527</a>] - Cannot interpret the BBCode definition</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15532">PHPBB3-15532</a>] - Update pull request template</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15533">PHPBB3-15533</a>] - Typo in viewtopic_topic_tools.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15558">PHPBB3-15558</a>] - phpbb\report\report_handler_post.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15559">PHPBB3-15559</a>] - phpbb\report\report_handler_pm.php:56</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15595">PHPBB3-15595</a>] - Migration Module Exists Tool Broken</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12579">PHPBB3-12579</a>] - Add BUTTON_ language strings for post &amp; PM buttons</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15495">PHPBB3-15495</a>] - Use transactions for queries in move_forum</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15499">PHPBB3-15499</a>] - Drop HHVM support</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15510">PHPBB3-15510</a>] - Link Orphan attachments in ACP&gt;General to Orphaned attachments page </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15514">PHPBB3-15514</a>] - Improve accessibility by adding vital info from explanation to a title</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15518">PHPBB3-15518</a>] - Do not attempt to accurately determine whether posters can read private messages in viewtopic</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15528">PHPBB3-15528</a>] - Display the version of the installed styles in acp</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15529">PHPBB3-15529</a>] - Color groups in ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15531">PHPBB3-15531</a>] - Log malformed BBCodes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15534">PHPBB3-15534</a>] - Outdated ACP extensions database link for phpBB 3.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15535">PHPBB3-15535</a>] - Add S_FIRST_POST to postrow on viewtopic</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15537">PHPBB3-15537</a>] - Add events core.search_(native|mysql|postgres|sphinx)_index_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15547">PHPBB3-15547</a>] - Add file object to event core.avatar_driver_upload_move_file_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15561">PHPBB3-15561</a>] - Add core events for adding columns to MySQL and Postgres search backends</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15568">PHPBB3-15568</a>] - Update depencies to latest versions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15569">PHPBB3-15569</a>] - Adjust update instructions to suggest file replacement method</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15398">PHPBB3-15398</a>] - Add event to oauth login after ID check</li>
+ </ul>
+ <h4>Security Issue</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15570">PHPBB3-15570</a>] - Extension version check is restricted to TLS 1.0</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15466">PHPBB3-15466</a>] - Move Nils in CREDITS.txt</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15516">PHPBB3-15516</a>] - Add instructions on running UI tests</li>
+ </ul>
+
+ <a name="v321"></a><h3>Changes since 3.2.1</h3>
+ <h4>Security Issue</h4>
+ <ul>
+ <li>[SECURITY-211] - URLs with javascript scheme should not be made clickable</li>
+ </ul>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-7845">PHPBB3-7845</a>] - Error on posting local image when script path is empty</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13214">PHPBB3-13214</a>] - Contact us page textarea looks narrow in responsive mode</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14629">PHPBB3-14629</a>] - acp global quick reply will not enable quick reply correctly</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14857">PHPBB3-14857</a>] - ordinal suffix in dateformat is not handled in translations</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15041">PHPBB3-15041</a>] - Cannot delete Orphaned Attachments when large number of attachments</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15060">PHPBB3-15060</a>] - Online user list fails on notifications</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15089">PHPBB3-15089</a>] - Enable/Disable settings backwards for Cookie Secure</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15133">PHPBB3-15133</a>] - Fast image size library sometimes returns no size or invalid sizes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15149">PHPBB3-15149</a>] - Unexpected Ctrl+Enter behavior on reply</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15171">PHPBB3-15171</a>] - Confusing bitfield values</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15172">PHPBB3-15172</a>] - $request-&gt;server('server_port') is returning wrong port</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15174">PHPBB3-15174</a>] - Unable to purge cache (ext &amp; acp)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15195">PHPBB3-15195</a>] - Code direction in print view is not defined as &quot;ltr&quot;</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15201">PHPBB3-15201</a>] - Removing style sets user_style to 0</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15224">PHPBB3-15224</a>] - Advanced search in &quot;message text only&quot; crashes with SQL error when using Mysql fulltext search index</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15245">PHPBB3-15245</a>] - Relative URLs in atom feeds broken when accessing via app.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15262">PHPBB3-15262</a>] - WebFontConfig google families script issue in 3.2.1</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15266">PHPBB3-15266</a>] - Content visibility events do not allow what they describe</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15273">PHPBB3-15273</a>] - 'COOKIE_PATH_EXPLAIN' does not make sense</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15285">PHPBB3-15285</a>] - Travis tests are failing due to trusty changes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15292">PHPBB3-15292</a>] - Retina imageset is blurry when displayed in Chrome browser</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15297">PHPBB3-15297</a>] - Current date in board index is broken into lines in RTL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15298">PHPBB3-15298</a>] - Errors being suppressed in cli</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15303">PHPBB3-15303</a>] - Typo in memcached driver</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15306">PHPBB3-15306</a>] - Error and missing information in core.acp_users_profile_validate event</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15309">PHPBB3-15309</a>] - Improved fix for pagination layout in tables</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15314">PHPBB3-15314</a>] - Wrong class constructor definition for convertor component</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15319">PHPBB3-15319</a>] - Database update v310\style_update_p2 fails to drop sequences</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15320">PHPBB3-15320</a>] - Redis cache does not save keys with expiration date 0 (no expiration)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15322">PHPBB3-15322</a>] - Wrong return Return-Path in emails</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15331">PHPBB3-15331</a>] - Gravatars cannot be overridden</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15332">PHPBB3-15332</a>] - Dark background is always removed after confirm popup</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15333">PHPBB3-15333</a>] - Callback isn't called when confirm dialog is canceled</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15339">PHPBB3-15339</a>] - Missing acp_send_statistics -&gt; Upgrading to 3.2.0 fails for phpBB 3.0.5</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15346">PHPBB3-15346</a>] - The installer tries to enable all extensions even if they are not enableable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15347">PHPBB3-15347</a>] - Password updater in cron generates invalid postgres SQL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15349">PHPBB3-15349</a>] - Cli doesn't check if an extension is enableable before enable it</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15350">PHPBB3-15350</a>] - Links to Plural rules are outdated</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15351">PHPBB3-15351</a>] - Confirm box function does not work with symlink on server config</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15353">PHPBB3-15353</a>] - Invalid HTML in ACP board settings</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15355">PHPBB3-15355</a>] - Empty version field in versioncheck when using the latest version</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15356">PHPBB3-15356</a>] - Avatar remote upload doesn't work</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15361">PHPBB3-15361</a>] - Topic / Forum Icons Look Withered (on Safari)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15362">PHPBB3-15362</a>] - Excessive value for {NOTIFICATION_TYPES_COLS}</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15365">PHPBB3-15365</a>] - Fix invalidating OPcache</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15367">PHPBB3-15367</a>] - Sphinx search backend doesn't escape special characters</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15368">PHPBB3-15368</a>] - Schema upgrade fails in 3.2.1 when using SQL Server</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15379">PHPBB3-15379</a>] - Reparser cron will always run</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15381">PHPBB3-15381</a>] - L_CONTACT_US_ENABLE_EXPLAIN should specify that &quot;Enable board-wide emails&quot; is also needed for it to work</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15390">PHPBB3-15390</a>] - Admin permissions role tooltip popup has vertical bar running through it.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15396">PHPBB3-15396</a>] - revert_schema() steps not executed in correct order</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15401">PHPBB3-15401</a>] - Use separate constant for memcached driver config</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15419">PHPBB3-15419</a>] - Sphinx does not search UTF keywords in delta index</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15423">PHPBB3-15423</a>] - Wrong title for topic's &quot;Unappproved posts&quot; icon</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15432">PHPBB3-15432</a>] - Don't remove dark background if fadedark is false</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15433">PHPBB3-15433</a>] - phpbbcli can enable non-existent extension</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15445">PHPBB3-15445</a>] - Git Contribution Guidelines in README.md is outdated</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15464">PHPBB3-15464</a>] - Can't reparse [IMG] - in uppercase</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15475">PHPBB3-15475</a>] - Restore Travis PR commit message validation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15478">PHPBB3-15478</a>] - core.js $loadingIndicator JavaScript errors</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15489">PHPBB3-15489</a>] - Wrong footer text on forum of type &quot;category&quot;</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15496">PHPBB3-15496</a>] - SQL Error in PostgreSQL Fulltext search when results displayed as topics</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15497">PHPBB3-15497</a>] - Declaration of admin_activate_user::create_insert_array not compatible with base</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15498">PHPBB3-15498</a>] - confirm_box() adds duplicate strings to URLs in extensions</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-7488">PHPBB3-7488</a>] - View Only - Categories: No Message</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9819">PHPBB3-9819</a>] - Move functions definitions out of mcp.php and includes/mcp/mcp_*.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12291">PHPBB3-12291</a>] - Allow extensions to use custom topic icons</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12939">PHPBB3-12939</a>] - Drop support for IE &lt;11 on January 2016</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14677">PHPBB3-14677</a>] - Extension update check is not very colorblind / colourblind friendly.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14820">PHPBB3-14820</a>] - Style Version Missing</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14919">PHPBB3-14919</a>] - Inconsistent use of globals vs class elements in acp_extensions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14927">PHPBB3-14927</a>] - event core.user_add_modify_data</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14944">PHPBB3-14944</a>] - Add possibility to search for template loop indexes by key</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14950">PHPBB3-14950</a>] - Add possibility to delete a template block with alter_block_array</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14979">PHPBB3-14979</a>] - Remove underline from unread icon</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14994">PHPBB3-14994</a>] - Refactor template-&gt;assign_block_var to be consistent with alter_block_array</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14995">PHPBB3-14995</a>] - Add ACP template events acp_ext_list_*_name_after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15111">PHPBB3-15111</a>] - Fix the typo in ucp_pm_view_messsage</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15134">PHPBB3-15134</a>] - Avatar upload driver should use filesystem service</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15247">PHPBB3-15247</a>] - Add driver for APCu v5.x cache</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15267">PHPBB3-15267</a>] - Hide birthday block if the user cannot view profile</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15291">PHPBB3-15291</a>] - Allow short array notation in event declarations</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15293">PHPBB3-15293</a>] - Prevent skipping file changes in automatic updater</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15307">PHPBB3-15307</a>] - Allow extensions to add custom modes to acp_users module</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15328">PHPBB3-15328</a>] - Disable email/jabber checkbox if notification method isn't supported</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15340">PHPBB3-15340</a>] - Update to plupload 2.3.1, stable for one year</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15352">PHPBB3-15352</a>] - Add text to clarify forum descriptions won't display on categories</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15374">PHPBB3-15374</a>] - Add core event to modify page title in viewforum.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15384">PHPBB3-15384</a>] - Add linebreaks to SMTP configuration option explanations</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15385">PHPBB3-15385</a>] - nginx sample config: www redirection, security regex</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15387">PHPBB3-15387</a>] - prosilver: vertical bars on forum rows on index page not full height</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15389">PHPBB3-15389</a>] - Simplify migration between event names</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15391">PHPBB3-15391</a>] - Remove not needed image rendering from topic/forum images</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15394">PHPBB3-15394</a>] - Add $user_cache and $post_edit_list to core.viewtopic_modify_post_row</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15408">PHPBB3-15408</a>] - Reject duplicate BBCodes in ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15409">PHPBB3-15409</a>] - Add u_action to core.acp_users_overview_run_quicktool</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15442">PHPBB3-15442</a>] - Allow unsafe HTML in bbcode.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15444">PHPBB3-15444</a>] - Merge duplicate BBCodes via a migration</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15446">PHPBB3-15446</a>] - Add event core.acp_profile_action</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15447">PHPBB3-15447</a>] - Add event core.acp_profile_modify_profile_row</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15451">PHPBB3-15451</a>] - [EVENT] - mcp_topic_postrow_attachments_before/after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15452">PHPBB3-15452</a>] - [EVENT] - mcp_topic_postrow_post_before</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15453">PHPBB3-15453</a>] - Add event in acp_language after delete language</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15454">PHPBB3-15454</a>] - event - mcp_queue_approve_details_template</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15470">PHPBB3-15470</a>] - attachment boxes need there own font-size</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15471">PHPBB3-15471</a>] - Add core events to ACP when pruning a forum</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15476">PHPBB3-15476</a>] - Add core event before search rows are edited</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15485">PHPBB3-15485</a>] - Add template event to forumlist_body &gt; forum images</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15486">PHPBB3-15486</a>] - Add core event to the function user_add() to modify notifications data</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13344">PHPBB3-13344</a>] - Add new events for logging</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15122">PHPBB3-15122</a>] - Support using memcached instead of memcache</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15372">PHPBB3-15372</a>] - Add a &quot;Can view topics&quot; permission</li>
+ </ul>
+ <h4>Sub-task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13150">PHPBB3-13150</a>] - [Event] - core.phpbb_log_get_topic_auth_sql_after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15468">PHPBB3-15468</a>] - Add a service to merge duplicate BBCodes</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15179">PHPBB3-15179</a>] - Update 3.2.x dependencies and fix Twig &gt; 1.25 compatibility</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15304">PHPBB3-15304</a>] - Update s9e/text-formatter dependency</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15455">PHPBB3-15455</a>] - Margin discrepancy due to &lt;!-- INCLUDE jumpbox.html --&gt;</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15457">PHPBB3-15457</a>] - Update s9e/text-formatter dependency</li>
+ </ul>
+
+ <a name="v320"></a><h3>Changes since 3.2.0</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-7336">PHPBB3-7336</a>] - Words in new topic title aren't found by search after topic is split</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11076">PHPBB3-11076</a>] - Update notification in ACP for minimum PHP version missing essential information</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11611">PHPBB3-11611</a>] - setup_github_network.php no longer creates a repository</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13250">PHPBB3-13250</a>] - File cache does not write entries starting with _ and containing a slash</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14732">PHPBB3-14732</a>] - Update/remove PHP Code syntax highlighting references</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14790">PHPBB3-14790</a>] - Nested color/list BBCode is not parsed correctly</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14938">PHPBB3-14938</a>] - Inconsistent data results from ext_mgr-&gt;all_available() vs ext_mgr-&gt;is_available()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14967">PHPBB3-14967</a>] - Cookie Notice</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14971">PHPBB3-14971</a>] - PHP 7.1 warning on pagination</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14975">PHPBB3-14975</a>] - incorrect RTL style appearance </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14984">PHPBB3-14984</a>] - wrong arrow direction in PM inbox</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14985">PHPBB3-14985</a>] - Plain text is stored as HTML and not decoded before usage</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14989">PHPBB3-14989</a>] - url bbcode does not support irc protocol</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14992">PHPBB3-14992</a>] - User notifications table allowing duplicate entries</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14999">PHPBB3-14999</a>] - Next PM icon pointing in wrong direction</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15002">PHPBB3-15002</a>] - Topic icons not showing in search results</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15003">PHPBB3-15003</a>] - When using mark all, disabled check boxes should not become checked</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15006">PHPBB3-15006</a>] - Permission inheritance with checkbox not working</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15008">PHPBB3-15008</a>] - Disable emoji when smilies are disabled</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15010">PHPBB3-15010</a>] - Crash on user profile custom field</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15011">PHPBB3-15011</a>] - Error not checked on metadata load failure</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15012">PHPBB3-15012</a>] - Invalid constructor in FTP file updater</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15015">PHPBB3-15015</a>] - phpbb 3.2.0 install error in the board-wide emails description...</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15016">PHPBB3-15016</a>] - Smilies that contain some characters cause an exception to be thrown</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15023">PHPBB3-15023</a>] - Undo and properly fix post row paging</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15025">PHPBB3-15025</a>] - Use SSL in version check for extension</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15035">PHPBB3-15035</a>] - Add phpinfo.php to 3.2.x install directory</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15036">PHPBB3-15036</a>] - Failure at board setup in functional tests with install_config present</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15044">PHPBB3-15044</a>] - Installation does not create search index</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15047">PHPBB3-15047</a>] - Error migrating from 3.0.12 to 3.2. MS SQL Server</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15050">PHPBB3-15050</a>] - Updater incorrectly adds files when new file already exists</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15056">PHPBB3-15056</a>] - Mark forums read does not update subforum icons</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15058">PHPBB3-15058</a>] - At new feature release phpBB's CSS files should carry information for cache busting</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15062">PHPBB3-15062</a>] - Update to Rhea version number the CSS files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15079">PHPBB3-15079</a>] - MySql Error when saving draft with Emoji</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15083">PHPBB3-15083</a>] - emoji's not always size constrained</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15084">PHPBB3-15084</a>] - Wrong order of breadcrumbs in module management</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15090">PHPBB3-15090</a>] - Missing acp_send_statistics -&gt; Upgrading to 3.2.0 fails for phpBBs &lt; 3.0.6-rc1</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15102">PHPBB3-15102</a>] - Missing parameter calling version_check</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15103">PHPBB3-15103</a>] - JPEG dimensions undetectable when JFIF header is missing</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15118">PHPBB3-15118</a>] - HTML error/typo in jumpbox.html </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15124">PHPBB3-15124</a>] - Navbar icon titles don't get hidden in responsive view</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15126">PHPBB3-15126</a>] - Incorrect links with clever quotes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15135">PHPBB3-15135</a>] - Undefined $user in metadata manager</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15137">PHPBB3-15137</a>] - Global Announcements shouldn't always be never ending</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15150">PHPBB3-15150</a>] - Yabber SSL/TLS certification</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15152">PHPBB3-15152</a>] - Update Font Awesome</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15158">PHPBB3-15158</a>] - Facebook OAuth login results in fatal error</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15163">PHPBB3-15163</a>] - Braces in smilies &quot;emotion&quot; are not treated as literals</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15173">PHPBB3-15173</a>] - Resizing the posting editor's text area lags</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15180">PHPBB3-15180</a>] - Container broken because of template.twig.environment changes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15186">PHPBB3-15186</a>] - The force_delete_allowed flag does not affect actual posts deletion ability</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15187">PHPBB3-15187</a>] - ACP Template files not purged during Extension Enable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15198">PHPBB3-15198</a>] - Fix phpBB and PHP version info displayed in the ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15202">PHPBB3-15202</a>] - Should not be possible to disable available extensions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15212">PHPBB3-15212</a>] - Code box has double horizontal scrollbars</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15217">PHPBB3-15217</a>] - Allow extension to overwrite user::format_date()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15221">PHPBB3-15221</a>] - missing commas in language/en/install.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15222">PHPBB3-15222</a>] - Typo in generate_text_for_display_test.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15243">PHPBB3-15243</a>] - Check permissions before installing with SQLite</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15246">PHPBB3-15246</a>] - Memcache driver incorrectly handles Unix sockets</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15248">PHPBB3-15248</a>] - Event core.modify_posting_auth does not honor its parameters</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15252">PHPBB3-15252</a>] - Wrapping poll title and options text by extra &lt;t&gt; tags if edited a topic by user having no f_poll permission</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13603">PHPBB3-13603</a>] - New event upon index_body_online_block_after</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14557">PHPBB3-14557</a>] - Simplify updating overloaded events for extensions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14849">PHPBB3-14849</a>] - Add ACP extension event</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14928">PHPBB3-14928</a>] - Users will not understand the phrase '&quot;%s&quot; is not a valid stability.'</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14973">PHPBB3-14973</a>] - BC break with the rename of db/tools.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14974">PHPBB3-14974</a>] - Cookie notice link not configurable but links to english website</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15037">PHPBB3-15037</a>] - Make imageset retina capable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15068">PHPBB3-15068</a>] - Add ability to retrieve template vars from the template object</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15097">PHPBB3-15097</a>] - Board statistics page should show PHP version</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15123">PHPBB3-15123</a>] - Check if extension was enabled/disabled before enable or disable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15142">PHPBB3-15142</a>] - Extension Version Check Should Support Branches</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15157">PHPBB3-15157</a>] - Fix lack of proper font support</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15176">PHPBB3-15176</a>] - Add setting for the maximum number of posts a user must have to have his activity shown in profile</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15199">PHPBB3-15199</a>] - Add core event to the function send() in the messenger</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15200">PHPBB3-15200</a>] - Allow extensions using custom templates for help/faq controllers </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15205">PHPBB3-15205</a>] - Add template events to forumlist_body.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15219">PHPBB3-15219</a>] - Add cron to update passwords hashes to bcrypt</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15226">PHPBB3-15226</a>] - Add index for latest topics query in feeds</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15227">PHPBB3-15227</a>] - Remove unused code in startup</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15237">PHPBB3-15237</a>] - Unguarded includes functions_user</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15238">PHPBB3-15238</a>] - Add console command to fix left/right IDs for the forums and modules</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15241">PHPBB3-15241</a>] - Add ACP template event acp_profile_contact_last</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15250">PHPBB3-15250</a>] - Add core event to MCP at the end of merge_posts</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13730">PHPBB3-13730</a>] - [PHP] - core.delete_post_end</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14498">PHPBB3-14498</a>] - Not possible to deactivate display of &quot;who is online&quot; and birthdays for guests</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15040">PHPBB3-15040</a>] - Update s9e\TextFormatter to 0.9.1</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15045">PHPBB3-15045</a>] - Fix missing incorrect constructor for user object in version_test</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15086">PHPBB3-15086</a>] - Replace quote.gif with fontawesome icon</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15125">PHPBB3-15125</a>] - Remove the function play_qt_file in forum_fn.js</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15144">PHPBB3-15144</a>] - Bug - MCP Multiple attachments icon display</li>
+ </ul>
+
+ <a name="v320rc1"></a><h3>Changes since 3.2.0-RC1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14588">PHPBB3-14588</a>] - RTL Search Bar</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14612">PHPBB3-14612</a>] - Double .panel class on confirmation page (ajax error?)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14628">PHPBB3-14628</a>] - CLI installer doesn't support the translatable error messages</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14633">PHPBB3-14633</a>] - Creating a new topic leaves a white page</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14636">PHPBB3-14636</a>] - BC compatibility broken using request_var</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14640">PHPBB3-14640</a>] - Wrong link to documentation in language/en/install.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14660">PHPBB3-14660</a>] - Emails are being sent unparsed</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14663">PHPBB3-14663</a>] - Incorrect unicode chars handling in custom BBCode</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14665">PHPBB3-14665</a>] - Invalid syntax in report_id_auto_increment migration</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14684">PHPBB3-14684</a>] - Extension Sniff script should use NOTESTS</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14690">PHPBB3-14690</a>] - Email queue cron task never runs for phpBB 3.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14692">PHPBB3-14692</a>] - Duplicate subexpression in questionnaire.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14700">PHPBB3-14700</a>] - Updating from 3.1 to 3.2, just stops</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14706">PHPBB3-14706</a>] - nested BB-Code [list] - shows different behaviour between 3.1 and 3.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14709">PHPBB3-14709</a>] - Deleting posts from mcp_main causes missing post_id notice</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14714">PHPBB3-14714</a>] - Update composer dependencies to latest versions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14716">PHPBB3-14716</a>] - Impossible to install with open basedir restrictions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14717">PHPBB3-14717</a>] - Quote any scalar in yaml files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14739">PHPBB3-14739</a>] - Remove old SQLite 2.8.Ñ… database driver</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14740">PHPBB3-14740</a>] - BBcodes with quotes dont get parsed correctly</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14742">PHPBB3-14742</a>] - Improvements to migrator</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14746">PHPBB3-14746</a>] - Don't depend on container in installer msg_handler</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14748">PHPBB3-14748</a>] - Modify tests to pass PHP 7.1 tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14763">PHPBB3-14763</a>] - Files services definition specifies form for local type</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14764">PHPBB3-14764</a>] - Incomplete update notification points to wrong update-link</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14765">PHPBB3-14765</a>] - Parameter vs requirement spelling mismatch in installer routing config</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14774">PHPBB3-14774</a>] - Content-Range only supported for resuming downloads</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14782">PHPBB3-14782</a>] - Quick Links &gt; Your Posts gives mysql error</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14788">PHPBB3-14788</a>] - Update developer list to reflect team changes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14791">PHPBB3-14791</a>] - Trying to get form from wrong button in search test base</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14793">PHPBB3-14793</a>] - &quot;A non-numeric value encountered&quot; PHP warning on PHP 7.1+</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14794">PHPBB3-14794</a>] - Fix redirect behavior in according to parse_url() behavior changes in PHP 7.1+</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14797">PHPBB3-14797</a>] - Remove PHP 7.1 builds from allowed failures</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14799">PHPBB3-14799</a>] - purge_notifications() leaves open transaction for bad notification types.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14813">PHPBB3-14813</a>] - functions_compatibility missing in phpbbcli</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14814">PHPBB3-14814</a>] - Text reparser reparses already correctly [re] -parsed objects</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14821">PHPBB3-14821</a>] - Do not expect parsed HTML in kernel subscriber output</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14846">PHPBB3-14846</a>] - Swapped variables in bbcode, first one doesn't get parsed</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14873">PHPBB3-14873</a>] - Missing width and height variables for smilies</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14875">PHPBB3-14875</a>] - Cannot use HTML entity type database passwords during installation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14883">PHPBB3-14883</a>] - Text Reparser is Reparsing Empty Data</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14892">PHPBB3-14892</a>] - Assets paths broken on Windows instances</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14894">PHPBB3-14894</a>] - Update: download of conflict files offers .tar file without file extension</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14896">PHPBB3-14896</a>] - Link after installation fails at redirecting to ACP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14897">PHPBB3-14897</a>] - IOHandler in the installer declares member variable only in the constructor</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14900">PHPBB3-14900</a>] - Disabled extension breakage in ACP</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10961">PHPBB3-10961</a>] - &quot;You are not authorised...&quot; still sends HTTP status 200 instead of i.e. 403</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13709">PHPBB3-13709</a>] - Fallback to english in email templates by extensions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14586">PHPBB3-14586</a>] - phpBB Oauth V1 Wrapper Support</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14595">PHPBB3-14595</a>] - smtp port</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14620">PHPBB3-14620</a>] - Update docs/ for 3.2.x</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14689">PHPBB3-14689</a>] - Build 3.2.x API docs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14729">PHPBB3-14729</a>] - Report post controller and report helper require specific implementation of config class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14734">PHPBB3-14734</a>] - Use SVG emoji</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14805">PHPBB3-14805</a>] - Allow building package for previous versions on PHP 7</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14867">PHPBB3-14867</a>] - INCLUDECSS Path broken</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14885">PHPBB3-14885</a>] - Migrator logs need line breaks</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12610">PHPBB3-12610</a>] - Add a command to check if the board is up to date.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14484">PHPBB3-14484</a>] - Support extensions in UI tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14492">PHPBB3-14492</a>] - Improve send stats page and include VigLink</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14547">PHPBB3-14547</a>] - Add Vagrant Support</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10809">PHPBB3-10809</a>] - Remove PHP MSSQL Support</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13573">PHPBB3-13573</a>] - Investigate ability to use set_config() and similar compatibility functions.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14671">PHPBB3-14671</a>] - Deduplicate database schema definiton</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14696">PHPBB3-14696</a>] - Fix email template test for '0' username</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14807">PHPBB3-14807</a>] - Updates dependencies</li>
+ </ul>
+
+ <a name="v320b2"></a><h3>Changes since 3.2.0-b2</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9435">PHPBB3-9435</a>] - &quot;magic numbers&quot; in message_parser.php/bbcode.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13616">PHPBB3-13616</a>] - Pass lexer directly to TWIG environment</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13972">PHPBB3-13972</a>] - 3.1.5 - Waiting time conflict</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14136">PHPBB3-14136</a>] - IE compatibility meta is missing in overall_header.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14198">PHPBB3-14198</a>] - Container cache filename doesn't depend on the build options</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14260">PHPBB3-14260</a>] - Right parenthesis breaks (some?) magic URLs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14318">PHPBB3-14318</a>] - Board Notifications Config Migration Not Working</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14329">PHPBB3-14329</a>] - Updater Cannot remove files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14381">PHPBB3-14381</a>] - Text Reparser fails with empty sql fields</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14393">PHPBB3-14393</a>] - Update 3.2.0a1 to 3.2.0a2 --&gt; Error: CANNOT_DELETE_FILES </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14426">PHPBB3-14426</a>] - viewtopic error posts bbcode pregmatch</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14481">PHPBB3-14481</a>] - phpBB does not obey HTTP_X_FORWARDED_PORT header</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14497">PHPBB3-14497</a>] - Update nginx sample config for new installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14527">PHPBB3-14527</a>] - Dataloss caused by link shortening</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14528">PHPBB3-14528</a>] - Structured data - breadcrumbs error</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14530">PHPBB3-14530</a>] - Signature parsing inconsistant</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14532">PHPBB3-14532</a>] - Database column default incorrectly escaped on MSSQL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14550">PHPBB3-14550</a>] - function unique_id()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14555">PHPBB3-14555</a>] - Inconsistent usage of the cache directory</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14559">PHPBB3-14559</a>] - Attachments' behaviour in quotes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14562">PHPBB3-14562</a>] - Extension's permissions don't have language fallback</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14564">PHPBB3-14564</a>] - config cookie domain is empty</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14569">PHPBB3-14569</a>] - Add a method for console progress bar initialisation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14572">PHPBB3-14572</a>] - Quote notifications deleted on edit</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14576">PHPBB3-14576</a>] - Functional Test Framework should include functions.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14577">PHPBB3-14577</a>] - Stop using sizeof() inside for() loop</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14589">PHPBB3-14589</a>] - Requirements test showing required text for &quot;yellow/amber&quot; (optional) requirements</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14590">PHPBB3-14590</a>] - Installer gets stuck at sending notification e-mail</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14591">PHPBB3-14591</a>] - Some installation data not being inserted when running under MS SQL Server</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14607">PHPBB3-14607</a>] - Missing Auto Increment in Report Table</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14619">PHPBB3-14619</a>] - docs/ folder need work to change 3.1.x to 3.2.x in readme, install, changelog etc</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14648">PHPBB3-14648</a>] - Users don't receive default notifications if another setting is set.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14649">PHPBB3-14649</a>] - Missing variable within event</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13502">PHPBB3-13502</a>] - controller resolver should handle callable functions and objects</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14540">PHPBB3-14540</a>] - Adjust class recursive_dot_prefix_filter_iterator to increase performance</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14561">PHPBB3-14561</a>] - Add additional commands for user actions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14664">PHPBB3-14664</a>] - Fix PHPDoc comment in cron manager</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12684">PHPBB3-12684</a>] - Add a command to add a user from the CLI</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13969">PHPBB3-13969</a>] - Remove old help_* language files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14565">PHPBB3-14565</a>] - Updates composer to 1.0.0-b2</li>
+ </ul>
+
+ <a name="v320b1"></a><h3>Changes since 3.2.0-b1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14307">PHPBB3-14307</a>] - Incorrect wording used in installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14315">PHPBB3-14315</a>] - Changing multiple forum permissions at once forces identical permissions on all groups</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14416">PHPBB3-14416</a>] - navlnks in header have incorrect tool tip styling</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14431">PHPBB3-14431</a>] - Remote avatar uploading does not support https</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14440">PHPBB3-14440</a>] - Paths can break for extensions with deep route patterns/paths</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14460">PHPBB3-14460</a>] - Use the selected language in AJAX pages as well in the installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14461">PHPBB3-14461</a>] - Text reparser migration might finish too late</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14488">PHPBB3-14488</a>] - Grab correct session ID in ui tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14489">PHPBB3-14489</a>] - Extension compiler pass cannot find class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14503">PHPBB3-14503</a>] - Allow superglobals in installer cli</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14510">PHPBB3-14510</a>] - Prevent infinite loop in adding bots task</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14312">PHPBB3-14312</a>] - Allow installer updating only without updating files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14448">PHPBB3-14448</a>] - Use guzzle for remote files uploading</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14462">PHPBB3-14462</a>] - Add further measures to prevent timeouts in the installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14478">PHPBB3-14478</a>] - Move facebook/webdriver to main composer.json</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14499">PHPBB3-14499</a>] - CLI updater</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14447">PHPBB3-14447</a>] - Cleanup whitespaces in Prosilver</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14477">PHPBB3-14477</a>] - Update text formatter to latest release</li>
+ </ul>
+
+ <a name="v320a2"></a><h3>Changes since 3.2.0-a2</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10628">PHPBB3-10628</a>] - http:// prepended to &quot;www.&quot; urls (but not reflected in preview)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11875">PHPBB3-11875</a>] - mediumint(8) too small for post_id</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12221">PHPBB3-12221</a>] - URLs Containing javascript: are Garbled</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14129">PHPBB3-14129</a>] - Adding custom extensions autoloaders feature slow downs the board</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14321">PHPBB3-14321</a>] - Fatal error on download the merged conflicts archive during update from 3.1.6 to 3.2-a1</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14323">PHPBB3-14323</a>] - Long urls are no longer shortened</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14368">PHPBB3-14368</a>] - Post Editors Text Should Be Black, Not Blue</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14371">PHPBB3-14371</a>] - Small fix for the aligment quick links</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14373">PHPBB3-14373</a>] - Do not use strpos() on arrays in iohandler_base::add_error_message()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14378">PHPBB3-14378</a>] - Maintain consistent template var paths in 3.2 installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14380">PHPBB3-14380</a>] - Maintain consistent template var paths in 3.2 installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14402">PHPBB3-14402</a>] - Tidy plupload cron should not rely on user id/ip being available</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14403">PHPBB3-14403</a>] - phpbb\log should still work even when no user data is given</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14405">PHPBB3-14405</a>] - Text processor parses invalid use of url bbcode</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14419">PHPBB3-14419</a>] - Update composer dependencies and fix outdated composer lock file</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14420">PHPBB3-14420</a>] - Search Results pagination not up to date / broken</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14428">PHPBB3-14428</a>] - Use other links for files remote test</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14431">PHPBB3-14431</a>] - Remote avatar uploading does not support https</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14432">PHPBB3-14432</a>] - The lang() function needs to handle key array</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14434">PHPBB3-14434</a>] - Schema generator fails if extensions have non-migrations in migrations dir</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14436">PHPBB3-14436</a>] - Default data type migration misses oauth_states dependency</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14442">PHPBB3-14442</a>] - Use Goutte ~2.0 after allowing PHP &gt;= 5.4</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14444">PHPBB3-14444</a>] - Fatal error in functions_messenger.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14446">PHPBB3-14446</a>] - Add predefined placeholder variables to twig</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14452">PHPBB3-14452</a>] - Undefined $progressFillerText in installer.js</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14453">PHPBB3-14453</a>] - Missing dependency in the text_reparser migration</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13454">PHPBB3-13454</a>] - Remove unused variables, globals, parameters</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13733">PHPBB3-13733</a>] - Allow non-migration files inside migrations folder</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14177">PHPBB3-14177</a>] - Catch exceptions and display a nice error page</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14253">PHPBB3-14253</a>] - Show group requests pending aproval at the ACP groups summary</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14377">PHPBB3-14377</a>] - Allow extensions to register custom compiler pass</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14418">PHPBB3-14418</a>] - Add missing language string PM_TOOLS</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14445">PHPBB3-14445</a>] - Force page refresh before the installer generates the schema</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14250">PHPBB3-14250</a>] - Review/bump composer dependencies</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14262">PHPBB3-14262</a>] - Move converter code into a controller</li>
+ </ul>
+
+ <a name="v320a1"></a><h3>Changes since 3.2.0-a1</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9791">PHPBB3-9791</a>] - invalid [] - chars on search URI</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13451">PHPBB3-13451</a>] - A very long string inside message crashes PHP</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14273">PHPBB3-14273</a>] - Unnecessary core.root_path dependency in files.upload service</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14293">PHPBB3-14293</a>] - Responsive .postbody width not expanding</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14295">PHPBB3-14295</a>] - Icon on left side of &quot;Post awaiting approval&quot; inside messages is missing</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14311">PHPBB3-14311</a>] - Installer error messages not being reported back to client properly</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14317">PHPBB3-14317</a>] - Run lang_migrate_help_lang script on master</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14320">PHPBB3-14320</a>] - Language selector is broken in the installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14325">PHPBB3-14325</a>] - Renamed Event Variables Backwards Incompatible</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14326">PHPBB3-14326</a>] - Diffed files are not decoded at update</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14339">PHPBB3-14339</a>] - State support for PHP 7.0 in docs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14344">PHPBB3-14344</a>] - Improve formatting of errors during install</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14345">PHPBB3-14345</a>] - Check if message description exists in install cli iohandler</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14349">PHPBB3-14349</a>] - Improve error messages and remove output of suppressed messages</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14350">PHPBB3-14350</a>] - Remove duplicate semi-colon from functions_user</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14358">PHPBB3-14358</a>] - Fatal error when running create_schema_files.php (missing composer autoloader)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14359">PHPBB3-14359</a>] - Wrong service definition for console.command.reparser.reparse</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12649">PHPBB3-12649</a>] - Change sort &amp; display options in footers to dropdown menu</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14257">PHPBB3-14257</a>] - Reparse after update</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14269">PHPBB3-14269</a>] - Use http_exceptions instead of die() in installer controllers</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14310">PHPBB3-14310</a>] - Progress bar in new installer not very clear</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14340">PHPBB3-14340</a>] - Revert the workaround fix for segmentation fault error on phpBB 3.2 PHP 7 tests</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14247">PHPBB3-14247</a>] - Usage of @ at begining of an unquoted string in a yaml file is deprecated</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14341">PHPBB3-14341</a>] - Update to Symfony 2.8</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14348">PHPBB3-14348</a>] - Add an index.html to the install folder</li>
+ </ul>
+
+ <a name="v31x"></a><h3>Changes since 3.1.x</h3>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-6466">PHPBB3-6466</a>] - Permission Role Tooltips do not display in Safari</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-7187">PHPBB3-7187</a>] - Quote smilies error</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-7275">PHPBB3-7275</a>] - Custom bbodes trim('${1}')</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-8064">PHPBB3-8064</a>] - forum author sort not using username_clean</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-8419">PHPBB3-8419</a>] - custom tag eats up space character</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-8420">PHPBB3-8420</a>] - emoticon removes space before itself when using preview</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-8613">PHPBB3-8613</a>] - BBCode_uid- and censor-bug</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9073">PHPBB3-9073</a>] - Word censoring in URLs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9109">PHPBB3-9109</a>] - Maximum allowed recepients restriction precedence</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9377">PHPBB3-9377</a>] - Custom BB Code Nesting</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10002">PHPBB3-10002</a>] - (incomplete) BBCode usage of [quote] - and [list] - forces closing [/list] - and [/quote] -s, ultimately breaking HTML/Design</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10388">PHPBB3-10388</a>] - Template engine should use json_encode() to properly escape JS properties</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10572">PHPBB3-10572</a>] - Unguarded includes in acp/</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10989">PHPBB3-10989</a>] - Bug in BBCode</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11444">PHPBB3-11444</a>] - Unnecessary notify column in phpbb_user_notifications table</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11967">PHPBB3-11967</a>] - Notification settings are not respected</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12143">PHPBB3-12143</a>] - Untranslated group name from index if not special group</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12195">PHPBB3-12195</a>] - Double-slash URLs not supported</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12387">PHPBB3-12387</a>] - mysqli_free_result is called with false value</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12554">PHPBB3-12554</a>] - Quotes do not display correctly as list elements</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12698">PHPBB3-12698</a>] - Replace all instances of magic numbers with constants in javascript</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12957">PHPBB3-12957</a>] - The template engine is not constructed properly in install/index</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12974">PHPBB3-12974</a>] - Update nightly version of develop to 3.2.0-a1-dev</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13101">PHPBB3-13101</a>] - Remove WLM contact from profile</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13238">PHPBB3-13238</a>] - \phpbb\db\migration\data\v310\mysql_fulltext_drop tries to drop non existent indexes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13359">PHPBB3-13359</a>] - Develop tests fail due to wrong template set up in tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13362">PHPBB3-13362</a>] - The whole cache dir (excluding the .htaccess and index.html files) should be ignored by git</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13371">PHPBB3-13371</a>] - Lang vars not loaded during install process</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13372">PHPBB3-13372</a>] - Environment Bug - Routing broken for extensions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13377">PHPBB3-13377</a>] - Function decode_message() incorrectly decodes www type URLs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13425">PHPBB3-13425</a>] - Smiley code at start of text being quoted doesn't show smiley image in quote</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13513">PHPBB3-13513</a>] - Mixed routing file paths in the router</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13555">PHPBB3-13555</a>] - Poll options preview rendered incorrectly by &lt;br /&gt; collision</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13619">PHPBB3-13619</a>] - Remove unneeded folders/files from vendor folder in release package</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13638">PHPBB3-13638</a>] - INCLUDECSS and INCLUDEJS Broken in 3.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13670">PHPBB3-13670</a>] - Fix fatal function name must be a string in functional tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13680">PHPBB3-13680</a>] - Notification for a quote within a quote</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13718">PHPBB3-13718</a>] - Spambot countermeasures/CAPTCHA admin panel won't load</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13749">PHPBB3-13749</a>] - Add missing slash to base uri in helper route tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13766">PHPBB3-13766</a>] - Missing style_parent_id in textformater's data_access::get_styles()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13769">PHPBB3-13769</a>] - bin/phpbbcli.php ignores PHPBB_ENVIRONMENT constant from config.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13772">PHPBB3-13772</a>] - Error in @param variable type for phpbb\passwords\manager</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13782">PHPBB3-13782</a>] - ACM null caching driver class is named with the reserved word 'null'</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13792">PHPBB3-13792</a>] - Travis fails installing hhvm-nigthly</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13814">PHPBB3-13814</a>] - phpbb_is_writable() method of the new filesystem class truncates files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13825">PHPBB3-13825</a>] - create_thumbnail() incorrectly calls phpbb\filesystem::phpbb_chmod</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13828">PHPBB3-13828</a>] - Rename null driver to dummy for PHP7 compatibility in tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13829">PHPBB3-13829</a>] - Router requires cache directory to be writable</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13839">PHPBB3-13839</a>] - Failing test when the phpBB root directory isn't named phpbb</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13849">PHPBB3-13849</a>] - Development environment broken</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13860">PHPBB3-13860</a>] - Array to string conversion in parser service</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13871">PHPBB3-13871</a>] - Call to a member function realpath() on a non-object in functions.php on line 3474</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13875">PHPBB3-13875</a>] - Lint test should ignore cache, ext, and store folder</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13890">PHPBB3-13890</a>] - Failling tests in master</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13896">PHPBB3-13896</a>] - Coding style issue in master</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13897">PHPBB3-13897</a>] - Non-existent environment causes fatal error</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13906">PHPBB3-13906</a>] - BBCodes in signatures are not correctly parsed in post preview</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13990">PHPBB3-13990</a>] - Reparse markup inside of forum rules/description</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13993">PHPBB3-13993</a>] - Signature Editing Broken</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14008">PHPBB3-14008</a>] - Do not add a user_id value to quotes from guests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14033">PHPBB3-14033</a>] - Correct docblock errors</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14034">PHPBB3-14034</a>] - Fix reparser names that contain &quot;text_reparser&quot; in the middle</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14036">PHPBB3-14036</a>] - Replace path_helper with a mock</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14052">PHPBB3-14052</a>] - New installer - The commands are not translated</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14074">PHPBB3-14074</a>] - Not possible to clear notification (mark as read)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14076">PHPBB3-14076</a>] - Notifications settings are not correctly handled when a non default setting is set</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14078">PHPBB3-14078</a>] - Notification related sql general error on submission of editing post</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14079">PHPBB3-14079</a>] - Cannot mark notification as read from the dropdown</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14094">PHPBB3-14094</a>] - Current master branch is getting segmentation fault error on PHP 7 tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14128">PHPBB3-14128</a>] - Image posting overflow regression</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14137">PHPBB3-14137</a>] - Fix Notification Menu Settings spacing issue caused by new jump-box improvements</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14138">PHPBB3-14138</a>] - Use span tags instead of abbr tags in the footer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14165">PHPBB3-14165</a>] - Fix layout of ucp/mcp after 14139</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14178">PHPBB3-14178</a>] - Installer database helper tests fail if sqlite3 is not present</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14180">PHPBB3-14180</a>] - Use unix line ending in files classes tests</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14182">PHPBB3-14182</a>] - Move the v310\notifications_board migration to v320\notifications_board</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14183">PHPBB3-14183</a>] - Remove deprecated max-device-width</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14193">PHPBB3-14193</a>] - Custom BBCode Buttons Broken</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14194">PHPBB3-14194</a>] - Responsive Quick Links Menu Broken</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14195">PHPBB3-14195</a>] - Plupload Attachments Not Quite Working</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14199">PHPBB3-14199</a>] - We need to hide icons from screen readers</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14202">PHPBB3-14202</a>] - Add missing sr-only classes to icons</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14216">PHPBB3-14216</a>] - Do not run thumbnail test if gd is not enabled</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14221">PHPBB3-14221</a>] - Fix viewforum header issue</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14222">PHPBB3-14222</a>] - ACP users page tries to cast deactivated_super_global to int</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14225">PHPBB3-14225</a>] - Inject the resolver in routing loaders when using them</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14230">PHPBB3-14230</a>] - Unread posts' icons don't have different color in viewtopic</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14234">PHPBB3-14234</a>] - Do not use references in trigger_event()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14235">PHPBB3-14235</a>] - Font Awesome not available with simple_header.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14240">PHPBB3-14240</a>] - Always include all config files in the update package</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14274">PHPBB3-14274</a>] - New installer has weak inclusion of user functions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14277">PHPBB3-14277</a>] - Don't use user_id in migrations as it is not defined</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14278">PHPBB3-14278</a>] - Don't use user_id in installer if not available</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-8672">PHPBB3-8672</a>] - No file size limit in getimagesize() and remote upload</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-8708">PHPBB3-8708</a>] - Splitting global announcements from f_announce</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9485">PHPBB3-9485</a>] - Please include link to specific post in moderator's activity logs.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10268">PHPBB3-10268</a>] - extend function make_clickable() to also recognize semicolons as leading URL borders</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10620">PHPBB3-10620</a>] - Quote tag improvement</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10922">PHPBB3-10922</a>] - Allow parameters for [email] - BBCode content instead of addresses only</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11649">PHPBB3-11649</a>] - Move construction of twig environment to DIC</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11742">PHPBB3-11742</a>] - BBCode 'code' doesn't support tabs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12466">PHPBB3-12466</a>] - Move classes from acp_database.php to their own files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12487">PHPBB3-12487</a>] - Update PHP code</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12608">PHPBB3-12608</a>] - Improve notifications drop-down menu styling in header</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12654">PHPBB3-12654</a>] - Improve header search-box styling</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12681">PHPBB3-12681</a>] - Cache the compiled routes and dump the url_generator</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12719">PHPBB3-12719</a>] - Convert to Normalize &amp; SUITCSS - base for reset</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12745">PHPBB3-12745</a>] - Allow Emoji characters in posts</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12769">PHPBB3-12769</a>] - Add and use Font-Awesome to handle proSilver icons</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12821">PHPBB3-12821</a>] - Use CSS instead of images for gradients</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12958">PHPBB3-12958</a>] - Remove subsilver2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13063">PHPBB3-13063</a>] - Move functions_url_matcher to a proper class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13132">PHPBB3-13132</a>] - Twig: move the loops content from loops. to the root context</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13137">PHPBB3-13137</a>] - Remove schema.json from repository</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13178">PHPBB3-13178</a>] - Allow posting Emoji characters if the database supports it</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13206">PHPBB3-13206</a>] - DEBUG mode should automatically recompile stale style components</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13266">PHPBB3-13266</a>] - Enabling twig dump function if DEBUG is defined</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13388">PHPBB3-13388</a>] - Integrate routing and di parameters resolution</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13450">PHPBB3-13450</a>] - Type-hint return value of $phpbb_container-&gt;get()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13455">PHPBB3-13455</a>] - Change request_var() calls with $request-&gt;variable()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13468">PHPBB3-13468</a>] - Change add_log() calls with $phpbb_log-&gt;add()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13494">PHPBB3-13494</a>] - Replace set_config() calls with $config-&gt;set()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13496">PHPBB3-13496</a>] - Replace set_config_count() calls with $config-&gt;increment()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13497">PHPBB3-13497</a>] - Change get_tables() calls with $db_tools-&gt;sql_list_tables()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13498">PHPBB3-13498</a>] - Change get_user_avatar() calls with phpbb_get_avatar()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13499">PHPBB3-13499</a>] - Move get_remote_file() to functions_compatibility.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13595">PHPBB3-13595</a>] - Remove unused instances of the bbcode class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13614">PHPBB3-13614</a>] - Remove phpbb_pcre_utf8_support() and assume Unicode is supported by PCRE</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13652">PHPBB3-13652</a>] - Extend SQL query builder functionality</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13697">PHPBB3-13697</a>] - Rewriting/moving file system functions to filesystem class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13740">PHPBB3-13740</a>] - Refactoring installer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13762">PHPBB3-13762</a>] - Moving translation loading and language related functions into a service</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13770">PHPBB3-13770</a>] - Make DI Container builder constructor dependency free</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13789">PHPBB3-13789</a>] - Implement Googles noCAPTCHA reCAPTCHA</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13801">PHPBB3-13801</a>] - Decouple the user object from the text_formatter.s9e.parser service</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13803">PHPBB3-13803</a>] - Implement a generic and scalable way to reparse rich text</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13805">PHPBB3-13805</a>] - Make generate_text_for_storage() match the signature and feature set of message_parser::parse()</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13844">PHPBB3-13844</a>] - Replace help_ language magic with a help manager and normal language files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13847">PHPBB3-13847</a>] - Move quote generation to text_formatter.utils</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13891">PHPBB3-13891</a>] - Add CLI commands for reparsing text</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13901">PHPBB3-13901</a>] - Give quotes more whitespace in the posting form for readability</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13902">PHPBB3-13902</a>] - Increase the CSS margin around blockquote</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13904">PHPBB3-13904</a>] - Refactor attachment upload functions into service</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13921">PHPBB3-13921</a>] - Try harder to fix block elements BBCodes used inside of inline elements BBCodes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13946">PHPBB3-13946</a>] - Increase the CSS margin around [code] - and [list] -</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13970">PHPBB3-13970</a>] - Save the value of the optional parameter in [code] - BBCode</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13986">PHPBB3-13986</a>] - Add --resume option to reparser CLI</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13987">PHPBB3-13987</a>] - Add --dry-run option to reparser CLI</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14000">PHPBB3-14000</a>] - Make it possible to use emojis in posts</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14097">PHPBB3-14097</a>] - Catch and show all exceptions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14107">PHPBB3-14107</a>] - dropdown rendering on rtl</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14124">PHPBB3-14124</a>] - Automatically translate exception in CLI</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14139">PHPBB3-14139</a>] - stop styling IDs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14157">PHPBB3-14157</a>] - Allow administrators to set an alt attribute for topic icons</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14162">PHPBB3-14162</a>] - Add CLI commands to manage migrations</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14168">PHPBB3-14168</a>] - Refactor attachment management functions into classes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14174">PHPBB3-14174</a>] - issues in language\en\install_new.php </li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14175">PHPBB3-14175</a>] - Refactor responsive implementation for easier manipulation</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14206">PHPBB3-14206</a>] - Fix jumpbox incosistencies</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14220">PHPBB3-14220</a>] - Adding routing file locator and route loader services</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14231">PHPBB3-14231</a>] - Fix double home icon in breadcrumbs</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14237">PHPBB3-14237</a>] - Use language class in the notifications component</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14264">PHPBB3-14264</a>] - Don't use constants in textreparser plugins</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10165">PHPBB3-10165</a>] - Send test email feature on email settings ACP page</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11768">PHPBB3-11768</a>] - Integrate s9e\TextFormatter</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12516">PHPBB3-12516</a>] - Always preview signature in UCP/ACP module</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12620">PHPBB3-12620</a>] - Allow the user to define multiples environments</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12692">PHPBB3-12692</a>] - Add a console command to manage the thumbnail</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13329">PHPBB3-13329</a>] - Rely on Intl and mbstring, use patchwork/utf8 as fallback</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13641">PHPBB3-13641</a>] - problem with custom BBCode</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13961">PHPBB3-13961</a>] - Add orderable service collections</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14125">PHPBB3-14125</a>] - Add --env option to all CLI commands</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14158">PHPBB3-14158</a>] - Add a lang_array function to the language service to avoid using call_user_func</li>
+ </ul>
+ <h4>Sub-task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12577">PHPBB3-12577</a>] - Use a lazy service to delay the construction of the passwords_manager</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12581">PHPBB3-12581</a>] - Use the proxy pattern for the template lexer</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12632">PHPBB3-12632</a>] - Use a twig.debug environment config value to enable Twig debug</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12633">PHPBB3-12633</a>] - Add debug.template.events</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12699">PHPBB3-12699</a>] - Replace instances in the message textarea keydown callback</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13421">PHPBB3-13421</a>] - Create an interface for db\tools.php</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13487">PHPBB3-13487</a>] - Add factory for db tool class</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13645">PHPBB3-13645</a>] - Moving feeds to controllers</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13647">PHPBB3-13647</a>] - Move FAQ to controller</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13654">PHPBB3-13654</a>] - Moving reports to controller</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13881">PHPBB3-13881</a>] - Unify quote removal in 3.1 and 3.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13935">PHPBB3-13935</a>] - Allow more admin-configurable schemes in post links</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14039">PHPBB3-14039</a>] - Refactoring the updater</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14044">PHPBB3-14044</a>] - Deduplicate the installers</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9457">PHPBB3-9457</a>] - [Accessibility] - Add WAI-ARIA landmarks to the Prosilver template files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11528">PHPBB3-11528</a>] - Use mink for acceptance tests involving javascript execution</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12384">PHPBB3-12384</a>] - Run Travis CI HHVM tests against MySQLi instead of MySQL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12505">PHPBB3-12505</a>] - Remove outdated media handling in attachment.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12564">PHPBB3-12564</a>] - Remove obsolete version definitions from module info files</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12916">PHPBB3-12916</a>] - Add separate nightly builds for 3.1 and 3.2</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13130">PHPBB3-13130</a>] - Update dependencies to Symfony 2.5</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13139">PHPBB3-13139</a>] - Update Twig to 1.18.0</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13363">PHPBB3-13363</a>] - Replace phpbb\php\ini with composer package bantu/ini-get-wrapper</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13407">PHPBB3-13407</a>] - Update Symfony Components to 2.7.x</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13572">PHPBB3-13572</a>] - Upgrade composer to 1.0.0-alpha9</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13634">PHPBB3-13634</a>] - Update README to show new branch names</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13725">PHPBB3-13725</a>] - Coding guidelines: static public</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13767">PHPBB3-13767</a>] - Remove .git from vendor/s9e/text-formatter</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13768">PHPBB3-13768</a>] - Update to Symfony 2.8@dev</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13774">PHPBB3-13774</a>] - Update s9e\TextFormatter</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13777">PHPBB3-13777</a>] - Move acp/modules module handling code into a service</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13793">PHPBB3-13793</a>] - Remove message translation from exceptions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13800">PHPBB3-13800</a>] - Make extension manager an optional dependency for the router</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13804">PHPBB3-13804</a>] - Make template's user dependency optional</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13832">PHPBB3-13832</a>] - Replace use of deprecated e modifier of preg_replace in bbcode functions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13985">PHPBB3-13985</a>] - Update s9e\TextFormatter</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14015">PHPBB3-14015</a>] - Update Symfony to the latest 2.8@dev</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14053">PHPBB3-14053</a>] - Remove @covers annotations from installer config test</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14056">PHPBB3-14056</a>] - Keep install schema resources in the install folder</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14096">PHPBB3-14096</a>] - Update Symfony to the latest 2.8@dev</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14140">PHPBB3-14140</a>] - Update Symfony to benefit from improvement to the console component</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14150">PHPBB3-14150</a>] - Update fast-image-size to newest release</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14205">PHPBB3-14205</a>] - Bump PHP requirement to 5.4</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14238">PHPBB3-14238</a>] - Update Symfony to the latest 2.8@dev</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14243">PHPBB3-14243</a>] - Exclude every .git directory from the pakages</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14256">PHPBB3-14256</a>] - Remove PHP7 from the allowed failures</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14265">PHPBB3-14265</a>] - Make all tables available in the container</li>
+ </ul>
+
+ <a name="v3111"></a><h3>Changes since 3.1.11</h3>
+
+ <h4>Security Issue</h4>
+ <ul>
+ <li>[SECURITY-211] - URLs with javascript scheme should not be made clickable</li>
+ </ul>
+ <h4>Bug</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-9533">PHPBB3-9533</a>] - phpbb_own_realpath() doesn't always replicate realpath() behaviour</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-12835">PHPBB3-12835</a>] - Jump-box dropdown menu doesn't expand with according to line length in IE8</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13360">PHPBB3-13360</a>] - rename_too_long_indexes migration never deleted the old unique index</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13464">PHPBB3-13464</a>] - problem with drop down options and Arabic letters in chrome</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13574">PHPBB3-13574</a>] - Last post not showing in &quot;Active topics&quot; when Prosilver goes responsive</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15174">PHPBB3-15174</a>] - Unable to purge cache (ext &amp; acp)</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15285">PHPBB3-15285</a>] - Travis tests are failing due to trusty changes</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15303">PHPBB3-15303</a>] - Typo in memcached driver</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15347">PHPBB3-15347</a>] - Password updater in cron generates invalid postgres SQL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15367">PHPBB3-15367</a>] - Sphinx search backend doesn't escape special characters</li>
+ </ul>
+ <h4>Improvement</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10122">PHPBB3-10122</a>] - [list=] - should support &quot;none&quot;, along with CSS2 types</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11063">PHPBB3-11063</a>] - Change version check to SSL</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14820">PHPBB3-14820</a>] - Style Version Missing</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14919">PHPBB3-14919</a>] - Inconsistent use of globals vs class elements in acp_extensions</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14927">PHPBB3-14927</a>] - event core.user_add_modify_data</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14944">PHPBB3-14944</a>] - Add possibility to search for template loop indexes by key</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14995">PHPBB3-14995</a>] - Add ACP template events acp_ext_list_*_name_after</li>
+ </ul>
+ <h4>New Feature</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13344">PHPBB3-13344</a>] - Add new events for logging</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-15122">PHPBB3-15122</a>] - Support using memcached instead of memcache</li>
+ </ul>
+ <h4>Sub-task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11182">PHPBB3-11182</a>] - Ensure that template files use L_COLON instead of colons.</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-11676">PHPBB3-11676</a>] - generate_text_for_storage on includes/acp/acp_users.php</li>
+ </ul>
+ <h4>Task</h4>
+ <ul>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10758">PHPBB3-10758</a>] - Improve Functional Test Code Coverage</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10791">PHPBB3-10791</a>] - Add a section for extensions to readme.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-10792">PHPBB3-10792</a>] - Add a section for 3.0 to 3.1 upgrades to install.html</li>
+ <li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-13874">PHPBB3-13874</a>] - Add master to sami API docs</li>
+ </ul>
<a name="v3110"></a><h3>Changes since 3.1.10</h3>
@@ -560,7 +1877,6 @@
<li>[<a href="http://tracker.phpbb.com/browse/PHPBB3-14140">PHPBB3-14140</a>] - Update Symfony to benefit from improvement to the console component</li>
</ul>
-
<a name="v315"></a><h3>Changes since 3.1.5</h3>
<h4>Bug</h4>
diff --git a/phpBB/docs/CREDITS.txt b/phpBB/docs/CREDITS.txt
index 26ff8fcc80..596f4545fa 100644
--- a/phpBB/docs/CREDITS.txt
+++ b/phpBB/docs/CREDITS.txt
@@ -1,7 +1,7 @@
/**
*
-* phpBB © Copyright phpBB Limited 2003-2016
-* http://www.phpbb.com
+* phpBB © Copyright phpBB Limited 2003-2019
+* https://www.phpbb.com
*
* phpBB is free software. You can redistribute it and/or modify it
* under the terms of the GNU General Public License, version 2 (GPL-2.0)
@@ -20,15 +20,15 @@
phpBB Project Manager: Marshalrusty (Yuriy Rusko)
-phpBB Product Manager: naderman (Nils Adermann)
-
phpBB Lead Developer: Marc (Marc Alexander)
phpBB Developers: bantu (Andreas Fischer)
CHItA (Máté Bartus)
+ Derky (Derk Ruitenbeek)
Elsensee (Oliver Schramm)
+ Hanakin (Michael Miday)
Nicofuma (Tristan Darricau)
- prototech (Cesar Gallegos)
+ rubencm (Rubén Calvo)
For a list of phpBB Team members, please see:
http://www.phpbb.com/about/team/
@@ -41,7 +41,10 @@ https://github.com/phpbb/phpbb/graphs/contributors
phpBB Project Manager: theFinn (James Atkinson) [Founder - 04/2007]
SHS` (Jonathan Stanley)
-phpBB Lead Developer: Acyd Burn (Meik Sievertsen) [09/2005 - 01/2010]
+phpBB Product Manager: naderman (Nils Adermann) [02/2016 - 02/2017]
+
+phpBB Lead Developer: naderman (Nils Adermann) [01/2010 - 02/2016]
+ Acyd Burn (Meik Sievertsen) [09/2005 - 01/2010]
psoTFX (Paul S. Owen) [2001 - 09/2005]
phpBB Developers: A_Jelly_Doughnut (Josh Woody) [01/2010 - 11/2010]
@@ -59,8 +62,10 @@ phpBB Developers: A_Jelly_Doughnut (Josh Woody) [01/2010 - 11/2010]
igorw (Igor Wiedler) [08/2010 - 02/2013]
imkingdavid (David King) [11/2012 - 06/2014]
kellanved (Henry Sudhof) [04/2007 - 03/2011]
+ MichaelC (Michael Cullum) [11/2017 - 09/2019]
nickvergessen (Joas Schilling)[04/2010 - 12/2015]
Oleg (Oleg Pudeyev) [01/2011 - 05/2013]
+ prototech (Cesar Gallegos) [01/2014 - 12/2016]
rxu (Ruslan Uzdenov) [04/2010 - 12/2012]
TerraFrost (Jim Wigginton) [04/2009 - 01/2011]
ToonArmy (Chris Smith) [06/2008 - 11/2011]
@@ -75,9 +80,7 @@ Major contributions by: leviatan21 (Gabriel Vazquez)
Visual Confirmation: Xore (Robert Hetzler)
-Original subSilver by subBlue Design, Tom Beddard, (c) 2001 phpBB Limited
prosilver by subBlue Design, Tom Beddard, (c) 2004 phpBB Limited
-subsilver2 by subBlue Design, Tom Beddard, (c) 2004 phpBB Limited
phpBB contains code from the following applications:
@@ -99,4 +102,8 @@ Pear (c) 2001-2004 PHP Group, http://pear.php.net
Text_Diff-0.2.1 http://pear.php.net/package/Text_Diff
MIT licenced:
-Symfony2 (c) 2004-2011 Fabien Potencier, http://symfony.com/
+Symfony2 (c) 2004-2011 Fabien Potencier, https://symfony.com/
+Cookie Consent (c) 2015 Silktide Ltd, https://cookieconsent.insites.com
+
+Emoji by:
+Twemoji (c) 2018 Twitter, Inc, https://twemoji.twitter.com/
diff --git a/phpBB/docs/FAQ.html b/phpBB/docs/FAQ.html
index 5f3a425cda..09ee6c1ddd 100644
--- a/phpBB/docs/FAQ.html
+++ b/phpBB/docs/FAQ.html
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="" />
-<meta name="description" content="phpBB 3.1.x frequently asked questions" />
+<meta name="description" content="phpBB 3.2.x frequently asked questions" />
<title>phpBB &bull; FAQ</title>
<link href="assets/css/stylesheet.css" rel="stylesheet" type="text/css" media="screen" />
@@ -21,8 +21,8 @@
<div id="doc-description">
<a href="../index.php" id="logo"><img src="assets/images/site_logo.gif" alt="" /></a>
- <h1>phpBB 3.1.x FAQ</h1>
- <p>phpBB 3.1.x frequently asked questions</p>
+ <h1>phpBB 3.2.x FAQ</h1>
+ <p>phpBB 3.2.x frequently asked questions</p>
<p style="display: none;"><a href="#start_here">Skip</a></p>
</div>
@@ -249,7 +249,7 @@ I want to sue you because i think you host an illegal board!</h2>
<div class="content">
-<p>Please read the paragraph about permissions in our extensive <a href="https://www.phpbb.com/support/docs/en/3.1/ug/">online documentation</a>.</p>
+<p>Please read the paragraph about permissions in our extensive <a href="https://www.phpbb.com/support/docs/en/3.2/ug/">online documentation</a>.</p>
</div>
@@ -305,7 +305,7 @@ I want to sue you because i think you host an illegal board!</h2>
<div class="content">
-<p>Please read our <a href="https://www.phpbb.com/support/docs/en/3.1/ug/">extensive user documentation</a> first, it may just explain what you want to know.</p>
+<p>Please read our <a href="https://www.phpbb.com/support/docs/en/3.2/ug/">extensive user documentation</a> first, it may just explain what you want to know.</p>
<p>Feel free to search our community forum for the information you require. <strong>PLEASE DO NOT</strong> post your question without having first used search, chances are someone has already asked and answered your question. You can find our board here:</p>
diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html
index 19644327c2..4f7f07d3dc 100644
--- a/phpBB/docs/INSTALL.html
+++ b/phpBB/docs/INSTALL.html
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="" />
-<meta name="description" content="phpBB 3.1.x Installation, updating and conversion informations" />
+<meta name="description" content="phpBB 3.2.x Installation, updating and conversion informations" />
<title>phpBB &bull; Install</title>
<link href="assets/css/stylesheet.css" rel="stylesheet" type="text/css" media="screen" />
@@ -21,8 +21,8 @@
<div id="doc-description">
<a href="../index.php" id="logo"><img src="assets/images/site_logo.gif" alt="" /></a>
- <h1>phpBB 3.1.x Install</h1>
- <p>phpBB 3.1.x Installation, updating and conversion informations</p>
+ <h1>phpBB 3.2.x Install</h1>
+ <p>phpBB 3.2.x Installation, updating and conversion informations</p>
<p style="display: none;"><a href="#start_here">Skip</a></p>
</div>
@@ -44,7 +44,7 @@
<p>
A basic overview of running phpBB can be found in the accompanying <a href="README.html">README</a> file.
Please ensure you read that document in addition to this! For more detailed information on using, installing,
- updating and converting phpBB you should read <a href="https://www.phpbb.com/support/docs/en/3.1/ug/">the documentation</a>
+ updating and converting phpBB you should read <a href="https://www.phpbb.com/support/docs/en/3.2/ug/">the documentation</a>
available online.
</p>
</div>
@@ -59,7 +59,7 @@
<li><a href="#quickinstall">Quick install</a></li>
<li><a href="#require">Requirements</a></li>
<li><a href="#install">New installation</a></li>
- <li><a href="#update">Updating from stable releases of phpBB 3.1.x</a>
+ <li><a href="#update">Updating from stable releases of phpBB 3.2.x</a>
<ol style="list-style-type: lower-roman;">
<li><a href="#update_full">Full package</a></li>
<li><a href="#update_files">Changed files</a></li>
@@ -68,8 +68,8 @@
<li><a href="#update_all">All package types</a></li>
</ol>
</li>
- <li><a href="#update30">Updating from phpBB 3.0.x to phpBB 3.1.x</a></li>
- <li><a href="#convert">Conversion from phpBB 2.0.x to phpBB 3.1.x</a>
+ <li><a href="#update30_31">Updating from phpBB 3.0.x/3.1.x to phpBB 3.2.x</a></li>
+ <li><a href="#convert">Conversion from phpBB 2.0.x to phpBB 3.2.x</a>
<ol style="list-style-type: lower-roman;">
<li><a href="#prereq">Requirements before converting</a></li>
<li><a href="#conversion">Converting</a></li>
@@ -109,7 +109,7 @@
<li>Change the permissions on config.php to be writable by all (666 or -rw-rw-rw- within your FTP Client)</li>
<li>Change the permissions on the following directories to be writable by all (777 or -rwxrwxrwx within your FTP Client):<br />
<code>store/</code>, <code>cache/</code>, <code>files/</code> and <code>images/avatars/upload/</code>.</li>
- <li>Point your web browser to the location where you uploaded the phpBB3 files with the addition of <code>install/index.php</code> or simply <code>install/</code>, e.g. <code>http://www.example.com/phpBB3/install/index.php</code>, <code>http://www.example.com/forum/install/</code>.</li>
+ <li>Point your web browser to the location where you uploaded the phpBB3 files with the addition of <code>install/app.php</code> or simply <code>install/</code>, e.g. <code>http://www.example.com/phpBB3/install/app.php</code>, <code>http://www.example.com/forum/install/</code>.</li>
<li>Click the <strong><em>INSTALL</em></strong> tab, follow the steps and fill out all the requested information.</li>
<li>Change the permissions on config.php to be writable only by yourself (644 or -rw-r--r-- within your FTP Client)</li>
<li>phpBB3 should now be available, please <strong>MAKE SURE</strong> you read at least <a href="#postinstall">Section 6</a> below for important, security related post-installation instructions, and also take note of <a href="#anti_spam">Section 7</a> regarding anti-spam measures.</li>
@@ -133,7 +133,7 @@
<div class="content">
- <p>phpBB 3.1.x has a few requirements which must be met before you are able to install and use it.</p>
+ <p>phpBB 3.2.x has a few requirements which must be met before you are able to install and use it.</p>
<ul>
<li>A webserver or web hosting account running on any major Operating System with support for PHP</li>
@@ -142,13 +142,12 @@
<li>MySQL 3.23 or above (MySQLi supported)</li>
<li>MariaDB 5.1 or above</li>
<li>PostgreSQL 8.3+</li>
- <li>SQLite 2.8.2+</li>
<li>SQLite 3.6.15+</li>
- <li>MS SQL Server 2000 or above (directly or via ODBC or the native adapter)</li>
+ <li>MS SQL Server 2000 or above (via ODBC or the native adapter)</li>
<li>Oracle</li>
</ul>
</li>
- <li><strong>PHP 5.3.3+</strong> and <strong>PHP &lt; 7.0</strong> with support for the database you intend to use.</li>
+ <li><strong>PHP 5.4.7+</strong> but less than <strong>PHP 7.3</strong> with support for the database you intend to use.</li>
<li>The following PHP modules are required:
<ul>
<li>json</li>
@@ -160,13 +159,12 @@
<li>zlib Compression support</li>
<li>Remote FTP support</li>
<li>XML support</li>
- <li>ImageMagick support</li>
<li>GD Support</li>
</ul>
</li>
</ul>
- <p>If your server or hosting account does not meet the requirements above then you will be unable to install phpBB 3.1.x.</p>
+ <p>If your server or hosting account does not meet the requirements above then you will be unable to install phpBB 3.2.x.</p>
</div>
@@ -192,7 +190,7 @@
<p>phpBB comes supplied with British English as its standard language. However, a number of separate packs for different languages are available. If you are not a native English speaker you may wish to install one or more of these packages before continuing. The installation process below will allow you to select a default language from those available (you can, of course, change this default at a later stage). For more details on language packs, where to obtain them and how to install them please see the <a href="README.html#i18n">README</a>.</p>
- <p>Once all the files have been uploaded to your site, you should point your browser at this location with the addition of <code>/install/</code>. For example, if your domain name is <code>www.example.com</code> and you placed the phpBB files in the directory <code>/phpBB3</code> off your web root you would enter <code>http://www.example.com/phpBB3/install/</code> or (alternatively) <code>http://www.example.com/phpBB3/install/index.php</code> into your browser. When you have done this, you should see the <strong><em>phpBB Introduction</em></strong> screen appear.</p>
+ <p>Once all the files have been uploaded to your site, you should point your browser at this location with the addition of <code>/install/</code>. For example, if your domain name is <code>www.example.com</code> and you placed the phpBB files in the directory <code>/phpBB3</code> off your web root you would enter <code>http://www.example.com/phpBB3/install/</code> or (alternatively) <code>http://www.example.com/phpBB3/install/app.php</code> into your browser. When you have done this, you should see the <strong><em>phpBB Introduction</em></strong> screen appear.</p>
<h4>Introduction:</h4>
@@ -257,7 +255,7 @@
<hr />
- <a name="update"></a><h2>4. Updating from stable releases of phpBB 3.1.x</h2>
+ <a name="update"></a><h2>4. Updating from stable releases of phpBB 3.2.x</h2>
<div class="paragraph">
<div class="inner">
@@ -266,45 +264,45 @@
<p>If you are currently using a stable release of phpBB, updating to this version is straightforward. You would have downloaded one of four packages and your choice determines what you need to do. <strong>Note</strong>: Before updating, we heavily recommend you do a <em>full backup of your database and existing phpBB files</em>! If you are unsure how to achieve this please ask your hosting provider for advice.</p>
-<p><strong>Please make sure you update your phpBB source files too, even if you run the <code>database_update.php</code> file.</strong> If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
+<p><strong>Please make sure you update your phpBB source files too, even if you just run the database updater.</strong> If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
<a name="update_full"></a><h3>4.i. Full package</h3>
- <p>The full package is normally meant for new installations only, but if you want to replace all source files, this package comes in handy.</p>
+ <p>Updating using the full package is the recommended update method for boards without modifications to core phpBB files.</p>
- <p>First, you should make a copy of your existing <code>config.php</code> file; keep it in a safe place! Next, delete all the existing phpBB files, you may want to leave your <code>files/</code> and <code>images/</code> directories in place. You can leave alternative styles in place too. With this complete, you can upload the new phpBB files (see <a href="#install">New installation</a> for details if necessary). Once complete, copy back your saved <code>config.php</code>, replacing the new one. Another method is to just <strong>replace</strong> the existing files with the files from the full package - though make sure you do <strong>not</strong> overwrite your config.php file.</p>
+ <p>First, you should make a copy of your existing <code>config.php</code> file; keep it in a safe place! Next, delete all the existing phpBB files, you should leave your <code>files/</code>, <code>images/</code> and <code>ext/</code> directories in place, otherwise you will lose your file attachments, uploaded images and get errors due to missing extension files. You can leave alternative styles in place too. With this complete, you can upload the new phpBB files (see <a href="#install">New installation</a> for details if necessary). Once complete, copy back your saved <code>config.php</code>, replacing the new one. Another method is to just <strong>replace</strong> the existing files with the files from the full package - though make sure you do <strong>not</strong> overwrite your config.php file.</p>
- <p>You should now run <code>install/database_update.php</code> which, depending on your previous version, will make a number of database changes. You may receive <em>FAILURES</em> during this procedure. They should not be a cause for concern unless you see an actual <em>ERROR</em>, in which case the script will stop (in this case you should seek help via our forums or bug tracker). If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
+ <p>You should now got to <code>/install/app.php/update</code> which will display a warning: <strong>No valid update directory was found, please make sure you uploaded the relevant files</strong>. Beneath that warning you will see a radio button <em>Update database only</em>, just click <strong>Submit</strong>. Depending on your previous version this will make a number of database changes. You may receive <em>FAILURES</em> during this procedure. They should not be a cause for concern unless you see an actual <em>ERROR</em>, in which case the script will stop (in this case you should seek help via our forums or bug tracker). If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
- <p>Once <code>install/database_update.php</code> has completed, you may proceed to the Administration Control Panel and then remove the install directory as advised.</p>
+ <p>Once <code>/install/app.php/update</code> has completed, it displays the success message: <strong>The database update was successful</strong>. You may proceed to the Administration Control Panel and then remove the install directory as advised.</p>
<a name="update_files"></a><h3>4.ii. Changed files</h3>
<p>This package is meant for those wanting to only replace the files that were changed between a previous version and the latest version.</p>
- <p>This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have <strong>3.1.0</strong> you should select the appropriate <code>phpBB-3.1.1-files.zip/tar.bz2</code> file.</p>
+ <p>This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have <strong>3.2.0</strong> you should select the appropriate <code>phpBB-3.2.1-files.zip/tar.bz2</code> file.</p>
<p>The directory structure has been preserved, enabling you (if you wish) to simply upload the uncompressed contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any modifications (MODs) these files will overwrite the originals, possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.</p>
- <p>As for the other update procedures, you should run <code>install/database_update.php</code> after you have finished updating the files. This will update your database schema and increment the version number. If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
+ <p>As for the other update procedures, you should go to <code>/install/app.php/update</code>, select "Update database only" and submit the page after you have finished updating the files. This will update your database schema and increment the version number. If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
<a name="update_patch"></a><h3>4.iii. Patch file</h3>
<p>The patch file package is for those wanting to update through the patch application, and should only be used by those who are comfortable with it.</p>
- <p>The patch file is one solution for those with many Modifications (MODs) or other changes and do not want to re-add them back to all the changed files. To use this you will need command line access to a standard UNIX type <strong>patch</strong> application. If you do not have access to such an application, but still want to use this update approach, we strongly recommend the <a href="#update_auto">Automatic update package</a> explained below. It is also the recommended update method.</p>
+ <p>The patch file is one solution for those with changes in to the phpBB core files and do not want to re-add them back to all the changed files. To use this you will need command line access to a standard UNIX type <strong>patch</strong> application. If you do not have access to such an application, but still want to use this update approach, we strongly recommend the <a href="#update_auto">Automatic update package</a> explained below. It is also the recommended update method.</p>
- <p>A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is <strong>3.1.0</strong>, you need the <code>phpBB-3.1.1-patch.zip/tar.bz2</code> file. Place the correct patch in the parent directory containing the phpBB core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: <code>patch -cl -d [PHPBB DIRECTORY] -p1 &lt; [PATCH NAME]</code> (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.</p>
+ <p>A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is <strong>3.2.0</strong>, you need the <code>phpBB-3.2.1-patch.zip/tar.bz2</code> file. Place the correct patch in the parent directory containing the phpBB core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: <code>patch -cl -d [PHPBB DIRECTORY] -p1 &lt; [PATCH NAME]</code> (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.</p>
<p>If you do get failures, you should look at using the <a href="#update_files">Changed Files</a> package to replace the files which failed to patch. Please note that you will need to manually re-add any MODs to these particular files. Alternatively, if you know how, you can examine the .rej files to determine what failed where and make manual adjustments to the relevant source.</p>
- <p>You should, of course, delete the patch file (or files) after use. As for the other update procedures, you should run <code>install/database_update.php</code> after you have finished updating the files. This will update your database schema and data (if appropriate) and increment the version number. If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
+ <p>You should, of course, delete the patch file (or files) after use. As for the other update procedures, you should navigate to <code>/install/app.php/update</code>, select "Update database only" and submit the page after you have finished updating the files. This will update your database schema and data (if appropriate) and increment the version number. If you have shell access to your server, you may wish to update via the command line interface. From your board's root, execute the following command: <code>php bin/phpbbcli.php --safe-mode db:migrate</code>.</p>
<a name="update_auto"></a><h3>4.iv. Automatic update package</h3>
- <p>This update method is the recommended method for updating. This package detects changed files automatically and merges in changes if needed.</p>
+ <p>This update method is only recommended for installations with modifications to core phpBB files. This package detects changed files automatically and merges in changes if needed.</p>
- <p>The automatic update package will update the board from a given version to the latest version. A number of automatic update files are available, and you should choose the one that corresponds to the version of the board that you are currently running. For example, if your current version is <strong>3.1.5</strong>, you need the <code>phpBB-3.1.5_to_3.1.6.zip/tar.bz2</code> file.</p>
+ <p>The automatic update package will update the board from a given version to the latest version. A number of automatic update files are available, and you should choose the one that corresponds to the version of the board that you are currently running. For example, if your current version is <strong>3.2.0</strong>, you need the <code>phpBB-3.2.0_to_3.2.1.zip/tar.bz2</code> file.</p>
<p>To perform the update, either follow the instructions from the <strong>Administration Control Panel-&gt;System</strong> Tab - this should point out that you are running an outdated version and will guide you through the update - or follow the instructions listed below.</p>
@@ -322,7 +320,7 @@
<p>If you have non-English language packs installed, you may want to see if a new version has been made available. A number of missing strings may have been added which, though not essential, may be beneficial to users. Please note that at this time not all language packs have been updated so you should be prepared to periodically check for updates.</p>
- <p>These update methods will only update the standard styles, <code>prosilver</code> and <code>subsilver2</code>, any other styles you have installed for your board will usually also need to be updated.</p>
+ <p>These update methods will only update the standard style <code>prosilver</code>, any other styles you have installed for your board will usually also need to be updated.</p>
</div>
@@ -333,16 +331,16 @@
<hr />
- <a name="update30"></a><h2>5. Updating from phpBB 3.0.x to phpBB 3.1.x</h2>
+ <a name="update30_31"></a><h2>5. Updating from phpBB 3.0.x/3.1x to phpBB 3.2.x</h2>
<div class="paragraph">
<div class="inner"><span class="corners-top"><span></span></span>
<div class="content">
- <p>Updating from phpBB 3.0.x to 3.1.x is just the same as <a href="#update">updating from stable releases of phpBB 3.1.x</a></p>
+ <p>Updating from phpBB 3.0.x or 3.1.x to 3.2.x is just the same as <a href="#update">updating from stable releases of phpBB 3.2.x</a></p>
- <p>However you can also start with a new set of phpBB 3.1.x files.</p>
+ <p>However you can also start with a new set of phpBB 3.2.x files.</p>
<ol>
<li>Delete all files <strong>EXCEPT</strong> for the following:
@@ -352,10 +350,12 @@
<li>The <code>images/</code> directory</li>
<li>The <code>files/</code> directory</li>
<li>The <code>store/</code> directory</li>
+ <li>(The <code>ext/</code> directory</li>
</ul></li>
- <li>Upload the contents of the 3.1.x Full Package into your forum's directory. Make sure the root level .htaccess file is included in the upload.</li>
- <li>Browse to install/database_update.php</li>
+ <li>Upload the contents of the 3.2.x Full Package into your forum's directory. Make sure the root level .htaccess file is included in the upload.</li>
+ <li>Browse to <code>/install/app.php/update</code></li>
+ <li>Read the notice <em>Update database only</em> and press <strong>Submit</strong></li>
<li>Delete the <code>install/</code> directory</li>
</ol>
</div>
@@ -367,7 +367,7 @@
<hr />
- <a name="convert"></a><h2>6. Conversion from phpBB 2.0.x to phpBB 3.1.x</h2>
+ <a name="convert"></a><h2>6. Conversion from phpBB 2.0.x to phpBB 3.2.x</h2>
<div class="paragraph">
<div class="inner">
diff --git a/phpBB/docs/README.html b/phpBB/docs/README.html
index 38f74c199a..8fb9036ad8 100644
--- a/phpBB/docs/README.html
+++ b/phpBB/docs/README.html
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="" />
-<meta name="description" content="phpBB 3.1.x Readme" />
+<meta name="description" content="phpBB 3.2.x Readme" />
<title>phpBB &bull; Readme</title>
<link href="assets/css/stylesheet.css" rel="stylesheet" type="text/css" media="screen" />
@@ -21,7 +21,7 @@
<div id="doc-description">
<a href="../index.php" id="logo"><img src="assets/images/site_logo.gif" alt="" /></a>
- <h1>phpBB 3.1.x Readme</h1>
+ <h1>phpBB 3.2.x Readme</h1>
<p style="display: none;"><a href="#start_here">Skip</a></p>
</div>
@@ -91,24 +91,23 @@
<div class="content">
<p>Installation, update and conversion instructions can be found in the <a href="INSTALL.html">INSTALL</a> document in this directory. If you are intending on converting from a phpBB 2.0.x or 3.0.x installation we highly recommend that you backup any existing data before proceeding!</p>
- <p>Users of phpBB 3.0 and 3.1 Beta versions cannot directly update.</p>
+ <p>Users of phpBB 3.0, 3.1 and 3.2 Beta versions cannot directly update.</p>
<p>Please note that we don't support the following installation types:</p>
<ul>
- <li>Updates from phpBB 3.0 Beta versions to phpBB 3.0 RC1 and higher</li>
- <li>Updates from phpBB 3.1 Beta versions to phpBB 3.1 RC1 and higher</li>
- <li>Conversions from phpBB 2.0.x to phpBB 3.0 or 3.1 Beta versions</li>
- <li>phpBB 3.0 or 3.1 Beta installations</li>
+ <li>Updates from phpBB Beta versions and lower to phpBB Release Candidates and higher</li>
+ <li>Conversions from phpBB 2.0.x to phpBB 3.0 Beta, 3.1 Beta and 3.2 Beta versions</li>
+ <li>phpBB 3.0 Beta, 3.1 Beta or 3.2 beta installations</li>
</ul>
<p>We give support for the following installation types:</p>
<ul>
- <li>Updates from phpBB 3.0 RC1 and 3.1 RC1 to the latest version</li>
+ <li>Updates from phpBB 3.0 RC1, 3.1 RC1 and 3.2 RC1 to the latest version</li>
<li>Note: if using the <em>Automatic Update Package</em>, updates are supported from phpBB 3.0.2 onward. To update a pre-3.0.2 installation, first update to 3.0.2 and then update to the current version.</li>
<li>Conversions from phpBB 2.0.x to the latest version</li>
- <li>New installations of phpBB 3.0.x - only the latest released version</li>
<li>New installations of phpBB 3.1.x - only the latest released version</li>
+ <li>New installations of phpBB 3.2.x - only the latest released version</li>
</ul>
</div>
@@ -131,7 +130,7 @@
<a name="i18n"></a><h3>2.i. Languages (Internationalisation - i18n)</h3>
- <p>A number of language packs with included style localisations are available. You can find them listed in the <a href="https://www.phpbb.com/languages/">Language Packs</a> pages of our downloads section or from the <a href="https://www.phpbb.com/customise/db/language_packs-25/">Language Packs</a> section of the <a href="https://www.phpbb.com/customise/db/">Customisation Database</a>.</p>
+ <p>A number of language packs with included style localisations are available. You can find them listed in the <a href="https://www.phpbb.com/languages/">Language Packs</a> pages of our downloads section or from the <a href="https://www.phpbb.com/customise/db/language_packs-25">Language Packs</a> section of the <a href="https://www.phpbb.com/customise/db/">Customisation Database</a>.</p>
<p>For more information about language packs, please see: <a href="https://www.phpbb.com/languages/">https://www.phpbb.com/languages/</a></p>
@@ -139,7 +138,7 @@
<p>Installation of these packages is straightforward: simply download the required language pack, uncompress (unzip) it and via FTP transfer the included <code>language</code> and <code>styles</code> folders to the root of your board installation. The language can then be installed via the Administration Control Panel of your board: <code>Customise tab -&gt; Language management -&gt; Language packs</code>. A more detailed description of the process is in the Knowledge Base article, <a href="https://www.phpbb.com/kb/article/how-to-install-a-language-pack/">How to Install a Language Pack</a>.</p>
- <p>If your language is not available, please visit our <a href="https://www.phpbb.com/community/viewforum.php?f=491">[3.1.x] Translations</a> forum where you will find topics on translations in progress. Should you wish to volunteer to translate a language not currently available or assist in maintaining an existing language pack, you can <a href="https://www.phpbb.com/languages/apply.php">Apply to become a translator</a>.</p>
+ <p>If your language is not available, please visit our <a href="https://www.phpbb.com/community/viewforum.php?f=566">[3.2.x] Translations</a> forum where you will find topics on translations in progress. Should you wish to volunteer to translate a language not currently available or assist in maintaining an existing language pack, you can <a href="https://www.phpbb.com/languages/apply.php">Apply to become a translator</a>.</p>
<a name="styles"></a><h3>2.ii. Styles</h3>
@@ -185,7 +184,7 @@
<p>Comprehensive documentation is now available on the phpBB website:</p>
- <p><a href="https://www.phpbb.com/support/docs/en/3.1/ug/">https://www.phpbb.com/support/docs/en/3.1/ug/</a></p>
+ <p><a href="https://www.phpbb.com/support/docs/en/3.2/ug/">https://www.phpbb.com/support/docs/en/3.2/ug/</a></p>
<p>This covers everything from installation to setting permissions and managing users.</p>
@@ -225,7 +224,7 @@
<div class="content">
- <p>This is a stable release of phpBB. The 3.1.x line is feature frozen, with point releases principally including fixes for bugs and security issues. Feature alterations and minor feature additions may be done if deemed absolutely required. The next major release will be phpBB 3.2 which is currently under development. Please do not post questions asking when 3.2 will be available, no release date has been set.</p>
+ <p>This is a stable release of phpBB. The 3.2.x line is feature frozen, with point releases principally including fixes for bugs and security issues. Feature alterations and minor feature additions may be done if deemed absolutely required. The next major release will be phpBB 3.3 which is currently under development. Please do not post questions asking when 3.3 will be available, no release date has been set.</p>
<p>Those interested in the development of phpBB should keep an eye on the development forums to see how things are progressing:</p>
@@ -266,15 +265,15 @@
<ul>
<li>Your server type/version, e.g. Apache 2.2.3, IIS 7, Sambar, etc.</li>
- <li>PHP version and mode of operation, e.g. PHP 5.3.3 as a module, PHP 5.4.0 running as CGI, etc.</li>
- <li>DB type/version, e.g. MySQL 5.0.77, PostgreSQL 9.0.6, MSSQL Server 2000 SP1, etc.</li>
+ <li>PHP version and mode of operation, e.g. PHP 5.4.0 as a module, PHP 5.4.0 running as CGI, etc.</li>
+ <li>DB type/version, e.g. MySQL 5.0.77, PostgreSQL 9.0.6, MSSQL Server 2000 (via ODBC), etc.</li>
</ul>
<p>The relevant database type/version is listed within the administration control panel.</p>
<p>Please be as detailed as you can in your report, and if possible, list the steps required to duplicate the problem. If you have a patch that fixes the issue, please attach it to the ticket or submit a pull request to our repository <a href="https://github.com/phpbb/phpbb">on GitHub</a>.</p>
- <p>If you create a patch, it is very much appreciated (but not required) if you follow the phpBB coding guidelines. Please note that the coding guidelines are somewhat different between different versions of phpBB. For phpBB 3.1.x the coding guidelines may be found here: <a href="http://area51.phpbb.com/docs/31x/coding-guidelines.html">http://area51.phpbb.com/docs/31x/coding-guidelines.html</a></p>
+ <p>If you create a patch, it is very much appreciated (but not required) if you follow the phpBB coding guidelines. Please note that the coding guidelines are somewhat different between different versions of phpBB. For phpBB 3.2.x the coding guidelines may be found here: <a href="http://area51.phpbb.com/docs/32x/coding-guidelines.html">http://area51.phpbb.com/docs/32x/coding-guidelines.html</a></p>
<p>Once a bug has been submitted you will be emailed any follow up comments added to it. <strong>Please</strong> if you are requested to supply additional information, do so! It is frustrating for us to receive bug reports, ask for additional information but get nothing. In these cases we have a policy of closing the bug, which may leave a very real problem in place. Obviously we would rather not have this situation arise.</p>
@@ -324,11 +323,11 @@
<div class="content">
- <p>phpBB 3.1.x takes advantage of new features added in PHP 5.3. We recommend that you upgrade to the latest stable release of PHP5 to run phpBB. The minimum version required is PHP 5.3.3 and the maximum supported version is any version prior to PHP 7.0.</p>
+ <p>phpBB 3.2.x takes advantage of new features added in PHP 5.4. We recommend that you upgrade to the latest stable release of PHP to run phpBB. The minimum version required is PHP 5.4.7 and the maximum supported version is the latest stable version of PHP.</p>
<p>Please remember that running any application on a development (unstable, e.g. a beta release) version of PHP can lead to strange/unexpected results which may appear to be bugs in the application. Therefore, we recommend you upgrade to the newest stable version of PHP before running phpBB. If you are running a development version of PHP please check any bugs you find on a system running a stable release before submitting.</p>
- <p>This board has been developed and tested under Linux and Windows (amongst others) running Apache using MySQL 3.23, 4.x, 5.x, MariaDB 5.x, MSSQL Server 2000, PostgreSQL 8.x, Oracle 8, SQLite 2 and SQLite 3. Versions of PHP used range from 5.3.x to 5.4.x without problem.</p>
+ <p>This board has been developed and tested under Linux and Windows (amongst others) running Apache using MySQL 3.23, 4.x, 5.x, MariaDB 5.x, PostgreSQL 8.x, Oracle 8 and SQLite 3. Versions of PHP used range from 5.4.7 above 5.6.x to 7.1.x and 7.2.x without problem.</p>
<a name="phpsec"></a><h3>7.i. Notice on PHP security issues</h3>
diff --git a/phpBB/docs/coding-guidelines.html b/phpBB/docs/coding-guidelines.html
index 56b71006c7..569ffe680c 100644
--- a/phpBB/docs/coding-guidelines.html
+++ b/phpBB/docs/coding-guidelines.html
@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="keywords" content="" />
-<meta name="description" content="Ascraeus coding guidelines document" />
+<meta name="description" content="Rhea coding guidelines document" />
<title>phpBB3 &bull; Coding Guidelines</title>
<link href="assets/css/stylesheet.css" rel="stylesheet" type="text/css" media="screen" />
@@ -22,7 +22,7 @@
<div id="doc-description">
<a href="../index.php" id="logo"><img src="assets/images/site_logo.gif" alt="" /></a>
<h1>Coding Guidelines</h1>
- <p>Ascraeus coding guidelines document</p>
+ <p>Rhea coding guidelines document</p>
<p style="display: none;"><a href="#start_here">Skip</a></p>
</div>
@@ -37,7 +37,7 @@
<!-- BEGIN DOCUMENT -->
<p class="paragraph main-description">
- These are the phpBB Coding Guidelines for Ascraeus, all attempts should be made to follow them as closely as possible.
+ These are the phpBB Coding Guidelines for Rhea, all attempts should be made to follow them as closely as possible.
</p>
<h1>Coding Guidelines</h1>
@@ -627,7 +627,7 @@ $min = ($i &lt; $j) ? $i : $j;</pre>
<pre>if (isset($forum) &amp;&amp; $forum == 5)</pre>
</div>
- <p>The <code>empty()</code> function is useful if you want to check if a variable is not set or being empty (an empty string, 0 as an integer or string, NULL, false, an empty array or a variable declared, but without a value in a class). Therefore empty should be used in favor of <code>isset($array) &amp;&amp; sizeof($array) &gt; 0</code> - this can be written in a shorter way as <code>!empty($array)</code>.</p>
+ <p>The <code>empty()</code> function is useful if you want to check if a variable is not set or being empty (an empty string, 0 as an integer or string, NULL, false, an empty array or a variable declared, but without a value in a class). Therefore empty should be used in favor of <code>isset($array) &amp;&amp; count($array) &gt; 0</code> - this can be written in a shorter way as <code>!empty($array)</code>.</p>
<h4>Switch statements:</h4>
<p>Switch/case code blocks can get a bit long sometimes. To have some level of notice and being in-line with the opening/closing brace requirement (where they are on the same line for better readability), this also applies to switch/case code blocks and the breaks. An example:</p>
@@ -994,9 +994,9 @@ $sql = $db-&gt;sql_build_query('SELECT', $sql_array);</pre>
<h4>Operations in loop definition: </h4>
<p>Always try to optimize your loops if operations are going on at the comparing part, since this part is executed every time the loop is parsed through. For assignments a descriptive name should be chosen. Example:</p>
- <p class="bad">// On every iteration the sizeof function is called</p>
+ <p class="bad">// On every iteration the count function is called</p>
<div class="codebox"><pre>
-for ($i = 0; $i &lt; sizeof($post_data); $i++)
+for ($i = 0; $i &lt; count($post_data); $i++)
{
do_something();
}</pre>
@@ -1004,7 +1004,7 @@ for ($i = 0; $i &lt; sizeof($post_data); $i++)
<p class="good">// You are able to assign the (not changing) result within the loop itself</p>
<div class="codebox"><pre>
-for ($i = 0, $size = sizeof($post_data); $i &lt; $size; $i++)
+for ($i = 0, $size = count($post_data); $i &lt; $size; $i++)
{
do_something();
}</pre>
@@ -1184,8 +1184,8 @@ append_sid(&quot;{$phpbb_root_path}memberlist.$phpEx&quot;, 'mode=group&amp;amp;
# General Information about this style
name = prosilver_duplicate
copyright = © phpBB Limited, 2007
-style_version = 3.1.0
-phpbb_version = 3.1.0
+style_version = 3.2.0
+phpbb_version = 3.2.0
# Defining a different template bitfield
# template_bitfield = lNg=
@@ -1674,8 +1674,8 @@ div
# General Information about this style
name = Custom Style
copyright = © phpBB Limited, 2007
-style_version = 3.1.0-b1
-phpbb_version = 3.1.0-b1
+style_version = 3.2.0-b1
+phpbb_version = 3.2.0-b1
# Defining a different template bitfield
# template_bitfield = lNg=
@@ -1722,7 +1722,7 @@ This may span multiple lines.
+ first/file/path.html
+ second/file/path.html
* Purpose: Same as above.
-* Since: 3.1.0-b1
+* Since: 3.2.0-b1
</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
@@ -1731,7 +1731,7 @@ This may span multiple lines.
+ first/file/path.html (2)
+ second/file/path.html
* Purpose: Same as above.
-* Since: 3.1.0-b1
+* Since: 3.2.0-b1
</pre></div></li>
<li>An actual example event documentation:
<div class="codebox"><pre>forumlist_body_last_post_title_prepend
@@ -1740,7 +1740,7 @@ This may span multiple lines.
+ 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.
-* Since: 3.1.0-a1
+* Since: 3.2.0-a1
</pre></div></ul><br />
</div>
@@ -2387,7 +2387,7 @@ if (utf8_case_fold_nfc($string1) == utf8_case_fold_nfc($string2))
You have <code>[1/21/31] slon</code>, <code>[2/3/4] slona</code>, <code>[0/5/6] slonova</code> and <code>[7/8/9/11] ...</code> and some more difficult rules.
</p>
- <p>The <a href="https://wiki.phpbb.com/Plural_Rules">plural system</a> takes care of this and can be used as follows:</p>
+ <p>The <a href="https://area51.phpbb.com/docs/dev/32x/language/plurals.html">plural system</a> takes care of this and can be used as follows:</p>
<p>The PHP code will basically look like this:</p>
diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md
index 417666c09e..bfe26b4951 100644
--- a/phpBB/docs/events.md
+++ b/phpBB/docs/events.md
@@ -28,29 +28,29 @@ acp_bbcodes_edit_fieldsets_after
* Since: 3.1.0-a3
* Purpose: Add settings to BBCode add/edit form
-acp_email_group_options_append
+acp_email_find_username_append
===
* Location: adm/style/acp_email.html
* Since: 3.1.7-RC1
-* Purpose: Add content at the end of the group options select box
+* Purpose: Add content at the end of the find username link
-acp_email_group_options_prepend
+acp_email_find_username_prepend
===
* Location: adm/style/acp_email.html
* Since: 3.1.7-RC1
-* Purpose: Add content at the start of the group options select box
+* Purpose: Add content at the start of the find username link
-acp_email_find_username_append
+acp_email_group_options_append
===
* Location: adm/style/acp_email.html
* Since: 3.1.7-RC1
-* Purpose: Add content at the end of the fimd username link
+* Purpose: Add content at the end of the group options select box
-acp_email_find_username_prepend
+acp_email_group_options_prepend
===
* Location: adm/style/acp_email.html
* Since: 3.1.7-RC1
-* Purpose: Add content at the start of the fimd username link
+* Purpose: Add content at the start of the group options select box
acp_email_options_after
===
@@ -160,17 +160,29 @@ acp_forums_rules_settings_prepend
* Since: 3.1.2-RC1
* Purpose: Add settings to forums before rules settings section
-acp_group_options_before
+acp_group_options_after
===
* Location: adm/style/acp_groups.html
* Since: 3.1.0-b4
-* Purpose: Add addtional options to group settings (before GROUP_FOUNDER_MANAGE)
+* Purpose: Add additional options to group settings (after GROUP_RECEIVE_PM)
-acp_group_options_after
+acp_group_options_before
===
* Location: adm/style/acp_groups.html
* Since: 3.1.0-b4
-* Purpose: Add addtional options to group settings (after GROUP_RECEIVE_PM)
+* Purpose: Add additional options to group settings (before GROUP_FOUNDER_MANAGE)
+
+acp_group_types_append
+===
+* Location: adm/style/acp_groups.html
+* Since: 3.2.9-RC1
+* Purpose: Add additional group type options to group settings (append the list)
+
+acp_group_types_prepend
+===
+* Location: adm/style/acp_groups.html
+* Since: 3.2.9-RC1
+* Purpose: Add additional group type options to group settings (prepend the list)
acp_groups_find_username_append
===
@@ -220,6 +232,18 @@ acp_groups_position_teampage_add_button_before
* Since: 3.1.7-RC1
* Purpose: Add content before adding group to teampage submit button
+acp_help_phpbb_stats_after
+===
+* Location: adm/style/acp_help_phpbb.html
+* Since: 3.2.0-RC2
+* Purpose: Add content after send statistics tile
+
+acp_help_phpbb_stats_before
+===
+* Location: adm/style/acp_help_phpbb.html
+* Since: 3.2.0-RC2
+* Purpose: Add content before send statistics tile
+
acp_logs_quick_select_forum_button_append
===
* Location: adm/style/acp_logs.html
@@ -269,29 +293,29 @@ acp_overall_header_stylesheets_after
* Purpose: Add assets after stylesheets within the `<head>` tags in the ACP.
Note that INCLUDECSS will not work with this event.
-acp_permission_forum_copy_src_forum_append
+acp_permission_forum_copy_dest_forum_append
===
* Location: adm/style/permission_forum_copy.html
* Since: 3.1.7-RC1
-* Purpose: Add content after the sourse forum select form
+* Purpose: Add content after the destination forum select form
-acp_permission_forum_copy_src_forum_prepend
+acp_permission_forum_copy_dest_forum_prepend
===
* Location: adm/style/permission_forum_copy.html
* Since: 3.1.7-RC1
-* Purpose: Add content before the sourse forum select form
+* Purpose: Add content before the destination forum select form
-acp_permission_forum_copy_dest_forum_append
+acp_permission_forum_copy_src_forum_append
===
* Location: adm/style/permission_forum_copy.html
* Since: 3.1.7-RC1
-* Purpose: Add content after the destiny forum select form
+* Purpose: Add content after the source forum select form
-acp_permission_forum_copy_dest_forum_prepend
+acp_permission_forum_copy_src_forum_prepend
===
* Location: adm/style/permission_forum_copy.html
* Since: 3.1.7-RC1
-* Purpose: Add content before the destiny forum select form
+* Purpose: Add content before the source forum select form
acp_permissions_add_group_options_append
===
@@ -421,6 +445,13 @@ acp_prune_forums_prepend
* Since: 3.1.7-RC1
* Purpose: Add content before the forum select form label
+acp_prune_forums_settings_append
+===
+* Locations:
+ + adm/style/acp_prune_forums.html
+* Since: 3.2.2-RC1
+* Purpose: Add content after the prune settings
+
acp_prune_users_find_username_append
===
* Locations:
@@ -479,34 +510,6 @@ acp_ranks_list_header_before
* Purpose: Add content after the last header-column (but before the action column)
in the ranks list in the ACP
-acp_styles_list_before
-===
-* Locations:
- + adm/style/acp_styles.html
-* Since: 3.1.7-RC1
-* Purpose: Add content before list of styles
-
-acp_users_profile_before
-===
-* Locations:
- + adm/style/acp_users_profile.html
-* Since: 3.1.4-RC1
-* Purpose: Add content before the profile details when editing a user in the ACP
-
-acp_users_profile_after
-===
-* Locations:
- + adm/style/acp_users_profile.html
-* Since: 3.1.4-RC1
-* Purpose: Add content after the profile details but before the custom profile fields when editing a user in the ACP
-
-acp_users_profile_custom_after
-===
-* Locations:
- + adm/style/acp_users_profile.html
-* Since: 3.1.4-RC1
-* Purpose: Add content after the the custom profile fields when editing a user in the ACP
-
acp_simple_footer_after
===
* Location: adm/style/simple_footer.html
@@ -532,6 +535,20 @@ acp_simple_header_stylesheets_after
* Purpose: Add assets after stylesheets within the `<head>` tags in the simple header
of the ACP. Note that INCLUDECSS will not work with this event.
+acp_styles_list_before
+===
+* Locations:
+ + adm/style/acp_styles.html
+* Since: 3.1.7-RC1
+* Purpose: Add content before list of styles
+
+acp_users_mode_add
+===
+* Locations:
+ + adm/style/acp_users.html
+* Since: 3.2.2-RC1
+* Purpose: Add extra modes to the ACP user page
+
acp_users_overview_options_append
===
* Location: adm/style/acp_users_overview.html
@@ -544,12 +561,6 @@ acp_users_prefs_append
* Since: 3.1.0-b3
* Purpose: Add user options fieldset to the bottom of ACP users prefs settings
-acp_users_prefs_prepend
-===
-* Location: adm/style/acp_users_prefs.html
-* Since: 3.1.0-b3
-* Purpose: Add user options fieldset to the top of ACP users prefs settings
-
acp_users_prefs_personal_append
===
* Location: adm/style/acp_users_prefs.html
@@ -574,6 +585,12 @@ acp_users_prefs_post_prepend
* Since: 3.1.0-b3
* Purpose: Add user options fieldset to the top of ACP users post prefs settings
+acp_users_prefs_prepend
+===
+* Location: adm/style/acp_users_prefs.html
+* Since: 3.1.0-b3
+* Purpose: Add user options fieldset to the top of ACP users prefs settings
+
acp_users_prefs_view_append
===
* Location: adm/style/acp_users_prefs.html
@@ -586,6 +603,27 @@ acp_users_prefs_view_prepend
* Since: 3.1.0-b3
* Purpose: Add user options fieldset to the top of ACP users view prefs settings
+acp_users_profile_after
+===
+* Locations:
+ + adm/style/acp_users_profile.html
+* Since: 3.1.4-RC1
+* Purpose: Add content after the profile details but before the custom profile fields when editing a user in the ACP
+
+acp_users_profile_before
+===
+* Locations:
+ + adm/style/acp_users_profile.html
+* Since: 3.1.4-RC1
+* Purpose: Add content before the profile details when editing a user in the ACP
+
+acp_users_profile_custom_after
+===
+* Locations:
+ + adm/style/acp_users_profile.html
+* Since: 3.1.4-RC1
+* Purpose: Add content after the the custom profile fields when editing a user in the ACP
+
acp_users_select_group_after
===
* Location: adm/style/acp_users.html
@@ -602,7 +640,6 @@ attachment_file_after
===
* Locations:
+ styles/prosilver/template/attachment.html
- + styles/subsilver2/template/attachment.html
* Since: 3.1.6-RC1
* Purpose: Add content after the attachment.
@@ -610,7 +647,6 @@ attachment_file_append
===
* Locations:
+ styles/prosilver/template/attachment.html
- + styles/subsilver2/template/attachment.html
* Since: 3.1.6-RC1
* Purpose: Add custom attachment types displaying to the bottom of attachment block.
@@ -618,7 +654,6 @@ attachment_file_before
===
* Locations:
+ styles/prosilver/template/attachment.html
- + styles/subsilver2/template/attachment.html
* Since: 3.1.6-RC1
* Purpose: Add content before the attachment.
@@ -626,15 +661,20 @@ attachment_file_prepend
===
* Locations:
+ styles/prosilver/template/attachment.html
- + styles/subsilver2/template/attachment.html
* Since: 3.1.6-RC1
* Purpose: Add custom attachment types displaying to the top of attachment block.
+confirm_delete_body_delete_reason_before
+===
+* Locations:
+ + styles/prosilver/template/confirm_delete_body.html
+* Since: 3.2.4-RC1
+* Purpose: Add custom text to the confirmation of a post that is deleted.
+
forumlist_body_category_header_after
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-a4
* Purpose: Add content after the header of the category on the forum list.
@@ -642,7 +682,6 @@ forumlist_body_category_header_before
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-a4
* Purpose: Add content before the header of the category on the forum list.
@@ -660,11 +699,38 @@ forumlist_body_category_header_row_prepend
* Since: 3.1.5-RC1
* Purpose: Add content before the header row of the category on the forum list.
+forumlist_body_forum_image_after
+===
+* Locations:
+ + styles/prosilver/template/forumlist_body.html
+* Since: 3.2.2-RC1
+* Purpose: Add content after the forum image on the forum list.
+
+forumlist_body_forum_image_append
+===
+* Locations:
+ + styles/prosilver/template/forumlist_body.html
+* Since: 3.2.2-RC1
+* Purpose: Add content at the start of the forum image on the forum list.
+
+forumlist_body_forum_image_before
+===
+* Locations:
+ + styles/prosilver/template/forumlist_body.html
+* Since: 3.2.2-RC1
+* Purpose: Add content before the forum image on the forum list.
+
+forumlist_body_forum_image_prepend
+===
+* Locations:
+ + styles/prosilver/template/forumlist_body.html
+* Since: 3.2.2-RC1
+* Purpose: Add content at the end of the forum image on the forum list.
+
forumlist_body_forum_row_after
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-RC5
* Purpose: Add content after the forum list item.
@@ -672,7 +738,6 @@ forumlist_body_forum_row_append
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-RC5
* Purpose: Add content at the start of the forum list item.
@@ -680,7 +745,6 @@ forumlist_body_forum_row_before
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-RC5
* Purpose: Add content before the forum list item.
@@ -688,7 +752,6 @@ forumlist_body_forum_row_prepend
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-RC5
* Purpose: Add content at the end of the forum list item.
@@ -696,15 +759,34 @@ forumlist_body_last_post_title_prepend
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-a1
* Purpose: Add content before the post title of the latest post in a forum on the forum list.
+forumlist_body_last_poster_username_append
+===
+* Locations:
+ + styles/prosilver/template/forumlist_body.html
+* Since: 3.2.4-RC1
+* Purpose: Append information to last poster username of member
+
+forumlist_body_last_poster_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/forumlist_body.html
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to last poster username of member
+
+forumlist_body_last_row_after
+===
+* Locations:
+ + styles/prosilver/template/forumlist_body.html
+* Since: 3.1.0-b2
+* Purpose: Add content after the very last row of the forum list.
+
forumlist_body_subforum_link_append
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.11-RC1
* Purpose: Add content at the end of subforum link item.
@@ -712,7 +794,6 @@ forumlist_body_subforum_link_prepend
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.11-RC1
* Purpose: Add content at the start of subforum link item.
@@ -720,7 +801,6 @@ forumlist_body_subforums_after
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-a4
* Purpose: Add content after the list of subforums (if any) for each forum on the forum list.
@@ -728,23 +808,13 @@ forumlist_body_subforums_before
===
* Locations:
+ styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
* Since: 3.1.0-a4
* Purpose: Add content before the list of subforums (if any) for each forum on the forum list.
-forumlist_body_last_row_after
-===
-* Locations:
- + styles/prosilver/template/forumlist_body.html
- + styles/subsilver2/template/forumlist_body.html
-* Since: 3.1.0-b2
-* Purpose: Add content after the very last row of the forum list.
-
index_body_birthday_block_before
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.11-RC1
* Purpose: Add new statistic blocks before the Birthday block
@@ -752,7 +822,6 @@ index_body_block_birthday_append
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Append content to the birthday list on the Board index
@@ -760,7 +829,6 @@ index_body_block_birthday_prepend
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Prepend content to the birthday list on the Board index
@@ -768,7 +836,6 @@ index_body_block_online_append
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Append content to the online list on the Board index
@@ -776,7 +843,6 @@ index_body_block_online_prepend
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Prepend content to the online list on the Board index
@@ -784,7 +850,6 @@ index_body_block_stats_append
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Append content to the statistics list on the Board index
@@ -792,7 +857,6 @@ index_body_block_stats_prepend
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Prepend content to the statistics list on the Board index
@@ -800,7 +864,6 @@ index_body_forumlist_body_after
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.1
* Purpose: Add content after the forum list body on the index page
@@ -808,7 +871,6 @@ index_body_markforums_after
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-RC2
* Purpose: Add content after the mark-read link above the forum list on Board index
@@ -816,7 +878,6 @@ index_body_markforums_before
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-RC2
* Purpose: Add content before the mark-read link above the forum list on Board index
@@ -824,7 +885,6 @@ index_body_stat_blocks_after
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Add new statistic blocks below the Who Is Online and Board Statistics blocks
@@ -832,7 +892,6 @@ index_body_stat_blocks_before
===
* Locations:
+ styles/prosilver/template/index_body.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-a1
* Purpose: Add new statistic blocks above the Who Is Online and Board Statistics blocks
@@ -840,7 +899,6 @@ mcp_ban_fields_after
===
* Locations:
+ styles/prosilver/template/mcp_ban.html
- + styles/subsilver2/template/mcp_ban.html
* Since: 3.1.0-RC3
* Purpose: Add additional fields to the ban form in MCP
@@ -848,7 +906,6 @@ mcp_ban_fields_before
===
* Locations:
+ styles/prosilver/template/mcp_ban.html
- + styles/subsilver2/template/mcp_ban.html
* Since: 3.1.0-RC3
* Purpose: Add additional fields to the ban form in MCP
@@ -856,7 +913,6 @@ mcp_ban_unban_after
===
* Locations:
+ styles/prosilver/template/mcp_ban.html
- + styles/subsilver2/template/mcp_ban.html
* Since: 3.1.0-RC3
* Purpose: Add additional fields to the unban form in MCP
@@ -864,7 +920,6 @@ mcp_ban_unban_before
===
* Locations:
+ styles/prosilver/template/mcp_ban.html
- + styles/subsilver2/template/mcp_ban.html
* Since: 3.1.0-RC3
* Purpose: Add additional fields to the unban form in MCP
@@ -872,7 +927,6 @@ mcp_forum_actions_after
===
* Locations:
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.11-RC1
* Purpose: Add some information after actions fieldset
@@ -880,7 +934,6 @@ mcp_forum_actions_append
===
* Locations:
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.11-RC1
* Purpose: Add additional options to actions select
@@ -888,31 +941,27 @@ mcp_forum_actions_before
===
* Locations:
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.11-RC1
* Purpose: Add some information before actions fieldset
-mcp_forum_topic_title_before
+mcp_forum_topic_title_after
===
* Locations:
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.6-RC1
-* Purpose: Add some information before the topic title
+* Purpose: Add some information after the topic title
-mcp_forum_topic_title_after
+mcp_forum_topic_title_before
===
* Locations:
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.6-RC1
-* Purpose: Add some information after the topic title
+* Purpose: Add some information before the topic title
mcp_front_latest_logs_after
===
* Locations:
+ styles/prosilver/template/mcp_front.html
- + styles/subsilver2/template/mcp_front.html
* Since: 3.1.3-RC1
* Purpose: Add content after latest logs list
@@ -920,7 +969,6 @@ mcp_front_latest_logs_before
===
* Locations:
+ styles/prosilver/template/mcp_front.html
- + styles/subsilver2/template/mcp_front.html
* Since: 3.1.3-RC1
* Purpose: Add content before latest logs list
@@ -928,7 +976,6 @@ mcp_front_latest_reported_before
===
* Locations:
+ styles/prosilver/template/mcp_front.html
- + styles/subsilver2/template/mcp_front.html
* Since: 3.1.3-RC1
* Purpose: Add content before latest reported posts list
@@ -936,7 +983,6 @@ mcp_front_latest_reported_pms_before
===
* Locations:
+ styles/prosilver/template/mcp_front.html
- + styles/subsilver2/template/mcp_front.html
* Since: 3.1.3-RC1
* Purpose: Add content before latest reported private messages list
@@ -944,7 +990,6 @@ mcp_front_latest_unapproved_before
===
* Locations:
+ styles/prosilver/template/mcp_front.html
- + styles/subsilver2/template/mcp_front.html
* Since: 3.1.3-RC1
* Purpose: Add content before latest unapproved posts list
@@ -952,23 +997,62 @@ mcp_move_before
===
* Locations:
+ styles/prosilver/template/mcp_move.html
- + styles/subsilver2/template/mcp_move.html
* Since: 3.1.10-RC1
* Purpose: Add content before move topic/post form
+mcp_move_destination_forum_after
+===
+* Locations:
+ + styles/prosilver/template/mcp_move.html
+* Since: 3.2.8-RC1
+* Purpose: Add content after the destination select element in the move topic/post form
+
+mcp_move_destination_forum_before
+===
+* Locations:
+ + styles/prosilver/template/mcp_move.html
+* Since: 3.2.8-RC1
+* Purpose: Add content before the destination select element in the move topic/post form
+
mcp_post_additional_options
===
* Locations:
+ styles/prosilver/template/mcp_post.html
- + styles/subsilver2/template/mcp_post.html
* Since: 3.1.5-RC1
* Purpose: Add content within the list of post moderation actions
+mcp_post_report_buttons_top_after
+===
+* Locations:
+ + styles/prosilver/template/mcp_post.html
+* Since: 3.2.4-RC1
+* Purpose: Add content after report buttons
+
+mcp_post_report_buttons_top_before
+===
+* Locations:
+ + styles/prosilver/template/mcp_post.html
+* Since: 3.2.4-RC1
+* Purpose: Add content before report buttons
+
+mcp_post_text_after
+===
+* Locations:
+ + styles/prosilver/template/mcp_post.html
+* Since: 3.2.6-RC1
+* Purpose: Add content after the post text
+
+mcp_post_text_before
+===
+* Locations:
+ + styles/prosilver/template/mcp_post.html
+* Since: 3.2.6-RC1
+* Purpose: Add content before the post text
+
mcp_topic_options_after
===
* Locations:
+ styles/prosilver/template/mcp_topic.html
- + styles/subsilver2/template/mcp_topic.html
* Since: 3.1.6-RC1
* Purpose: Add some options (field, checkbox, ...) after the subject field when split a subject
@@ -976,15 +1060,48 @@ mcp_topic_options_before
===
* Locations:
+ styles/prosilver/template/mcp_topic.html
- + styles/subsilver2/template/mcp_topic.html
* Since: 3.1.6-RC1
* Purpose: Add some options (field, checkbox, ...) before the subject field when split a subject
+mcp_topic_post_author_full_append
+===
+* Locations:
+ + styles/prosilver/template/mcp_topic.html
+* Since: 3.2.8-RC1
+* Purpose: Append information to message author username for post details in topic moderation
+
+mcp_topic_post_author_full_prepend
+===
+* Locations:
+ + styles/prosilver/template/mcp_topic.html
+* Since: 3.2.8-RC1
+* Purpose: Prepend information to message author username for post details in topic moderation
+
+mcp_topic_postrow_attachments_after
+===
+* Locations:
+ + styles/prosilver/template/mcp_topic.html
+* Since: 3.2.2-RC1
+* Purpose: Show additional content after attachments in mcp topic review
+
+mcp_topic_postrow_attachments_before
+===
+* Locations:
+ + styles/prosilver/template/mcp_topic.html
+* Since: 3.2.2-RC1
+* Purpose: Show additional content before attachments in mcp topic review
+
+mcp_topic_postrow_post_before
+===
+* Locations:
+ + styles/prosilver/template/mcp_topic.html
+* Since: 3.2.2-RC1
+* Purpose: Show additional content after postrow begins in mcp topic review
+
mcp_topic_postrow_post_details_after
===
* Locations:
+ styles/prosilver/template/mcp_topic.html
- + styles/subsilver2/template/mcp_topic.html
* Since: 3.1.10-RC1
* Purpose: Add content after post details in topic moderation
@@ -992,7 +1109,6 @@ mcp_topic_postrow_post_details_before
===
* Locations:
+ styles/prosilver/template/mcp_topic.html
- + styles/subsilver2/template/mcp_topic.html
* Since: 3.1.10-RC1
* Purpose: Add content before post details in topic moderation
@@ -1014,7 +1130,6 @@ mcp_topic_topic_title_after
===
* Locations:
+ styles/prosilver/template/mcp_topic.html
- + styles/subsilver2/template/mcp_topic.html
* Since: 3.1.6-RC1
* Purpose: Add some information after the topic title
@@ -1022,7 +1137,6 @@ mcp_topic_topic_title_before
===
* Locations:
+ styles/prosilver/template/mcp_topic.html
- + styles/subsilver2/template/mcp_topic.html
* Since: 3.1.6-RC1
* Purpose: Add some information before the topic title
@@ -1030,7 +1144,6 @@ mcp_warn_post_add_warning_field_after
===
* Locations:
+ styles/prosilver/template/mcp_warn_post.html
- + styles/subsilver2/template/mcp_warn_post.html
* Since: 3.1.0-RC4
* Purpose: Add content during warning for a post - after add warning field.
@@ -1038,7 +1151,6 @@ mcp_warn_post_add_warning_field_before
===
* Locations:
+ styles/prosilver/template/mcp_warn_post.html
- + styles/subsilver2/template/mcp_warn_post.html
* Since: 3.1.0-RC4
* Purpose: Add content during warning for a post - before add warning field.
@@ -1046,7 +1158,6 @@ mcp_warn_user_add_warning_field_after
===
* Locations:
+ styles/prosilver/template/mcp_warn_user.html
- + styles/subsilver2/template/mcp_warn_user.html
* Since: 3.1.0-RC4
* Purpose: Add content during warning a user - after add warning field.
@@ -1054,15 +1165,90 @@ mcp_warn_user_add_warning_field_before
===
* Locations:
+ styles/prosilver/template/mcp_warn_user.html
- + styles/subsilver2/template/mcp_warn_user.html
* Since: 3.1.0-RC4
* Purpose: Add content during warning a user - before add warning field.
+memberlist_body_group_desc_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the group description and type in the group profile page.
+
+memberlist_body_group_name_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the group name in the group profile page.
+
+memberlist_body_group_name_before
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data before the group name in the group profile page.
+
+memberlist_body_group_rank_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the group rank in the group profile page.
+
+memberlist_body_group_rank_before
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data before the group rank in the group profile page.
+
+memberlist_body_leaders_set_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the last row in the memberlist mode leaders.
+
+memberlist_body_memberlist_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the last row in the memberlist.
+
+memberlist_body_memberrow_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the last memberrow in the memberlist.
+
+memberlist_body_page_footer_before
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data before the page footer.
+
+memberlist_body_page_header_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the page header.
+
+memberlist_body_page_title_before
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data before the page title.
+
memberlist_body_rank_append
===
* Locations:
+ styles/prosilver/template/memberlist_body.html
- + styles/subsilver2/template/memberlist_body.html
* Since: 3.1.6-RC1
* Purpose: Add information after rank in memberlist. Works in
all display modes (leader, group and normal memberlist).
@@ -1071,16 +1257,21 @@ memberlist_body_rank_prepend
===
* Locations:
+ styles/prosilver/template/memberlist_body.html
- + styles/subsilver2/template/memberlist_body.html
* Since: 3.1.6-RC1
* Purpose: Add information before rank in memberlist. Works in
all display modes (leader, group and normal memberlist).
+memberlist_body_show_group_after
+===
+* Locations:
+ + styles/prosilver/template/memberlist_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add data after the last row in the memberlist mode group.
+
memberlist_body_username_append
===
* Locations:
+ styles/prosilver/template/memberlist_body.html
- + styles/subsilver2/template/memberlist_body.html
* Since: 3.1.0-a1
* Purpose: Add information after every username in the memberlist. Works in
all display modes (leader, group and normal memberlist).
@@ -1089,7 +1280,6 @@ memberlist_body_username_prepend
===
* Locations:
+ styles/prosilver/template/memberlist_body.html
- + styles/subsilver2/template/memberlist_body.html
* Since: 3.1.0-a1
* Purpose: Add information before every username in the memberlist. Works in
all display modes (leader, group and normal memberlist).
@@ -1098,7 +1288,6 @@ memberlist_email_before
===
* Locations:
+ styles/prosilver/template/memberlist_email.html
- + styles/subsilver2/template/memberlist_email.html
* Since: 3.1.10-RC1
* Purpose: Allow adding customizations before the memberlist_email form.
@@ -1106,7 +1295,6 @@ memberlist_search_fields_after
===
* Locations:
+ styles/prosilver/template/memberlist_search.html
- + styles/subsilver2/template/memberlist_search.html
* Since: 3.1.2-RC1
* Purpose: Add information after the search fields column.
@@ -1114,7 +1302,6 @@ memberlist_search_fields_before
===
* Locations:
+ styles/prosilver/template/memberlist_search.html
- + styles/subsilver2/template/memberlist_search.html
* Since: 3.1.2-RC1
* Purpose: Add information before the search fields column.
@@ -1122,7 +1309,6 @@ memberlist_search_sorting_options_before
===
* Locations:
+ styles/prosilver/template/memberlist_search.html
- + styles/subsilver2/template/memberlist_search.html
* Since: 3.1.2-RC1
* Purpose: Add information before the search sorting options field.
@@ -1130,7 +1316,6 @@ memberlist_team_username_append
===
* Locations:
+ styles/prosilver/template/memberlist_team.html
- + styles/subsilver2/template/memberlist_team.html
* Since: 3.1.11-RC1
* Purpose: Append information to username of team member
@@ -1138,7 +1323,6 @@ memberlist_team_username_prepend
===
* Locations:
+ styles/prosilver/template/memberlist_team.html
- + styles/subsilver2/template/memberlist_team.html
* Since: 3.1.11-RC1
* Purpose: Add information before team user username
@@ -1146,7 +1330,6 @@ memberlist_view_contact_after
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.0-b2
* Purpose: Add content after the user contact part of any user profile
@@ -1154,7 +1337,6 @@ memberlist_view_contact_before
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.0-b2
* Purpose: Add content before the user contact part of any user profile
@@ -1162,7 +1344,6 @@ memberlist_view_contact_custom_fields_after
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.9-RC1
* Purpose: Add content after the user contact related custom fields
@@ -1170,7 +1351,6 @@ memberlist_view_contact_custom_fields_before
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.9-RC1
* Purpose: Add content before the user contact related custom fields
@@ -1178,7 +1358,6 @@ memberlist_view_content_append
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.0-b2
* Purpose: Add custom content to the user profile view after the main content
@@ -1186,7 +1365,6 @@ memberlist_view_content_prepend
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.0-b3
* Purpose: Add custom content to the user profile view before the main content
@@ -1194,7 +1372,6 @@ memberlist_view_non_contact_custom_fields_after
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.9-RC1
* Purpose: Add content after the user not contact related custom fields
@@ -1202,17 +1379,9 @@ memberlist_view_non_contact_custom_fields_before
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.9-RC1
* Purpose: Add content before the user not contact related custom fields
-memberlist_view_rank_after
-===
-* Locations:
- + styles/subsilver2/template/memberlist_view.html
-* Since: 3.1.6-RC1
-* Purpose: Add information after rank in memberlist
-
memberlist_view_rank_avatar_after
===
* Locations:
@@ -1227,13 +1396,6 @@ memberlist_view_rank_avatar_before
* Since: 3.1.6-RC1
* Purpose: Add information before rank in memberlist (with avatar)
-memberlist_view_rank_before
-===
-* Locations:
- + styles/subsilver2/template/memberlist_view.html
-* Since: 3.1.6-RC1
-* Purpose: Add information after rank in memberlist
-
memberlist_view_rank_no_avatar_after
===
* Locations:
@@ -1252,7 +1414,6 @@ memberlist_view_user_statistics_after
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.0-a1
* Purpose: Add entries after the user statistics part of any user profile
@@ -1260,15 +1421,27 @@ memberlist_view_user_statistics_before
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.0-a1
* Purpose: Add entries before the user statistics part of any user profile
+memberlist_view_username_append
+===
+* Locations:
+ + styles/prosilver/template/memberlist_view.html
+* Since: 3.2.4-RC1
+* Purpose: Append information to username of member
+
+memberlist_view_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/memberlist_view.html
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to username of member
+
memberlist_view_zebra_after
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.9-RC1
* Purpose: Add content after the user friends/foes links
@@ -1276,7 +1449,6 @@ memberlist_view_zebra_before
===
* Locations:
+ styles/prosilver/template/memberlist_view.html
- + styles/subsilver2/template/memberlist_view.html
* Since: 3.1.9-RC1
* Purpose: Add content before the user friends/foes links
@@ -1347,7 +1519,6 @@ overall_footer_after
===
* Locations:
+ styles/prosilver/template/overall_footer.html
- + styles/subsilver2/template/overall_footer.html
* Since: 3.1.0-a1
* Purpose: Add content at the end of the file, directly prior to the `</body>` tag
@@ -1355,7 +1526,6 @@ overall_footer_body_after
===
* Locations:
+ styles/prosilver/template/overall_footer.html
- + styles/subsilver2/template/overall_footer.html
* Since: 3.1.3-RC1
* Purpose: Add content before the `</body>` tag but after the $SCRIPTS var, i.e. after the js scripts have been loaded
@@ -1363,7 +1533,6 @@ overall_footer_breadcrumb_append
===
* Locations:
+ styles/prosilver/template/navbar_footer.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-a1
* Purpose: Add links to the list of breadcrumbs in the footer
@@ -1371,7 +1540,6 @@ overall_footer_breadcrumb_prepend
===
* Locations:
+ styles/prosilver/template/navbar_footer.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-RC3
* Purpose: Add links to the list of breadcrumbs in the footer (after site-home, but before board-index)
@@ -1379,7 +1547,6 @@ overall_footer_content_after
===
* Locations:
+ styles/prosilver/template/overall_footer.html
- + styles/subsilver2/template/overall_footer.html
* Since: 3.1.0-a3
* Purpose: Add content on all pages after the main content, before the footer
@@ -1387,7 +1554,6 @@ overall_footer_copyright_append
===
* Locations:
+ styles/prosilver/template/overall_footer.html
- + styles/subsilver2/template/overall_footer.html
* Since: 3.1.0-a1
* Purpose: Add content after the copyright line (no new line by default), before the ACP link
@@ -1395,7 +1561,6 @@ overall_footer_copyright_prepend
===
* Locations:
+ styles/prosilver/template/overall_footer.html
- + styles/subsilver2/template/overall_footer.html
* Since: 3.1.0-a1
* Purpose: Add content before the copyright line
@@ -1403,7 +1568,6 @@ overall_footer_page_body_after
===
* Locations:
+ styles/prosilver/template/overall_footer.html
- + styles/subsilver2/template/overall_footer.html
* Since: 3.1.0-b3
* Purpose: Add content after the page-body, but before the footer
@@ -1411,7 +1575,6 @@ overall_footer_teamlink_after
===
* Locations:
+ styles/prosilver/template/navbar_footer.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Add contents after the team-link in the footer
@@ -1419,7 +1582,6 @@ overall_footer_teamlink_before
===
* Locations:
+ styles/prosilver/template/navbar_footer.html
- + styles/subsilver2/template/index_body.html
* Since: 3.1.0-b3
* Purpose: Add contents before the team-link in the footer
@@ -1427,7 +1589,6 @@ overall_footer_timezone_after
===
* Locations:
+ styles/prosilver/template/navbar_footer.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-b3
* Purpose: Add content to the navbar in the page footer, after "Timezone"
@@ -1435,7 +1596,6 @@ overall_footer_timezone_before
===
* Locations:
+ styles/prosilver/template/navbar_footer.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-b3
* Purpose: Add content to the navbar in the page footer, before "Timezone"
@@ -1443,7 +1603,6 @@ overall_header_body_before
===
* Locations:
+ styles/prosilver/template/overall_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.0-b2
* Purpose: Add content to the header body
@@ -1451,7 +1610,6 @@ overall_header_breadcrumb_append
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-a1
* Purpose: Add links to the list of breadcrumbs in the header
@@ -1459,7 +1617,6 @@ overall_header_breadcrumb_prepend
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-RC3
* Purpose: Add links to the list of breadcrumbs in the header (after site-home, but before board-index)
@@ -1467,7 +1624,6 @@ overall_header_breadcrumbs_after
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-RC3
* Purpose: Add content after the breadcrumbs (outside of the breadcrumbs container)
@@ -1475,7 +1631,6 @@ overall_header_breadcrumbs_before
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-RC3
* Purpose: Add content before the breadcrumbs (outside of the breadcrumbs container)
@@ -1483,7 +1638,6 @@ overall_header_content_before
===
* Locations:
+ styles/prosilver/template/overall_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.0-a3
* Purpose: Add content on all pages before the main content, after the header
@@ -1491,7 +1645,6 @@ overall_header_feeds
===
* Locations:
+ styles/prosilver/template/overall_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.6-RC1
* Purpose: Add custom feeds
@@ -1499,7 +1652,6 @@ overall_header_head_append
===
* Locations:
+ styles/prosilver/template/overall_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.0-a1
* Purpose: Add asset calls directly before the `</head>` tag
@@ -1521,7 +1673,6 @@ overall_header_navbar_before
===
* Locations:
+ styles/prosilver/template/overall_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.4-RC1
* Purpose: Add content before the navigation bar
@@ -1529,7 +1680,6 @@ overall_header_navigation_append
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.0-a1
* Purpose: Add links after the navigation links in the header
@@ -1537,7 +1687,6 @@ overall_header_navigation_prepend
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.0-a1
* Purpose: Add links before the navigation links in the header
@@ -1545,7 +1694,6 @@ overall_header_navlink_append
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-b3
* Purpose: Add content after each individual navlink (breadcrumb)
@@ -1553,7 +1701,6 @@ overall_header_navlink_prepend
===
* Locations:
+ styles/prosilver/template/navbar_header.html
- + styles/subsilver2/template/breadcrumbs.html
* Since: 3.1.0-b3
* Purpose: Add content before each individual navlink (breadcrumb)
@@ -1561,7 +1708,6 @@ overall_header_page_body_before
===
* Locations:
+ styles/prosilver/template/overall_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.0-b3
* Purpose: Add content after the page-header, but before the page-body
@@ -1583,11 +1729,66 @@ overall_header_stylesheets_after
===
* Locations:
+ styles/prosilver/template/overall_header.html
- + styles/subsilver2/template/overall_header.html
* Since: 3.1.0-RC3
* Purpose: Add asset calls after stylesheets within the `</head>` tag.
Note that INCLUDECSS will not work with this event.
+posting_attach_body_attach_row_after
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add content after attachment row in the file list
+
+posting_attach_body_attach_row_append
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add content appending the attachment row in the file list
+
+posting_attach_body_attach_row_before
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add content before attachment row in the file list
+
+posting_attach_body_attach_row_controls_append
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.2-RC1
+* Purpose: Add content after attachment control elements
+
+posting_attach_body_attach_row_controls_prepend
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.2-RC1
+* Purpose: Add content before attachment control elements
+
+posting_attach_body_attach_row_prepend
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add content prepending attachment row in the file list
+
+posting_attach_body_file_list_after
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add content after attachments list
+
+posting_attach_body_file_list_before
+===
+* Locations:
+ + styles/prosilver/template/posting_attach_body.html
+* Since: 3.2.6-RC1
+* Purpose: Add content before attachments list
+
posting_editor_add_panel_tab
===
* Locations:
@@ -1599,7 +1800,6 @@ posting_editor_bbcode_status_after
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.4-RC1
* Purpose: Add content after bbcode status
@@ -1607,7 +1807,6 @@ posting_editor_buttons_after
===
* Locations:
+ styles/prosilver/template/posting_buttons.html
- + styles/subsilver2/template/posting_buttons.html
* Since: 3.1.0-a3
* Purpose: Add content after the BBCode posting buttons
@@ -1615,7 +1814,6 @@ posting_editor_buttons_before
===
* Locations:
+ styles/prosilver/template/posting_buttons.html
- + styles/subsilver2/template/posting_buttons.html
* Since: 3.1.0-a3
* Purpose: Add content before the BBCode posting buttons
@@ -1623,7 +1821,6 @@ posting_editor_buttons_custom_tags_before
===
* Locations:
+ styles/prosilver/template/posting_buttons.html
- + styles/subsilver2/template/posting_buttons.html
* Since: 3.1.2-RC1
* Purpose: Add content inside the BBCode posting buttons and before the customs BBCode
@@ -1631,7 +1828,6 @@ posting_editor_message_after
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.0-a2
* Purpose: Add field (e.g. textbox) to the posting screen after the message
@@ -1639,7 +1835,6 @@ posting_editor_message_before
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.0-a2
* Purpose: Add field (e.g. textbox) to the posting screen before the message
@@ -1647,7 +1842,6 @@ posting_editor_options_prepend
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.0-a1
* Purpose: Add posting options on the posting screen
@@ -1655,7 +1849,6 @@ posting_editor_smilies_after
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.4-RC1
* Purpose: Add content after smilies
@@ -1663,7 +1856,6 @@ posting_editor_smilies_before
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.4-RC1
* Purpose: Add content before the smilies
@@ -1671,7 +1863,6 @@ posting_editor_subject_after
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.0-a2
* Purpose: Add field (e.g. textbox) to the posting screen after the subject
@@ -1679,7 +1870,6 @@ posting_editor_subject_append
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.10-RC1
* Purpose: Add field, text, etc. to the posting after the subject text box
@@ -1687,7 +1877,6 @@ posting_editor_subject_before
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.0-a2
* Purpose: Add field (e.g. textbox) to the posting screen before the subject
@@ -1695,7 +1884,6 @@ posting_editor_subject_prepend
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.10-RC1
* Purpose: Add field, text, etc. to the posting before the subject text box
@@ -1703,7 +1891,6 @@ posting_editor_submit_buttons
===
* Locations:
+ styles/prosilver/template/posting_editor.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.6-RC1
* Purpose: Add custom buttons in the posting editor
@@ -1718,7 +1905,6 @@ posting_pm_header_find_username_after
===
* Locations:
+ styles/prosilver/template/posting_pm_header.html
- + styles/subsilver2/template/ucp_header.html
* Since: 3.1.0-RC4
* Purpose: Add content after the find username link on composing pm
@@ -1726,7 +1912,6 @@ posting_pm_header_find_username_before
===
* Locations:
+ styles/prosilver/template/posting_pm_header.html
- + styles/subsilver2/template/ucp_header.html
* Since: 3.1.0-RC4
* Purpose: Add content before the find username link on composing pm
@@ -1748,23 +1933,62 @@ posting_poll_body_options_after
===
* Locations:
+ styles/prosilver/template/posting_poll_body.html
- + styles/subsilver2/template/posting_poll_body.html
* Since: 3.1.4-RC1
* Purpose: Add content after the poll options on creating a poll
+posting_preview_content_after
+===
+* Locations:
+ + styles/prosilver/template/posting_preview.html
+* Since: 3.2.4-RC1
+* Purpose: Add content after the message content preview
+
posting_preview_poll_after
===
* Locations:
+ styles/prosilver/template/posting_preview.html
- + styles/subsilver2/template/posting_preview.html
* Since: 3.1.7-RC1
* Purpose: Add content after the poll preview block
+posting_review_row_post_author_username_append
+===
+* Locations:
+ + styles/prosilver/template/posting_review.html
+* Since: 3.2.8-RC1
+* Purpose: Append information to post author username of member
+
+posting_review_row_post_author_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/posting_review.html
+* Since: 3.2.8-RC1
+* Purpose: Prepend information to post author username of member
+
+posting_topic_review_row_content_after
+===
+* Locations:
+ + styles/prosilver/template/posting_topic_review.html
+* Since: 3.2.4-RC1
+* Purpose: Add content after the message content in topic review
+
+posting_topic_review_row_post_author_username_append
+===
+* Locations:
+ + styles/prosilver/template/posting_topic_review.html
+* Since: 3.2.8-RC1
+* Purpose: Append information to post author username of member
+
+posting_topic_review_row_post_author_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/posting_topic_review.html
+* Since: 3.2.8-RC1
+* Purpose: Prepend information to post author username of member
+
posting_topic_review_row_post_details_after
===
* Locations:
+ styles/prosilver/template/posting_topic_review.html
- + styles/subsilver2/template/posting_topic_review.html
* Since: 3.1.10-RC1
* Purpose: Add content after post details in topic review
@@ -1772,7 +1996,6 @@ posting_topic_review_row_post_details_before
===
* Locations:
+ styles/prosilver/template/posting_topic_review.html
- + styles/subsilver2/template/posting_topic_review.html
* Since: 3.1.10-RC1
* Purpose: Add content before post details in topic review
@@ -1780,7 +2003,6 @@ posting_topic_title_after
===
* Locations:
+ styles/prosilver/template/posting_layout.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.7-RC1
* Purpose: Allows to add some information after the topic title in the posting form
@@ -1788,47 +2010,41 @@ posting_topic_title_before
===
* Locations:
+ styles/prosilver/template/posting_layout.html
- + styles/subsilver2/template/posting_body.html
* Since: 3.1.6-RC1
* Purpose: Allows to add some information on the left of the topic title in the posting form
-quickreply_editor_panel_after
+quickreply_editor_message_after
===
* Locations:
+ styles/prosilver/template/quickreply_editor.html
- + styles/subsilver2/template/quickreply_editor.html
-* Since: 3.1.0-b2
-* Purpose: Add content after the quick reply panel (but inside the form)
+* Since: 3.1.0-a4
+* Purpose: Add content after the quick reply textbox
-quickreply_editor_panel_before
+quickreply_editor_message_before
===
* Locations:
+ styles/prosilver/template/quickreply_editor.html
- + styles/subsilver2/template/quickreply_editor.html
-* Since: 3.1.0-b2
-* Purpose: Add content before the quick reply panel (but inside the form)
+* Since: 3.1.0-a4
+* Purpose: Add content before the quick reply textbox
-quickreply_editor_message_after
+quickreply_editor_panel_after
===
* Locations:
+ styles/prosilver/template/quickreply_editor.html
- + styles/subsilver2/template/quickreply_editor.html
-* Since: 3.1.0-a4
-* Purpose: Add content after the quick reply textbox
+* Since: 3.1.0-b2
+* Purpose: Add content after the quick reply panel (but inside the form)
-quickreply_editor_message_before
+quickreply_editor_panel_before
===
* Locations:
+ styles/prosilver/template/quickreply_editor.html
- + styles/subsilver2/template/quickreply_editor.html
-* Since: 3.1.0-a4
-* Purpose: Add content before the quick reply textbox
+* Since: 3.1.0-b2
+* Purpose: Add content before the quick reply panel (but inside the form)
quickreply_editor_subject_before
===
* Locations:
+ styles/prosilver/template/quickreply_editor.html
- + styles/subsilver2/template/quickreply_editor.html
* Since: 3.1.7-RC1
* Purpose: Add content before the quick reply subject textbox
@@ -1836,7 +2052,6 @@ search_body_form_after
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Add content after the search form
@@ -1844,7 +2059,6 @@ search_body_form_before
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.5-RC1
* Purpose: Add content before the search form
@@ -1852,7 +2066,6 @@ search_body_recent_search_after
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Add content after the recent search queries list
@@ -1860,7 +2073,6 @@ search_body_recent_search_before
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Add content before the recent search queries list
@@ -1868,7 +2080,6 @@ search_body_search_display_options_append
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Put content at the bottom of the search query display options fields set
@@ -1876,7 +2087,6 @@ search_body_search_display_options_prepend
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Put content at the top of the search query display options fields set
@@ -1884,7 +2094,6 @@ search_body_search_options_after
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Add content after the search query options fields set
@@ -1892,7 +2101,6 @@ search_body_search_options_append
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Put content at the bottom of the search query options fields set
@@ -1900,7 +2108,6 @@ search_body_search_options_before
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Add content before the search query options fields set
@@ -1908,7 +2115,6 @@ search_body_search_options_prepend
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Put content at the top of the search query options fields set
@@ -1916,7 +2122,6 @@ search_body_search_query_after
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Add content after the search query fields set
@@ -1924,7 +2129,6 @@ search_body_search_query_append
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Put content at the bottom of the search query fields set
@@ -1932,7 +2136,6 @@ search_body_search_query_before
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Add content before the search query fields set
@@ -1940,15 +2143,20 @@ search_body_search_query_prepend
===
* Locations:
+ styles/prosilver/template/search_body.html
- + styles/subsilver2/template/search_body.html
* Since: 3.1.7-RC1
* Purpose: Put content at the top of the search query fields set
+search_results_content_after
+===
+* Locations:
+ + styles/prosilver/template/search_results.html
+* Since: 3.2.4-RC1
+* Purpose: Add content after the message content in search results
+
search_results_header_after
===
* Locations:
+ styles/prosilver/template/search_results.html
- + styles/subsilver2/template/search_results.html
* Since: 3.1.4-RC1
* Purpose: Add content after the header of the search results
@@ -1956,23 +2164,48 @@ search_results_header_before
===
* Locations:
+ styles/prosilver/template/search_results.html
- + styles/subsilver2/template/search_results.html
* Since: 3.1.4-RC1
* Purpose: Add content before the header of the search results.
+search_results_last_post_author_username_append
+===
+* Locations:
+ + styles/prosilver/template/search_results.html (2)
+* Since: 3.2.4-RC1
+* Purpose: Append information to last post author username of member
+
+search_results_last_post_author_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/search_results.html (2)
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to last post author username of member
+
search_results_post_after
===
* Locations:
+ styles/prosilver/template/search_results.html
- + styles/subsilver2/template/search_results.html
* Since: 3.1.0-b3
* Purpose: Add data after search result posts
+search_results_post_author_username_append
+===
+* Locations:
+ + styles/prosilver/template/search_results.html
+* Since: 3.2.4-RC1
+* Purpose: Append information to post author username of member
+
+search_results_post_author_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/search_results.html
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to post author username of member
+
search_results_post_before
===
* Locations:
+ styles/prosilver/template/search_results.html
- + styles/subsilver2/template/search_results.html
* Since: 3.1.0-b3
* Purpose: Add data before search result posts
@@ -1994,7 +2227,6 @@ search_results_searchbox_after
===
* Locations:
+ styles/prosilver/template/search_results.html
- + styles/subsilver2/template/search_results.html
* Since: 3.1.4-RC1
* Purpose: Add content right after the searchbox of the search results.
@@ -2002,15 +2234,27 @@ search_results_topic_after
===
* Locations:
+ styles/prosilver/template/search_results.html
- + styles/subsilver2/template/search_results.html
* Since: 3.1.0-b4
* Purpose: Add data after search result topics
+search_results_topic_author_username_append
+===
+* Locations:
+ + styles/prosilver/template/search_results.html
+* Since: 3.2.4-RC1
+* Purpose: Append information to topic author username of member
+
+search_results_topic_author_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/search_results.html
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to topic author username of member
+
search_results_topic_before
===
* Locations:
+ styles/prosilver/template/search_results.html
- + styles/subsilver2/template/search_results.html
* Since: 3.1.0-b4
* Purpose: Add data before search result topics
@@ -2025,15 +2269,20 @@ simple_footer_after
===
* Locations:
+ styles/prosilver/template/simple_footer.html
- + styles/subsilver2/template/simple_footer.html
* Since: 3.1.0-a1
+* Purpose: Add content prior to the scripts of the simple footer
+
+simple_footer_body_after
+===
+* Locations:
+ + styles/prosilver/template/simple_footer.html
+* Since: 3.2.4-RC1
* Purpose: Add content directly prior to the `</body>` tag of the simple footer
simple_header_body_before
===
* Locations:
+ styles/prosilver/template/simple_header.html
- + styles/subsilver2/template/simple_header.html
* Since: 3.1.0-b2
* Purpose: Add content to the header body
@@ -2041,7 +2290,6 @@ simple_header_head_append
===
* Locations:
+ styles/prosilver/template/simple_header.html
- + styles/subsilver2/template/simple_header.html
* Since: 3.1.0-b4
* Purpose: Add asset calls directly before the `</head>` tag
@@ -2049,46 +2297,54 @@ simple_header_stylesheets_after
===
* Locations:
+ styles/prosilver/template/simple_header.html
- + styles/subsilver2/template/simple_header.html
* Since: 3.1.0-RC3
* Purpose: Add asset calls after stylesheets within the `</head>` tag.
Note that INCLUDECSS will not work with this event.
-topiclist_row_prepend
+topiclist_row_append
===
* Locations:
+ styles/prosilver/template/search_results.html
+ styles/prosilver/template/viewforum_body.html
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/search_results.html
- + styles/subsilver2/template/viewforum_body.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.0-a1
* Changed: 3.1.6-RC1 Added event to mcp_forum.html
* Purpose: Add content into topic rows (inside the elements containing topic titles)
-topiclist_row_append
+topiclist_row_prepend
===
* Locations:
+ styles/prosilver/template/search_results.html
+ styles/prosilver/template/viewforum_body.html
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/search_results.html
- + styles/subsilver2/template/viewforum_body.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.0-a1
* Changed: 3.1.6-RC1 Added event to mcp_forum.html
* Purpose: Add content into topic rows (inside the elements containing topic titles)
+topiclist_row_topic_by_author_after
+===
+* Locations:
+ + styles/prosilver/template/search_results.html
+ + styles/prosilver/template/viewforum_body.html
+ + styles/prosilver/template/mcp_forum.html
+* Since: 3.2.8-RC1
+* Purpose: Add content into topic rows (after the "by topic author" row)
+
+topiclist_row_topic_by_author_before
+===
+* Locations:
+ + styles/prosilver/template/search_results.html
+ + styles/prosilver/template/viewforum_body.html
+ + styles/prosilver/template/mcp_forum.html
+* Since: 3.2.8-RC1
+* Purpose: Add content into topic rows (before the "by topic author" row)
+
topiclist_row_topic_title_after
===
* Locations:
+ styles/prosilver/template/search_results.html
+ styles/prosilver/template/viewforum_body.html
+ styles/prosilver/template/mcp_forum.html
- + styles/subsilver2/template/search_results.html
- + styles/subsilver2/template/viewforum_body.html
- + styles/subsilver2/template/mcp_forum.html
* Since: 3.1.10-RC1
* Purpose: Add content into topic rows (after the elements containing the topic titles)
@@ -2096,7 +2352,6 @@ ucp_agreement_terms_after
===
* Locations:
+ styles/prosilver/template/ucp_agreement.html
- + styles/subsilver2/template/ucp_agreement.html
* Since: 3.1.0-b3
* Purpose: Add content after the terms of agreement text at user registration
@@ -2104,15 +2359,27 @@ ucp_agreement_terms_before
===
* Locations:
+ styles/prosilver/template/ucp_agreement.html
- + styles/subsilver2/template/ucp_agreement.html
* Since: 3.1.0-b3
* Purpose: Add content before the terms of agreement text at user registration
+ucp_friend_list_after
+===
+* Locations:
+ + styles/prosilver/template/ucp_zebra_friends.html
+* Since: 3.1.0-a4
+* Purpose: Add optional elements after list of friends in UCP
+
+ucp_friend_list_before
+===
+* Locations:
+ + styles/prosilver/template/ucp_zebra_friends.html
+* Since: 3.1.0-a4
+* Purpose: Add optional elements before list of friends in UCP
+
ucp_main_front_user_activity_after
===
* Locations:
+ styles/prosilver/template/ucp_main_front.html
- + styles/subsilver2/template/ucp_main_front.html
* Since: 3.1.6-RC1
* Purpose: Add content right after the user activity info viewing UCP front page
@@ -2120,7 +2387,6 @@ ucp_main_front_user_activity_append
===
* Locations:
+ styles/prosilver/template/ucp_main_front.html
- + styles/subsilver2/template/ucp_main_front.html
* Since: 3.1.11-RC1
* Purpose: Add content after last user activity info viewing UCP front page
@@ -2128,7 +2394,6 @@ ucp_main_front_user_activity_before
===
* Locations:
+ styles/prosilver/template/ucp_main_front.html
- + styles/subsilver2/template/ucp_main_front.html
* Since: 3.1.6-RC1
* Purpose: Add content right before the user activity info viewing UCP front page
@@ -2136,7 +2401,6 @@ ucp_main_front_user_activity_prepend
===
* Locations:
+ styles/prosilver/template/ucp_main_front.html
- + styles/subsilver2/template/ucp_main_front.html
* Since: 3.1.11-RC1
* Purpose: Add content before first user activity info viewing UCP front page
@@ -2144,7 +2408,6 @@ ucp_pm_history_post_buttons_after
===
* Locations:
+ styles/prosilver/template/ucp_pm_history.html
- + styles/subsilver2/template/ucp_pm_history.html
* Since: 3.1.6-RC1
* Purpose: Add post button to private messages in history review (next to quote etc), at
the end of the list.
@@ -2153,7 +2416,6 @@ ucp_pm_history_post_buttons_before
===
* Locations:
+ styles/prosilver/template/ucp_pm_history.html
- + styles/subsilver2/template/ucp_pm_history.html
* Since: 3.1.6-RC1
* Purpose: Add post button to private messages in history review (next to quote etc), at
the start of the list.
@@ -2178,7 +2440,6 @@ ucp_pm_history_review_after
===
* Locations:
+ styles/prosilver/template/ucp_pm_history.html
- + styles/subsilver2/template/ucp_pm_history.html
* Since: 3.1.6-RC1
* Purpose: Add content after the private messages history review.
@@ -2186,10 +2447,23 @@ ucp_pm_history_review_before
===
* Locations:
+ styles/prosilver/template/ucp_pm_history.html
- + styles/subsilver2/template/ucp_pm_history.html
* Since: 3.1.6-RC1
* Purpose: Add content before the private messages history review.
+ucp_pm_history_row_message_author_username_append
+===
+* Locations:
+ + styles/prosilver/template/ucp_pm_history.html
+* Since: 3.2.8-RC1
+* Purpose: Append information to message author username of member
+
+ucp_pm_history_row_message_author_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/ucp_pm_history.html
+* Since: 3.2.8-RC1
+* Purpose: Prepend information to message author username of member
+
ucp_pm_viewmessage_avatar_after
===
* Locations:
@@ -2247,7 +2521,6 @@ ucp_pm_viewmessage_post_buttons_after
===
* Locations:
+ styles/prosilver/template/ucp_pm_viewmessage.html
- + styles/subsilver2/template/ucp_pm_viewmessage.html
* Since: 3.1.0-RC3
* Purpose: Add post button to private messages (next to edit, quote etc), at
the end of the list.
@@ -2256,7 +2529,6 @@ ucp_pm_viewmessage_post_buttons_before
===
* Locations:
+ styles/prosilver/template/ucp_pm_viewmessage.html
- + styles/subsilver2/template/ucp_pm_viewmessage.html
* Since: 3.1.0-RC3
* Purpose: Add post button to private messages (next to edit, quote etc), at
the start of the list.
@@ -2281,7 +2553,6 @@ ucp_pm_viewmessage_print_head_append
===
* Locations:
+ styles/prosilver/template/ucp_pm_viewmessage_print.html
- + styles/subsilver2/template/ucp_pm_viewmessage_print.html
* Since: 3.1.0-a1
* Purpose: Add asset calls directly before the `</head>` tag of the Print PM screen
@@ -2301,175 +2572,182 @@ ucp_pm_viewmessage_rank_before
* Purpose: Add data before the rank on the user profile when viewing
a private message
+ucp_prefs_personal_append
+===
+* Locations:
+ + styles/prosilver/template/ucp_prefs_personal.html
+* Since: 3.1.0-a1
+* Purpose: Add user options to the bottom of the Edit Global Settings block
+
ucp_prefs_personal_prepend
===
* Locations:
+ styles/prosilver/template/ucp_prefs_personal.html
- + styles/subsilver2/template/ucp_prefs_personal.html
* Since: 3.1.0-a1
* Purpose: Add user options to the top of the Edit Global Settings block
-ucp_prefs_personal_append
+ucp_prefs_post_append
===
* Locations:
- + styles/prosilver/template/ucp_prefs_personal.html
- + styles/subsilver2/template/ucp_prefs_personal.html
+ + styles/prosilver/template/ucp_prefs_post.html
* Since: 3.1.0-a1
-* Purpose: Add user options to the bottom of the Edit Global Settings block
+* Purpose: Add user options to the bottom of the Edit Posting Defaults block
ucp_prefs_post_prepend
===
* Locations:
+ styles/prosilver/template/ucp_prefs_post.html
- + styles/subsilver2/template/ucp_prefs_post.html
* Since: 3.1.0-a1
* Purpose: Add user options to the top of the Edit Posting Defaults block
-ucp_prefs_post_append
+ucp_prefs_view_radio_buttons_append
===
* Locations:
- + styles/prosilver/template/ucp_prefs_post.html
- + styles/subsilver2/template/ucp_prefs_post.html
+ + styles/prosilver/template/ucp_prefs_view.html
* Since: 3.1.0-a1
-* Purpose: Add user options to the bottom of the Edit Posting Defaults block
+* Purpose: Add options to the bottom of the radio buttons block of the Edit
+Display Options screen
ucp_prefs_view_radio_buttons_prepend
===
* Locations:
+ styles/prosilver/template/ucp_prefs_view.html
- + styles/subsilver2/template/ucp_prefs_view.html
* Since: 3.1.0-a1
* Purpose: Add options to the top of the radio buttons block of the Edit
Display Options screen
-ucp_prefs_view_radio_buttons_append
+ucp_prefs_view_select_menu_append
===
* Locations:
+ styles/prosilver/template/ucp_prefs_view.html
- + styles/subsilver2/template/ucp_prefs_view.html
* Since: 3.1.0-a1
-* Purpose: Add options to the bottom of the radio buttons block of the Edit
+* Purpose: Add options to the bottom of the drop-down lists block of the Edit
Display Options screen
ucp_prefs_view_select_menu_prepend
===
* Locations:
+ styles/prosilver/template/ucp_prefs_view.html
- + styles/subsilver2/template/ucp_prefs_view.html
* Since: 3.1.0-a1
* Purpose: Add options to the top of the drop-down lists block of the Edit
Display Options screen
-ucp_prefs_view_select_menu_append
+ucp_profile_profile_info_after
===
* Locations:
- + styles/prosilver/template/ucp_prefs_view.html
- + styles/subsilver2/template/ucp_prefs_view.html
-* Since: 3.1.0-a1
-* Purpose: Add options to the bottom of the drop-down lists block of the Edit
-Display Options screen
+ + styles/prosilver/template/ucp_profile_profile_info.html
+* Since: 3.1.4-RC1
+* Purpose: Add options in profile page fieldset - after custom profile fields.
ucp_profile_profile_info_before
===
* Locations:
+ styles/prosilver/template/ucp_profile_profile_info.html
- + styles/subsilver2/template/ucp_profile_profile_info.html
* Since: 3.1.4-RC1
* Purpose: Add options in profile page fieldset - before jabber field.
-ucp_profile_profile_info_after
+ucp_profile_profile_info_birthday_label_append
===
* Locations:
+ styles/prosilver/template/ucp_profile_profile_info.html
- + styles/subsilver2/template/ucp_profile_profile_info.html
+* Since: 3.2.9-RC1
+* Purpose: Add more text to birthday label, such as required asterisk
+
+ucp_profile_register_details_after
+===
+* Locations:
+ + styles/prosilver/template/ucp_profile_reg_details.html
* Since: 3.1.4-RC1
-* Purpose: Add options in profile page fieldset - after custom profile fields.
+* Purpose: Add options in profile page fieldset - after confirm password field.
ucp_profile_register_details_before
===
* Locations:
+ styles/prosilver/template/ucp_profile_reg_details.html
- + styles/subsilver2/template/ucp_profile_reg_details.html
* Since: 3.1.4-RC1
* Purpose: Add options in profile page fieldset - before first field.
-ucp_profile_register_details_after
+ucp_profile_signature_posting_editor_options_prepend
===
* Locations:
- + styles/prosilver/template/ucp_profile_reg_details.html
- + styles/subsilver2/template/ucp_profile_reg_details.html
-* Since: 3.1.4-RC1
-* Purpose: Add options in profile page fieldset - after confirm password field.
+ + styles/prosilver/template/ucp_profile_signature.html
+* Since: 3.2.6-RC1
+* Purpose: Add options signature posting editor - before first option.
ucp_register_buttons_before
===
* Locations:
+ styles/prosilver/template/ucp_register.html
- + styles/subsilver2/template/ucp_register.html
* Since: 3.1.11-RC1
* Purpose: Add content before buttons in registration form.
-ucp_register_credentials_before
+ucp_register_credentials_after
===
* Locations:
+ styles/prosilver/template/ucp_register.html
- + styles/subsilver2/template/ucp_register.html
* Since: 3.1.0-b5
-* Purpose: Add options in registration page fieldset - before first field.
+* Purpose: Add options in registration page fieldset - after password field.
-ucp_register_profile_fields_after
+ucp_register_credentials_before
===
* Locations:
+ styles/prosilver/template/ucp_register.html
- + styles/subsilver2/template/ucp_register.html
* Since: 3.1.0-b5
-* Purpose: Add options in registration page fieldset - after last field.
+* Purpose: Add options in registration page fieldset - before first field.
-ucp_register_credentials_after
+ucp_register_options_before
===
* Locations:
+ styles/prosilver/template/ucp_register.html
- + styles/subsilver2/template/ucp_register.html
* Since: 3.1.0-b5
-* Purpose: Add options in registration page fieldset - after password field.
+* Purpose: Add options in registration page fieldset - before language selector.
-ucp_register_options_before
+ucp_register_profile_fields_after
===
* Locations:
+ styles/prosilver/template/ucp_register.html
- + styles/subsilver2/template/ucp_register.html
* Since: 3.1.0-b5
-* Purpose: Add options in registration page fieldset - before language selector.
+* Purpose: Add options in registration page fieldset - after last field.
ucp_register_profile_fields_before
===
* Locations:
+ styles/prosilver/template/ucp_register.html
- + styles/subsilver2/template/ucp_register.html
* Since: 3.1.0-b5
* Purpose: Add options in registration page fieldset - before profile fields.
-ucp_friend_list_before
+viewforum_body_last_post_author_username_append
===
* Locations:
- + styles/prosilver/template/ucp_zebra_friends.html
- + styles/subsilver2/template/ucp_zebra_friends.html
-* Since: 3.1.0-a4
-* Purpose: Add optional elements before list of friends in UCP
+ + styles/prosilver/template/viewforum_body.html (2)
+* Since: 3.2.4-RC1
+* Purpose: Append information to last post author username of member
-ucp_friend_list_after
+viewforum_body_last_post_author_username_prepend
===
* Locations:
- + styles/prosilver/template/ucp_zebra_friends.html
- + styles/subsilver2/template/ucp_zebra_friends.html
-* Since: 3.1.0-a4
-* Purpose: Add optional elements after list of friends in UCP
+ + styles/prosilver/template/viewforum_body.html (2)
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to last post author username of member
+
+viewforum_body_topic_author_username_append
+===
+* Locations:
+ + styles/prosilver/template/viewforum_body.html
+* Since: 3.2.4-RC1
+* Purpose: Append information to topic author username of member
+
+viewforum_body_topic_author_username_prepend
+===
+* Locations:
+ + styles/prosilver/template/viewforum_body.html
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to topic author username of member
viewforum_body_topic_row_after
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.7-RC1
* Purpose: Add content after the topic list item.
@@ -2477,7 +2755,6 @@ viewforum_body_topic_row_append
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.7-RC1
* Purpose: Add content at the start of the topic list item.
@@ -2485,7 +2762,6 @@ viewforum_body_topic_row_before
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.7-RC1
* Purpose: Add content before the topic list item.
@@ -2493,7 +2769,6 @@ viewforum_body_topic_row_prepend
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.7-RC1
* Purpose: Add content at the end of the topic list item.
@@ -2501,93 +2776,41 @@ viewforum_body_topicrow_row_before
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.10-RC1
* Purpose: Add content before list of topics.
-viewforum_buttons_bottom_before
-===
-* Locations:
- + styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
-* Since: 3.1.0-RC5
-* Purpose: Add buttons before New Topic button on the bottom of the topic's list
-
viewforum_buttons_bottom_after
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.0-RC5
* Purpose: Add buttons after New Topic button on the bottom of the topic's list
-viewforum_buttons_top_before
+viewforum_buttons_bottom_before
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.0-RC5
-* Purpose: Add buttons before New Topic button on the top of the topic's list
+* Purpose: Add buttons before New Topic button on the bottom of the topic's list
viewforum_buttons_top_after
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.0-RC5
* Purpose: Add buttons after New Topic button on the top of the topic's list
-viewtopic_buttons_bottom_before
-===
-* Locations:
- + styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
-* Since: 3.1.0-RC5
-* Purpose: Add buttons before Post Reply button on the bottom of the posts's list
-
-viewtopic_buttons_bottom_after
-===
-* Locations:
- + styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
-* Since: 3.1.0-RC5
-* Purpose: Add buttons after Post Reply button on the bottom of the posts's list
-
-viewtopic_buttons_top_before
-===
-* Locations:
- + styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
-* Since: 3.1.0-RC5
-* Purpose: Add buttons before Post Reply button on the top of the posts's list
-
-viewtopic_buttons_top_after
+viewforum_buttons_top_before
===
* Locations:
- + styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
+ + styles/prosilver/template/viewforum_body.html
* Since: 3.1.0-RC5
-* Purpose: Add buttons after Post Reply button on the top of the posts's list
-
-viewtopic_dropdown_bottom_custom
-===
-* Locations:
- + styles/prosilver/template/viewtopic_body.html
-* Since: 3.1.6-RC1
-* Purpose: Create a custom dropdown menu
-
-viewtopic_dropdown_top_custom
-===
-* Locations:
- + styles/prosilver/template/viewtopic_body.html
-* Since: 3.1.6-RC1
-* Purpose: Create a custom dropdown menu
+* Purpose: Add buttons before New Topic button on the top of the topic's list
viewforum_forum_name_append
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.0-b3
* Purpose: Add content directly after the forum name link on the View forum screen
@@ -2595,7 +2818,6 @@ viewforum_forum_name_prepend
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.0-b3
* Purpose: Add content directly before the forum name link on the View forum screen
@@ -2603,7 +2825,6 @@ viewforum_forum_title_after
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.5-RC1
* Purpose: Add content directly after the forum title on the View forum screen
@@ -2611,31 +2832,27 @@ viewforum_forum_title_before
===
* Locations:
+ styles/prosilver/template/viewforum_body.html
- + styles/subsilver2/template/viewforum_body.html
* Since: 3.1.5-RC1
* Purpose: Add content directly before the forum title on the View forum screen
-viewtopic_print_head_append
+viewonline_body_username_append
===
* Locations:
- + styles/prosilver/template/viewtopic_print.html
- + styles/subsilver2/template/viewtopic_print.html
-* Since: 3.1.0-a1
-* Purpose: Add asset calls directly before the `</head>` tag of the Print Topic screen
+ + styles/prosilver/template/viewonline_body.html
+* Since: 3.2.4-RC1
+* Purpose: Append information to username of member
-viewtopic_body_pagination_top_after
+viewonline_body_username_prepend
===
* Locations:
- + styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
-* Since: 3.1.4-RC1
-* Purpose: Add content after the pagination at top
+ + styles/prosilver/template/viewonline_body.html
+* Since: 3.2.4-RC1
+* Purpose: Prepend information to username of member
viewtopic_body_avatar_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-RC3
* Purpose: Add content right after the avatar when viewing topics
@@ -2643,7 +2860,6 @@ viewtopic_body_avatar_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-RC3
* Purpose: Add content right before the avatar when viewing topics
@@ -2667,17 +2883,21 @@ viewtopic_body_footer_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a1
* Purpose: Add content to the bottom of the View topic screen below the posts
-and quick reply, directly before the jumpbox in Prosilver, breadcrumbs in
-Subsilver2.
+and quick reply, directly before the jumpbox in Prosilver.
+
+viewtopic_body_pagination_top_after
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.4-RC1
+* Purpose: Add content after the pagination at top
viewtopic_body_poll_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.6-RC1
* Purpose: Add content after the poll panel.
@@ -2685,7 +2905,6 @@ viewtopic_body_poll_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.6-RC1
* Purpose: Add content before the poll panel.
@@ -2693,7 +2912,6 @@ viewtopic_body_poll_option_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-b3
* Purpose: Add content after the poll option
the list.
@@ -2702,7 +2920,6 @@ viewtopic_body_poll_option_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-b3
* Purpose: Add content before the poll option
the list.
@@ -2711,7 +2928,6 @@ viewtopic_body_poll_question_append
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-b3
* Purpose: Add content directly after the poll question on the View topic screen
@@ -2719,7 +2935,6 @@ viewtopic_body_poll_question_prepend
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-b3
* Purpose: Add content directly before the poll question on the View topic screen
@@ -2727,7 +2942,6 @@ viewtopic_body_post_author_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.3-RC1
* Purpose: Add content directly after the post author on the view topic screen
@@ -2735,7 +2949,6 @@ viewtopic_body_post_author_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.3-RC1
* Purpose: Add content directly before the post author on the view topic screen
@@ -2743,7 +2956,6 @@ viewtopic_body_post_buttons_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a1
* Purpose: Add post button to posts (next to edit, quote etc), at the end of
the list.
@@ -2752,7 +2964,6 @@ viewtopic_body_post_buttons_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a1
* Purpose: Add post button to posts (next to edit, quote etc), at the start of
the list.
@@ -2777,7 +2988,6 @@ viewtopic_body_post_subject_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.7-RC1
* Purpose: Add data before post icon and subject
@@ -2785,39 +2995,41 @@ viewtopic_body_postrow_back2top_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.8-RC1
-* Purpose: Add content to the post's bottom after the back to top link
+* Purpose: Add content to the post's bottom after the back to top link
viewtopic_body_postrow_back2top_append
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.8-RC1
-* Purpose: Add content to the post's bottom directly after the back to top link
+* Purpose: Add content to the post's bottom directly after the back to top link
viewtopic_body_postrow_back2top_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.8-RC1
-* Purpose: Add content to the post's bottom before the back to top link
+* Purpose: Add content to the post's bottom before the back to top link
viewtopic_body_postrow_back2top_prepend
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.8-RC1
-* Purpose: Add content to the post's bottom directly before the back to top link
+* Purpose: Add content to the post's bottom directly before the back to top link
+
+viewtopic_body_postrow_content_after
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.2.4-RC1
+* Purpose: Add content after the message content in topics views
viewtopic_body_postrow_custom_fields_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a1
* Purpose: Add data after the custom fields on the user profile when viewing
a post
@@ -2826,7 +3038,6 @@ viewtopic_body_postrow_custom_fields_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a1
* Purpose: Add data before the custom fields on the user profile when viewing
a post
@@ -2835,7 +3046,6 @@ viewtopic_body_postrow_post_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a4
* Purpose: Add data after posts
@@ -2843,7 +3053,6 @@ viewtopic_body_postrow_post_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a4
* Purpose: Add data before posts
@@ -2851,7 +3060,6 @@ viewtopic_body_postrow_post_content_footer
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-RC4
* Purpose: Add data at the end of the posts.
@@ -2859,7 +3067,6 @@ viewtopic_body_postrow_post_details_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.4-RC1
* Purpose: Add content after the post details
@@ -2867,7 +3074,6 @@ viewtopic_body_postrow_post_details_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.4-RC1
* Purpose: Add content before the post details
@@ -2875,7 +3081,6 @@ viewtopic_body_postrow_post_notices_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-b2
* Purpose: Add posts specific custom notices at the notices bottom.
@@ -2883,7 +3088,6 @@ viewtopic_body_postrow_post_notices_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-b2
* Purpose: Add posts specific custom notices at the notices top.
@@ -2891,7 +3095,6 @@ viewtopic_body_postrow_rank_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.6-RC1
* Purpose: Add data after the rank on the user profile when viewing
a post
@@ -2900,7 +3103,6 @@ viewtopic_body_postrow_rank_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.6-RC1
* Purpose: Add data before the rank on the user profile when viewing
a post
@@ -2909,15 +3111,62 @@ viewtopic_body_topic_actions_before
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a4
* Purpose: Add data before the topic actions buttons (after the posts sorting options)
+viewtopic_buttons_bottom_after
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.0-RC5
+* Purpose: Add buttons after Post Reply button on the bottom of the posts's list
+
+viewtopic_buttons_bottom_before
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.0-RC5
+* Purpose: Add buttons before Post Reply button on the bottom of the posts's list
+
+viewtopic_buttons_top_after
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.0-RC5
+* Purpose: Add buttons after Post Reply button on the top of the posts's list
+
+viewtopic_buttons_top_before
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.0-RC5
+* Purpose: Add buttons before Post Reply button on the top of the posts's list
+
+viewtopic_dropdown_bottom_custom
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.6-RC1
+* Purpose: Create a custom dropdown menu
+
+viewtopic_dropdown_top_custom
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.6-RC1
+* Purpose: Create a custom dropdown menu
+
+viewtopic_print_head_append
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_print.html
+* Since: 3.1.0-a1
+* Purpose: Add asset calls directly before the `</head>` tag of the Print Topic screen
+
viewtopic_topic_title_after
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.7-RC1
* Purpose: Add content directly after the topic title link on the View topic screen (outside of the h2 HTML tag)
@@ -2925,15 +3174,20 @@ viewtopic_topic_title_append
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-b3
* Purpose: Add content directly after the topic title link on the View topic screen
+viewtopic_topic_title_before
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.2.2-RC1
+* Purpose: Add content directly before the topic title link on the View topic screen (outside of the h2 HTML tag)
+
viewtopic_topic_title_prepend
===
* Locations:
+ styles/prosilver/template/viewtopic_body.html
- + styles/subsilver2/template/viewtopic_body.html
* Since: 3.1.0-a1
* Purpose: Add content directly before the topic title link on the View topic screen
diff --git a/phpBB/docs/install-config.sample.yml b/phpBB/docs/install-config.sample.yml
new file mode 100644
index 0000000000..a354e52e2f
--- /dev/null
+++ b/phpBB/docs/install-config.sample.yml
@@ -0,0 +1,38 @@
+installer:
+ admin:
+ name: admin
+ password: adminadmin
+ email: admin@example.org
+
+ board:
+ lang: en
+ name: My Board
+ description: My amazing new phpBB board
+
+ database:
+ dbms: sqlite3
+ dbhost: /tmp/phpbb.sqlite3
+ dbport: ~
+ dbuser: ~
+ dbpasswd: ~
+ dbname: ~
+ table_prefix: phpbb_
+
+ email:
+ enabled: false
+ smtp_delivery : ~
+ smtp_host: ~
+ smtp_port: ~
+ smtp_auth: ~
+ smtp_user: ~
+ smtp_pass: ~
+
+ server:
+ cookie_secure: false
+ server_protocol: http://
+ force_server_vars: false
+ server_name: localhost
+ server_port: 80
+ script_path: /
+
+ extensions: ['phpbb/viglink']
diff --git a/phpBB/docs/nginx.sample.conf b/phpBB/docs/nginx.sample.conf
index bf33f4e73d..c5a9472a1c 100644
--- a/phpBB/docs/nginx.sample.conf
+++ b/phpBB/docs/nginx.sample.conf
@@ -18,11 +18,11 @@ http {
gzip_vary on;
gzip_http_version 1.1;
gzip_min_length 700;
-
+
# Compression levels over 6 do not give an appreciable improvement
# in compression ratio, but take more resources.
gzip_comp_level 6;
-
+
# IE 6 and lower do not support gzip with Vary correctly.
gzip_disable "msie6";
# Before nginx 0.7.63:
@@ -49,9 +49,7 @@ http {
server_name myforums.com;
# A trick from http://wiki.nginx.org/Pitfalls#Taxing_Rewrites:
- rewrite ^ http://www.myforums.com$request_uri permanent;
- # Equivalent to:
- #rewrite ^(.*)$ http://www.myforums.com$1 permanent;
+ return 301 http://www.myforums.com$request_uri;
}
# The actual board domain.
@@ -62,7 +60,7 @@ http {
root /path/to/phpbb;
location / {
- # phpbb uses index.htm
+ # phpBB uses index.htm
index index.php index.html index.htm;
try_files $uri $uri/ @rewriteapp;
}
@@ -72,7 +70,7 @@ http {
}
# Deny access to internal phpbb files.
- location ~ /(config\.php|common\.php|cache|files|images/avatars/upload|includes|phpbb|store|vendor) {
+ location ~ /(config\.php|common\.php|cache|files|images/avatars/upload|includes|(?<!ext/)phpbb(?!\w+)|store|vendor) {
deny all;
# deny was ignored before 0.8.40 for connections over IPv6.
# Use internal directive to prohibit access on older versions.
@@ -92,6 +90,29 @@ http {
fastcgi_pass php;
}
+ # Correctly pass scripts for installer
+ location /install/ {
+ # phpBB uses index.htm
+ try_files $uri $uri/ @rewrite_installapp =404;
+
+ # Pass the php scripts to fastcgi server specified in upstream declaration.
+ location ~ \.php(/|$) {
+ # Unmodified fastcgi_params from nginx distribution.
+ include fastcgi_params;
+ # Necessary for php.
+ fastcgi_split_path_info ^(.+\.php)(/.*)$;
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
+ fastcgi_param DOCUMENT_ROOT $realpath_root;
+ try_files $uri $uri/ /install/app.php$is_args$args =404;
+ fastcgi_pass php;
+ }
+ }
+
+ location @rewrite_installapp {
+ rewrite ^(.*)$ /install/app.php/$1 last;
+ }
+
# Deny access to version control system directories.
location ~ /\.svn|/\.git {
deny all;
diff --git a/phpBB/docs/sphinx.sample.conf b/phpBB/docs/sphinx.sample.conf
index 0a210ecd1a..d7f2fd782c 100644
--- a/phpBB/docs/sphinx.sample.conf
+++ b/phpBB/docs/sphinx.sample.conf
@@ -29,7 +29,6 @@ source source_phpbb_{SPHINX_ID}_main
AND p.post_id >= $start AND p.post_id <= $end
sql_query_post =
sql_query_post_index = UPDATE phpbb_sphinx SET max_doc_id = $maxid WHERE counter_id = 1
- sql_query_info = SELECT * FROM phpbb_posts WHERE post_id = $id
sql_attr_uint = forum_id
sql_attr_uint = topic_id
sql_attr_uint = poster_id
@@ -42,7 +41,7 @@ source source_phpbb_{SPHINX_ID}_main
}
source source_phpbb_{SPHINX_ID}_delta : source_phpbb_{SPHINX_ID}_main
{
- sql_query_pre =
+ sql_query_pre = SET NAMES 'utf8'
sql_query_range =
sql_range_step =
sql_query = SELECT \
@@ -62,7 +61,7 @@ source source_phpbb_{SPHINX_ID}_delta : source_phpbb_{SPHINX_ID}_main
WHERE \
p.topic_id = t.topic_id \
AND p.post_id >= ( SELECT max_doc_id FROM phpbb_sphinx WHERE counter_id=1 )
- sql_query_pre =
+ sql_query_post_index =
}
index index_phpbb_{SPHINX_ID}_main
{
@@ -72,10 +71,10 @@ index index_phpbb_{SPHINX_ID}_main
morphology = none
stopwords =
min_word_len = 2
- charset_type = utf-8
charset_table = U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z, A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6, U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101, U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109, U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F, U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, U+0116->U+0117, U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D, U+011D, U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, U+0134->U+0135, U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, U+013C, U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, U+0143->U+0144, U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, U+014B, U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, U+0152->U+0153, U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159, U+0159, U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, U+0160->U+0161, U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, U+0167, U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, U+016E->U+016F, U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175, U+0175, U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, U+017B->U+017C, U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, U+0430..U+044F, U+4E00..U+9FFF
min_prefix_len = 0
min_infix_len = 0
+ html_strip = 1
}
index index_phpbb_{SPHINX_ID}_delta : index_phpbb_{SPHINX_ID}_main
{
@@ -88,13 +87,11 @@ indexer
}
searchd
{
- compat_sphinxql_magics = 0
listen = localhost:9312
log = {DATA_PATH}/log/searchd.log
query_log = {DATA_PATH}/log/sphinx-query.log
read_timeout = 5
max_children = 30
pid_file = {DATA_PATH}/searchd.pid
- max_matches = 20000
binlog_path = {DATA_PATH}
}
diff --git a/phpBB/docs/update-config.sample.yml b/phpBB/docs/update-config.sample.yml
new file mode 100644
index 0000000000..caa1a9ef1e
--- /dev/null
+++ b/phpBB/docs/update-config.sample.yml
@@ -0,0 +1,3 @@
+updater:
+ type: all
+ extensions: ['phpbb/viglink']
diff --git a/phpBB/docs/vagrant.md b/phpBB/docs/vagrant.md
new file mode 100644
index 0000000000..ac318270c1
--- /dev/null
+++ b/phpBB/docs/vagrant.md
@@ -0,0 +1,123 @@
+## Using Vagrant with phpBB
+
+phpBB includes support for Vagrant. This allows developers and contributors to run phpBB without the need to set up their own local web server with traditional WAMP/MAMP stacks. It also provides a consistent environment between developers for writing and debugging code changes more productively.
+
+phpBB uses the [Laravel/Homestead](https://laravel.com/docs/5.1/homestead) Vagrant box. It runs a Linux server with Ubuntu 14.04, PHP 5.6, Nginx, SQLite3, MySQL, and a whole lot more (complete specs below).
+
+## Get Started
+
+* Download and Install [Vagrant](https://www.vagrantup.com/downloads.html)
+* Download and Install [VirtualBox](https://www.virtualbox.org/wiki/Downloads)
+* Run `vagrant up` from the root of your cloned fork of the phpBB Git repository
+
+```sh
+$ vagrant up
+```
+
+* Access phpBB at `http://192.168.10.10/`
+* Username: **admin**
+* Password: **adminadmin**
+
+## Additional commands:
+* Access your Linux server from the command line:
+
+```sh
+$ vagrant ssh
+```
+
+* Pause your server:
+
+```sh
+$ vagrant suspend
+```
+
+* Shut down your server:
+
+```sh
+$ vagrant halt
+```
+
+* Delete and remove your server:
+
+```sh
+$ vagrant destroy
+```
+
+> Note: destroying the vagrant server will remove all traces of the VM from your computer, reclaiming any disk space used by it. However, it also means the next time you vagrant up, you will be creating a brand new VM with a fresh install of phpBB and a new database.
+
+## Customising the phpBB configuration
+
+By default, phpBB is pre-configured to install with a MySQL database. You can, however, switch to PostegreSQL or SQLite3 by editing the `phpbb-install-config.yml` file in the vagrant directory. The next time you run `vagrant up` (or `vagrant provision`) it will be installed under the new configuration.
+
+If you prefer to access phpBB from the more friendly URL `http://phpbb.app` then you must update your computer's hosts file. This file is typically located at `/etc/hosts` for Mac/Linux or `C:\Windows\System32\drivers\etc\hosts` for Windows. Open this file and add the following line to it, at the very bottom, and save.
+
+```
+192.168.10.10 phpbb.app
+```
+
+## How it all works
+
+When you vagrant up, the Laravel/Homestead box is transparently loaded as a Virtual Machine on your computer (this may take several minutes the very first time while it downloads the VM image to your computer). Your local phpBB repository clone is mirrored/shared with the VM, so you can work on the phpBB code on your computer, and see the changes immediately when you browse to phpBB at the URL provided by the VM.
+
+This is very similar to traditional methods of working with a local WAMP/MAMP stack, except the webserver is now being provided by a VM of a Linux server. The advantages here are the exact same Linux server environment is being used by everybody who uses Vagrant with phpBB, so there will be consist behaviour unlike when everybody is developing on different versions of PHP, server configurations, etc.
+
+The environment is also "sandboxed" from your system. This means you don't need to worry about adjusting your own computer's internal PHP settings, setting up databases, or doing damage to your system or to phpBB. Other than the phpBB codebase, which lives on your computer, all execution is taking place within the VM and you can at any time, halt or destroy the VM and start a brand new one.
+
+There are some caveats, however. You can only run one vagrant VM for the phpBB repository. And of course, the database will be destroyed when you vagrant destroy. If the database is important, you should SSH into your vagrant VM and export/import the DB as needed using SSH commands.
+
+For example, to export/import a MySQL database (using phpBB's `store` directory):
+
+SSH into the VM
+
+```sh
+$ vagrant ssh
+```
+
+Export MySQL:
+
+```sh
+$ mysqldump -uhomestead -psecret phpbb > /home/vagrant/phpbb/phpBB/store/phpbb.sql
+```
+
+Import MySQL:
+
+```sh
+$ mysql -uhomestead -psecret phpbb < /home/vagrant/phpbb/phpBB/store/phpbb.sql
+```
+
+---
+
+## About the Laravel/Homestead box
+
+### Included Software
+
+* Ubuntu 14.04
+* Git
+* PHP 5.6
+* HHVM
+* Nginx
+* MySQL
+* Sqlite3
+* Postgres
+* Composer
+* Node (With PM2, Bower, Grunt, and Gulp)
+* Redis
+* Memcached
+* Beanstalkd
+* Blackfire Profiler
+
+### MySQL Access
+
+- Hostname: 127.0.0.1
+- Username: homestead
+- Password: secret
+- Database: phpbb
+- Port: 3306
+
+### PostgreSQL Access
+
+- Hostname: 127.0.0.1
+- Username: homestead
+- Password: secret
+- Database: phpbb
+- Port: 5432
diff --git a/phpBB/download/file.php b/phpBB/download/file.php
index e60ffad6b0..9ee489cef4 100644
--- a/phpBB/download/file.php
+++ b/phpBB/download/file.php
@@ -42,6 +42,11 @@ if (isset($_GET['avatar']))
$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
extract($phpbb_config_php_file->get_all());
+ if (!defined('PHPBB_ENVIRONMENT'))
+ {
+ @define('PHPBB_ENVIRONMENT', 'production');
+ }
+
if (!defined('PHPBB_INSTALLED') || empty($dbms) || empty($acm_type))
{
exit;
@@ -56,40 +61,45 @@ if (isset($_GET['avatar']))
$phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx);
$phpbb_class_loader_ext->register();
- phpbb_load_extensions_autoloaders($phpbb_root_path);
-
// Set up container
- $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
- $phpbb_container = $phpbb_container_builder->get_container();
+ $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+ $phpbb_container = $phpbb_container_builder->with_config($phpbb_config_php_file)->get_container();
$phpbb_class_loader->set_cache($phpbb_container->get('cache.driver'));
$phpbb_class_loader_ext->set_cache($phpbb_container->get('cache.driver'));
// set up caching
+ /* @var $cache \phpbb\cache\service */
$cache = $phpbb_container->get('cache');
+ /* @var $phpbb_dispatcher \phpbb\event\dispatcher */
$phpbb_dispatcher = $phpbb_container->get('dispatcher');
+
+ /* @var $request \phpbb\request\request_interface */
$request = $phpbb_container->get('request');
+
+ /* @var $db \phpbb\db\driver\driver_interface */
$db = $phpbb_container->get('dbal.conn');
+
+ /* @var $phpbb_log \phpbb\log\log_interface */
$phpbb_log = $phpbb_container->get('log');
unset($dbpasswd);
- request_var('', 0, false, false, $request);
-
+ /* @var $config \phpbb\config\config */
$config = $phpbb_container->get('config');
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
// load extensions
+ /* @var $phpbb_extension_manager \phpbb\extension\manager */
$phpbb_extension_manager = $phpbb_container->get('ext.manager');
// worst-case default
$browser = strtolower($request->header('User-Agent', 'msie 6.0'));
+ /* @var $phpbb_avatar_manager \phpbb\avatar\manager */
$phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
- $filename = request_var('avatar', '');
+ $filename = $request->variable('avatar', '');
$avatar_group = false;
$exit = false;
@@ -140,15 +150,17 @@ if (isset($_GET['avatar']))
include($phpbb_root_path . 'common.' . $phpEx);
require($phpbb_root_path . 'includes/functions_download' . '.' . $phpEx);
-$attach_id = request_var('id', 0);
-$mode = request_var('mode', '');
-$thumbnail = request_var('t', false);
+$attach_id = $request->variable('id', 0);
+$mode = $request->variable('mode', '');
+$thumbnail = $request->variable('t', false);
// Start session management, do not update session page.
$user->session_begin(false);
$auth->acl($user->data);
$user->setup('viewtopic');
+$phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
if (!$config['allow_attachments'] && !$config['allow_pm_attach'])
{
send_status_line(404, 'Not Found');
@@ -215,7 +227,7 @@ else
$post_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- if (!$post_row || ($post_row['post_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $post_row['forum_id'])))
+ if (!$post_row || !$phpbb_content_visibility->is_visible('post', $post_row['forum_id'], $post_row))
{
// Attachment of a soft deleted post and the user is not allowed to see the post
send_status_line(404, 'Not Found');
diff --git a/phpBB/faq.php b/phpBB/faq.php
index cf34ce809a..36a33c97a8 100644
--- a/phpBB/faq.php
+++ b/phpBB/faq.php
@@ -24,94 +24,13 @@ $user->session_begin();
$auth->acl($user->data);
$user->setup();
-$mode = request_var('mode', '');
-$template_file = 'faq_body.html';
-
-// Load the appropriate faq file
-switch ($mode)
-{
- case 'bbcode':
- $l_title = $user->lang['BBCODE_GUIDE'];
- $user->add_lang('bbcode', false, true);
- break;
-
- default:
- $page_title = $user->lang['FAQ_EXPLAIN'];
- $ext_name = $lang_file = '';
-
- /**
- * You can use this event display a custom help page
- *
- * @event core.faq_mode_validation
- * @var string page_title Title of the page
- * @var string mode FAQ that is going to be displayed
- * @var string lang_file Language file containing the help data
- * @var string ext_name Vendor and extension name where the help
- * language file can be loaded from
- * @var string template_file Template file name
- * @since 3.1.4-RC1
- * @changed 3.1.11-RC1 Added template_file var
- */
- $vars = array(
- 'page_title',
- 'mode',
- 'lang_file',
- 'ext_name',
- 'template_file',
- );
- extract($phpbb_dispatcher->trigger_event('core.faq_mode_validation', compact($vars)));
-
- $l_title = $page_title;
- $user->add_lang(($lang_file) ? $lang_file : 'faq', false, true, $ext_name);
- break;
-}
-
-// Pull the array data from the lang pack
-$switch_column = $found_switch = false;
-$help_blocks = array();
-foreach ($user->help as $help_ary)
-{
- if ($help_ary[0] == '--')
- {
- if ($help_ary[1] == '--')
- {
- $switch_column = true;
- $found_switch = true;
- continue;
- }
-
- $template->assign_block_vars('faq_block', array(
- 'BLOCK_TITLE' => $help_ary[1],
- 'SWITCH_COLUMN' => $switch_column,
- ));
-
- if ($switch_column)
- {
- $switch_column = false;
- }
- continue;
- }
-
- $template->assign_block_vars('faq_block.faq_row', array(
- 'FAQ_QUESTION' => $help_ary[0],
- 'FAQ_ANSWER' => $help_ary[1])
- );
-}
-
-// Lets build a page ...
-$template->assign_vars(array(
- 'L_FAQ_TITLE' => $l_title,
- 'L_BACK_TO_TOP' => $user->lang['BACK_TO_TOP'],
-
- 'SWITCH_COLUMN_MANUALLY' => (!$found_switch) ? true : false,
- 'S_IN_FAQ' => true,
-));
-
-page_header($l_title);
-
-$template->set_filenames(array(
- 'body' => $template_file)
+/** @var \phpbb\controller\helper $controller_helper */
+$controller_helper = $phpbb_container->get('controller.helper');
+
+$response = new \Symfony\Component\HttpFoundation\RedirectResponse(
+ $controller_helper->route(
+ $request->variable('mode', 'faq') === 'bbcode' ? 'phpbb_help_bbcode_controller' : 'phpbb_help_faq_controller'
+ ),
+ 301
);
-make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"));
-
-page_footer();
+$response->send();
diff --git a/phpBB/feed.php b/phpBB/feed.php
index 6fd0ed800f..1480867d6c 100644
--- a/phpBB/feed.php
+++ b/phpBB/feed.php
@@ -16,6 +16,9 @@
*
**/
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\Routing\Exception\InvalidParameterException;
+
/**
* @ignore
**/
@@ -23,234 +26,33 @@ define('IN_PHPBB', true);
$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
include($phpbb_root_path . 'common.' . $phpEx);
-include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
-
-if (!$config['feed_enable'])
-{
- trigger_error('NO_FEED_ENABLED');
-}
-
-// Start session
-$user->session_begin();
-
-if (!empty($config['feed_http_auth']) && request_var('auth', '') == 'http')
-{
- phpbb_http_login(array(
- 'auth_message' => 'Feed',
- 'viewonline' => request_var('viewonline', true),
- ));
-}
-
-$auth->acl($user->data);
-$user->setup('viewtopic');
-// Initial var setup
-$forum_id = request_var('f', 0);
-$topic_id = request_var('t', 0);
-$mode = request_var('mode', '');
+/** @var \phpbb\controller\helper $controller_helper */
+$controller_helper = $phpbb_container->get('controller.helper');
-// We do not use a template, therefore we simply define the global template variables here
-$global_vars = $item_vars = array();
-$feed_updated_time = 0;
+$forum_id = $request->variable('f', 0);
+$topic_id = $request->variable('t', 0);
+$mode = $request->variable('mode', '');
-// Generate params array for use in append_sid() to correctly link back to this page
-$params = false;
-if ($forum_id || $topic_id || $mode)
+if ($forum_id !== 0)
{
- $params = array(
- 'f' => ($forum_id) ? $forum_id : NULL,
- 't' => ($topic_id) ? $topic_id : NULL,
- 'mode' => ($mode) ? $mode : NULL,
- );
+ $url = $controller_helper->route('phpbb_feed_forum', array('forum_id' => $forum_id));
}
-
-// This boards URL
-$phpbb_feed_helper = $phpbb_container->get('feed.helper');
-$board_url = $phpbb_feed_helper->get_board_url();
-
-// Get correct feed object
-$phpbb_feed_factory = $phpbb_container->get('feed.factory');
-$feed = $phpbb_feed_factory->get_feed($mode, $forum_id, $topic_id);
-
-// No feed found
-if ($feed === false)
+else if ($topic_id !== 0)
{
- trigger_error('NO_FEED');
+ $url = $controller_helper->route('phpbb_feed_topic', array('topic_id' => $topic_id));
}
-
-// Open Feed
-$feed->open();
-
-// Iterate through items
-while ($row = $feed->get_item())
+else
{
- /**
- * Event to modify the feed row
- *
- * @event core.feed_modify_feed_row
- * @var int forum_id Forum ID
- * @var string mode Feeds mode (forums|topics|topics_new|topics_active|news)
- * @var array row Array with feed data
- * @var int topic_id Topic ID
- *
- * @since 3.1.10-RC1
- */
- $vars = array('forum_id', 'mode', 'row', 'topic_id');
- extract($phpbb_dispatcher->trigger_event('core.feed_modify_feed_row', compact($vars)));
-
- // BBCode options to correctly disable urls, smilies, bbcode...
- if ($feed->get('options') === NULL)
+ try
{
- // Allow all combinations
- $options = 7;
-
- if ($feed->get('enable_bbcode') !== NULL && $feed->get('enable_smilies') !== NULL && $feed->get('enable_magic_url') !== NULL)
- {
- $options = (($row[$feed->get('enable_bbcode')]) ? OPTION_FLAG_BBCODE : 0) + (($row[$feed->get('enable_smilies')]) ? OPTION_FLAG_SMILIES : 0) + (($row[$feed->get('enable_magic_url')]) ? OPTION_FLAG_LINKS : 0);
- }
+ $url = $controller_helper->route('phpbb_feed_overall', array('mode' => $mode));
}
- else
+ catch (InvalidParameterException $e)
{
- $options = $row[$feed->get('options')];
+ $url = $controller_helper->route('phpbb_feed_index');
}
-
- $title = (isset($row[$feed->get('title')]) && $row[$feed->get('title')] !== '') ? $row[$feed->get('title')] : ((isset($row[$feed->get('title2')])) ? $row[$feed->get('title2')] : '');
-
- $published = ($feed->get('published') !== NULL) ? (int) $row[$feed->get('published')] : 0;
- $updated = ($feed->get('updated') !== NULL) ? (int) $row[$feed->get('updated')] : 0;
-
- $display_attachments = ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && isset($row['post_attachment']) && $row['post_attachment']) ? true : false;
-
- $item_row = array(
- 'author' => ($feed->get('creator') !== NULL) ? $row[$feed->get('creator')] : '',
- 'published' => ($published > 0) ? $phpbb_feed_helper->format_date($published) : '',
- 'updated' => ($updated > 0) ? $phpbb_feed_helper->format_date($updated) : '',
- 'link' => '',
- 'title' => censor_text($title),
- 'category' => ($config['feed_item_statistics'] && !empty($row['forum_id'])) ? $board_url . '/viewforum.' . $phpEx . '?f=' . $row['forum_id'] : '',
- 'category_name' => ($config['feed_item_statistics'] && isset($row['forum_name'])) ? $row['forum_name'] : '',
- 'description' => censor_text($phpbb_feed_helper->generate_content($row[$feed->get('text')], $row[$feed->get('bbcode_uid')], $row[$feed->get('bitfield')], $options, $row['forum_id'], ($display_attachments ? $feed->get_attachments($row['post_id']) : array()))),
- 'statistics' => '',
- );
-
- // Adjust items, fill link, etc.
- $feed->adjust_item($item_row, $row);
-
- $item_vars[] = $item_row;
-
- $feed_updated_time = max($feed_updated_time, $published, $updated);
}
-// If we do not have any items at all, sending the current time is better than sending no time.
-if (!$feed_updated_time)
-{
- $feed_updated_time = time();
-}
-
-// Some default assignments
-// FEED_IMAGE is not used (atom)
-$global_vars = array_merge($global_vars, array(
- 'FEED_IMAGE' => '',
- 'SELF_LINK' => $phpbb_feed_helper->append_sid('feed.' . $phpEx, $params),
- 'FEED_LINK' => $board_url . '/index.' . $phpEx,
- 'FEED_TITLE' => $config['sitename'],
- 'FEED_SUBTITLE' => $config['site_desc'],
- 'FEED_UPDATED' => $phpbb_feed_helper->format_date($feed_updated_time),
- 'FEED_LANG' => $user->lang['USER_LANG'],
- 'FEED_AUTHOR' => $config['sitename'],
-));
-
-$feed->close();
-
-// Output page
-
-// gzip_compression
-if ($config['gzip_compress'])
-{
- if (@extension_loaded('zlib') && !headers_sent())
- {
- ob_start('ob_gzhandler');
- }
-}
-
-// IF debug extra is enabled and admin want to "explain" the page we need to set other headers...
-if (defined('DEBUG') && request_var('explain', 0) && $auth->acl_get('a_'))
-{
- header('Content-type: text/html; charset=UTF-8');
- header('Cache-Control: private, no-cache="set-cookie"');
- header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
-
- $mtime = explode(' ', microtime());
- $totaltime = $mtime[0] + $mtime[1] - $starttime;
-
- if (method_exists($db, 'sql_report'))
- {
- $db->sql_report('display');
- }
-
- garbage_collection();
- exit_handler();
-}
-
-header("Content-Type: application/atom+xml; charset=UTF-8");
-header("Last-Modified: " . gmdate('D, d M Y H:i:s', $feed_updated_time) . ' GMT');
-
-if (!empty($user->data['is_bot']))
-{
- // Let reverse proxies know we detected a bot.
- header('X-PHPBB-IS-BOT: yes');
-}
-
-echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
-echo '<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="' . $global_vars['FEED_LANG'] . '">' . "\n";
-echo '<link rel="self" type="application/atom+xml" href="' . $global_vars['SELF_LINK'] . '" />' . "\n\n";
-
-echo (!empty($global_vars['FEED_TITLE'])) ? '<title>' . $global_vars['FEED_TITLE'] . '</title>' . "\n" : '';
-echo (!empty($global_vars['FEED_SUBTITLE'])) ? '<subtitle>' . $global_vars['FEED_SUBTITLE'] . '</subtitle>' . "\n" : '';
-echo (!empty($global_vars['FEED_LINK'])) ? '<link href="' . $global_vars['FEED_LINK'] .'" />' . "\n" : '';
-echo '<updated>' . $global_vars['FEED_UPDATED'] . '</updated>' . "\n\n";
-
-echo '<author><name><![CDATA[' . $global_vars['FEED_AUTHOR'] . ']]></name></author>' . "\n";
-echo '<id>' . $global_vars['SELF_LINK'] . '</id>' . "\n";
-
-foreach ($item_vars as $row)
-{
- echo '<entry>' . "\n";
-
- if (!empty($row['author']))
- {
- echo '<author><name><![CDATA[' . $row['author'] . ']]></name></author>' . "\n";
- }
-
- echo '<updated>' . ((!empty($row['updated'])) ? $row['updated'] : $row['published']) . '</updated>' . "\n";
-
- if (!empty($row['published']))
- {
- echo '<published>' . $row['published'] . '</published>' . "\n";
- }
-
- echo '<id>' . $row['link'] . '</id>' . "\n";
- echo '<link href="' . $row['link'] . '"/>' . "\n";
- echo '<title type="html"><![CDATA[' . $row['title'] . ']]></title>' . "\n\n";
-
- if (!empty($row['category']) && isset($row['category_name']) && $row['category_name'] !== '')
- {
- echo '<category term="' . $row['category_name'] . '" scheme="' . $row['category'] . '" label="' . $row['category_name'] . '"/>' . "\n";
- }
-
- echo '<content type="html" xml:base="' . $row['link'] . '"><![CDATA[' . "\n";
- echo $row['description'];
-
- if (!empty($row['statistics']))
- {
- echo '<p>' . $user->lang['STATISTICS'] . ': ' . $row['statistics'] . '</p>';
- }
-
- echo '<hr />' . "\n" . ']]></content>' . "\n";
- echo '</entry>' . "\n";
-}
-
-echo '</feed>';
-
-garbage_collection();
-exit_handler();
+$response = new RedirectResponse($url, 301);
+$response->send();
diff --git a/phpBB/images/icons/misc/fire.gif b/phpBB/images/icons/misc/fire.gif
index e436d6e8c9..4adba205e5 100644
--- a/phpBB/images/icons/misc/fire.gif
+++ b/phpBB/images/icons/misc/fire.gif
Binary files differ
diff --git a/phpBB/images/icons/misc/heart.gif b/phpBB/images/icons/misc/heart.gif
index c626dcb99f..c391c37433 100644
--- a/phpBB/images/icons/misc/heart.gif
+++ b/phpBB/images/icons/misc/heart.gif
Binary files differ
diff --git a/phpBB/images/icons/misc/radioactive.gif b/phpBB/images/icons/misc/radioactive.gif
index 517ae6397b..6d7527c03e 100644
--- a/phpBB/images/icons/misc/radioactive.gif
+++ b/phpBB/images/icons/misc/radioactive.gif
Binary files differ
diff --git a/phpBB/images/icons/misc/star.gif b/phpBB/images/icons/misc/star.gif
index dcde6eb66e..15a96ef87a 100644
--- a/phpBB/images/icons/misc/star.gif
+++ b/phpBB/images/icons/misc/star.gif
Binary files differ
diff --git a/phpBB/images/icons/misc/thinking.gif b/phpBB/images/icons/misc/thinking.gif
index fdec41bc19..23f226774d 100644
--- a/phpBB/images/icons/misc/thinking.gif
+++ b/phpBB/images/icons/misc/thinking.gif
Binary files differ
diff --git a/phpBB/images/icons/smile/alert.gif b/phpBB/images/icons/smile/alert.gif
index 024e2a969a..b0e1fe1737 100644
--- a/phpBB/images/icons/smile/alert.gif
+++ b/phpBB/images/icons/smile/alert.gif
Binary files differ
diff --git a/phpBB/images/icons/smile/info.gif b/phpBB/images/icons/smile/info.gif
index d715ac7c75..2b28d8c83a 100644
--- a/phpBB/images/icons/smile/info.gif
+++ b/phpBB/images/icons/smile/info.gif
Binary files differ
diff --git a/phpBB/images/icons/smile/mrgreen.gif b/phpBB/images/icons/smile/mrgreen.gif
index 9cd2715824..f6da47a117 100644
--- a/phpBB/images/icons/smile/mrgreen.gif
+++ b/phpBB/images/icons/smile/mrgreen.gif
Binary files differ
diff --git a/phpBB/images/icons/smile/question.gif b/phpBB/images/icons/smile/question.gif
index a07c038a9b..2c82028417 100644
--- a/phpBB/images/icons/smile/question.gif
+++ b/phpBB/images/icons/smile/question.gif
Binary files differ
diff --git a/phpBB/images/icons/smile/redface.gif b/phpBB/images/icons/smile/redface.gif
index 50e7ce3bfa..85c81f061c 100644
--- a/phpBB/images/icons/smile/redface.gif
+++ b/phpBB/images/icons/smile/redface.gif
Binary files differ
diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php
index e4650455c4..94e3660de8 100644
--- a/phpBB/includes/acp/acp_attachments.php
+++ b/phpBB/includes/acp/acp_attachments.php
@@ -27,6 +27,9 @@ class acp_attachments
/** @var \phpbb\config\config */
protected $config;
+ /** @var \phpbb\language\language */
+ protected $language;
+
/** @var ContainerBuilder */
protected $phpbb_container;
@@ -36,27 +39,36 @@ class acp_attachments
/** @var \phpbb\user */
protected $user;
+ /** @var \phpbb\filesystem\filesystem_interface */
+ protected $filesystem;
+
+ /** @var \phpbb\attachment\manager */
+ protected $attachment_manager;
+
public $id;
public $u_action;
protected $new_config;
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $phpbb_container, $phpbb_dispatcher;
- global $config, $phpbb_admin_path, $phpbb_root_path, $phpEx;
+ global $db, $user, $auth, $template, $cache, $phpbb_container, $phpbb_filesystem, $phpbb_dispatcher;
+ global $config, $phpbb_admin_path, $phpbb_root_path, $phpEx, $phpbb_log, $request;
$this->id = $id;
$this->db = $db;
$this->config = $config;
+ $this->language = $phpbb_container->get('language');
$this->template = $template;
$this->user = $user;
$this->phpbb_container = $phpbb_container;
+ $this->filesystem = $phpbb_filesystem;
+ $this->attachment_manager = $phpbb_container->get('attachment.manager');
$user->add_lang(array('posting', 'viewtopic', 'acp/attachments'));
$error = $notify = array();
$submit = (isset($_POST['submit'])) ? true : false;
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$form_key = 'acp_attach';
add_form_key($form_key);
@@ -120,7 +132,7 @@ class acp_attachments
$s_assigned_groups = array();
while ($row = $db->sql_fetchrow($result))
{
- $row['group_name'] = (isset($user->lang['EXT_GROUP_' . $row['group_name']])) ? $user->lang['EXT_GROUP_' . $row['group_name']] : $row['group_name'];
+ $row['group_name'] = $this->language->is_set('EXT_GROUP_' . utf8_strtoupper($row['group_name'])) ? $this->language->lang('EXT_GROUP_' . utf8_strtoupper($row['group_name'])) : $row['group_name'];
$s_assigned_groups[$row['cat_id']][] = $row['group_name'];
}
$db->sql_freeresult($result);
@@ -156,7 +168,6 @@ class acp_attachments
'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
- 'img_imagick' => array('lang' => 'IMAGICK_PATH', 'validate' => 'absolute_path', 'type' => 'text:20:200', 'explain' => true, 'append' => '&nbsp;&nbsp;<span>[ <a href="' . $this->u_action . '&amp;action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'),
'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
)
@@ -175,14 +186,14 @@ class acp_attachments
extract($phpbb_dispatcher->trigger_event('core.acp_attachments_config_edit_add', compact($vars)));
$this->new_config = $config;
- $cfg_array = (isset($_REQUEST['config'])) ? request_var('config', array('' => '')) : $this->new_config;
+ $cfg_array = (isset($_REQUEST['config'])) ? $request->variable('config', array('' => '')) : $this->new_config;
$error = array();
// We validate the complete config if whished
validate_config_vars($display_vars['vars'], $cfg_array, $error);
// Do not write values if there is an error
- if (sizeof($error))
+ if (count($error))
{
$submit = false;
}
@@ -199,13 +210,13 @@ class acp_attachments
if (in_array($config_name, array('attachment_quota', 'max_filesize', 'max_filesize_pm')))
{
- $size_var = request_var($config_name, '');
+ $size_var = $request->variable($config_name, '');
$this->new_config[$config_name] = $config_value = ($size_var == 'kb') ? round($config_value * 1024) : (($size_var == 'mb') ? round($config_value * 1048576) : $config_value);
}
if ($submit)
{
- set_config($config_name, $config_value);
+ $config->set($config_name, $config_value);
}
}
@@ -213,12 +224,12 @@ class acp_attachments
if ($submit)
{
- add_log('admin', 'LOG_CONFIG_ATTACH');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_ATTACH');
// Check Settings
$this->test_upload($error, $this->new_config['upload_path'], false);
- if (!sizeof($error))
+ if (!count($error))
{
trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
}
@@ -226,38 +237,6 @@ class acp_attachments
$template->assign_var('S_ATTACHMENT_SETTINGS', true);
- if ($action == 'imgmagick')
- {
- $this->new_config['img_imagick'] = $this->search_imagemagick();
- }
-
- // We strip eventually manual added convert program, we only want the patch
- if ($this->new_config['img_imagick'])
- {
- // Change path separator
- $this->new_config['img_imagick'] = str_replace('\\', '/', $this->new_config['img_imagick']);
- $this->new_config['img_imagick'] = str_replace(array('convert', '.exe'), array('', ''), $this->new_config['img_imagick']);
-
- // Check for trailing slash
- if (substr($this->new_config['img_imagick'], -1) !== '/')
- {
- $this->new_config['img_imagick'] .= '/';
- }
- }
-
- $supported_types = get_supported_image_types();
-
- // Check Thumbnail Support
- if (!$this->new_config['img_imagick'] && (!isset($supported_types['format']) || !sizeof($supported_types['format'])))
- {
- $this->new_config['img_create_thumbnail'] = 0;
- }
-
- $template->assign_vars(array(
- 'U_SEARCH_IMAGICK' => $this->u_action . '&amp;action=imgmagick',
- 'S_THUMBNAIL_SUPPORT' => (!$this->new_config['img_imagick'] && (!isset($supported_types['format']) || !sizeof($supported_types['format']))) ? false : true)
- );
-
// Secure Download Options - Same procedure as with banning
$allow_deny = ($this->new_config['secure_allow_deny']) ? 'ALLOWED' : 'DISALLOWED';
@@ -282,7 +261,7 @@ class acp_attachments
$template->assign_vars(array(
'S_SECURE_DOWNLOADS' => $this->new_config['secure_downloads'],
'S_DEFINED_IPS' => ($defined_ips != '') ? true : false,
- 'S_WARNING' => (sizeof($error)) ? true : false,
+ 'S_WARNING' => (count($error)) ? true : false,
'WARNING_MSG' => implode('<br />', $error),
'DEFINED_IPS' => $defined_ips,
@@ -349,13 +328,13 @@ class acp_attachments
if ($submit)
{
// Change Extensions ?
- $extension_change_list = request_var('extension_change_list', array(0));
- $group_select_list = request_var('group_select', array(0));
+ $extension_change_list = $request->variable('extension_change_list', array(0));
+ $group_select_list = $request->variable('group_select', array(0));
// Generate correct Change List
$extensions = array();
- for ($i = 0, $size = sizeof($extension_change_list); $i < $size; $i++)
+ for ($i = 0, $size = count($extension_change_list); $i < $size; $i++)
{
$extensions[$extension_change_list[$i]]['group_id'] = $group_select_list[$i];
}
@@ -374,15 +353,15 @@ class acp_attachments
WHERE extension_id = ' . $row['extension_id'];
$db->sql_query($sql);
- add_log('admin', 'LOG_ATTACH_EXT_UPDATE', $row['extension']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXT_UPDATE', false, array($row['extension']));
}
}
$db->sql_freeresult($result);
// Delete Extension?
- $extension_id_list = request_var('extension_id_list', array(0));
+ $extension_id_list = $request->variable('extension_id_list', array(0));
- if (sizeof($extension_id_list))
+ if (count($extension_id_list))
{
$sql = 'SELECT extension
FROM ' . EXTENSIONS_TABLE . '
@@ -401,18 +380,18 @@ class acp_attachments
WHERE ' . $db->sql_in_set('extension_id', $extension_id_list);
$db->sql_query($sql);
- add_log('admin', 'LOG_ATTACH_EXT_DEL', $extension_list);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXT_DEL', false, array($extension_list));
}
}
// Add Extension?
- $add_extension = strtolower(request_var('add_extension', ''));
- $add_extension_group = request_var('add_group_select', 0);
+ $add_extension = strtolower($request->variable('add_extension', ''));
+ $add_extension_group = $request->variable('add_group_select', 0);
$add = (isset($_POST['add_extension_check'])) ? true : false;
if ($add_extension && $add)
{
- if (!sizeof($error))
+ if (!count($error))
{
$sql = 'SELECT extension_id
FROM ' . EXTENSIONS_TABLE . "
@@ -425,7 +404,7 @@ class acp_attachments
}
$db->sql_freeresult($result);
- if (!sizeof($error))
+ if (!count($error))
{
$sql_ary = array(
'group_id' => $add_extension_group,
@@ -433,12 +412,13 @@ class acp_attachments
);
$db->sql_query('INSERT INTO ' . EXTENSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
- add_log('admin', 'LOG_ATTACH_EXT_ADD', $add_extension);
+
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXT_ADD', false, array($add_extension));
}
}
}
- if (!sizeof($error))
+ if (!count($error))
{
$notify[] = $user->lang['EXTENSIONS_UPDATED'];
}
@@ -490,8 +470,8 @@ class acp_attachments
if ($submit)
{
- $action = request_var('action', '');
- $group_id = request_var('g', 0);
+ $action = $request->variable('action', '');
+ $group_id = $request->variable('g', 0);
if ($action != 'add' && $action != 'edit')
{
@@ -522,7 +502,7 @@ class acp_attachments
$ext_row = array();
}
- $group_name = utf8_normalize_nfc(request_var('group_name', '', true));
+ $group_name = $request->variable('group_name', '', true);
$new_group_name = ($action == 'add') ? $group_name : (($ext_row['group_name'] != $group_name) ? $group_name : '');
if (!$group_name)
@@ -549,15 +529,15 @@ class acp_attachments
$db->sql_freeresult($result);
}
- if (!sizeof($error))
+ if (!count($error))
{
// Ok, build the update/insert array
- $upload_icon = request_var('upload_icon', 'no_image');
- $size_select = request_var('size_select', 'b');
- $forum_select = request_var('forum_select', false);
- $allowed_forums = request_var('allowed_forums', array(0));
+ $upload_icon = $request->variable('upload_icon', 'no_image');
+ $size_select = $request->variable('size_select', 'b');
+ $forum_select = $request->variable('forum_select', false);
+ $allowed_forums = $request->variable('allowed_forums', array(0));
$allow_in_pm = (isset($_POST['allow_in_pm'])) ? true : false;
- $max_filesize = request_var('max_filesize', 0);
+ $max_filesize = $request->variable('max_filesize', 0);
$max_filesize = ($size_select == 'kb') ? round($max_filesize * 1024) : (($size_select == 'mb') ? round($max_filesize * 1048576) : $max_filesize);
$allow_group = (isset($_POST['allow_group'])) ? true : false;
@@ -566,14 +546,14 @@ class acp_attachments
$max_filesize = 0;
}
- if (!sizeof($allowed_forums))
+ if (!count($allowed_forums))
{
$forum_select = false;
}
$group_ary = array(
'group_name' => $group_name,
- 'cat_id' => request_var('special_category', ATTACHMENT_CATEGORY_NONE),
+ 'cat_id' => $request->variable('special_category', ATTACHMENT_CATEGORY_NONE),
'allow_group' => ($allow_group) ? 1 : 0,
'upload_icon' => ($upload_icon == 'no_image') ? '' : $upload_icon,
'max_filesize' => $max_filesize,
@@ -597,13 +577,13 @@ class acp_attachments
$group_id = $db->sql_nextid();
}
- $group_name = (isset($user->lang['EXT_GROUP_' . $group_name])) ? $user->lang['EXT_GROUP_' . $group_name] : $group_name;
- add_log('admin', 'LOG_ATTACH_EXTGROUP_' . strtoupper($action), $group_name);
+ $group_name = $this->language->is_set('EXT_GROUP_' . utf8_strtoupper($group_name)) ? $this->language->lang('EXT_GROUP_' . utf8_strtoupper($group_name)) : $group_name;
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXTGROUP_' . strtoupper($action), false, array($group_name));
}
- $extension_list = request_var('extensions', array(0));
+ $extension_list = $request->variable('extensions', array(0));
- if ($action == 'edit' && sizeof($extension_list))
+ if ($action == 'edit' && count($extension_list))
{
$sql = 'UPDATE ' . EXTENSIONS_TABLE . "
SET group_id = 0
@@ -611,7 +591,7 @@ class acp_attachments
$db->sql_query($sql);
}
- if (sizeof($extension_list))
+ if (count($extension_list))
{
$sql = 'UPDATE ' . EXTENSIONS_TABLE . "
SET group_id = $group_id
@@ -621,7 +601,7 @@ class acp_attachments
$cache->destroy('_extensions');
- if (!sizeof($error))
+ if (!count($error))
{
$notify[] = $user->lang['SUCCESS_EXTENSION_GROUP_' . strtoupper($action)];
}
@@ -630,13 +610,10 @@ class acp_attachments
$cat_lang = array(
ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'],
ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'],
- ATTACHMENT_CATEGORY_WM => $user->lang['CAT_WM_FILES'],
- ATTACHMENT_CATEGORY_RM => $user->lang['CAT_RM_FILES'],
ATTACHMENT_CATEGORY_FLASH => $user->lang['CAT_FLASH_FILES'],
- ATTACHMENT_CATEGORY_QUICKTIME => $user->lang['CAT_QUICKTIME_FILES'],
);
- $group_id = request_var('g', 0);
+ $group_id = $request->variable('g', 0);
$action = (isset($_POST['add'])) ? 'add' : $action;
switch ($action)
@@ -663,7 +640,7 @@ class acp_attachments
WHERE group_id = $group_id";
$db->sql_query($sql);
- add_log('admin', 'LOG_ATTACH_EXTGROUP_DEL', $group_name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_EXTGROUP_DEL', false, array($group_name));
$cache->destroy('_extensions');
@@ -704,7 +681,7 @@ class acp_attachments
if ($action == 'add')
{
$ext_group_row = array(
- 'group_name' => utf8_normalize_nfc(request_var('group_name', '', true)),
+ 'group_name' => $request->variable('group_name', '', true),
'cat_id' => 0,
'allow_group' => 1,
'allow_in_pm' => 1,
@@ -715,8 +692,6 @@ class acp_attachments
$forum_ids = array();
}
- $extensions = array();
-
$sql = 'SELECT *
FROM ' . EXTENSIONS_TABLE . "
WHERE group_id = $group_id
@@ -802,7 +777,7 @@ class acp_attachments
'S_FILENAME_LIST' => $filename_list,
'S_EDIT_GROUP' => true,
'S_NO_IMAGE' => $no_image_select,
- 'S_FORUM_IDS' => (sizeof($forum_ids)) ? true : false,
+ 'S_FORUM_IDS' => (count($forum_ids)) ? true : false,
'U_EXTENSIONS' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&amp;mode=extensions"),
'U_BACK' => $this->u_action,
@@ -904,7 +879,7 @@ class acp_attachments
'U_EDIT' => $this->u_action . "&amp;action=edit&amp;g={$row['group_id']}",
'U_DELETE' => $this->u_action . "&amp;action=delete&amp;g={$row['group_id']}",
- 'GROUP_NAME' => (isset($user->lang['EXT_GROUP_' . $row['group_name']])) ? $user->lang['EXT_GROUP_' . $row['group_name']] : $row['group_name'],
+ 'GROUP_NAME' => $this->language->is_set('EXT_GROUP_' . utf8_strtoupper($row['group_name'])) ? $this->language->lang('EXT_GROUP_' . utf8_strtoupper($row['group_name'])) : $row['group_name'],
'CATEGORY' => $cat_lang[$row['cat_id']],
)
);
@@ -918,13 +893,16 @@ class acp_attachments
case 'orphan':
+ /* @var $pagination \phpbb\pagination */
+ $pagination = $this->phpbb_container->get('pagination');
+
if ($submit)
{
- $delete_files = (isset($_POST['delete'])) ? array_keys(request_var('delete', array('' => 0))) : array();
- $add_files = (isset($_POST['add'])) ? array_keys(request_var('add', array('' => 0))) : array();
- $post_ids = request_var('post_id', array('' => 0));
+ $delete_files = (isset($_POST['delete'])) ? array_keys($request->variable('delete', array('' => 0))) : array();
+ $add_files = (isset($_POST['add'])) ? array_keys($request->variable('add', array('' => 0))) : array();
+ $post_ids = $request->variable('post_id', array('' => 0));
- if (sizeof($delete_files))
+ if (count($delete_files))
{
$sql = 'SELECT *
FROM ' . ATTACHMENTS_TABLE . '
@@ -935,11 +913,11 @@ class acp_attachments
$delete_files = array();
while ($row = $db->sql_fetchrow($result))
{
- phpbb_unlink($row['physical_filename'], 'file');
+ $this->attachment_manager->unlink($row['physical_filename'], 'file');
if ($row['thumbnail'])
{
- phpbb_unlink($row['physical_filename'], 'thumbnail');
+ $this->attachment_manager->unlink($row['physical_filename'], 'thumbnail');
}
$delete_files[$row['attach_id']] = $row['real_filename'];
@@ -947,13 +925,13 @@ class acp_attachments
$db->sql_freeresult($result);
}
- if (sizeof($delete_files))
+ if (count($delete_files))
{
$sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
WHERE ' . $db->sql_in_set('attach_id', array_keys($delete_files));
$db->sql_query($sql);
- add_log('admin', 'LOG_ATTACH_ORPHAN_DEL', implode(', ', $delete_files));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_ORPHAN_DEL', false, array(implode(', ', $delete_files)));
$notify[] = sprintf($user->lang['LOG_ATTACH_ORPHAN_DEL'], implode($user->lang['COMMA_SEPARATOR'], $delete_files));
}
@@ -967,7 +945,7 @@ class acp_attachments
}
unset($add_files);
- if (sizeof($upload_list))
+ if (count($upload_list))
{
$template->assign_var('S_UPLOADING_FILES', true);
@@ -1044,14 +1022,14 @@ class acp_attachments
$space_taken += $row['filesize'];
$files_added++;
- add_log('admin', 'LOG_ATTACH_FILEUPLOAD', $post_row['post_id'], $row['real_filename']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACH_FILEUPLOAD', false, array($post_row['post_id'], $row['real_filename']));
}
$db->sql_freeresult($result);
if ($files_added)
{
- set_config_count('upload_dir_size', $space_taken, true);
- set_config_count('num_files', $files_added, true);
+ $config->increment('upload_dir_size', $space_taken, false);
+ $config->increment('num_files', $files_added, false);
}
}
}
@@ -1060,13 +1038,29 @@ class acp_attachments
'S_ORPHAN' => true)
);
+ $attachments_per_page = (int) $config['topics_per_page'];
+
+ // Get total number or orphans older than 3 hours
+ $sql = 'SELECT COUNT(attach_id) as num_files, SUM(filesize) as total_size
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE is_orphan = 1
+ AND filetime < ' . (time() - 3*60*60);
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $num_files = (int) $row['num_files'];
+ $total_size = (int) $row['total_size'];
+ $this->db->sql_freeresult($result);
+
+ $start = $request->variable('start', 0);
+ $start = $pagination->validate_start($start, $attachments_per_page, $num_files);
+
// Just get the files with is_orphan set and older than 3 hours
$sql = 'SELECT *
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 1
AND filetime < ' . (time() - 3*60*60) . '
ORDER BY filetime DESC';
- $result = $db->sql_query($sql);
+ $result = $db->sql_query_limit($sql, $attachments_per_page, $start);
while ($row = $db->sql_fetchrow($result))
{
@@ -1082,15 +1076,29 @@ class acp_attachments
}
$db->sql_freeresult($result);
+ $pagination->generate_template_pagination(
+ $this->u_action,
+ 'pagination',
+ 'start',
+ $num_files,
+ $attachments_per_page,
+ $start
+ );
+
+ $template->assign_vars(array(
+ 'TOTAL_FILES' => $num_files,
+ 'TOTAL_SIZE' => get_formatted_filesize($total_size),
+ ));
+
break;
case 'manage':
if ($submit)
{
- $delete_files = (isset($_POST['delete'])) ? array_keys(request_var('delete', array('' => 0))) : array();
+ $delete_files = (isset($_POST['delete'])) ? array_keys($request->variable('delete', array('' => 0))) : array();
- if (sizeof($delete_files))
+ if (count($delete_files))
{
// Select those attachments we want to delete...
$sql = 'SELECT real_filename
@@ -1104,13 +1112,14 @@ class acp_attachments
}
$db->sql_freeresult($result);
- if ($num_deleted = delete_attachments('attach', $delete_files))
+ if ($num_deleted = $this->attachment_manager->delete('attach', $delete_files))
{
- if (sizeof($delete_files) != $num_deleted)
+ if (count($delete_files) != $num_deleted)
{
$error[] = $user->lang['FILES_GONE'];
}
- add_log('admin', 'LOG_ATTACHMENTS_DELETED', implode(', ', $deleted_filenames));
+
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACHMENTS_DELETED', false, array(implode(', ', $deleted_filenames)));
$notify[] = sprintf($user->lang['LOG_ATTACHMENTS_DELETED'], implode($user->lang['COMMA_SEPARATOR'], $deleted_filenames));
}
else
@@ -1136,12 +1145,12 @@ class acp_attachments
'S_MANAGE' => true,
));
- $start = request_var('start', 0);
+ $start = $request->variable('start', 0);
// Sort keys
- $sort_days = request_var('st', 0);
- $sort_key = request_var('sk', 't');
- $sort_dir = request_var('sd', 'd');
+ $sort_days = $request->variable('st', 0);
+ $sort_key = $request->variable('sk', 't');
+ $sort_dir = $request->variable('sd', 'd');
// Sorting
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
@@ -1162,6 +1171,7 @@ class acp_attachments
$total_size = $stats['upload_dir_size'];
// Make sure $start is set to the last page if it exceeds the amount
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
$start = $pagination->validate_start($start, $attachments_per_page, $num_files);
@@ -1225,28 +1235,24 @@ class acp_attachments
// Grab extensions
$extensions = $cache->obtain_attach_extensions(true);
- for ($i = 0, $end = sizeof($attachments_list); $i < $end; ++$i)
+ for ($i = 0, $end = count($attachments_list); $i < $end; ++$i)
{
$row = $attachments_list[$i];
$row['extension'] = strtolower(trim((string) $row['extension']));
$comment = ($row['attach_comment'] && !$row['in_message']) ? str_replace(array("\n", "\r"), array('<br />', "\n"), $row['attach_comment']) : '';
- $display_cat = $extensions[$row['extension']]['display_cat'];
+ $display_cat = isset($extensions[$row['extension']]['display_cat']) ? $extensions[$row['extension']]['display_cat'] : ATTACHMENT_CATEGORY_NONE;
$l_downloaded_viewed = ($display_cat == ATTACHMENT_CATEGORY_NONE) ? 'DOWNLOAD_COUNTS' : 'VIEWED_COUNTS';
$template->assign_block_vars('attachments', array(
'ATTACHMENT_POSTER' => get_username_string('full', (int) $row['poster_id'], (string) $row['username'], (string) $row['user_colour'], (string) $row['username']),
'FILESIZE' => get_formatted_filesize((int) $row['filesize']),
'FILETIME' => $user->format_date((int) $row['filetime']),
- 'REAL_FILENAME' => (!$row['in_message']) ? utf8_basename((string) $row['real_filename']) : '',
- 'PHYSICAL_FILENAME' => utf8_basename((string) $row['physical_filename']),
- 'EXT_GROUP_NAME' => (!empty($extensions[$row['extension']]['group_name'])) ? $user->lang['EXT_GROUP_' . $extensions[$row['extension']]['group_name']] : '',
+ 'REAL_FILENAME' => utf8_basename((string) $row['real_filename']),
+ 'EXT_GROUP_NAME' => $this->language->is_set('EXT_GROUP_' . utf8_strtoupper($extensions[$row['extension']]['group_name'])) ? $this->language->lang('EXT_GROUP_' . utf8_strtoupper($extensions[$row['extension']]['group_name'])) : $extensions[$row['extension']]['group_name'],
'COMMENT' => $comment,
'TOPIC_TITLE' => (!$row['in_message']) ? (string) $row['topic_title'] : '',
'ATTACH_ID' => (int) $row['attach_id'],
- 'POST_ID' => (int) $row['post_msg_id'],
- 'TOPIC_ID' => (int) $row['topic_id'],
- 'POST_IDS' => (!empty($post_ids[$row['attach_id']])) ? (int) $post_ids[$row['attach_id']] : '',
'L_DOWNLOAD_COUNT' => $user->lang($l_downloaded_viewed, (int) $row['download_count']),
@@ -1260,7 +1266,7 @@ class acp_attachments
break;
}
- if (sizeof($error))
+ if (count($error))
{
$template->assign_vars(array(
'S_WARNING' => true,
@@ -1268,7 +1274,7 @@ class acp_attachments
);
}
- if (sizeof($notify))
+ if (count($notify))
{
$template->assign_vars(array(
'S_NOTIFY' => true,
@@ -1361,6 +1367,8 @@ class acp_attachments
else
{
$this->set_attachment_stats($this->get_attachment_stats());
+
+ /* @var $log \phpbb\log\log_interface */
$log = $this->phpbb_container->get('log');
$log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_RESYNC_FILES_STATS');
}
@@ -1377,10 +1385,7 @@ class acp_attachments
$types = array(
ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'],
ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'],
- ATTACHMENT_CATEGORY_WM => $user->lang['CAT_WM_FILES'],
- ATTACHMENT_CATEGORY_RM => $user->lang['CAT_RM_FILES'],
ATTACHMENT_CATEGORY_FLASH => $user->lang['CAT_FLASH_FILES'],
- ATTACHMENT_CATEGORY_QUICKTIME => $user->lang['CAT_QUICKTIME_FILES'],
);
if ($group_id)
@@ -1429,7 +1434,7 @@ class acp_attachments
$group_name = array();
while ($row = $db->sql_fetchrow($result))
{
- $row['group_name'] = (isset($user->lang['EXT_GROUP_' . $row['group_name']])) ? $user->lang['EXT_GROUP_' . $row['group_name']] : $row['group_name'];
+ $row['group_name'] = $this->language->is_set('EXT_GROUP_' . utf8_strtoupper($row['group_name'])) ? $this->language->lang('EXT_GROUP_' . utf8_strtoupper($row['group_name'])) : $row['group_name'];
$group_name[] = $row;
}
$db->sql_freeresult($result);
@@ -1438,7 +1443,7 @@ class acp_attachments
$row['group_name'] = $user->lang['NOT_ASSIGNED'];
$group_name[] = $row;
- for ($i = 0, $groups_size = sizeof($group_name); $i < $groups_size; $i++)
+ for ($i = 0, $groups_size = count($group_name); $i < $groups_size; $i++)
{
if ($default_group === false)
{
@@ -1458,47 +1463,6 @@ class acp_attachments
}
/**
- * Search Imagick
- */
- function search_imagemagick()
- {
- $imagick = '';
-
- $exe = ((defined('PHP_OS')) && (preg_match('#^win#i', PHP_OS))) ? '.exe' : '';
-
- $magic_home = getenv('MAGICK_HOME');
-
- if (empty($magic_home))
- {
- $locations = array('C:/WINDOWS/', 'C:/WINNT/', 'C:/WINDOWS/SYSTEM/', 'C:/WINNT/SYSTEM/', 'C:/WINDOWS/SYSTEM32/', 'C:/WINNT/SYSTEM32/', '/usr/bin/', '/usr/sbin/', '/usr/local/bin/', '/usr/local/sbin/', '/opt/', '/usr/imagemagick/', '/usr/bin/imagemagick/');
- $path_locations = str_replace('\\', '/', (explode(($exe) ? ';' : ':', getenv('PATH'))));
-
- $locations = array_merge($path_locations, $locations);
-
- foreach ($locations as $location)
- {
- // The path might not end properly, fudge it
- if (substr($location, -1) !== '/')
- {
- $location .= '/';
- }
-
- if (@file_exists($location) && @is_readable($location . 'mogrify' . $exe) && @filesize($location . 'mogrify' . $exe) > 3000)
- {
- $imagick = str_replace('\\', '/', $location);
- continue;
- }
- }
- }
- else
- {
- $imagick = str_replace('\\', '/', $magic_home);
- }
-
- return $imagick;
- }
-
- /**
* Test Settings
*/
function test_upload(&$error, $upload_dir, $create_directory = false)
@@ -1511,7 +1475,15 @@ class acp_attachments
if (!file_exists($phpbb_root_path . $upload_dir))
{
@mkdir($phpbb_root_path . $upload_dir, 0777);
- phpbb_chmod($phpbb_root_path . $upload_dir, CHMOD_READ | CHMOD_WRITE);
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($phpbb_root_path . $upload_dir, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
}
}
@@ -1527,7 +1499,7 @@ class acp_attachments
return;
}
- if (!phpbb_is_writable($phpbb_root_path . $upload_dir))
+ if (!$this->filesystem->is_writable($phpbb_root_path . $upload_dir))
{
$error[] = sprintf($user->lang['NO_WRITE_UPLOAD'], $upload_dir);
return;
@@ -1539,13 +1511,12 @@ class acp_attachments
*/
function perform_site_list()
{
- global $db, $user;
- global $request;
+ global $db, $user, $request, $phpbb_log;
if (isset($_REQUEST['securesubmit']))
{
// Grab the list of entries
- $ips = request_var('ips', '');
+ $ips = $request->variable('ips', '');
$ip_list = array_unique(explode("\n", $ips));
$ip_list_log = implode(', ', $ip_list);
@@ -1570,7 +1541,6 @@ class acp_attachments
if ($ip_2_counter == 0 && $ip_2_end == 254)
{
$ip_2_counter = 256;
- $ip_2_fragment = 256;
$iplist[] = "'$ip_1_counter.*'";
}
@@ -1583,7 +1553,6 @@ class acp_attachments
if ($ip_3_counter == 0 && $ip_3_end == 254)
{
$ip_3_counter = 256;
- $ip_3_fragment = 256;
$iplist[] = "'$ip_1_counter.$ip_2_counter.*'";
}
@@ -1596,7 +1565,6 @@ class acp_attachments
if ($ip_4_counter == 0 && $ip_4_end == 254)
{
$ip_4_counter = 256;
- $ip_4_fragment = 256;
$iplist[] = "'$ip_1_counter.$ip_2_counter.$ip_3_counter.*'";
}
@@ -1667,7 +1635,7 @@ class acp_attachments
}
$db->sql_freeresult($result);
- if (sizeof($iplist))
+ if (count($iplist))
{
foreach ($iplist as $ip_entry)
{
@@ -1677,7 +1645,7 @@ class acp_attachments
}
}
- if (sizeof($hostlist))
+ if (count($hostlist))
{
foreach ($hostlist as $host_entry)
{
@@ -1691,16 +1659,16 @@ class acp_attachments
{
// Update log
$log_entry = ($ip_exclude) ? 'LOG_DOWNLOAD_EXCLUDE_IP' : 'LOG_DOWNLOAD_IP';
- add_log('admin', $log_entry, $ip_list_log);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log_entry, false, array($ip_list_log));
}
trigger_error($user->lang['SECURE_DOWNLOAD_UPDATE_SUCCESS'] . adm_back_link($this->u_action));
}
else if (isset($_POST['unsecuresubmit']))
{
- $unip_sql = request_var('unip', array(0));
+ $unip_sql = $request->variable('unip', array(0));
- if (sizeof($unip_sql))
+ if (count($unip_sql))
{
$l_unip_list = '';
@@ -1720,7 +1688,7 @@ class acp_attachments
WHERE ' . $db->sql_in_set('site_id', $unip_sql);
$db->sql_query($sql);
- add_log('admin', 'LOG_DOWNLOAD_REMOVE_IP', $l_unip_list);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DOWNLOAD_REMOVE_IP', false, array($l_unip_list));
}
trigger_error($user->lang['SECURE_DOWNLOAD_UPDATE_SUCCESS'] . adm_back_link($this->u_action));
diff --git a/phpBB/includes/acp/acp_ban.php b/phpBB/includes/acp/acp_ban.php
index 286bc92813..5aed78be08 100644
--- a/phpBB/includes/acp/acp_ban.php
+++ b/phpBB/includes/acp/acp_ban.php
@@ -195,7 +195,6 @@ class acp_ban
case 'user':
$field = 'username';
- $l_ban_cell = $user->lang['USERNAME'];
$sql = 'SELECT b.*, u.user_id, u.username, u.username_clean
FROM ' . BANLIST_TABLE . ' b, ' . USERS_TABLE . ' u
@@ -208,7 +207,6 @@ class acp_ban
case 'ip':
$field = 'ban_ip';
- $l_ban_cell = $user->lang['IP_HOSTNAME'];
$sql = 'SELECT *
FROM ' . BANLIST_TABLE . '
@@ -221,7 +219,6 @@ class acp_ban
case 'email':
$field = 'ban_email';
- $l_ban_cell = $user->lang['EMAIL_ADDRESS'];
$sql = 'SELECT *
FROM ' . BANLIST_TABLE . '
diff --git a/phpBB/includes/acp/acp_bbcodes.php b/phpBB/includes/acp/acp_bbcodes.php
index c98be241e9..bd8df6a63b 100644
--- a/phpBB/includes/acp/acp_bbcodes.php
+++ b/phpBB/includes/acp/acp_bbcodes.php
@@ -25,15 +25,14 @@ class acp_bbcodes
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $template, $cache, $request, $phpbb_dispatcher, $phpbb_container;
+ global $phpbb_log;
$user->add_lang('acp/posting');
// Set up general vars
- $action = request_var('action', '');
- $bbcode_id = request_var('bbcode', 0);
- $submit = $request->is_set_post('submit');
+ $action = $request->variable('action', '');
+ $bbcode_id = $request->variable('bbcode', 0);
$this->tpl_name = 'acp_bbcodes';
$this->page_title = 'ACP_BBCODES';
@@ -41,11 +40,6 @@ class acp_bbcodes
add_form_key($form_key);
- if ($submit && !check_form_key($form_key))
- {
- trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
- }
-
// Set up mode-specific vars
switch ($action)
{
@@ -89,11 +83,11 @@ class acp_bbcodes
// No break here
case 'create':
- $display_on_posting = request_var('display_on_posting', 0);
+ $display_on_posting = $request->variable('display_on_posting', 0);
- $bbcode_match = request_var('bbcode_match', '');
- $bbcode_tpl = htmlspecialchars_decode(utf8_normalize_nfc(request_var('bbcode_tpl', '', true)));
- $bbcode_helpline = utf8_normalize_nfc(request_var('bbcode_helpline', '', true));
+ $bbcode_match = $request->variable('bbcode_match', '');
+ $bbcode_tpl = htmlspecialchars_decode($request->variable('bbcode_tpl', '', true));
+ $bbcode_helpline = $request->variable('bbcode_helpline', '', true);
break;
}
@@ -179,6 +173,12 @@ class acp_bbcodes
extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_modify_create', compact($vars)));
$warn_text = preg_match('%<[^>]*\{text[\d]*\}[^>]*>%i', $bbcode_tpl);
+
+ if (!$warn_text && !check_form_key($form_key))
+ {
+ trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+
if (!$warn_text || confirm_box(true))
{
$data = $this->build_regexp($bbcode_match, $bbcode_tpl);
@@ -211,11 +211,6 @@ class acp_bbcodes
$test = $data['bbcode_tag'];
}
- if (!preg_match('%\\[' . $test . '[^]]*].*?\\[/' . $test . ']%s', $bbcode_match))
- {
- trigger_error($user->lang['BBCODE_OPEN_ENDED_TAG'] . adm_back_link($this->u_action), E_USER_WARNING);
- }
-
if (strlen($data['bbcode_tag']) > 16)
{
trigger_error($user->lang['BBCODE_TAG_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING);
@@ -253,7 +248,7 @@ class acp_bbcodes
if ($row)
{
- $bbcode_id = $row['max_bbcode_id'] + 1;
+ $bbcode_id = (int) $row['max_bbcode_id'] + 1;
// Make sure it is greater than the core bbcode ids...
if ($bbcode_id <= NUM_CORE_BBCODES)
@@ -275,6 +270,7 @@ class acp_bbcodes
$db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary));
$cache->destroy('sql', BBCODES_TABLE);
+ $phpbb_container->get('text_formatter.cache')->invalidate();
$lang = 'BBCODE_ADDED';
$log_action = 'LOG_BBCODE_ADD';
@@ -286,12 +282,29 @@ class acp_bbcodes
WHERE bbcode_id = ' . $bbcode_id;
$db->sql_query($sql);
$cache->destroy('sql', BBCODES_TABLE);
+ $phpbb_container->get('text_formatter.cache')->invalidate();
$lang = 'BBCODE_EDITED';
$log_action = 'LOG_BBCODE_EDIT';
}
- add_log('admin', $log_action, $data['bbcode_tag']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log_action, false, array($data['bbcode_tag']));
+
+ /**
+ * Event after a BBCode has been added or updated
+ *
+ * @event core.acp_bbcodes_modify_create_after
+ * @var string action Type of the action: modify|create
+ * @var int bbcode_id The id of the added or updated bbcode
+ * @var array sql_ary Array with bbcode data (read only)
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'action',
+ 'bbcode_id',
+ 'sql_ary',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_modify_create_after', compact($vars)));
trigger_error($user->lang[$lang] . adm_back_link($this->u_action));
}
@@ -323,9 +336,28 @@ class acp_bbcodes
{
if (confirm_box(true))
{
+ $bbcode_tag = $row['bbcode_tag'];
+
$db->sql_query('DELETE FROM ' . BBCODES_TABLE . " WHERE bbcode_id = $bbcode_id");
$cache->destroy('sql', BBCODES_TABLE);
- add_log('admin', 'LOG_BBCODE_DELETE', $row['bbcode_tag']);
+ $phpbb_container->get('text_formatter.cache')->invalidate();
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_BBCODE_DELETE', false, array($bbcode_tag));
+
+ /**
+ * Event after a BBCode has been deleted
+ *
+ * @event core.acp_bbcodes_delete_after
+ * @var string action Type of the action: delete
+ * @var int bbcode_id The id of the deleted bbcode
+ * @var string bbcode_tag The tag of the deleted bbcode
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'action',
+ 'bbcode_id',
+ 'bbcode_tag',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.acp_bbcodes_delete_after', compact($vars)));
if ($request->is_ajax())
{
@@ -419,8 +451,6 @@ class acp_bbcodes
// Allow unicode characters for URL|LOCAL_URL|RELATIVE_URL|INTTEXT tokens
$utf8 = preg_match('/(URL|LOCAL_URL|RELATIVE_URL|INTTEXT)/', $bbcode_match);
- $utf8_pcre_properties = phpbb_pcre_utf8_support();
-
$fp_match = preg_quote($bbcode_match, '!');
$fp_replace = preg_replace('#^\[(.*?)\]#', '[$1:$uid]', $bbcode_match);
$fp_replace = preg_replace('#\[/(.*?)\]$#', '[/$1:$uid]', $fp_replace);
@@ -451,7 +481,7 @@ class acp_bbcodes
'!([a-zA-Z0-9-+.,_ ]+)!' => "$1"
),
'INTTEXT' => array(
- ($utf8_pcre_properties) ? '!([\p{L}\p{N}\-+,_. ]+)!u' : '!([a-zA-Z0-9\-+,_. ]+)!u' => "$1"
+ '!([\p{L}\p{N}\-+,_. ]+)!u' => "$1"
),
'IDENTIFIER' => array(
'!([a-zA-Z0-9-_]+)!' => "$1"
@@ -471,7 +501,7 @@ class acp_bbcodes
'EMAIL' => '(' . get_preg_expression('email') . ')',
'TEXT' => '(.*?)',
'SIMPLETEXT' => '([a-zA-Z0-9-+.,_ ]+)',
- 'INTTEXT' => ($utf8_pcre_properties) ? '([\p{L}\p{N}\-+,_. ]+)' : '([a-zA-Z0-9\-+,_. ]+)',
+ 'INTTEXT' => '([\p{L}\p{N}\-+,_. ]+)',
'IDENTIFIER' => '([a-zA-Z0-9-_]+)',
'COLOR' => '([a-zA-Z]+|#[0-9abcdefABCDEF]+)',
'NUMBER' => '([0-9]+)',
@@ -479,7 +509,7 @@ class acp_bbcodes
$pad = 0;
$modifiers = 'i';
- $modifiers .= ($utf8 && $utf8_pcre_properties) ? 'u' : '';
+ $modifiers .= ($utf8) ? 'u' : '';
if (preg_match_all('/\{(' . implode('|', array_keys($tokens)) . ')[0-9]*\}/i', $bbcode_match, $m))
{
@@ -493,8 +523,10 @@ class acp_bbcodes
// Pad backreference numbers from tokens
if (preg_match_all('/(?<!\\\\)\$([0-9]+)/', $replace, $repad))
{
- $repad = $pad + sizeof(array_unique($repad[0]));
- $replace = preg_replace('/(?<!\\\\)\$([0-9]+)/e', "'\${' . (\$1 + \$pad) . '}'", $replace);
+ $repad = $pad + count(array_unique($repad[0]));
+ $replace = preg_replace_callback('/(?<!\\\\)\$([0-9]+)/', function ($match) use ($pad) {
+ return '${' . ($match[1] + $pad) . '}';
+ }, $replace);
$pad = $repad;
}
@@ -550,19 +582,27 @@ class acp_bbcodes
}
// Lowercase tags
- $bbcode_tag = preg_replace('/.*?\[([a-z0-9_-]+=?).*/i', '$1', $bbcode_match);
- $bbcode_search = preg_replace('/.*?\[([a-z0-9_-]+)=?.*/i', '$1', $bbcode_match);
+ $bbcode_tag = preg_replace('/.*?\[([a-z0-9_-]+).*/i', '$1', $bbcode_match);
+ $bbcode_search = preg_replace('/.*?\[([a-z0-9_-]+).*/i', '$1', $bbcode_match);
- if (!preg_match('/^[a-zA-Z0-9_-]+=?$/', $bbcode_tag))
+ if (!preg_match('/^[a-zA-Z0-9_-]+$/', $bbcode_tag))
{
global $user;
trigger_error($user->lang['BBCODE_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- $fp_match = preg_replace('#\[/?' . $bbcode_search . '#ie', "strtolower('\$0')", $fp_match);
- $fp_replace = preg_replace('#\[/?' . $bbcode_search . '#ie', "strtolower('\$0')", $fp_replace);
- $sp_match = preg_replace('#\[/?' . $bbcode_search . '#ie', "strtolower('\$0')", $sp_match);
- $sp_replace = preg_replace('#\[/?' . $bbcode_search . '#ie', "strtolower('\$0')", $sp_replace);
+ $fp_match = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
+ return strtolower($match[0]);
+ }, $fp_match);
+ $fp_replace = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
+ return strtolower($match[0]);
+ }, $fp_replace);
+ $sp_match = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
+ return strtolower($match[0]);
+ }, $sp_match);
+ $sp_replace = preg_replace_callback('#\[/?' . $bbcode_search . '#i', function ($match) {
+ return strtolower($match[0]);
+ }, $sp_replace);
return array(
'bbcode_tag' => $bbcode_tag,
diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php
index 5c3c7f30aa..0730b4e285 100644
--- a/phpBB/includes/acp/acp_board.php
+++ b/phpBB/includes/acp/acp_board.php
@@ -30,13 +30,15 @@ class acp_board
function main($id, $mode)
{
- global $db, $user, $auth, $template;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
- global $cache, $phpbb_container, $phpbb_dispatcher;
+ global $user, $template, $request, $language;
+ global $config, $phpbb_root_path, $phpEx;
+ global $cache, $phpbb_container, $phpbb_dispatcher, $phpbb_log;
+
+ /** @var \phpbb\language\language $language Language object */
+ $language = $phpbb_container->get('language');
$user->add_lang('acp/board');
- $action = request_var('action', '');
$submit = (isset($_POST['submit']) || isset($_POST['allow_quick_reply_enable'])) ? true : false;
$form_key = 'acp_board';
@@ -57,7 +59,7 @@ class acp_board
'legend1' => 'ACP_BOARD_SETTINGS',
'sitename' => array('lang' => 'SITE_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
'site_desc' => array('lang' => 'SITE_DESC', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
- 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'string', 'type' => 'url:40:255', 'explain' => true),
+ 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'url', 'type' => 'url:40:255', 'explain' => true),
'site_home_text' => array('lang' => 'SITE_HOME_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
'board_index_text' => array('lang' => 'BOARD_INDEX_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
'board_disable' => array('lang' => 'DISABLE_BOARD', 'validate' => 'bool', 'type' => 'custom', 'method' => 'board_disable', 'explain' => true),
@@ -94,6 +96,7 @@ class acp_board
'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
+ 'allow_board_notifications' => array('lang' => 'ALLOW_BOARD_NOTIFICATIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_birthdays' => array('lang' => 'ALLOW_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -115,12 +118,14 @@ class acp_board
break;
case 'avatar':
+ /* @var $phpbb_avatar_manager \phpbb\avatar\manager */
$phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
$avatar_drivers = $phpbb_avatar_manager->get_all_drivers();
$avatar_vars = array();
foreach ($avatar_drivers as $current_driver)
{
+ /** @var \phpbb\avatar\driver\driver_interface $driver */
$driver = $phpbb_avatar_manager->get_driver($current_driver, false);
/*
@@ -195,6 +200,7 @@ class acp_board
'allow_post_flash' => array('lang' => 'ALLOW_POST_FLASH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'allow_post_links' => array('lang' => 'ALLOW_POST_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'allowed_schemes_links' => array('lang' => 'ALLOWED_SCHEMES_LINKS', 'validate' => 'string', 'type' => 'text:0:255', 'explain' => true),
'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'enable_post_confirm' => array('lang' => 'VISUAL_CONFIRM_POST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -321,7 +327,8 @@ class acp_board
'cookie_domain' => array('lang' => 'COOKIE_DOMAIN', 'validate' => 'string', 'type' => 'text::255', 'explain' => true),
'cookie_name' => array('lang' => 'COOKIE_NAME', 'validate' => 'string', 'type' => 'text::16', 'explain' => true),
'cookie_path' => array('lang' => 'COOKIE_PATH', 'validate' => 'string', 'type' => 'text::255', 'explain' => true),
- 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'validate' => 'bool', 'type' => 'radio:disabled_enabled', 'explain' => true),
+ 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
+ 'cookie_notice' => array('lang' => 'COOKIE_NOTICE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
)
);
break;
@@ -350,8 +357,10 @@ class acp_board
'load_moderators' => array('lang' => 'YES_MODERATORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'load_user_activity' => array('lang' => 'LOAD_USER_ACTIVITY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'load_user_activity_limit' => array('lang' => 'LOAD_USER_ACTIVITY_LIMIT', 'validate' => 'int:0:99999999', 'type' => 'number:0:99999999', 'explain' => true),
'load_tplcompile' => array('lang' => 'RECOMPILE_STYLES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_cdn' => array('lang' => 'ALLOW_CDN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'enable_accurate_pm_button' => array('lang' => 'YES_ACCURATE_PM_BUTTON', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_live_searches' => array('lang' => 'ALLOW_LIVE_SEARCHES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'legend3' => 'CUSTOM_PROFILE_FIELDS',
@@ -414,6 +423,7 @@ class acp_board
'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'forwarded_for_check' => array('lang' => 'FORWARDED_FOR_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'referer_validation' => array('lang' => 'REFERRER_VALID', 'validate' => 'int:0:3','type' => 'custom', 'method' => 'select_ref_check', 'explain' => true),
+ 'remote_upload_verify' => array('lang' => 'UPLOAD_CERT_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'check_dnsbl' => array('lang' => 'CHECK_DNSBL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'email_check_mx' => array('lang' => 'EMAIL_CHECK_MX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,),
@@ -439,13 +449,15 @@ class acp_board
'legend1' => 'GENERAL_SETTINGS',
'email_enable' => array('lang' => 'ENABLE_EMAIL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
'board_email_form' => array('lang' => 'BOARD_EMAIL_FORM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
- 'email_function_name' => array('lang' => 'EMAIL_FUNCTION_NAME', 'validate' => 'string', 'type' => 'text:20:50', 'explain' => true),
'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'number:0:99999', 'explain' => true),
+ 'email_max_chunk_size' => array('lang' => 'EMAIL_MAX_CHUNK_SIZE', 'validate' => 'int:1:99999', 'type' => 'number:1:99999', 'explain' => true),
'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true),
'board_contact_name' => array('lang' => 'CONTACT_EMAIL_NAME', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => true),
'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true),
+ 'email_force_sender' => array('lang' => 'EMAIL_FORCE_SENDER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'board_email_sig' => array('lang' => 'EMAIL_SIG', 'validate' => 'string', 'type' => 'textarea:5:30', 'explain' => true),
'board_hide_emails' => array('lang' => 'BOARD_HIDE_EMAILS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'send_test_email' => array('lang' => 'SEND_TEST_EMAIL', 'validate' => 'bool', 'type' => 'custom', 'method' => 'send_test_email', 'explain' => true),
'legend2' => 'SMTP_SETTINGS',
'smtp_delivery' => array('lang' => 'USE_SMTP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -486,7 +498,7 @@ class acp_board
}
$this->new_config = clone $config;
- $cfg_array = (isset($_REQUEST['config'])) ? utf8_normalize_nfc(request_var('config', array('' => ''), true)) : $this->new_config;
+ $cfg_array = (isset($_REQUEST['config'])) ? $request->variable('config', array('' => ''), true) : $this->new_config;
$error = array();
// We validate the complete config if wished
@@ -497,7 +509,7 @@ class acp_board
$error[] = $user->lang['FORM_INVALID'];
}
// Do not write values if there is an error
- if (sizeof($error))
+ if (count($error))
{
$submit = false;
}
@@ -526,13 +538,6 @@ class acp_board
$this->new_config[$config_name] = $config_value = $cfg_array[$config_name];
- if ($config_name == 'email_function_name')
- {
- $this->new_config['email_function_name'] = trim(str_replace(array('(', ')'), array('', ''), $this->new_config['email_function_name']));
- $this->new_config['email_function_name'] = (empty($this->new_config['email_function_name']) || !function_exists($this->new_config['email_function_name'])) ? 'mail' : $this->new_config['email_function_name'];
- $config_value = $this->new_config['email_function_name'];
- }
-
if ($submit)
{
if (strpos($data['type'], 'password') === 0 && $config_value === '********')
@@ -542,15 +547,21 @@ class acp_board
// send the password to the output
continue;
}
- set_config($config_name, $config_value);
+ $config->set($config_name, $config_value);
if ($config_name == 'allow_quick_reply' && isset($_POST['allow_quick_reply_enable']))
{
- enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', log(FORUM_FLAG_QUICK_REPLY, 2));
+ enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', round(log(FORUM_FLAG_QUICK_REPLY, 2)));
}
}
}
+ // Invalidate the text_formatter cache when posting options are changed
+ if ($mode == 'post' && $submit)
+ {
+ $phpbb_container->get('text_formatter.cache')->invalidate();
+ }
+
// Store news and exclude ids
if ($mode == 'feed' && $submit)
{
@@ -564,6 +575,7 @@ class acp_board
if ($mode == 'auth')
{
// Retrieve a list of auth plugins and check their config values
+ /* @var $auth_providers \phpbb\auth\provider_collection */
$auth_providers = $phpbb_container->get('auth.provider_collection');
$updated_auth_settings = false;
@@ -578,7 +590,7 @@ class acp_board
{
if (!isset($config[$field]))
{
- set_config($field, '');
+ $config->set($field, '');
}
if (!isset($cfg_array[$field]) || strpos($field, 'legend') !== false)
@@ -601,7 +613,7 @@ class acp_board
if ($submit)
{
$updated_auth_settings = true;
- set_config($field, $config_value);
+ $config->set($field, $config_value);
}
}
}
@@ -618,11 +630,11 @@ class acp_board
{
foreach ($old_auth_config as $config_name => $config_value)
{
- set_config($config_name, $config_value);
+ $config->set($config_name, $config_value);
}
trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
}
- set_config('auth_method', basename($cfg_array['auth_method']));
+ $config->set('auth_method', basename($cfg_array['auth_method']));
}
else
{
@@ -631,9 +643,33 @@ class acp_board
}
}
+ if ($mode == 'email' && $request->is_set_post('send_test_email'))
+ {
+ if ($config['email_enable'])
+ {
+ include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
+
+ $messenger = new messenger(false);
+ $messenger->template('test');
+ $messenger->set_addresses($user->data);
+ $messenger->anti_abuse_headers($config, $user);
+ $messenger->assign_vars(array(
+ 'USERNAME' => htmlspecialchars_decode($user->data['username']),
+ ));
+ $messenger->send(NOTIFY_EMAIL);
+
+ trigger_error($user->lang('TEST_EMAIL_SENT') . adm_back_link($this->u_action));
+ }
+ else
+ {
+ $user->add_lang('memberlist');
+ trigger_error($user->lang('EMAIL_DISABLED') . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+ }
+
if ($submit)
{
- add_log('admin', 'LOG_CONFIG_' . strtoupper($mode));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_' . strtoupper($mode));
$message = $user->lang('CONFIG_UPDATED');
$message_type = E_USER_NOTICE;
@@ -653,7 +689,7 @@ class acp_board
'L_TITLE' => $user->lang[$display_vars['title']],
'L_TITLE_EXPLAIN' => $user->lang[$display_vars['title'] . '_EXPLAIN'],
- 'S_ERROR' => (sizeof($error)) ? true : false,
+ 'S_ERROR' => (count($error)) ? true : false,
'ERROR_MSG' => implode('<br />', $error),
'U_ACTION' => $this->u_action)
@@ -699,7 +735,7 @@ class acp_board
$template->assign_block_vars('options', array(
'KEY' => $config_key,
'TITLE' => (isset($user->lang[$vars['lang']])) ? $user->lang[$vars['lang']] : $vars['lang'],
- 'S_EXPLAIN' => $vars['explain'],
+ 'S_EXPLAIN' => $vars['explain'] && !empty($l_explain),
'TITLE_EXPLAIN' => $l_explain,
'CONTENT' => $content,
)
@@ -738,10 +774,11 @@ class acp_board
*/
function select_auth_method($selected_method, $key = '')
{
- global $phpbb_root_path, $phpEx, $phpbb_container;
+ global $phpbb_container;
- $auth_plugins = array();
+ /* @var $auth_providers \phpbb\auth\provider_collection */
$auth_providers = $phpbb_container->get('auth.provider_collection');
+ $auth_plugins = array();
foreach ($auth_providers as $key => $value)
{
@@ -917,8 +954,6 @@ class acp_board
*/
function board_disable($value, $key)
{
- global $user;
-
$radio_ary = array(1 => 'YES', 0 => 'NO');
return h_radio('config[board_disable]', $radio_ary, $value) . '<br /><input id="' . $key . '" type="text" name="config[board_disable_msg]" maxlength="255" size="40" value="' . $this->new_config['board_disable_msg'] . '" />';
@@ -1028,8 +1063,6 @@ class acp_board
*/
function select_news_forums($value, $key)
{
- global $user, $config;
-
$forum_list = make_forum_select(false, false, true, true, true, false, true);
// Build forum options
@@ -1047,8 +1080,6 @@ class acp_board
function select_exclude_forums($value, $key)
{
- global $user, $config;
-
$forum_list = make_forum_select(false, false, true, true, true, false, true);
// Build forum options
@@ -1066,10 +1097,10 @@ class acp_board
function store_feed_forums($option, $key)
{
- global $db, $cache;
+ global $db, $cache, $request;
// Get key
- $values = request_var($key, array(0 => 0));
+ $values = $request->variable($key, array(0 => 0));
// Empty option bit for all forums
$sql = 'UPDATE ' . FORUMS_TABLE . '
@@ -1078,7 +1109,7 @@ class acp_board
$db->sql_query($sql);
// Already emptied for all...
- if (sizeof($values))
+ if (count($values))
{
// Set for selected forums
$sql = 'UPDATE ' . FORUMS_TABLE . '
@@ -1104,7 +1135,7 @@ class acp_board
*/
function enable_mod_rewrite($value, $key)
{
- global $user, $config;
+ global $user;
// Determine whether mod_rewrite is enabled on the server
// NOTE: This only works on Apache servers on which PHP is NOT
@@ -1138,4 +1169,11 @@ class acp_board
return h_radio($field_name, array(1 => 'YES', 0 => 'NO'), $value) .
($message !== false ? '<br /><span>' . $user->lang($message) . '</span>' : '');
}
+
+ function send_test_email($value, $key)
+ {
+ global $user;
+
+ return '<input class="button2" type="submit" id="' . $key . '" name="' . $key . '" value="' . $user->lang['SEND_TEST_EMAIL'] . '" />';
+ }
}
diff --git a/phpBB/includes/acp/acp_bots.php b/phpBB/includes/acp/acp_bots.php
index 2188b90729..8bd357bc91 100644
--- a/phpBB/includes/acp/acp_bots.php
+++ b/phpBB/includes/acp/acp_bots.php
@@ -25,13 +25,13 @@ class acp_bots
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $cache, $request;
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix;
+ global $config, $db, $user, $template, $cache, $request, $phpbb_log;
+ global $phpbb_root_path, $phpEx;
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$submit = (isset($_POST['submit'])) ? true : false;
- $mark = request_var('mark', array(0));
- $bot_id = request_var('id', 0);
+ $mark = $request->variable('mark', array(0));
+ $bot_id = $request->variable('id', 0);
if (isset($_POST['add']))
{
@@ -55,7 +55,7 @@ class acp_bots
switch ($action)
{
case 'activate':
- if ($bot_id || sizeof($mark))
+ if ($bot_id || count($mark))
{
$sql_id = ($bot_id) ? " = $bot_id" : ' IN (' . implode(', ', $mark) . ')';
@@ -69,7 +69,7 @@ class acp_bots
break;
case 'deactivate':
- if ($bot_id || sizeof($mark))
+ if ($bot_id || count($mark))
{
$sql_id = ($bot_id) ? " = $bot_id" : ' IN (' . implode(', ', $mark) . ')';
@@ -83,7 +83,7 @@ class acp_bots
break;
case 'delete':
- if ($bot_id || sizeof($mark))
+ if ($bot_id || count($mark))
{
if (confirm_box(true))
{
@@ -109,7 +109,7 @@ class acp_bots
WHERE bot_id $sql_id";
$db->sql_query($sql);
- if (sizeof($user_id_ary))
+ if (count($user_id_ary))
{
$_tables = array(USERS_TABLE, USER_GROUP_TABLE);
foreach ($_tables as $table)
@@ -124,7 +124,7 @@ class acp_bots
$cache->destroy('_bots');
- add_log('admin', 'LOG_BOT_DELETE', implode(', ', $bot_name_ary));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_BOT_DELETE', false, array(implode(', ', $bot_name_ary)));
trigger_error($user->lang['BOT_DELETED'] . adm_back_link($this->u_action));
}
else
@@ -148,12 +148,12 @@ class acp_bots
}
$bot_row = array(
- 'bot_name' => utf8_normalize_nfc(request_var('bot_name', '', true)),
- 'bot_agent' => request_var('bot_agent', ''),
- 'bot_ip' => request_var('bot_ip', ''),
- 'bot_active' => request_var('bot_active', true),
- 'bot_lang' => request_var('bot_lang', $config['default_lang']),
- 'bot_style' => request_var('bot_style' , $config['default_style']),
+ 'bot_name' => $request->variable('bot_name', '', true),
+ 'bot_agent' => $request->variable('bot_agent', ''),
+ 'bot_ip' => $request->variable('bot_ip', ''),
+ 'bot_active' => $request->variable('bot_active', true),
+ 'bot_lang' => $request->variable('bot_lang', $config['default_lang']),
+ 'bot_style' => $request->variable('bot_style' , $config['default_style']),
);
if ($submit)
@@ -207,7 +207,7 @@ class acp_bots
$error[] = $user->lang['BOT_NAME_TAKEN'];
}
- if (!sizeof($error))
+ if (!count($error))
{
// New bot? Create a new user and group entry
if ($action == 'add')
@@ -296,7 +296,7 @@ class acp_bots
$cache->destroy('_bots');
- add_log('admin', 'LOG_BOT_' . $log, $bot_row['bot_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_BOT_' . $log, false, array($bot_row['bot_name']));
trigger_error($user->lang['BOT_' . $log] . adm_back_link($this->u_action));
}
@@ -338,7 +338,7 @@ class acp_bots
'L_TITLE' => $user->lang['BOT_' . $l_title],
'U_ACTION' => $this->u_action . "&amp;id=$bot_id&amp;action=$action",
'U_BACK' => $this->u_action,
- 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '',
'BOT_NAME' => $bot_row['bot_name'],
'BOT_IP' => $bot_row['bot_ip'],
@@ -348,7 +348,7 @@ class acp_bots
'S_ACTIVE_OPTIONS' => $s_active_options,
'S_STYLE_OPTIONS' => $style_select,
'S_LANG_OPTIONS' => $lang_select,
- 'S_ERROR' => (sizeof($error)) ? true : false,
+ 'S_ERROR' => (count($error)) ? true : false,
)
);
diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php
index 92d5e1dda6..b49c5ca0d3 100644
--- a/phpBB/includes/acp/acp_captcha.php
+++ b/phpBB/includes/acp/acp_captcha.php
@@ -25,17 +25,18 @@ class acp_captcha
function main($id, $mode)
{
- global $request, $user, $auth, $template;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container;
+ global $user, $template, $phpbb_log, $request;
+ global $config, $phpbb_container;
$user->add_lang('acp/board');
+ /* @var $factory \phpbb\captcha\factory */
$factory = $phpbb_container->get('captcha.factory');
$captchas = $factory->get_captcha_types();
- $selected = request_var('select_captcha', $config['captcha_plugin']);
+ $selected = $request->variable('select_captcha', $config['captcha_plugin']);
$selected = (isset($captchas['available'][$selected]) || isset($captchas['unavailable'][$selected])) ? $selected : $config['captcha_plugin'];
- $configure = request_var('configure', false);
+ $configure = $request->variable('configure', false);
// Oh, they are just here for the view
if (isset($_GET['captcha_demo']))
@@ -89,7 +90,7 @@ class acp_captcha
$form_key = 'acp_captcha';
add_form_key($form_key);
- $submit = request_var('main_submit', false);
+ $submit = $request->variable('main_submit', false);
$error = $cfg_array = array();
if ($submit)
@@ -125,11 +126,11 @@ class acp_captcha
$old_captcha = $factory->get_instance($config['captcha_plugin']);
$old_captcha->uninstall();
- set_config('captcha_plugin', $selected);
+ $config->set('captcha_plugin', $selected);
$new_captcha = $factory->get_instance($config['captcha_plugin']);
$new_captcha->install();
- add_log('admin', 'LOG_CONFIG_VISUAL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
}
else
{
@@ -157,7 +158,7 @@ class acp_captcha
foreach ($config_vars as $config_var => $options)
{
- $template->assign_var($options['tpl'], (isset($_POST[$config_var])) ? request_var($config_var, $options['default']) : $config[$config_var]) ;
+ $template->assign_var($options['tpl'], (isset($_POST[$config_var])) ? $request->variable($config_var, $options['default']) : $config[$config_var]) ;
}
$template->assign_vars(array(
@@ -177,7 +178,7 @@ class acp_captcha
*/
function deliver_demo($selected)
{
- global $db, $user, $config, $phpbb_container;
+ global $phpbb_container;
$captcha = $phpbb_container->get('captcha.factory')->get_instance($selected);
$captcha->init(CONFIRM_REG);
diff --git a/phpBB/includes/acp/acp_contact.php b/phpBB/includes/acp/acp_contact.php
index 4e46df21e0..1a4d5b95a3 100644
--- a/phpBB/includes/acp/acp_contact.php
+++ b/phpBB/includes/acp/acp_contact.php
@@ -48,6 +48,7 @@ class acp_contact
include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
}
+ /* @var $config_text \phpbb\config\db_text */
$config_text = $phpbb_container->get('config_text');
$contact_admin_data = $config_text->get_array(array(
@@ -104,6 +105,9 @@ class acp_contact
$contact_admin_edit = generate_text_for_edit($contact_admin_info, $contact_admin_info_uid, $contact_admin_info_flags);
+ /** @var \phpbb\controller\helper $controller_helper */
+ $controller_helper = $phpbb_container->get('controller.helper');
+
$template->assign_vars(array(
'ERRORS' => $error,
'CONTACT_ENABLED' => $config['contact_admin_form_enable'],
@@ -115,7 +119,7 @@ class acp_contact
'S_SMILIES_DISABLE_CHECKED' => !$contact_admin_edit['allow_smilies'],
'S_MAGIC_URL_DISABLE_CHECKED' => !$contact_admin_edit['allow_urls'],
- 'BBCODE_STATUS' => $user->lang('BBCODE_IS_ON', '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'),
+ 'BBCODE_STATUS' => $user->lang('BBCODE_IS_ON', '<a href="' . $controller_helper->route('phpbb_help_bbcode_controller') . '">', '</a>'),
'SMILIES_STATUS' => $user->lang['SMILIES_ARE_ON'],
'IMG_STATUS' => $user->lang['IMAGES_ARE_ON'],
'FLASH_STATUS' => $user->lang['FLASH_IS_ON'],
diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php
index dd0599e06a..677fce7217 100644
--- a/phpBB/includes/acp/acp_database.php
+++ b/phpBB/includes/acp/acp_database.php
@@ -23,21 +23,21 @@ class acp_database
{
var $db_tools;
var $u_action;
+ public $page_title;
function main($id, $mode)
{
- global $cache, $db, $user, $auth, $template, $table_prefix;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $cache, $db, $user, $template, $table_prefix, $request;
+ global $phpbb_root_path, $phpbb_container, $phpbb_log;
- $this->db_tools = new \phpbb\db\tools($db);
+ $this->db_tools = $phpbb_container->get('dbal.tools');
$user->add_lang('acp/database');
$this->tpl_name = 'acp_database';
$this->page_title = 'ACP_DATABASE';
- $action = request_var('action', '');
- $submit = (isset($_POST['submit'])) ? true : false;
+ $action = $request->variable('action', '');
$form_key = 'acp_database';
add_form_key($form_key);
@@ -55,12 +55,11 @@ class acp_database
switch ($action)
{
case 'download':
- $type = request_var('type', '');
- $table = array_intersect($this->db_tools->sql_list_tables(), request_var('table', array('')));
- $format = request_var('method', '');
- $where = request_var('where', '');
+ $type = $request->variable('type', '');
+ $table = array_intersect($this->db_tools->sql_list_tables(), $request->variable('table', array('')));
+ $format = $request->variable('method', '');
- if (!sizeof($table))
+ if (!count($table))
{
trigger_error($user->lang['TABLE_SELECT_ERROR'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -70,17 +69,9 @@ class acp_database
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- $store = $download = $structure = $schema_data = false;
-
- if ($where == 'store_and_download' || $where == 'store')
- {
- $store = true;
- }
-
- if ($where == 'store_and_download' || $where == 'download')
- {
- $download = true;
- }
+ $store = true;
+ $structure = false;
+ $schema_data = false;
if ($type == 'full' || $type == 'structure')
{
@@ -98,36 +89,10 @@ class acp_database
$time = time();
$filename = 'backup_' . $time . '_' . unique_id();
- switch ($db->get_sql_layer())
- {
- case 'mysqli':
- case 'mysql4':
- case 'mysql':
- $extractor = new mysql_extractor($format, $filename, $time, $download, $store);
- break;
-
- case 'sqlite':
- $extractor = new sqlite_extractor($format, $filename, $time, $download, $store);
- break;
- case 'sqlite3':
- $extractor = new sqlite3_extractor($format, $filename, $time, $download, $store);
- break;
-
- case 'postgres':
- $extractor = new postgres_extractor($format, $filename, $time, $download, $store);
- break;
-
- case 'oracle':
- $extractor = new oracle_extractor($format, $filename, $time, $download, $store);
- break;
-
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
- $extractor = new mssql_extractor($format, $filename, $time, $download, $store);
- break;
- }
+ /** @var phpbb\db\extractor\extractor_interface $extractor Database extractor */
+ $extractor = $phpbb_container->get('dbal.extractor');
+ $extractor->init_extractor($format, $filename, $time, false, $store);
$extractor->write_start($table_prefix);
@@ -143,12 +108,10 @@ class acp_database
// We might wanna empty out all that junk :D
switch ($db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
$extractor->flush('DELETE FROM ' . $table_name . ";\n");
break;
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n");
@@ -173,12 +136,7 @@ class acp_database
$extractor->write_end();
- add_log('admin', 'LOG_DB_BACKUP');
-
- if ($download == true)
- {
- exit;
- }
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_BACKUP');
trigger_error($user->lang['BACKUP_SUCCESS'] . adm_back_link($this->u_action));
break;
@@ -229,18 +187,12 @@ class acp_database
switch ($action)
{
case 'submit':
- $delete = request_var('delete', '');
- $file = request_var('file', '');
- $download = request_var('download', '');
+ $delete = $request->variable('delete', '');
+ $file = $request->variable('file', '');
- if (!preg_match('#^backup_\d{10,}_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches))
- {
- trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
- }
-
- $file_name = $phpbb_root_path . 'store/' . $matches[0];
+ $backup_info = $this->get_backup_file($phpbb_root_path . 'store/', $file);
- if (!file_exists($file_name) || !is_readable($file_name))
+ if (empty($backup_info) || !is_readable($backup_info['file_name']))
{
trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -249,8 +201,8 @@ class acp_database
{
if (confirm_box(true))
{
- unlink($file_name);
- add_log('admin', 'LOG_DB_DELETE');
+ unlink($backup_info['file_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_DELETE');
trigger_error($user->lang['BACKUP_DELETE'] . adm_back_link($this->u_action));
}
else
@@ -258,50 +210,12 @@ class acp_database
confirm_box(false, $user->lang['DELETE_SELECTED_BACKUP'], build_hidden_fields(array('delete' => $delete, 'file' => $file)));
}
}
- else if ($download || confirm_box(true))
+ else if (confirm_box(true))
{
- if ($download)
- {
- $name = $matches[0];
-
- switch ($matches[1])
- {
- case 'sql':
- $mimetype = 'text/x-sql';
- break;
- case 'sql.bz2':
- $mimetype = 'application/x-bzip2';
- break;
- case 'sql.gz':
- $mimetype = 'application/x-gzip';
- break;
- }
-
- header('Cache-Control: private, no-cache');
- header("Content-Type: $mimetype; name=\"$name\"");
- header("Content-disposition: attachment; filename=$name");
-
- @set_time_limit(0);
-
- $fp = @fopen($file_name, 'rb');
-
- if ($fp !== false)
- {
- while (!feof($fp))
- {
- echo fread($fp, 8192);
- }
- fclose($fp);
- }
-
- flush();
- exit;
- }
-
- switch ($matches[1])
+ switch ($backup_info['extension'])
{
case 'sql':
- $fp = fopen($file_name, 'rb');
+ $fp = fopen($backup_info['file_name'], 'rb');
$read = 'fread';
$seek = 'fseek';
$eof = 'feof';
@@ -310,7 +224,7 @@ class acp_database
break;
case 'sql.bz2':
- $fp = bzopen($file_name, 'r');
+ $fp = bzopen($backup_info['file_name'], 'r');
$read = 'bzread';
$seek = '';
$eof = 'feof';
@@ -319,13 +233,17 @@ class acp_database
break;
case 'sql.gz':
- $fp = gzopen($file_name, 'rb');
+ $fp = gzopen($backup_info['file_name'], 'rb');
$read = 'gzread';
$seek = 'gzseek';
$eof = 'gzeof';
$close = 'gzclose';
$fgetd = 'fgetd';
break;
+
+ default:
+ trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+ return;
}
switch ($db->get_sql_layer())
@@ -333,7 +251,6 @@ class acp_database
case 'mysql':
case 'mysql4':
case 'mysqli':
- case 'sqlite':
case 'sqlite3':
while (($sql = $fgetd($fp, ";\n", $read, $seek, $eof)) !== false)
{
@@ -388,7 +305,6 @@ class acp_database
}
break;
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
while (($sql = $fgetd($fp, "GO\n", $read, $seek, $eof)) !== false)
@@ -403,47 +319,17 @@ class acp_database
// Purge the cache due to updated data
$cache->purge();
- add_log('admin', 'LOG_DB_RESTORE');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DB_RESTORE');
trigger_error($user->lang['RESTORE_SUCCESS'] . adm_back_link($this->u_action));
break;
}
- else if (!$download)
+ else
{
confirm_box(false, $user->lang['RESTORE_SELECTED_BACKUP'], build_hidden_fields(array('file' => $file)));
}
default:
- $methods = array('sql');
- $available_methods = array('sql.gz' => 'zlib', 'sql.bz2' => 'bz2');
-
- foreach ($available_methods as $type => $module)
- {
- if (!@extension_loaded($module))
- {
- continue;
- }
- $methods[] = $type;
- }
-
- $dir = $phpbb_root_path . 'store/';
- $dh = @opendir($dir);
-
- $backup_files = array();
-
- if ($dh)
- {
- while (($file = readdir($dh)) !== false)
- {
- if (preg_match('#^backup_(\d{10,})_[a-z\d]{16}\.(sql(?:\.(?:gz|bz2))?)$#', $file, $matches))
- {
- if (in_array($matches[2], $methods))
- {
- $backup_files[(int) $matches[1]] = $file;
- }
- }
- }
- closedir($dh);
- }
+ $backup_files = $this->get_file_list($phpbb_root_path . 'store/');
if (!empty($backup_files))
{
@@ -452,8 +338,8 @@ class acp_database
foreach ($backup_files as $name => $file)
{
$template->assign_block_vars('files', array(
- 'FILE' => $file,
- 'NAME' => $user->format_date($name, 'd-m-Y H:i:s', true),
+ 'FILE' => sha1($file),
+ 'NAME' => $user->format_date($name, 'd-m-Y H:i', true),
'SUPPORTED' => true,
));
}
@@ -467,1636 +353,91 @@ class acp_database
break;
}
}
-}
-class base_extractor
-{
- var $fh;
- var $fp;
- var $write;
- var $close;
- var $store;
- var $download;
- var $time;
- var $format;
- var $run_comp = false;
-
- function base_extractor($format, $filename, $time, $download = false, $store = false)
+ /**
+ * Get backup file from file hash
+ *
+ * @param string $directory Relative path to directory
+ * @param string $file_hash Hash of selected file
+ *
+ * @return array Backup file data or empty array if unable to find file
+ */
+ protected function get_backup_file($directory, $file_hash)
{
- global $request;
+ $backup_data = [];
- $this->download = $download;
- $this->store = $store;
- $this->time = $time;
- $this->format = $format;
-
- switch ($format)
- {
- case 'text':
- $ext = '.sql';
- $open = 'fopen';
- $this->write = 'fwrite';
- $this->close = 'fclose';
- $mimetype = 'text/x-sql';
- break;
- case 'bzip2':
- $ext = '.sql.bz2';
- $open = 'bzopen';
- $this->write = 'bzwrite';
- $this->close = 'bzclose';
- $mimetype = 'application/x-bzip2';
- break;
- case 'gzip':
- $ext = '.sql.gz';
- $open = 'gzopen';
- $this->write = 'gzwrite';
- $this->close = 'gzclose';
- $mimetype = 'application/x-gzip';
- break;
- }
+ $file_list = $this->get_file_list($directory);
+ $supported_extensions = $this->get_supported_extensions();
- if ($download == true)
+ foreach ($file_list as $file)
{
- $name = $filename . $ext;
- header('Cache-Control: private, no-cache');
- header("Content-Type: $mimetype; name=\"$name\"");
- header("Content-disposition: attachment; filename=$name");
-
- switch ($format)
+ preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches);
+ if (sha1($file) === $file_hash && in_array($matches[2], $supported_extensions))
{
- case 'bzip2':
- ob_start();
- break;
-
- case 'gzip':
- if (strpos($request->header('Accept-Encoding'), 'gzip') !== false && strpos(strtolower($request->header('User-Agent')), 'msie') === false)
- {
- ob_start('ob_gzhandler');
- }
- else
- {
- $this->run_comp = true;
- }
+ $backup_data = [
+ 'file_name' => $directory . $file,
+ 'extension' => $matches[2],
+ ];
break;
}
}
- if ($store == true)
- {
- global $phpbb_root_path;
- $file = $phpbb_root_path . 'store/' . $filename . $ext;
-
- $this->fp = $open($file, 'w');
-
- if (!$this->fp)
- {
- trigger_error('FILE_WRITE_FAIL', E_USER_ERROR);
- }
- }
+ return $backup_data;
}
- function write_end()
+ /**
+ * Get backup file list for directory
+ *
+ * @param string $directory Relative path to backup directory
+ *
+ * @return array List of backup files in specified directory
+ */
+ protected function get_file_list($directory)
{
- static $close;
+ $supported_extensions = $this->get_supported_extensions();
- if ($this->store)
- {
- if ($close === null)
- {
- $close = $this->close;
- }
- $close($this->fp);
- }
+ $dh = @opendir($directory);
- // bzip2 must be written all the way at the end
- if ($this->download && $this->format === 'bzip2')
- {
- $c = ob_get_clean();
- echo bzcompress($c);
- }
- }
-
- function flush($data)
- {
- static $write;
- if ($this->store === true)
- {
- if ($write === null)
- {
- $write = $this->write;
- }
- $write($this->fp, $data);
- }
-
- if ($this->download === true)
- {
- if ($this->format === 'bzip2' || $this->format === 'text' || ($this->format === 'gzip' && !$this->run_comp))
- {
- echo $data;
- }
-
- // we can write the gzip data as soon as we get it
- if ($this->format === 'gzip')
- {
- if ($this->run_comp)
- {
- echo gzencode($data);
- }
- else
- {
- ob_flush();
- flush();
- }
- }
- }
- }
-}
-
-class mysql_extractor extends base_extractor
-{
- function write_start($table_prefix)
- {
- $sql_data = "#\n";
- $sql_data .= "# phpBB Backup Script\n";
- $sql_data .= "# Dump of tables for $table_prefix\n";
- $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
- $sql_data .= "#\n";
- $this->flush($sql_data);
- }
-
- function write_table($table_name)
- {
- global $db;
- static $new_extract;
-
- if ($new_extract === null)
- {
- if ($db->get_sql_layer() === 'mysqli' || version_compare($db->sql_server_info(true), '3.23.20', '>='))
- {
- $new_extract = true;
- }
- else
- {
- $new_extract = false;
- }
- }
-
- if ($new_extract)
- {
- $this->new_write_table($table_name);
- }
- else
- {
- $this->old_write_table($table_name);
- }
- }
-
- function write_data($table_name)
- {
- global $db;
- if ($db->get_sql_layer() === 'mysqli')
- {
- $this->write_data_mysqli($table_name);
- }
- else
- {
- $this->write_data_mysql($table_name);
- }
- }
-
- function write_data_mysqli($table_name)
- {
- global $db;
- $sql = "SELECT *
- FROM $table_name";
- $result = mysqli_query($db->get_db_connect_id(), $sql, MYSQLI_USE_RESULT);
- if ($result != false)
- {
- $fields_cnt = mysqli_num_fields($result);
-
- // Get field information
- $field = mysqli_fetch_fields($result);
- $field_set = array();
-
- for ($j = 0; $j < $fields_cnt; $j++)
- {
- $field_set[] = $field[$j]->name;
- }
-
- $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
- $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
- $fields = implode(', ', $field_set);
- $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
- $first_set = true;
- $query_len = 0;
- $max_len = get_usable_memory();
-
- while ($row = mysqli_fetch_row($result))
- {
- $values = array();
- if ($first_set)
- {
- $query = $sql_data . '(';
- }
- else
- {
- $query .= ',(';
- }
-
- for ($j = 0; $j < $fields_cnt; $j++)
- {
- if (!isset($row[$j]) || is_null($row[$j]))
- {
- $values[$j] = 'NULL';
- }
- else if (($field[$j]->flags & 32768) && !($field[$j]->flags & 1024))
- {
- $values[$j] = $row[$j];
- }
- else
- {
- $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
- }
- }
- $query .= implode(', ', $values) . ')';
-
- $query_len += strlen($query);
- if ($query_len > $max_len)
- {
- $this->flush($query . ";\n\n");
- $query = '';
- $query_len = 0;
- $first_set = true;
- }
- else
- {
- $first_set = false;
- }
- }
- mysqli_free_result($result);
+ $backup_files = [];
- // check to make sure we have nothing left to flush
- if (!$first_set && $query)
- {
- $this->flush($query . ";\n\n");
- }
- }
- }
-
- function write_data_mysql($table_name)
- {
- global $db;
- $sql = "SELECT *
- FROM $table_name";
- $result = mysql_unbuffered_query($sql, $db->get_db_connect_id());
-
- if ($result != false)
+ if ($dh)
{
- $fields_cnt = mysql_num_fields($result);
-
- // Get field information
- $field = array();
- for ($i = 0; $i < $fields_cnt; $i++)
+ while (($file = readdir($dh)) !== false)
{
- $field[] = mysql_fetch_field($result, $i);
- }
- $field_set = array();
-
- for ($j = 0; $j < $fields_cnt; $j++)
- {
- $field_set[] = $field[$j]->name;
- }
-
- $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
- $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
- $fields = implode(', ', $field_set);
- $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
- $first_set = true;
- $query_len = 0;
- $max_len = get_usable_memory();
-
- while ($row = mysql_fetch_row($result))
- {
- $values = array();
- if ($first_set)
- {
- $query = $sql_data . '(';
- }
- else
- {
- $query .= ',(';
- }
-
- for ($j = 0; $j < $fields_cnt; $j++)
+ if (preg_match('#^backup_(\d{10,})_(?:[a-z\d]{16}|[a-z\d]{32})\.(sql(?:\.(?:gz|bz2))?)$#i', $file, $matches))
{
- if (!isset($row[$j]) || is_null($row[$j]))
+ if (in_array($matches[2], $supported_extensions))
{
- $values[$j] = 'NULL';
- }
- else if ($field[$j]->numeric && ($field[$j]->type !== 'timestamp'))
- {
- $values[$j] = $row[$j];
- }
- else
- {
- $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
+ $backup_files[(int) $matches[1]] = $file;
}
}
- $query .= implode(', ', $values) . ')';
-
- $query_len += strlen($query);
- if ($query_len > $max_len)
- {
- $this->flush($query . ";\n\n");
- $query = '';
- $query_len = 0;
- $first_set = true;
- }
- else
- {
- $first_set = false;
- }
- }
- mysql_free_result($result);
-
- // check to make sure we have nothing left to flush
- if (!$first_set && $query)
- {
- $this->flush($query . ";\n\n");
}
+ closedir($dh);
}
- }
-
- function new_write_table($table_name)
- {
- global $db;
-
- $sql = 'SHOW CREATE TABLE ' . $table_name;
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
-
- $sql_data = '# Table: ' . $table_name . "\n";
- $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
- $this->flush($sql_data . $row['Create Table'] . ";\n\n");
- $db->sql_freeresult($result);
+ return $backup_files;
}
- function old_write_table($table_name)
+ /**
+ * Get supported extensions for backup
+ *
+ * @return array List of supported extensions
+ */
+ protected function get_supported_extensions()
{
- global $db;
+ $extensions = ['sql'];
+ $available_methods = ['sql.gz' => 'zlib', 'sql.bz2' => 'bz2'];
- $sql_data = '# Table: ' . $table_name . "\n";
- $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
- $sql_data .= "CREATE TABLE $table_name(\n";
- $rows = array();
-
- $sql = "SHOW FIELDS
- FROM $table_name";
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
+ foreach ($available_methods as $type => $module)
{
- $line = ' ' . $row['Field'] . ' ' . $row['Type'];
-
- if (!is_null($row['Default']))
- {
- $line .= " DEFAULT '{$row['Default']}'";
- }
-
- if ($row['Null'] != 'YES')
- {
- $line .= ' NOT NULL';
- }
-
- if ($row['Extra'] != '')
- {
- $line .= ' ' . $row['Extra'];
- }
-
- $rows[] = $line;
- }
- $db->sql_freeresult($result);
-
- $sql = "SHOW KEYS
- FROM $table_name";
-
- $result = $db->sql_query($sql);
-
- $index = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $kname = $row['Key_name'];
-
- if ($kname != 'PRIMARY')
- {
- if ($row['Non_unique'] == 0)
- {
- $kname = "UNIQUE|$kname";
- }
- }
-
- if ($row['Sub_part'])
- {
- $row['Column_name'] .= '(' . $row['Sub_part'] . ')';
- }
- $index[$kname][] = $row['Column_name'];
- }
- $db->sql_freeresult($result);
-
- foreach ($index as $key => $columns)
- {
- $line = ' ';
-
- if ($key == 'PRIMARY')
- {
- $line .= 'PRIMARY KEY (' . implode(', ', $columns) . ')';
- }
- else if (strpos($key, 'UNIQUE') === 0)
- {
- $line .= 'UNIQUE ' . substr($key, 7) . ' (' . implode(', ', $columns) . ')';
- }
- else if (strpos($key, 'FULLTEXT') === 0)
- {
- $line .= 'FULLTEXT ' . substr($key, 9) . ' (' . implode(', ', $columns) . ')';
- }
- else
- {
- $line .= "KEY $key (" . implode(', ', $columns) . ')';
- }
-
- $rows[] = $line;
- }
-
- $sql_data .= implode(",\n", $rows);
- $sql_data .= "\n);\n\n";
-
- $this->flush($sql_data);
- }
-}
-
-class sqlite_extractor extends base_extractor
-{
- function write_start($prefix)
- {
- $sql_data = "--\n";
- $sql_data .= "-- phpBB Backup Script\n";
- $sql_data .= "-- Dump of tables for $prefix\n";
- $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
- $sql_data .= "--\n";
- $sql_data .= "BEGIN TRANSACTION;\n";
- $this->flush($sql_data);
- }
-
- function write_table($table_name)
- {
- global $db;
- $sql_data = '-- Table: ' . $table_name . "\n";
- $sql_data .= "DROP TABLE $table_name;\n";
-
- $sql = "SELECT sql
- FROM sqlite_master
- WHERE type = 'table'
- AND name = '" . $db->sql_escape($table_name) . "'
- ORDER BY type DESC, name;";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // Create Table
- $sql_data .= $row['sql'] . ";\n";
-
- $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');");
-
- $ar = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $ar[] = $row;
- }
- $db->sql_freeresult($result);
-
- foreach ($ar as $value)
- {
- if (strpos($value['name'], 'autoindex') !== false)
+ if (!@extension_loaded($module))
{
continue;
}
-
- $result = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($value['name']) . "');");
-
- $fields = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $fields[] = $row['name'];
- }
- $db->sql_freeresult($result);
-
- $sql_data .= 'CREATE ' . ($value['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $value['name'] . ' on ' . $table_name . ' (' . implode(', ', $fields) . ");\n";
+ $extensions[] = $type;
}
- $this->flush($sql_data . "\n");
- }
-
- function write_data($table_name)
- {
- global $db;
-
- $col_types = sqlite_fetch_column_types($db->get_db_connect_id(), $table_name);
-
- $sql = "SELECT *
- FROM $table_name";
- $result = sqlite_unbuffered_query($db->get_db_connect_id(), $sql);
- $rows = sqlite_fetch_all($result, SQLITE_ASSOC);
- $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES (';
- foreach ($rows as $row)
- {
- foreach ($row as $column_name => $column_data)
- {
- if (is_null($column_data))
- {
- $row[$column_name] = 'NULL';
- }
- else if ($column_data == '')
- {
- $row[$column_name] = "''";
- }
- else if (strpos($col_types[$column_name], 'text') !== false || strpos($col_types[$column_name], 'char') !== false || strpos($col_types[$column_name], 'blob') !== false)
- {
- $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data));
- }
- }
- $this->flush($sql_insert . implode(', ', $row) . ");\n");
- }
- }
-
- function write_end()
- {
- $this->flush("COMMIT;\n");
- parent::write_end();
- }
-}
-
-class sqlite3_extractor extends base_extractor
-{
- function write_start($prefix)
- {
- $sql_data = "--\n";
- $sql_data .= "-- phpBB Backup Script\n";
- $sql_data .= "-- Dump of tables for $prefix\n";
- $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
- $sql_data .= "--\n";
- $sql_data .= "BEGIN TRANSACTION;\n";
- $this->flush($sql_data);
- }
-
- function write_table($table_name)
- {
- global $db;
- $sql_data = '-- Table: ' . $table_name . "\n";
- $sql_data .= "DROP TABLE $table_name;\n";
-
- $sql = "SELECT sql
- FROM sqlite_master
- WHERE type = 'table'
- AND name = '" . $db->sql_escape($table_name) . "'
- ORDER BY name ASC;";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // Create Table
- $sql_data .= $row['sql'] . ";\n";
-
- $result = $db->sql_query("PRAGMA index_list('" . $db->sql_escape($table_name) . "');");
-
- while ($row = $db->sql_fetchrow($result))
- {
- if (strpos($row['name'], 'autoindex') !== false)
- {
- continue;
- }
-
- $result2 = $db->sql_query("PRAGMA index_info('" . $db->sql_escape($row['name']) . "');");
-
- $fields = array();
- while ($row2 = $db->sql_fetchrow($result2))
- {
- $fields[] = $row2['name'];
- }
- $db->sql_freeresult($result2);
-
- $sql_data .= 'CREATE ' . ($row['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $row['name'] . ' ON ' . $table_name . ' (' . implode(', ', $fields) . ");\n";
- }
- $db->sql_freeresult($result);
-
- $this->flush($sql_data . "\n");
- }
-
- function write_data($table_name)
- {
- global $db;
-
- $result = $db->sql_query("PRAGMA table_info('" . $db->sql_escape($table_name) . "');");
-
- $col_types = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $col_types[$row['name']] = $row['type'];
- }
- $db->sql_freeresult($result);
-
- $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES (';
-
- $sql = "SELECT *
- FROM $table_name";
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- foreach ($row as $column_name => $column_data)
- {
- if (is_null($column_data))
- {
- $row[$column_name] = 'NULL';
- }
- else if ($column_data === '')
- {
- $row[$column_name] = "''";
- }
- else if (stripos($col_types[$column_name], 'text') !== false || stripos($col_types[$column_name], 'char') !== false || stripos($col_types[$column_name], 'blob') !== false)
- {
- $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data));
- }
- }
- $this->flush($sql_insert . implode(', ', $row) . ");\n");
- }
- }
-
- function write_end()
- {
- $this->flush("COMMIT;\n");
- parent::write_end();
- }
-}
-
-class postgres_extractor extends base_extractor
-{
- function write_start($prefix)
- {
- $sql_data = "--\n";
- $sql_data .= "-- phpBB Backup Script\n";
- $sql_data .= "-- Dump of tables for $prefix\n";
- $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
- $sql_data .= "--\n";
- $sql_data .= "BEGIN TRANSACTION;\n";
- $this->flush($sql_data);
- }
-
- function write_table($table_name)
- {
- global $db;
- static $domains_created = array();
-
- $sql = "SELECT a.domain_name, a.data_type, a.character_maximum_length, a.domain_default
- FROM INFORMATION_SCHEMA.domains a, INFORMATION_SCHEMA.column_domain_usage b
- WHERE a.domain_name = b.domain_name
- AND b.table_name = '{$table_name}'";
- $result = $db->sql_query($sql);
- while ($row = $db->sql_fetchrow($result))
- {
- if (empty($domains_created[$row['domain_name']]))
- {
- $domains_created[$row['domain_name']] = true;
- //$sql_data = "DROP DOMAIN {$row['domain_name']};\n";
- $sql_data = "CREATE DOMAIN {$row['domain_name']} as {$row['data_type']}";
- if (!empty($row['character_maximum_length']))
- {
- $sql_data .= '(' . $row['character_maximum_length'] . ')';
- }
- $sql_data .= ' NOT NULL';
- if (!empty($row['domain_default']))
- {
- $sql_data .= ' DEFAULT ' . $row['domain_default'];
- }
- $this->flush($sql_data . ";\n");
- }
- }
- $db->sql_freeresult($result);
-
- $sql_data = '-- Table: ' . $table_name . "\n";
- $sql_data .= "DROP TABLE $table_name;\n";
- // PGSQL does not "tightly" bind sequences and tables, we must guess...
- $sql = "SELECT relname
- FROM pg_class
- WHERE relkind = 'S'
- AND relname = '{$table_name}_seq'";
- $result = $db->sql_query($sql);
- // We don't even care about storing the results. We already know the answer if we get rows back.
- if ($db->sql_fetchrow($result))
- {
- $sql_data .= "DROP SEQUENCE {$table_name}_seq;\n";
- $sql_data .= "CREATE SEQUENCE {$table_name}_seq;\n";
- }
- $db->sql_freeresult($result);
-
- $field_query = "SELECT a.attnum, a.attname as field, t.typname as type, a.attlen as length, a.atttypmod as lengthvar, a.attnotnull as notnull
- FROM pg_class c, pg_attribute a, pg_type t
- WHERE c.relname = '" . $db->sql_escape($table_name) . "'
- AND a.attnum > 0
- AND a.attrelid = c.oid
- AND a.atttypid = t.oid
- ORDER BY a.attnum";
- $result = $db->sql_query($field_query);
-
- $sql_data .= "CREATE TABLE $table_name(\n";
- $lines = array();
- while ($row = $db->sql_fetchrow($result))
- {
- // Get the data from the table
- $sql_get_default = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
- FROM pg_attrdef d, pg_class c
- WHERE (c.relname = '" . $db->sql_escape($table_name) . "')
- AND (c.oid = d.adrelid)
- AND d.adnum = " . $row['attnum'];
- $def_res = $db->sql_query($sql_get_default);
- $def_row = $db->sql_fetchrow($def_res);
- $db->sql_freeresult($def_res);
-
- if (empty($def_row))
- {
- unset($row['rowdefault']);
- }
- else
- {
- $row['rowdefault'] = $def_row['rowdefault'];
- }
-
- if ($row['type'] == 'bpchar')
- {
- // Internally stored as bpchar, but isn't accepted in a CREATE TABLE statement.
- $row['type'] = 'char';
- }
-
- $line = ' ' . $row['field'] . ' ' . $row['type'];
-
- if (strpos($row['type'], 'char') !== false)
- {
- if ($row['lengthvar'] > 0)
- {
- $line .= '(' . ($row['lengthvar'] - 4) . ')';
- }
- }
-
- if (strpos($row['type'], 'numeric') !== false)
- {
- $line .= '(';
- $line .= sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff));
- $line .= ')';
- }
-
- if (isset($row['rowdefault']))
- {
- $line .= ' DEFAULT ' . $row['rowdefault'];
- }
-
- if ($row['notnull'] == 't')
- {
- $line .= ' NOT NULL';
- }
-
- $lines[] = $line;
- }
- $db->sql_freeresult($result);
-
- // Get the listing of primary keys.
- $sql_pri_keys = "SELECT ic.relname as index_name, bc.relname as tab_name, ta.attname as column_name, i.indisunique as unique_key, i.indisprimary as primary_key
- FROM pg_class bc, pg_class ic, pg_index i, pg_attribute ta, pg_attribute ia
- WHERE (bc.oid = i.indrelid)
- AND (ic.oid = i.indexrelid)
- AND (ia.attrelid = i.indexrelid)
- AND (ta.attrelid = bc.oid)
- AND (bc.relname = '" . $db->sql_escape($table_name) . "')
- AND (ta.attrelid = i.indrelid)
- AND (ta.attnum = i.indkey[ia.attnum-1])
- ORDER BY index_name, tab_name, column_name";
-
- $result = $db->sql_query($sql_pri_keys);
-
- $index_create = $index_rows = $primary_key = array();
-
- // We do this in two steps. It makes placing the comma easier
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['primary_key'] == 't')
- {
- $primary_key[] = $row['column_name'];
- $primary_key_name = $row['index_name'];
- }
- else
- {
- // We have to store this all this info because it is possible to have a multi-column key...
- // we can loop through it again and build the statement
- $index_rows[$row['index_name']]['table'] = $table_name;
- $index_rows[$row['index_name']]['unique'] = ($row['unique_key'] == 't') ? true : false;
- $index_rows[$row['index_name']]['column_names'][] = $row['column_name'];
- }
- }
- $db->sql_freeresult($result);
-
- if (!empty($index_rows))
- {
- foreach ($index_rows as $idx_name => $props)
- {
- $index_create[] = 'CREATE ' . ($props['unique'] ? 'UNIQUE ' : '') . "INDEX $idx_name ON $table_name (" . implode(', ', $props['column_names']) . ");";
- }
- }
-
- if (!empty($primary_key))
- {
- $lines[] = " CONSTRAINT $primary_key_name PRIMARY KEY (" . implode(', ', $primary_key) . ")";
- }
-
- // Generate constraint clauses for CHECK constraints
- $sql_checks = "SELECT conname as index_name, consrc
- FROM pg_constraint, pg_class bc
- WHERE conrelid = bc.oid
- AND bc.relname = '" . $db->sql_escape($table_name) . "'
- AND NOT EXISTS (
- SELECT *
- FROM pg_constraint as c, pg_inherits as i
- WHERE i.inhrelid = pg_constraint.conrelid
- AND c.conname = pg_constraint.conname
- AND c.consrc = pg_constraint.consrc
- AND c.conrelid = i.inhparent
- )";
- $result = $db->sql_query($sql_checks);
-
- // Add the constraints to the sql file.
- while ($row = $db->sql_fetchrow($result))
- {
- if (!is_null($row['consrc']))
- {
- $lines[] = ' CONSTRAINT ' . $row['index_name'] . ' CHECK ' . $row['consrc'];
- }
- }
- $db->sql_freeresult($result);
-
- $sql_data .= implode(", \n", $lines);
- $sql_data .= "\n);\n";
-
- if (!empty($index_create))
- {
- $sql_data .= implode("\n", $index_create) . "\n\n";
- }
- $this->flush($sql_data);
- }
-
- function write_data($table_name)
- {
- global $db;
- // Grab all of the data from current table.
- $sql = "SELECT *
- FROM $table_name";
- $result = $db->sql_query($sql);
-
- $i_num_fields = pg_num_fields($result);
- $seq = '';
-
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $ary_type[] = pg_field_type($result, $i);
- $ary_name[] = pg_field_name($result, $i);
-
- $sql = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
- FROM pg_attrdef d, pg_class c
- WHERE (c.relname = '{$table_name}')
- AND (c.oid = d.adrelid)
- AND d.adnum = " . strval($i + 1);
- $result2 = $db->sql_query($sql);
- if ($row = $db->sql_fetchrow($result2))
- {
- // Determine if we must reset the sequences
- if (strpos($row['rowdefault'], "nextval('") === 0)
- {
- $seq .= "SELECT SETVAL('{$table_name}_seq',(select case when max({$ary_name[$i]})>0 then max({$ary_name[$i]})+1 else 1 end FROM {$table_name}));\n";
- }
- }
- }
-
- $this->flush("COPY $table_name (" . implode(', ', $ary_name) . ') FROM stdin;' . "\n");
- while ($row = $db->sql_fetchrow($result))
- {
- $schema_vals = array();
-
- // Build the SQL statement to recreate the data.
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $str_val = $row[$ary_name[$i]];
-
- if (preg_match('#char|text|bool|bytea#i', $ary_type[$i]))
- {
- $str_val = str_replace(array("\n", "\t", "\r", "\b", "\f", "\v"), array('\n', '\t', '\r', '\b', '\f', '\v'), addslashes($str_val));
- $str_empty = '';
- }
- else
- {
- $str_empty = '\N';
- }
-
- if (empty($str_val) && $str_val !== '0')
- {
- $str_val = $str_empty;
- }
-
- $schema_vals[] = $str_val;
- }
-
- // Take the ordered fields and their associated data and build it
- // into a valid sql statement to recreate that field in the data.
- $this->flush(implode("\t", $schema_vals) . "\n");
- }
- $db->sql_freeresult($result);
- $this->flush("\\.\n");
-
- // Write out the sequence statements
- $this->flush($seq);
- }
-
- function write_end()
- {
- $this->flush("COMMIT;\n");
- parent::write_end();
- }
-}
-
-class mssql_extractor extends base_extractor
-{
- function write_end()
- {
- $this->flush("COMMIT\nGO\n");
- parent::write_end();
- }
-
- function write_start($prefix)
- {
- $sql_data = "--\n";
- $sql_data .= "-- phpBB Backup Script\n";
- $sql_data .= "-- Dump of tables for $prefix\n";
- $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
- $sql_data .= "--\n";
- $sql_data .= "BEGIN TRANSACTION\n";
- $sql_data .= "GO\n";
- $this->flush($sql_data);
- }
-
- function write_table($table_name)
- {
- global $db;
- $sql_data = '-- Table: ' . $table_name . "\n";
- $sql_data .= "IF OBJECT_ID(N'$table_name', N'U') IS NOT NULL\n";
- $sql_data .= "DROP TABLE $table_name;\n";
- $sql_data .= "GO\n";
- $sql_data .= "\nCREATE TABLE [$table_name] (\n";
- $rows = array();
-
- $text_flag = false;
-
- $sql = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as IS_IDENTITY
- FROM INFORMATION_SCHEMA.COLUMNS
- WHERE TABLE_NAME = '$table_name'";
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $line = "\t[{$row['COLUMN_NAME']}] [{$row['DATA_TYPE']}]";
-
- if ($row['DATA_TYPE'] == 'text')
- {
- $text_flag = true;
- }
-
- if ($row['IS_IDENTITY'])
- {
- $line .= ' IDENTITY (1 , 1)';
- }
-
- if ($row['CHARACTER_MAXIMUM_LENGTH'] && $row['DATA_TYPE'] !== 'text')
- {
- $line .= ' (' . $row['CHARACTER_MAXIMUM_LENGTH'] . ')';
- }
-
- if ($row['IS_NULLABLE'] == 'YES')
- {
- $line .= ' NULL';
- }
- else
- {
- $line .= ' NOT NULL';
- }
-
- if ($row['COLUMN_DEFAULT'])
- {
- $line .= ' DEFAULT ' . $row['COLUMN_DEFAULT'];
- }
-
- $rows[] = $line;
- }
- $db->sql_freeresult($result);
-
- $sql_data .= implode(",\n", $rows);
- $sql_data .= "\n) ON [PRIMARY]";
-
- if ($text_flag)
- {
- $sql_data .= " TEXTIMAGE_ON [PRIMARY]";
- }
-
- $sql_data .= "\nGO\n\n";
- $rows = array();
-
- $sql = "SELECT CONSTRAINT_NAME, COLUMN_NAME
- FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
- WHERE TABLE_NAME = '$table_name'";
- $result = $db->sql_query($sql);
- while ($row = $db->sql_fetchrow($result))
- {
- if (!sizeof($rows))
- {
- $sql_data .= "ALTER TABLE [$table_name] WITH NOCHECK ADD\n";
- $sql_data .= "\tCONSTRAINT [{$row['CONSTRAINT_NAME']}] PRIMARY KEY CLUSTERED \n\t(\n";
- }
- $rows[] = "\t\t[{$row['COLUMN_NAME']}]";
- }
- if (sizeof($rows))
- {
- $sql_data .= implode(",\n", $rows);
- $sql_data .= "\n\t) ON [PRIMARY] \nGO\n";
- }
- $db->sql_freeresult($result);
-
- $index = array();
- $sql = "EXEC sp_statistics '$table_name'";
- $result = $db->sql_query($sql);
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['TYPE'] == 3)
- {
- $index[$row['INDEX_NAME']][] = '[' . $row['COLUMN_NAME'] . ']';
- }
- }
- $db->sql_freeresult($result);
-
- foreach ($index as $index_name => $column_name)
- {
- $index[$index_name] = implode(', ', $column_name);
- }
-
- foreach ($index as $index_name => $columns)
- {
- $sql_data .= "\nCREATE INDEX [$index_name] ON [$table_name]($columns) ON [PRIMARY]\nGO\n";
- }
- $this->flush($sql_data);
- }
-
- function write_data($table_name)
- {
- global $db;
-
- if ($db->get_sql_layer() === 'mssql')
- {
- $this->write_data_mssql($table_name);
- }
- else if ($db->get_sql_layer() === 'mssqlnative')
- {
- $this->write_data_mssqlnative($table_name);
- }
- else
- {
- $this->write_data_odbc($table_name);
- }
- }
-
- function write_data_mssql($table_name)
- {
- global $db;
- $ary_type = $ary_name = array();
- $ident_set = false;
- $sql_data = '';
-
- // Grab all of the data from current table.
- $sql = "SELECT *
- FROM $table_name";
- $result = $db->sql_query($sql);
-
- $retrieved_data = mssql_num_rows($result);
-
- $i_num_fields = mssql_num_fields($result);
-
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $ary_type[$i] = mssql_field_type($result, $i);
- $ary_name[$i] = mssql_field_name($result, $i);
- }
-
- if ($retrieved_data)
- {
- $sql = "SELECT 1 as has_identity
- FROM INFORMATION_SCHEMA.COLUMNS
- WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
- $result2 = $db->sql_query($sql);
- $row2 = $db->sql_fetchrow($result2);
- if (!empty($row2['has_identity']))
- {
- $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
- $ident_set = true;
- }
- $db->sql_freeresult($result2);
- }
-
- while ($row = $db->sql_fetchrow($result))
- {
- $schema_vals = $schema_fields = array();
-
- // Build the SQL statement to recreate the data.
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $str_val = $row[$ary_name[$i]];
-
- if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
- {
- $str_quote = '';
- $str_empty = "''";
- $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
- }
- else if (preg_match('#date|timestamp#i', $ary_type[$i]))
- {
- if (empty($str_val))
- {
- $str_quote = '';
- }
- else
- {
- $str_quote = "'";
- }
- }
- else
- {
- $str_quote = '';
- $str_empty = 'NULL';
- }
-
- if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
- {
- $str_val = $str_empty;
- }
-
- $schema_vals[$i] = $str_quote . $str_val . $str_quote;
- $schema_fields[$i] = $ary_name[$i];
- }
-
- // Take the ordered fields and their associated data and build it
- // into a valid sql statement to recreate that field in the data.
- $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
-
- $this->flush($sql_data);
- $sql_data = '';
- }
- $db->sql_freeresult($result);
-
- if ($retrieved_data && $ident_set)
- {
- $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
- }
- $this->flush($sql_data);
- }
-
- function write_data_mssqlnative($table_name)
- {
- global $db;
- $ary_type = $ary_name = array();
- $ident_set = false;
- $sql_data = '';
-
- // Grab all of the data from current table.
- $sql = "SELECT * FROM $table_name";
- $db->mssqlnative_set_query_options(array('Scrollable' => SQLSRV_CURSOR_STATIC));
- $result = $db->sql_query($sql);
-
- $retrieved_data = $db->mssqlnative_num_rows($result);
-
- if (!$retrieved_data)
- {
- $db->sql_freeresult($result);
- return;
- }
-
- $sql = "SELECT COLUMN_NAME, DATA_TYPE
- FROM INFORMATION_SCHEMA.COLUMNS
- WHERE INFORMATION_SCHEMA.COLUMNS.TABLE_NAME = '" . $db->sql_escape($table_name) . "'";
- $result_fields = $db->sql_query($sql);
-
- $i_num_fields = 0;
- while ($row = $db->sql_fetchrow($result_fields))
- {
- $ary_type[$i_num_fields] = $row['DATA_TYPE'];
- $ary_name[$i_num_fields] = $row['COLUMN_NAME'];
- $i_num_fields++;
- }
- $db->sql_freeresult($result_fields);
-
- $sql = "SELECT 1 as has_identity
- FROM INFORMATION_SCHEMA.COLUMNS
- WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
- $result2 = $db->sql_query($sql);
- $row2 = $db->sql_fetchrow($result2);
-
- if (!empty($row2['has_identity']))
- {
- $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
- $ident_set = true;
- }
- $db->sql_freeresult($result2);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $schema_vals = $schema_fields = array();
-
- // Build the SQL statement to recreate the data.
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $str_val = $row[$ary_name[$i]];
-
- // defaults to type number - better quote just to be safe, so check for is_int too
- if (is_int($ary_type[$i]) || preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
- {
- $str_quote = '';
- $str_empty = "''";
- $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
- }
- else if (preg_match('#date|timestamp#i', $ary_type[$i]))
- {
- if (empty($str_val))
- {
- $str_quote = '';
- }
- else
- {
- $str_quote = "'";
- }
- }
- else
- {
- $str_quote = '';
- $str_empty = 'NULL';
- }
-
- if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
- {
- $str_val = $str_empty;
- }
-
- $schema_vals[$i] = $str_quote . $str_val . $str_quote;
- $schema_fields[$i] = $ary_name[$i];
- }
-
- // Take the ordered fields and their associated data and build it
- // into a valid sql statement to recreate that field in the data.
- $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
-
- $this->flush($sql_data);
- $sql_data = '';
- }
- $db->sql_freeresult($result);
-
- if ($ident_set)
- {
- $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
- }
- $this->flush($sql_data);
- }
-
- function write_data_odbc($table_name)
- {
- global $db;
- $ary_type = $ary_name = array();
- $ident_set = false;
- $sql_data = '';
-
- // Grab all of the data from current table.
- $sql = "SELECT *
- FROM $table_name";
- $result = $db->sql_query($sql);
-
- $retrieved_data = odbc_num_rows($result);
-
- if ($retrieved_data)
- {
- $sql = "SELECT 1 as has_identity
- FROM INFORMATION_SCHEMA.COLUMNS
- WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
- $result2 = $db->sql_query($sql);
- $row2 = $db->sql_fetchrow($result2);
- if (!empty($row2['has_identity']))
- {
- $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
- $ident_set = true;
- }
- $db->sql_freeresult($result2);
- }
-
- $i_num_fields = odbc_num_fields($result);
-
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $ary_type[$i] = odbc_field_type($result, $i + 1);
- $ary_name[$i] = odbc_field_name($result, $i + 1);
- }
-
- while ($row = $db->sql_fetchrow($result))
- {
- $schema_vals = $schema_fields = array();
-
- // Build the SQL statement to recreate the data.
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $str_val = $row[$ary_name[$i]];
-
- if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
- {
- $str_quote = '';
- $str_empty = "''";
- $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
- }
- else if (preg_match('#date|timestamp#i', $ary_type[$i]))
- {
- if (empty($str_val))
- {
- $str_quote = '';
- }
- else
- {
- $str_quote = "'";
- }
- }
- else
- {
- $str_quote = '';
- $str_empty = 'NULL';
- }
-
- if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
- {
- $str_val = $str_empty;
- }
-
- $schema_vals[$i] = $str_quote . $str_val . $str_quote;
- $schema_fields[$i] = $ary_name[$i];
- }
-
- // Take the ordered fields and their associated data and build it
- // into a valid sql statement to recreate that field in the data.
- $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
-
- $this->flush($sql_data);
-
- $sql_data = '';
-
- }
- $db->sql_freeresult($result);
-
- if ($retrieved_data && $ident_set)
- {
- $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
- }
- $this->flush($sql_data);
- }
-
-}
-
-class oracle_extractor extends base_extractor
-{
- function write_table($table_name)
- {
- global $db;
- $sql_data = '-- Table: ' . $table_name . "\n";
- $sql_data .= "DROP TABLE $table_name\n/\n";
- $sql_data .= "\nCREATE TABLE $table_name (\n";
-
- $sql = "SELECT COLUMN_NAME, DATA_TYPE, DATA_PRECISION, DATA_LENGTH, NULLABLE, DATA_DEFAULT
- FROM ALL_TAB_COLS
- WHERE table_name = '{$table_name}'";
- $result = $db->sql_query($sql);
-
- $rows = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $line = ' "' . $row['column_name'] . '" ' . $row['data_type'];
-
- if ($row['data_type'] !== 'CLOB')
- {
- if ($row['data_type'] !== 'VARCHAR2' && $row['data_type'] !== 'CHAR')
- {
- $line .= '(' . $row['data_precision'] . ')';
- }
- else
- {
- $line .= '(' . $row['data_length'] . ')';
- }
- }
-
- if (!empty($row['data_default']))
- {
- $line .= ' DEFAULT ' . $row['data_default'];
- }
-
- if ($row['nullable'] == 'N')
- {
- $line .= ' NOT NULL';
- }
- $rows[] = $line;
- }
- $db->sql_freeresult($result);
-
- $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
- FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
- WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
- AND B.CONSTRAINT_TYPE = 'P'
- AND A.TABLE_NAME = '{$table_name}'";
- $result = $db->sql_query($sql);
-
- $primary_key = array();
- $contraint_name = '';
- while ($row = $db->sql_fetchrow($result))
- {
- $constraint_name = '"' . $row['constraint_name'] . '"';
- $primary_key[] = '"' . $row['column_name'] . '"';
- }
- $db->sql_freeresult($result);
-
- if (sizeof($primary_key))
- {
- $rows[] = " CONSTRAINT {$constraint_name} PRIMARY KEY (" . implode(', ', $primary_key) . ')';
- }
-
- $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
- FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
- WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
- AND B.CONSTRAINT_TYPE = 'U'
- AND A.TABLE_NAME = '{$table_name}'";
- $result = $db->sql_query($sql);
-
- $unique = array();
- $contraint_name = '';
- while ($row = $db->sql_fetchrow($result))
- {
- $constraint_name = '"' . $row['constraint_name'] . '"';
- $unique[] = '"' . $row['column_name'] . '"';
- }
- $db->sql_freeresult($result);
-
- if (sizeof($unique))
- {
- $rows[] = " CONSTRAINT {$constraint_name} UNIQUE (" . implode(', ', $unique) . ')';
- }
-
- $sql_data .= implode(",\n", $rows);
- $sql_data .= "\n)\n/\n";
-
- $sql = "SELECT A.REFERENCED_NAME, C.*
- FROM USER_DEPENDENCIES A, USER_TRIGGERS B, USER_SEQUENCES C
- WHERE A.REFERENCED_TYPE = 'SEQUENCE'
- AND A.NAME = B.TRIGGER_NAME
- AND B.TABLE_NAME = '{$table_name}'
- AND C.SEQUENCE_NAME = A.REFERENCED_NAME";
- $result = $db->sql_query($sql);
-
- $type = request_var('type', '');
-
- while ($row = $db->sql_fetchrow($result))
- {
- $sql_data .= "\nDROP SEQUENCE \"{$row['referenced_name']}\"\n/\n";
- $sql_data .= "\nCREATE SEQUENCE \"{$row['referenced_name']}\"";
-
- if ($type == 'full')
- {
- $sql_data .= ' START WITH ' . $row['last_number'];
- }
-
- $sql_data .= "\n/\n";
- }
- $db->sql_freeresult($result);
-
- $sql = "SELECT DESCRIPTION, WHEN_CLAUSE, TRIGGER_BODY
- FROM USER_TRIGGERS
- WHERE TABLE_NAME = '{$table_name}'";
- $result = $db->sql_query($sql);
- while ($row = $db->sql_fetchrow($result))
- {
- $sql_data .= "\nCREATE OR REPLACE TRIGGER {$row['description']}WHEN ({$row['when_clause']})\n{$row['trigger_body']}\n/\n";
- }
- $db->sql_freeresult($result);
-
- $sql = "SELECT A.INDEX_NAME, B.COLUMN_NAME
- FROM USER_INDEXES A, USER_IND_COLUMNS B
- WHERE A.UNIQUENESS = 'NONUNIQUE'
- AND A.INDEX_NAME = B.INDEX_NAME
- AND B.TABLE_NAME = '{$table_name}'";
- $result = $db->sql_query($sql);
-
- $index = array();
-
- while ($row = $db->sql_fetchrow($result))
- {
- $index[$row['index_name']][] = $row['column_name'];
- }
-
- foreach ($index as $index_name => $column_names)
- {
- $sql_data .= "\nCREATE INDEX $index_name ON $table_name(" . implode(', ', $column_names) . ")\n/\n";
- }
- $db->sql_freeresult($result);
- $this->flush($sql_data);
- }
-
- function write_data($table_name)
- {
- global $db;
- $ary_type = $ary_name = array();
-
- // Grab all of the data from current table.
- $sql = "SELECT *
- FROM $table_name";
- $result = $db->sql_query($sql);
-
- $i_num_fields = ocinumcols($result);
-
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- $ary_type[$i] = ocicolumntype($result, $i + 1);
- $ary_name[$i] = ocicolumnname($result, $i + 1);
- }
-
- $sql_data = '';
-
- while ($row = $db->sql_fetchrow($result))
- {
- $schema_vals = $schema_fields = array();
-
- // Build the SQL statement to recreate the data.
- for ($i = 0; $i < $i_num_fields; $i++)
- {
- // Oracle uses uppercase - we use lowercase
- $str_val = $row[strtolower($ary_name[$i])];
-
- if (preg_match('#char|text|bool|raw|clob#i', $ary_type[$i]))
- {
- $str_quote = '';
- $str_empty = "''";
- $str_val = sanitize_data_oracle($str_val);
- }
- else if (preg_match('#date|timestamp#i', $ary_type[$i]))
- {
- if (empty($str_val))
- {
- $str_quote = '';
- }
- else
- {
- $str_quote = "'";
- }
- }
- else
- {
- $str_quote = '';
- $str_empty = 'NULL';
- }
-
- if (empty($str_val) && $str_val !== '0')
- {
- $str_val = $str_empty;
- }
-
- $schema_vals[$i] = $str_quote . $str_val . $str_quote;
- $schema_fields[$i] = '"' . $ary_name[$i] . '"';
- }
-
- // Take the ordered fields and their associated data and build it
- // into a valid sql statement to recreate that field in the data.
- $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ")\n/\n";
-
- $this->flush($sql_data);
- }
- $db->sql_freeresult($result);
- }
-
- function write_start($prefix)
- {
- $sql_data = "--\n";
- $sql_data .= "-- phpBB Backup Script\n";
- $sql_data .= "-- Dump of tables for $prefix\n";
- $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
- $sql_data .= "--\n";
- $this->flush($sql_data);
+ return $extensions;
}
}
@@ -2158,7 +499,7 @@ function sanitize_data_mssql($text)
{
$val[] = "'" . $value . "'";
}
- if (sizeof($matches[0]))
+ if (count($matches[0]))
{
$val[] = 'char(' . ord(array_shift($matches[0])) . ')';
}
@@ -2182,7 +523,7 @@ function sanitize_data_oracle($text)
{
$val[] = "'" . $value . "'";
}
- if (sizeof($matches[0]))
+ if (count($matches[0]))
{
$val[] = 'chr(' . ord(array_shift($matches[0])) . ')';
}
@@ -2204,7 +545,7 @@ function sanitize_data_generic($text)
{
$val[] = "'" . $value . "'";
}
- if (sizeof($matches[0]))
+ if (count($matches[0]))
{
$val[] = "'" . array_shift($matches[0]) . "'";
}
@@ -2246,7 +587,7 @@ function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
static $array = array();
static $record = '';
- if (!sizeof($array))
+ if (!count($array))
{
while (!$eof($fp))
{
@@ -2268,7 +609,7 @@ function fgetd_seekless(&$fp, $delim, $read, $seek, $eof, $buffer = 8192)
}
}
- if (sizeof($array))
+ if (count($array))
{
return array_shift($array);
}
diff --git a/phpBB/includes/acp/acp_disallow.php b/phpBB/includes/acp/acp_disallow.php
index 5b12013708..70eb398d07 100644
--- a/phpBB/includes/acp/acp_disallow.php
+++ b/phpBB/includes/acp/acp_disallow.php
@@ -25,8 +25,7 @@ class acp_disallow
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
- global $config, $phpbb_admin_path;
+ global $db, $user, $template, $cache, $phpbb_log, $request;
$user->add_lang('acp/posting');
@@ -47,7 +46,7 @@ class acp_disallow
if ($disallow)
{
- $disallowed_user = str_replace('*', '%', utf8_normalize_nfc(request_var('disallowed_user', '', true)));
+ $disallowed_user = str_replace('*', '%', $request->variable('disallowed_user', '', true));
if (!$disallowed_user)
{
@@ -72,13 +71,13 @@ class acp_disallow
$cache->destroy('_disallowed_usernames');
$message = $user->lang['DISALLOW_SUCCESSFUL'];
- add_log('admin', 'LOG_DISALLOW_ADD', str_replace('%', '*', $disallowed_user));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DISALLOW_ADD', false, array(str_replace('%', '*', $disallowed_user)));
trigger_error($message . adm_back_link($this->u_action));
}
else if ($allow)
{
- $disallowed_id = request_var('disallowed_id', 0);
+ $disallowed_id = $request->variable('disallowed_id', 0);
if (!$disallowed_id)
{
@@ -91,7 +90,7 @@ class acp_disallow
$cache->destroy('_disallowed_usernames');
- add_log('admin', 'LOG_DISALLOW_DELETE');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_DISALLOW_DELETE');
trigger_error($user->lang['DISALLOWED_DELETED'] . adm_back_link($this->u_action));
}
diff --git a/phpBB/includes/acp/acp_email.php b/phpBB/includes/acp/acp_email.php
index 917d02318e..5a1fbac9f6 100644
--- a/phpBB/includes/acp/acp_email.php
+++ b/phpBB/includes/acp/acp_email.php
@@ -25,8 +25,8 @@ class acp_email
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $cache;
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $phpbb_dispatcher;
+ global $config, $db, $user, $template, $phpbb_log, $request;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_dispatcher;
$user->add_lang('acp/email');
$this->tpl_name = 'acp_email';
@@ -39,11 +39,11 @@ class acp_email
$submit = (isset($_POST['submit'])) ? true : false;
$error = array();
- $usernames = request_var('usernames', '', true);
+ $usernames = $request->variable('usernames', '', true);
$usernames = (!empty($usernames)) ? explode("\n", $usernames) : array();
- $group_id = request_var('g', 0);
- $subject = utf8_normalize_nfc(request_var('subject', '', true));
- $message = utf8_normalize_nfc(request_var('message', '', true));
+ $group_id = $request->variable('g', 0);
+ $subject = $request->variable('subject', '', true);
+ $message = $request->variable('message', '', true);
// Do the job ...
if ($submit)
@@ -51,7 +51,7 @@ class acp_email
// Error checking needs to go here ... if no subject and/or no message then skip
// over the send and return to the form
$use_queue = (isset($_POST['send_immediately'])) ? false : true;
- $priority = request_var('mail_priority_flag', MAIL_NORMAL_PRIORITY);
+ $priority = $request->variable('mail_priority_flag', MAIL_NORMAL_PRIORITY);
if (!check_form_key($form_key))
{
@@ -68,7 +68,7 @@ class acp_email
$error[] = $user->lang['NO_EMAIL_MESSAGE'];
}
- if (!sizeof($error))
+ if (!count($error))
{
if (!empty($usernames))
{
@@ -168,7 +168,7 @@ class acp_email
{
$i = 0;
- if (sizeof($email_list))
+ if (count($email_list))
{
$j++;
}
@@ -235,16 +235,16 @@ class acp_email
);
extract($phpbb_dispatcher->trigger_event('core.acp_email_send_before', compact($vars)));
- for ($i = 0, $size = sizeof($email_list); $i < $size; $i++)
+ for ($i = 0, $size = count($email_list); $i < $size; $i++)
{
$used_lang = $email_list[$i][0]['lang'];
$used_method = $email_list[$i][0]['method'];
- for ($j = 0, $list_size = sizeof($email_list[$i]); $j < $list_size; $j++)
+ for ($j = 0, $list_size = count($email_list[$i]); $j < $list_size; $j++)
{
$email_row = $email_list[$i][$j];
- $messenger->{((sizeof($email_list[$i]) == 1) ? 'to' : 'bcc')}($email_row['email'], $email_row['name']);
+ $messenger->{((count($email_list[$i]) == 1) ? 'to' : 'bcc')}($email_row['email'], $email_row['name']);
$messenger->im($email_row['jabber'], $email_row['name']);
}
@@ -270,7 +270,7 @@ class acp_email
{
if (!empty($usernames))
{
- add_log('admin', 'LOG_MASS_EMAIL', implode(', ', utf8_normalize_nfc($usernames)));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MASS_EMAIL', false, array(implode(', ', utf8_normalize_nfc($usernames))));
}
else
{
@@ -284,7 +284,7 @@ class acp_email
$group_name = $user->lang['ALL_USERS'];
}
- add_log('admin', 'LOG_MASS_EMAIL', $group_name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MASS_EMAIL', false, array($group_name));
}
}
@@ -322,8 +322,8 @@ class acp_email
$s_priority_options .= '<option value="' . MAIL_HIGH_PRIORITY . '">' . $user->lang['MAIL_HIGH_PRIORITY'] . '</option>';
$template_data = array(
- 'S_WARNING' => (sizeof($error)) ? true : false,
- 'WARNING_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'S_WARNING' => (count($error)) ? true : false,
+ 'WARNING_MSG' => (count($error)) ? implode('<br />', $error) : '',
'U_ACTION' => $this->u_action,
'S_GROUP_OPTIONS' => $select_list,
'USERNAMES' => implode("\n", $usernames),
diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php
index f0348817c8..a1cb2108e7 100644
--- a/phpBB/includes/acp/acp_extensions.php
+++ b/phpBB/includes/acp/acp_extensions.php
@@ -11,6 +11,9 @@
*
*/
+use phpbb\exception\exception_interface;
+use phpbb\exception\version_check_exception;
+
/**
* @ignore
*/
@@ -28,25 +31,27 @@ class acp_extensions
private $config;
private $template;
private $user;
- private $cache;
private $log;
private $request;
private $phpbb_dispatcher;
private $ext_manager;
+ private $phpbb_container;
+ private $php_ini;
function main()
{
// Start the page
- global $config, $user, $template, $request, $phpbb_extension_manager, $phpbb_root_path, $phpEx, $phpbb_log, $cache, $phpbb_dispatcher;
+ global $config, $user, $template, $request, $phpbb_extension_manager, $phpbb_root_path, $phpbb_log, $phpbb_dispatcher, $phpbb_container;
$this->config = $config;
$this->template = $template;
$this->user = $user;
- $this->cache = $cache;
$this->request = $request;
$this->log = $phpbb_log;
$this->phpbb_dispatcher = $phpbb_dispatcher;
$this->ext_manager = $phpbb_extension_manager;
+ $this->phpbb_container = $phpbb_container;
+ $this->php_ini = $this->phpbb_container->get('php_ini');
$this->user->add_lang(array('install', 'acp/extensions', 'migrator'));
@@ -56,7 +61,7 @@ class acp_extensions
$ext_name = $this->request->variable('ext_name', '');
// What is a safe limit of execution time? Half the max execution time should be safe.
- $safe_time_limit = (ini_get('max_execution_time') / 2);
+ $safe_time_limit = ($this->php_ini->getNumeric('max_execution_time') / 2);
$start_time = time();
// Cancel action
@@ -96,15 +101,16 @@ class acp_extensions
// If they've specified an extension, let's load the metadata manager and validate it.
if ($ext_name)
{
- $md_manager = $this->ext_manager->create_extension_metadata_manager($ext_name, $this->template);
+ $md_manager = $this->ext_manager->create_extension_metadata_manager($ext_name);
try
{
$md_manager->get_metadata('all');
}
- catch (\phpbb\extension\exception $e)
+ catch (exception_interface $e)
{
- trigger_error($e, E_USER_WARNING);
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
}
@@ -159,9 +165,10 @@ class acp_extensions
{
$md_manager->validate_enable();
}
- catch (\phpbb\extension\exception $e)
+ catch (exception_interface $e)
{
- trigger_error($e . adm_back_link($this->u_action), E_USER_WARNING);
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
$extension = $this->ext_manager->get_extension($ext_name);
@@ -189,9 +196,10 @@ class acp_extensions
{
$md_manager->validate_enable();
}
- catch (\phpbb\extension\exception $e)
+ catch (exception_interface $e)
{
- trigger_error($e . adm_back_link($this->u_action), E_USER_WARNING);
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING);
}
$extension = $this->ext_manager->get_extension($ext_name);
@@ -323,26 +331,36 @@ class acp_extensions
case 'details':
// Output it to the template
- $md_manager->output_template_data();
+ $meta = $md_manager->get_metadata('all');
+ $this->output_metadata_to_template($meta);
- try
+ if (isset($meta['extra']['version-check']))
{
- $updates_available = $this->version_check($md_manager, $this->request->variable('versioncheck_force', false));
+ try
+ {
+ $updates_available = $this->ext_manager->version_check($md_manager, $this->request->variable('versioncheck_force', false), false, $this->config['extension_force_unstable'] ? 'unstable' : null);
- $this->template->assign_vars(array(
- 'S_UP_TO_DATE' => empty($updates_available),
- 'S_VERSIONCHECK' => true,
- 'UP_TO_DATE_MSG' => $this->user->lang(empty($updates_available) ? 'UP_TO_DATE' : 'NOT_UP_TO_DATE', $md_manager->get_metadata('display-name')),
- ));
+ $this->template->assign_vars(array(
+ 'S_UP_TO_DATE' => empty($updates_available),
+ 'UP_TO_DATE_MSG' => $this->user->lang(empty($updates_available) ? 'UP_TO_DATE' : 'NOT_UP_TO_DATE', $md_manager->get_metadata('display-name')),
+ ));
+
+ $this->template->assign_block_vars('updates_available', $updates_available);
+ }
+ catch (exception_interface $e)
+ {
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
- $this->template->assign_block_vars('updates_available', $updates_available);
+ $this->template->assign_vars(array(
+ 'S_VERSIONCHECK_FAIL' => true,
+ 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== 'VERSIONCHECK_FAIL') ? $message : '',
+ ));
+ }
+ $this->template->assign_var('S_VERSIONCHECK', true);
}
- catch (\RuntimeException $e)
+ else
{
- $this->template->assign_vars(array(
- 'S_VERSIONCHECK_STATUS' => $e->getCode(),
- 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== $this->user->lang('VERSIONCHECK_FAIL')) ? $e->getMessage() : '',
- ));
+ $this->template->assign_var('S_VERSIONCHECK', false);
}
$this->template->assign_vars(array(
@@ -387,7 +405,7 @@ class acp_extensions
foreach ($this->ext_manager->all_enabled() as $name => $location)
{
- $md_manager = $this->ext_manager->create_extension_metadata_manager($name, $this->template);
+ $md_manager = $this->ext_manager->create_extension_metadata_manager($name);
try
{
@@ -397,17 +415,32 @@ class acp_extensions
'META_VERSION' => $meta['version'],
);
- $force_update = $this->request->variable('versioncheck_force', false);
- $updates = $this->version_check($md_manager, $force_update, !$force_update);
+ if (isset($meta['extra']['version-check']))
+ {
+ try
+ {
+ $force_update = $this->request->variable('versioncheck_force', false);
+ $updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update);
- $enabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
- $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
- $enabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
+ $enabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
+ $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
+ $enabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
+ }
+ catch (exception_interface $e)
+ {
+ // Ignore exceptions due to the version check
+ }
+ }
+ else
+ {
+ $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
+ }
}
- catch (\phpbb\extension\exception $e)
+ catch (exception_interface $e)
{
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$this->template->assign_block_vars('disabled', array(
- 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e),
+ 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message),
'S_VERSIONCHECK' => false,
));
}
@@ -443,7 +476,7 @@ class acp_extensions
foreach ($this->ext_manager->all_disabled() as $name => $location)
{
- $md_manager = $this->ext_manager->create_extension_metadata_manager($name, $this->template);
+ $md_manager = $this->ext_manager->create_extension_metadata_manager($name);
try
{
@@ -453,23 +486,35 @@ class acp_extensions
'META_VERSION' => $meta['version'],
);
- $force_update = $this->request->variable('versioncheck_force', false);
- $updates = $this->version_check($md_manager, $force_update, !$force_update);
+ if (isset($meta['extra']['version-check']))
+ {
+ $force_update = $this->request->variable('versioncheck_force', false);
+ $updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update);
- $disabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
- $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
- $disabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
+ $disabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
+ $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
+ $disabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
+ }
+ else
+ {
+ $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
+ }
+ }
+ catch (version_check_exception $e)
+ {
+ $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
- catch (\phpbb\extension\exception $e)
+ catch (exception_interface $e)
{
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$this->template->assign_block_vars('disabled', array(
- 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e),
+ 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message),
'S_VERSIONCHECK' => false,
));
}
catch (\RuntimeException $e)
{
- $disabeld_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
+ $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
}
@@ -502,7 +547,7 @@ class acp_extensions
foreach ($uninstalled as $name => $location)
{
- $md_manager = $this->ext_manager->create_extension_metadata_manager($name, $this->template);
+ $md_manager = $this->ext_manager->create_extension_metadata_manager($name);
try
{
@@ -512,24 +557,32 @@ class acp_extensions
'META_VERSION' => $meta['version'],
);
- $force_update = $this->request->variable('versioncheck_force', false);
- $updates = $this->version_check($md_manager, $force_update, !$force_update);
+ if (isset($meta['extra']['version-check']))
+ {
+ $force_update = $this->request->variable('versioncheck_force', false);
+ $updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update);
- $available_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
- $available_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
- $available_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
+ $available_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates);
+ $available_extension_meta_data[$name]['S_VERSIONCHECK'] = true;
+ $available_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&amp;action=details&amp;versioncheck_force=1&amp;ext_name=' . urlencode($md_manager->get_metadata('name'));
+ }
+ else
+ {
+ $available_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
+ }
+ }
+ catch (version_check_exception $e)
+ {
+ $available_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
}
- catch (\phpbb\extension\exception $e)
+ catch (exception_interface $e)
{
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$this->template->assign_block_vars('disabled', array(
- 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $e),
+ 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message),
'S_VERSIONCHECK' => false,
));
}
- catch (\RuntimeException $e)
- {
- $available_extension_meta_data[$name]['S_VERSIONCHECK'] = false;
- }
}
uasort($available_extension_meta_data, array($this, 'sort_extension_meta_data_table'));
@@ -566,38 +619,47 @@ class acp_extensions
}
/**
- * Check the version and return the available updates.
- *
- * @param \phpbb\extension\metadata_manager $md_manager The metadata manager for the version to check.
- * @param bool $force_update Ignores cached data. Defaults to false.
- * @param bool $force_cache Force the use of the cache. Override $force_update.
- * @return array
- * @throws RuntimeException
+ * Sort helper for the table containing the metadata about the extensions.
*/
- protected function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false)
+ protected function sort_extension_meta_data_table($val1, $val2)
{
- $meta = $md_manager->get_metadata('all');
-
- if (!isset($meta['extra']['version-check']))
- {
- throw new \RuntimeException($this->user->lang('NO_VERSIONCHECK'), 1);
- }
-
- $version_check = $meta['extra']['version-check'];
-
- $version_helper = new \phpbb\version_helper($this->cache, $this->config, new \phpbb\file_downloader(), $this->user);
- $version_helper->set_current_version($meta['version']);
- $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename'], isset($version_check['ssl']) ? $version_check['ssl'] : false);
- $version_helper->force_stability($this->config['extension_force_unstable'] ? 'unstable' : null);
-
- return $version_helper->get_ext_update_on_branch($force_update, $force_cache);
+ return strnatcasecmp($val1['META_DISPLAY_NAME'], $val2['META_DISPLAY_NAME']);
}
/**
- * Sort helper for the table containing the metadata about the extensions.
+ * Outputs extension metadata into the template
+ *
+ * @param array $metadata Array with all metadata for the extension
+ * @return null
*/
- protected function sort_extension_meta_data_table($val1, $val2)
+ public function output_metadata_to_template($metadata)
{
- return strnatcasecmp($val1['META_DISPLAY_NAME'], $val2['META_DISPLAY_NAME']);
+ $this->template->assign_vars(array(
+ 'META_NAME' => $metadata['name'],
+ 'META_TYPE' => $metadata['type'],
+ 'META_DESCRIPTION' => (isset($metadata['description'])) ? $metadata['description'] : '',
+ 'META_HOMEPAGE' => (isset($metadata['homepage'])) ? $metadata['homepage'] : '',
+ 'META_VERSION' => $metadata['version'],
+ 'META_TIME' => (isset($metadata['time'])) ? $metadata['time'] : '',
+ 'META_LICENSE' => $metadata['license'],
+
+ 'META_REQUIRE_PHP' => (isset($metadata['require']['php'])) ? $metadata['require']['php'] : '',
+ 'META_REQUIRE_PHP_FAIL' => (isset($metadata['require']['php'])) ? false : true,
+
+ 'META_REQUIRE_PHPBB' => (isset($metadata['extra']['soft-require']['phpbb/phpbb'])) ? $metadata['extra']['soft-require']['phpbb/phpbb'] : '',
+ 'META_REQUIRE_PHPBB_FAIL' => (isset($metadata['extra']['soft-require']['phpbb/phpbb'])) ? false : true,
+
+ 'META_DISPLAY_NAME' => (isset($metadata['extra']['display-name'])) ? $metadata['extra']['display-name'] : '',
+ ));
+
+ foreach ($metadata['authors'] as $author)
+ {
+ $this->template->assign_block_vars('meta_authors', array(
+ 'AUTHOR_NAME' => $author['name'],
+ 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '',
+ 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '',
+ 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '',
+ ));
+ }
}
}
diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php
index 1e69a4ad20..22c775b7c3 100644
--- a/phpBB/includes/acp/acp_forums.php
+++ b/phpBB/includes/acp/acp_forums.php
@@ -27,7 +27,7 @@ class acp_forums
function main($id, $mode)
{
global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher;
- global $config, $phpbb_admin_path, $phpbb_root_path, $phpEx;
+ global $phpbb_admin_path, $phpbb_root_path, $phpEx, $phpbb_log;
$user->add_lang('acp/forums');
$this->tpl_name = 'acp_forums';
@@ -36,11 +36,11 @@ class acp_forums
$form_key = 'acp_forums';
add_form_key($form_key);
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$update = (isset($_POST['update'])) ? true : false;
- $forum_id = request_var('f', 0);
+ $forum_id = $request->variable('f', 0);
- $this->parent_id = request_var('parent_id', 0);
+ $this->parent_id = $request->variable('parent_id', 0);
$forum_data = $errors = array();
if ($update && !check_form_key($form_key))
{
@@ -52,8 +52,8 @@ class acp_forums
switch ($action)
{
case 'progress_bar':
- $start = request_var('start', 0);
- $total = request_var('total', 0);
+ $start = $request->variable('start', 0);
+ $total = $request->variable('total', 0);
$this->display_progress_bar($start, $total);
break;
@@ -83,14 +83,14 @@ class acp_forums
switch ($action)
{
case 'delete':
- $action_subforums = request_var('action_subforums', '');
- $subforums_to_id = request_var('subforums_to_id', 0);
- $action_posts = request_var('action_posts', '');
- $posts_to_id = request_var('posts_to_id', 0);
+ $action_subforums = $request->variable('action_subforums', '');
+ $subforums_to_id = $request->variable('subforums_to_id', 0);
+ $action_posts = $request->variable('action_posts', '');
+ $posts_to_id = $request->variable('posts_to_id', 0);
$errors = $this->delete_forum($forum_id, $action_posts, $action_subforums, $posts_to_id, $subforums_to_id);
- if (sizeof($errors))
+ if (count($errors))
{
break;
}
@@ -112,45 +112,45 @@ class acp_forums
case 'add':
$forum_data += array(
- 'parent_id' => request_var('forum_parent_id', $this->parent_id),
- 'forum_type' => request_var('forum_type', FORUM_POST),
- 'type_action' => request_var('type_action', ''),
- 'forum_status' => request_var('forum_status', ITEM_UNLOCKED),
+ 'parent_id' => $request->variable('forum_parent_id', $this->parent_id),
+ 'forum_type' => $request->variable('forum_type', FORUM_POST),
+ 'type_action' => $request->variable('type_action', ''),
+ 'forum_status' => $request->variable('forum_status', ITEM_UNLOCKED),
'forum_parents' => '',
- 'forum_name' => utf8_normalize_nfc(request_var('forum_name', '', true)),
- 'forum_link' => request_var('forum_link', ''),
- 'forum_link_track' => request_var('forum_link_track', false),
- 'forum_desc' => utf8_normalize_nfc(request_var('forum_desc', '', true)),
+ 'forum_name' => $request->variable('forum_name', '', true),
+ 'forum_link' => $request->variable('forum_link', ''),
+ 'forum_link_track' => $request->variable('forum_link_track', false),
+ 'forum_desc' => $request->variable('forum_desc', '', true),
'forum_desc_uid' => '',
'forum_desc_options' => 7,
'forum_desc_bitfield' => '',
- 'forum_rules' => utf8_normalize_nfc(request_var('forum_rules', '', true)),
+ 'forum_rules' => $request->variable('forum_rules', '', true),
'forum_rules_uid' => '',
'forum_rules_options' => 7,
'forum_rules_bitfield' => '',
- 'forum_rules_link' => request_var('forum_rules_link', ''),
- 'forum_image' => request_var('forum_image', ''),
- 'forum_style' => request_var('forum_style', 0),
- 'display_subforum_list' => request_var('display_subforum_list', false),
- 'display_on_index' => request_var('display_on_index', false),
- 'forum_topics_per_page' => request_var('topics_per_page', 0),
- 'enable_indexing' => request_var('enable_indexing', true),
- 'enable_icons' => request_var('enable_icons', false),
- 'enable_prune' => request_var('enable_prune', false),
- 'enable_post_review' => request_var('enable_post_review', true),
- 'enable_quick_reply' => request_var('enable_quick_reply', false),
- 'enable_shadow_prune' => request_var('enable_shadow_prune', false),
- 'prune_days' => request_var('prune_days', 7),
- 'prune_viewed' => request_var('prune_viewed', 7),
- 'prune_freq' => request_var('prune_freq', 1),
- 'prune_old_polls' => request_var('prune_old_polls', false),
- 'prune_announce' => request_var('prune_announce', false),
- 'prune_sticky' => request_var('prune_sticky', false),
- 'prune_shadow_days' => request_var('prune_shadow_days', 7),
- 'prune_shadow_freq' => request_var('prune_shadow_freq', 1),
- 'forum_password' => request_var('forum_password', '', true),
- 'forum_password_confirm'=> request_var('forum_password_confirm', '', true),
- 'forum_password_unset' => request_var('forum_password_unset', false),
+ 'forum_rules_link' => $request->variable('forum_rules_link', ''),
+ 'forum_image' => $request->variable('forum_image', ''),
+ 'forum_style' => $request->variable('forum_style', 0),
+ 'display_subforum_list' => $request->variable('display_subforum_list', false),
+ 'display_on_index' => $request->variable('display_on_index', false),
+ 'forum_topics_per_page' => $request->variable('topics_per_page', 0),
+ 'enable_indexing' => $request->variable('enable_indexing', true),
+ 'enable_icons' => $request->variable('enable_icons', false),
+ 'enable_prune' => $request->variable('enable_prune', false),
+ 'enable_post_review' => $request->variable('enable_post_review', true),
+ 'enable_quick_reply' => $request->variable('enable_quick_reply', false),
+ 'enable_shadow_prune' => $request->variable('enable_shadow_prune', false),
+ 'prune_days' => $request->variable('prune_days', 7),
+ 'prune_viewed' => $request->variable('prune_viewed', 7),
+ 'prune_freq' => $request->variable('prune_freq', 1),
+ 'prune_old_polls' => $request->variable('prune_old_polls', false),
+ 'prune_announce' => $request->variable('prune_announce', false),
+ 'prune_sticky' => $request->variable('prune_sticky', false),
+ 'prune_shadow_days' => $request->variable('prune_shadow_days', 7),
+ 'prune_shadow_freq' => $request->variable('prune_shadow_freq', 1),
+ 'forum_password' => $request->variable('forum_password', '', true),
+ 'forum_password_confirm'=> $request->variable('forum_password_confirm', '', true),
+ 'forum_password_unset' => $request->variable('forum_password_unset', false),
);
/**
@@ -173,7 +173,7 @@ class acp_forums
// Use link_display_on_index setting if forum type is link
if ($forum_data['forum_type'] == FORUM_LINK)
{
- $forum_data['display_on_index'] = request_var('link_display_on_index', false);
+ $forum_data['display_on_index'] = $request->variable('link_display_on_index', false);
}
// Linked forums and categories are not able to be locked...
@@ -182,25 +182,25 @@ class acp_forums
$forum_data['forum_status'] = ITEM_UNLOCKED;
}
- $forum_data['show_active'] = ($forum_data['forum_type'] == FORUM_POST) ? request_var('display_recent', true) : request_var('display_active', false);
+ $forum_data['show_active'] = ($forum_data['forum_type'] == FORUM_POST) ? $request->variable('display_recent', true) : $request->variable('display_active', false);
// Get data for forum rules if specified...
if ($forum_data['forum_rules'])
{
- generate_text_for_storage($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options'], request_var('rules_parse_bbcode', false), request_var('rules_parse_urls', false), request_var('rules_parse_smilies', false));
+ generate_text_for_storage($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options'], $request->variable('rules_parse_bbcode', false), $request->variable('rules_parse_urls', false), $request->variable('rules_parse_smilies', false));
}
// Get data for forum description if specified
if ($forum_data['forum_desc'])
{
- generate_text_for_storage($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options'], request_var('desc_parse_bbcode', false), request_var('desc_parse_urls', false), request_var('desc_parse_smilies', false));
+ generate_text_for_storage($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options'], $request->variable('desc_parse_bbcode', false), $request->variable('desc_parse_urls', false), $request->variable('desc_parse_smilies', false));
}
$errors = $this->update_forum_data($forum_data);
- if (!sizeof($errors))
+ if (!count($errors))
{
- $forum_perm_from = request_var('forum_perm_from', 0);
+ $forum_perm_from = $request->variable('forum_perm_from', 0);
$cache->destroy('sql', FORUMS_TABLE);
$copied_permissions = false;
@@ -266,7 +266,7 @@ class acp_forums
if ($move_forum_name !== false)
{
- add_log('admin', 'LOG_FORUM_' . strtoupper($action), $row['forum_name'], $move_forum_name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_' . strtoupper($action), false, array($row['forum_name'], $move_forum_name));
$cache->destroy('sql', FORUMS_TABLE);
}
@@ -311,7 +311,7 @@ class acp_forums
$row2['min_topic_id'] = (int) $row2['min_topic_id'];
$row2['max_topic_id'] = (int) $row2['max_topic_id'];
- $start = request_var('start', $row2['min_topic_id']);
+ $start = $request->variable('start', $row2['min_topic_id']);
$batch_size = 2000;
$end = $start + $batch_size;
@@ -327,7 +327,7 @@ class acp_forums
WHERE forum_id = ' . $forum_id . '
AND topic_id BETWEEN ' . $start . ' AND ' . $end;
$result = $db->sql_query($sql);
- $topics_done = request_var('topics_done', 0) + (int) $db->sql_fetchfield('num_topics');
+ $topics_done = $request->variable('topics_done', 0) + (int) $db->sql_fetchfield('num_topics');
$db->sql_freeresult($result);
$start += $batch_size;
@@ -377,7 +377,8 @@ class acp_forums
sync('forum', 'forum_id', $forum_id, false, true);
- add_log('admin', 'LOG_FORUM_SYNC', $row['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_SYNC', false, array($row['forum_name']));
+
$cache->destroy('sql', FORUMS_TABLE);
$template->assign_var('L_FORUM_RESYNCED', sprintf($user->lang['FORUM_RESYNCED'], $row['forum_name']));
@@ -390,13 +391,13 @@ class acp_forums
if ($update)
{
$forum_data['forum_flags'] = 0;
- $forum_data['forum_flags'] += (request_var('forum_link_track', false)) ? FORUM_FLAG_LINK_TRACK : 0;
- $forum_data['forum_flags'] += (request_var('prune_old_polls', false)) ? FORUM_FLAG_PRUNE_POLL : 0;
- $forum_data['forum_flags'] += (request_var('prune_announce', false)) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0;
- $forum_data['forum_flags'] += (request_var('prune_sticky', false)) ? FORUM_FLAG_PRUNE_STICKY : 0;
+ $forum_data['forum_flags'] += ($request->variable('forum_link_track', false)) ? FORUM_FLAG_LINK_TRACK : 0;
+ $forum_data['forum_flags'] += ($request->variable('prune_old_polls', false)) ? FORUM_FLAG_PRUNE_POLL : 0;
+ $forum_data['forum_flags'] += ($request->variable('prune_announce', false)) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0;
+ $forum_data['forum_flags'] += ($request->variable('prune_sticky', false)) ? FORUM_FLAG_PRUNE_STICKY : 0;
$forum_data['forum_flags'] += ($forum_data['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0;
- $forum_data['forum_flags'] += (request_var('enable_post_review', true)) ? FORUM_FLAG_POST_REVIEW : 0;
- $forum_data['forum_flags'] += (request_var('enable_quick_reply', false)) ? FORUM_FLAG_QUICK_REPLY : 0;
+ $forum_data['forum_flags'] += ($request->variable('enable_post_review', true)) ? FORUM_FLAG_POST_REVIEW : 0;
+ $forum_data['forum_flags'] += ($request->variable('enable_quick_reply', false)) ? FORUM_FLAG_QUICK_REPLY : 0;
}
// Initialise $row, so we always have it in the event
@@ -444,7 +445,7 @@ class acp_forums
'parent_id' => $this->parent_id,
'forum_type' => FORUM_POST,
'forum_status' => ITEM_UNLOCKED,
- 'forum_name' => utf8_normalize_nfc(request_var('forum_name', '', true)),
+ 'forum_name' => $request->variable('forum_name', '', true),
'forum_link' => '',
'forum_link_track' => false,
'forum_desc' => '',
@@ -511,12 +512,12 @@ class acp_forums
{
if (!isset($forum_data['forum_rules_uid']))
{
- // Before we are able to display the preview and plane text, we need to parse our request_var()'d value...
+ // Before we are able to display the preview and plane text, we need to parse our $request->variable()'d value...
$forum_data['forum_rules_uid'] = '';
$forum_data['forum_rules_bitfield'] = '';
$forum_data['forum_rules_options'] = 0;
- generate_text_for_storage($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options'], request_var('rules_allow_bbcode', false), request_var('rules_allow_urls', false), request_var('rules_allow_smilies', false));
+ generate_text_for_storage($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options'], $request->variable('rules_allow_bbcode', false), $request->variable('rules_allow_urls', false), $request->variable('rules_allow_smilies', false));
}
// Generate preview content
@@ -531,12 +532,12 @@ class acp_forums
{
if (!isset($forum_data['forum_desc_uid']))
{
- // Before we are able to display the preview and plane text, we need to parse our request_var()'d value...
+ // Before we are able to display the preview and plane text, we need to parse our $request->variable()'d value...
$forum_data['forum_desc_uid'] = '';
$forum_data['forum_desc_bitfield'] = '';
$forum_data['forum_desc_options'] = 0;
- generate_text_for_storage($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options'], request_var('desc_allow_bbcode', false), request_var('desc_allow_urls', false), request_var('desc_allow_smilies', false));
+ generate_text_for_storage($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options'], $request->variable('desc_allow_bbcode', false), $request->variable('desc_allow_urls', false), $request->variable('desc_allow_smilies', false));
}
// decode...
@@ -621,7 +622,7 @@ class acp_forums
$template_data = array(
'S_EDIT_FORUM' => true,
- 'S_ERROR' => (sizeof($errors)) ? true : false,
+ 'S_ERROR' => (count($errors)) ? true : false,
'S_PARENT_ID' => $this->parent_id,
'S_FORUM_PARENT_ID' => $forum_data['parent_id'],
'S_ADD_ACTION' => ($action == 'add') ? true : false,
@@ -631,7 +632,7 @@ class acp_forums
'L_COPY_PERMISSIONS_EXPLAIN' => $user->lang['COPY_PERMISSIONS_' . strtoupper($action) . '_EXPLAIN'],
'L_TITLE' => $user->lang[$this->page_title],
- 'ERROR_MSG' => (sizeof($errors)) ? implode('<br />', $errors) : '',
+ 'ERROR_MSG' => (count($errors)) ? implode('<br />', $errors) : '',
'FORUM_NAME' => $forum_data['forum_name'],
'FORUM_DATA_LINK' => $forum_data['forum_link'],
@@ -771,15 +772,15 @@ class acp_forums
'S_FORUM_LINK' => ($forum_data['forum_type'] == FORUM_LINK) ? true : false,
'S_HAS_SUBFORUMS' => ($forum_data['right_id'] - $forum_data['left_id'] > 1) ? true : false,
'S_FORUMS_LIST' => $forums_list,
- 'S_ERROR' => (sizeof($errors)) ? true : false,
- 'ERROR_MSG' => (sizeof($errors)) ? implode('<br />', $errors) : '')
+ 'S_ERROR' => (count($errors)) ? true : false,
+ 'ERROR_MSG' => (count($errors)) ? implode('<br />', $errors) : '')
);
return;
break;
case 'copy_perm':
- $forum_perm_from = request_var('forum_perm_from', 0);
+ $forum_perm_from = $request->variable('forum_perm_from', 0);
// Copy permissions?
if (!empty($forum_perm_from) && $forum_perm_from != $forum_id)
@@ -923,7 +924,7 @@ class acp_forums
unset($rowset);
$template->assign_vars(array(
- 'ERROR_MSG' => (sizeof($errors)) ? implode('<br />', $errors) : '',
+ 'ERROR_MSG' => (count($errors)) ? implode('<br />', $errors) : '',
'NAVIGATION' => $navigation,
'FORUM_BOX' => $forum_box,
'U_SEL_ACTION' => $this->u_action,
@@ -959,12 +960,13 @@ class acp_forums
/**
* Update forum data
*/
- function update_forum_data(&$forum_data)
+ function update_forum_data(&$forum_data_ary)
{
- global $db, $user, $cache, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
+ global $db, $user, $cache, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $phpbb_log, $request;
$errors = array();
+ $forum_data = $forum_data_ary;
/**
* Validate the forum data before we create/update the forum
*
@@ -976,42 +978,61 @@ class acp_forums
*/
$vars = array('forum_data', 'errors');
extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_validate_data', compact($vars)));
+ $forum_data_ary = $forum_data;
+ unset($forum_data);
- if ($forum_data['forum_name'] == '')
+ if ($forum_data_ary['forum_name'] == '')
{
$errors[] = $user->lang['FORUM_NAME_EMPTY'];
}
- if (utf8_strlen($forum_data['forum_desc']) > 4000)
+ /**
+ * Replace Emojis and other 4bit UTF-8 chars not allowed by MySql to UCR / NCR.
+ * Using their Numeric Character Reference's Hexadecimal notation.
+ */
+ $forum_data_ary['forum_name'] = utf8_encode_ucr($forum_data_ary['forum_name']);
+
+ /**
+ * This should never happen again.
+ * Leaving the fallback here just in case there will be the need of it.
+ */
+ if (preg_match_all('/[\x{10000}-\x{10FFFF}]/u', $forum_data_ary['forum_name'], $matches))
+ {
+ $character_list = implode('<br>', $matches[0]);
+
+ $errors[] = $user->lang('FORUM_NAME_EMOJI', $character_list);
+ }
+
+ if (utf8_strlen($forum_data_ary['forum_desc']) > 4000)
{
$errors[] = $user->lang['FORUM_DESC_TOO_LONG'];
}
- if (utf8_strlen($forum_data['forum_rules']) > 4000)
+ if (utf8_strlen($forum_data_ary['forum_rules']) > 4000)
{
$errors[] = $user->lang['FORUM_RULES_TOO_LONG'];
}
- if ($forum_data['forum_password'] || $forum_data['forum_password_confirm'])
+ if ($forum_data_ary['forum_password'] || $forum_data_ary['forum_password_confirm'])
{
- if ($forum_data['forum_password'] != $forum_data['forum_password_confirm'])
+ if ($forum_data_ary['forum_password'] != $forum_data_ary['forum_password_confirm'])
{
- $forum_data['forum_password'] = $forum_data['forum_password_confirm'] = '';
+ $forum_data_ary['forum_password'] = $forum_data_ary['forum_password_confirm'] = '';
$errors[] = $user->lang['FORUM_PASSWORD_MISMATCH'];
}
}
- if ($forum_data['prune_days'] < 0 || $forum_data['prune_viewed'] < 0 || $forum_data['prune_freq'] < 0)
+ if ($forum_data_ary['prune_days'] < 0 || $forum_data_ary['prune_viewed'] < 0 || $forum_data_ary['prune_freq'] < 0)
{
- $forum_data['prune_days'] = $forum_data['prune_viewed'] = $forum_data['prune_freq'] = 0;
+ $forum_data_ary['prune_days'] = $forum_data_ary['prune_viewed'] = $forum_data_ary['prune_freq'] = 0;
$errors[] = $user->lang['FORUM_DATA_NEGATIVE'];
}
$range_test_ary = array(
- array('lang' => 'FORUM_TOPICS_PAGE', 'value' => $forum_data['forum_topics_per_page'], 'column_type' => 'TINT:0'),
+ array('lang' => 'FORUM_TOPICS_PAGE', 'value' => $forum_data_ary['forum_topics_per_page'], 'column_type' => 'USINT:0'),
);
- if (!empty($forum_data['forum_image']) && !file_exists($phpbb_root_path . $forum_data['forum_image']))
+ if (!empty($forum_data_ary['forum_image']) && !file_exists($phpbb_root_path . $forum_data_ary['forum_image']))
{
$errors[] = $user->lang['FORUM_IMAGE_NO_EXIST'];
}
@@ -1025,17 +1046,17 @@ class acp_forums
// 8 = prune stickies
// 16 = show active topics
// 32 = enable post review
- $forum_data['forum_flags'] = 0;
- $forum_data['forum_flags'] += ($forum_data['forum_link_track']) ? FORUM_FLAG_LINK_TRACK : 0;
- $forum_data['forum_flags'] += ($forum_data['prune_old_polls']) ? FORUM_FLAG_PRUNE_POLL : 0;
- $forum_data['forum_flags'] += ($forum_data['prune_announce']) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0;
- $forum_data['forum_flags'] += ($forum_data['prune_sticky']) ? FORUM_FLAG_PRUNE_STICKY : 0;
- $forum_data['forum_flags'] += ($forum_data['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0;
- $forum_data['forum_flags'] += ($forum_data['enable_post_review']) ? FORUM_FLAG_POST_REVIEW : 0;
- $forum_data['forum_flags'] += ($forum_data['enable_quick_reply']) ? FORUM_FLAG_QUICK_REPLY : 0;
+ $forum_data_ary['forum_flags'] = 0;
+ $forum_data_ary['forum_flags'] += ($forum_data_ary['forum_link_track']) ? FORUM_FLAG_LINK_TRACK : 0;
+ $forum_data_ary['forum_flags'] += ($forum_data_ary['prune_old_polls']) ? FORUM_FLAG_PRUNE_POLL : 0;
+ $forum_data_ary['forum_flags'] += ($forum_data_ary['prune_announce']) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0;
+ $forum_data_ary['forum_flags'] += ($forum_data_ary['prune_sticky']) ? FORUM_FLAG_PRUNE_STICKY : 0;
+ $forum_data_ary['forum_flags'] += ($forum_data_ary['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0;
+ $forum_data_ary['forum_flags'] += ($forum_data_ary['enable_post_review']) ? FORUM_FLAG_POST_REVIEW : 0;
+ $forum_data_ary['forum_flags'] += ($forum_data_ary['enable_quick_reply']) ? FORUM_FLAG_QUICK_REPLY : 0;
// Unset data that are not database fields
- $forum_data_sql = $forum_data;
+ $forum_data_sql = $forum_data_ary;
unset($forum_data_sql['forum_link_track']);
unset($forum_data_sql['prune_old_polls']);
@@ -1049,7 +1070,7 @@ class acp_forums
// What are we going to do tonight Brain? The same thing we do everynight,
// try to take over the world ... or decide whether to continue update
// and if so, whether it's a new forum/cat/link or an existing one
- if (sizeof($errors))
+ if (count($errors))
{
return $errors;
}
@@ -1066,12 +1087,14 @@ class acp_forums
else
{
// Instantiate passwords manager
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
$forum_data_sql['forum_password'] = $passwords_manager->hash($forum_data_sql['forum_password']);
}
unset($forum_data_sql['forum_password_unset']);
+ $forum_data = $forum_data_ary;
/**
* Remove invalid values from forum_data_sql that should not be updated
*
@@ -1084,6 +1107,8 @@ class acp_forums
*/
$vars = array('forum_data', 'forum_data_sql');
extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_update_data_before', compact($vars)));
+ $forum_data_ary = $forum_data;
+ unset($forum_data);
$is_new_forum = !isset($forum_data_sql['forum_id']);
@@ -1140,9 +1165,9 @@ class acp_forums
$sql = 'INSERT INTO ' . FORUMS_TABLE . ' ' . $db->sql_build_array('INSERT', $forum_data_sql);
$db->sql_query($sql);
- $forum_data['forum_id'] = $db->sql_nextid();
+ $forum_data_ary['forum_id'] = $db->sql_nextid();
- add_log('admin', 'LOG_FORUM_ADD', $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_ADD', false, array($forum_data_ary['forum_name']));
}
else
{
@@ -1160,7 +1185,7 @@ class acp_forums
// we're turning a postable forum into a non-postable forum
if ($forum_data_sql['type_action'] == 'move')
{
- $to_forum_id = request_var('to_forum_id', 0);
+ $to_forum_id = $request->variable('to_forum_id', 0);
if ($to_forum_id)
{
@@ -1190,8 +1215,8 @@ class acp_forums
if ($row['right_id'] - $row['left_id'] > 1)
{
// We are turning a category into a link - but need to decide what to do with the subforums.
- $action_subforums = request_var('action_subforums', '');
- $subforums_to_id = request_var('subforums_to_id', 0);
+ $action_subforums = $request->variable('action_subforums', '');
+ $subforums_to_id = $request->variable('subforums_to_id', 0);
if ($action_subforums == 'delete')
{
@@ -1209,12 +1234,12 @@ class acp_forums
$errors = array_merge($errors, $this->delete_forum_content($_row['forum_id']));
}
- if (sizeof($errors))
+ if (count($errors))
{
return $errors;
}
- if (sizeof($forum_ids))
+ if (count($forum_ids))
{
$sql = 'DELETE FROM ' . FORUMS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
@@ -1244,7 +1269,7 @@ class acp_forums
$allowed_forums = array_diff($allowed_forums, $forum_ids);
$sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . "
- SET allowed_forums = '" . ((sizeof($allowed_forums)) ? serialize($allowed_forums) : '') . "'
+ SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "'
WHERE group_id = {$_row['group_id']}";
$db->sql_query($sql);
}
@@ -1272,8 +1297,6 @@ class acp_forums
return array($user->lang['NO_FORUM']);
}
- $subforums_to_name = $_row['forum_name'];
-
$sql = 'SELECT forum_id
FROM ' . FORUMS_TABLE . "
WHERE parent_id = {$row['forum_id']}";
@@ -1315,7 +1338,7 @@ class acp_forums
$forum_data_sql['forum_last_poster_colour'] = '';
}
- if (sizeof($errors))
+ if (count($errors))
{
return $errors;
}
@@ -1332,7 +1355,7 @@ class acp_forums
}
}
- if (sizeof($errors))
+ if (count($errors))
{
return $errors;
}
@@ -1357,11 +1380,12 @@ class acp_forums
$db->sql_query($sql);
// Add it back
- $forum_data['forum_id'] = $forum_id;
+ $forum_data_ary['forum_id'] = $forum_id;
- add_log('admin', 'LOG_FORUM_EDIT', $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_EDIT', false, array($forum_data_ary['forum_name']));
}
+ $forum_data = $forum_data_ary;
/**
* Event after a forum was updated or created
*
@@ -1377,6 +1401,8 @@ class acp_forums
*/
$vars = array('forum_data', 'forum_data_sql', 'is_new_forum', 'errors');
extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_update_data_after', compact($vars)));
+ $forum_data_ary = $forum_data;
+ unset($forum_data);
return $errors;
}
@@ -1388,7 +1414,7 @@ class acp_forums
{
global $db, $user, $phpbb_dispatcher;
- $to_data = $moved_ids = $errors = array();
+ $errors = array();
// Check if we want to move to a parent with link type
if ($to_id > 0)
@@ -1407,8 +1433,8 @@ class acp_forums
* This event may be triggered, when a forum is deleted
*
* @event core.acp_manage_forums_move_children
- * @var int from_id If of the current parent forum
- * @var int to_id If of the new parent forum
+ * @var int from_id Id of the current parent forum
+ * @var int to_id Id of the new parent forum
* @var array errors Array of errors, should be strings and not
* language key.
* @since 3.1.0-a1
@@ -1422,12 +1448,14 @@ class acp_forums
return $errors;
}
+ $db->sql_transaction('begin');
+
$moved_forums = get_forum_branch($from_id, 'children', 'descending');
$from_data = $moved_forums[0];
- $diff = sizeof($moved_forums) * 2;
+ $diff = count($moved_forums) * 2;
$moved_ids = array();
- for ($i = 0, $size = sizeof($moved_forums); $i < $size; ++$i)
+ for ($i = 0, $size = count($moved_forums); $i < $size; ++$i)
{
$moved_ids[] = $moved_forums[$i]['forum_id'];
}
@@ -1493,6 +1521,8 @@ class acp_forums
WHERE " . $db->sql_in_set('forum_id', $moved_ids);
$db->sql_query($sql);
+ $db->sql_transaction('commit');
+
return $errors;
}
@@ -1509,8 +1539,8 @@ class acp_forums
* Event when we move content from one forum to another
*
* @event core.acp_manage_forums_move_content
- * @var int from_id If of the current parent forum
- * @var int to_id If of the new parent forum
+ * @var int from_id Id of the current parent forum
+ * @var int to_id Id of the new parent forum
* @var bool sync Shall we sync the "to"-forum's data
* @var array errors Array of errors, should be strings and not
* language key. If this array is not empty,
@@ -1528,6 +1558,16 @@ class acp_forums
$table_ary = array(LOG_TABLE, POSTS_TABLE, TOPICS_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE);
+ /**
+ * Perform additional actions before move forum content
+ *
+ * @event core.acp_manage_forums_move_content_sql_before
+ * @var array table_ary Array of tables from which forum_id will be updated
+ * @since 3.2.4-RC1
+ */
+ $vars = array('table_ary');
+ extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content_sql_before', compact($vars)));
+
foreach ($table_ary as $table)
{
$sql = "UPDATE $table
@@ -1546,6 +1586,19 @@ class acp_forums
$db->sql_query($sql);
}
+ /**
+ * Event when content has been moved from one forum to another
+ *
+ * @event core.acp_manage_forums_move_content_after
+ * @var int from_id Id of the current parent forum
+ * @var int to_id Id of the new parent forum
+ * @var bool sync Shall we sync the "to"-forum's data
+ *
+ * @since 3.2.9-RC1
+ */
+ $vars = array('from_id', 'to_id', 'sync');
+ extract($phpbb_dispatcher->trigger_event('core.acp_manage_forums_move_content_after', compact($vars)));
+
if ($sync)
{
// Delete ghost topics that link back to the same forum then resync counters
@@ -1561,7 +1614,7 @@ class acp_forums
*/
function delete_forum($forum_id, $action_posts = 'delete', $action_subforums = 'delete', $posts_to_id = 0, $subforums_to_id = 0)
{
- global $db, $user, $cache;
+ global $db, $user, $cache, $phpbb_log;
$forum_data = $this->get_forum_info($forum_id);
@@ -1603,7 +1656,7 @@ class acp_forums
}
}
- if (sizeof($errors))
+ if (count($errors))
{
return $errors;
}
@@ -1619,12 +1672,12 @@ class acp_forums
$errors = array_merge($errors, $this->delete_forum_content($row['forum_id']));
}
- if (sizeof($errors))
+ if (count($errors))
{
return $errors;
}
- $diff = sizeof($forum_ids) * 2;
+ $diff = count($forum_ids) * 2;
$sql = 'DELETE FROM ' . FORUMS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_ids);
@@ -1697,7 +1750,7 @@ class acp_forums
}
}
- if (sizeof($errors))
+ if (count($errors))
{
return $errors;
}
@@ -1745,7 +1798,7 @@ class acp_forums
$allowed_forums = array_diff($allowed_forums, $forum_ids);
$sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . "
- SET allowed_forums = '" . ((sizeof($allowed_forums)) ? serialize($allowed_forums) : '') . "'
+ SET allowed_forums = '" . ((count($allowed_forums)) ? serialize($allowed_forums) : '') . "'
WHERE group_id = {$row['group_id']}";
$db->sql_query($sql);
}
@@ -1758,39 +1811,39 @@ class acp_forums
switch ($log_action)
{
case 'MOVE_POSTS_MOVE_FORUMS':
- add_log('admin', 'LOG_FORUM_DEL_MOVE_POSTS_MOVE_FORUMS', $posts_to_name, $subforums_to_name, $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_POSTS_MOVE_FORUMS', false, array($posts_to_name, $subforums_to_name, $forum_data['forum_name']));
break;
case 'MOVE_POSTS_FORUMS':
- add_log('admin', 'LOG_FORUM_DEL_MOVE_POSTS_FORUMS', $posts_to_name, $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_POSTS_FORUMS', false, array($posts_to_name, $forum_data['forum_name']));
break;
case 'POSTS_MOVE_FORUMS':
- add_log('admin', 'LOG_FORUM_DEL_POSTS_MOVE_FORUMS', $subforums_to_name, $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS_MOVE_FORUMS', false, array($subforums_to_name, $forum_data['forum_name']));
break;
case '_MOVE_FORUMS':
- add_log('admin', 'LOG_FORUM_DEL_MOVE_FORUMS', $subforums_to_name, $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_FORUMS', false, array($subforums_to_name, $forum_data['forum_name']));
break;
case 'MOVE_POSTS_':
- add_log('admin', 'LOG_FORUM_DEL_MOVE_POSTS', $posts_to_name, $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_MOVE_POSTS', false, array($posts_to_name, $forum_data['forum_name']));
break;
case 'POSTS_FORUMS':
- add_log('admin', 'LOG_FORUM_DEL_POSTS_FORUMS', $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS_FORUMS', false, array($forum_data['forum_name']));
break;
case '_FORUMS':
- add_log('admin', 'LOG_FORUM_DEL_FORUMS', $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUMS', false, array($forum_data['forum_name']));
break;
case 'POSTS_':
- add_log('admin', 'LOG_FORUM_DEL_POSTS', $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_POSTS', false, array($forum_data['forum_name']));
break;
default:
- add_log('admin', 'LOG_FORUM_DEL_FORUM', $forum_data['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_DEL_FORUM', false, array($forum_data['forum_name']));
break;
}
@@ -1802,7 +1855,7 @@ class acp_forums
*/
function delete_forum_content($forum_id)
{
- global $db, $config, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $db, $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
@@ -1823,7 +1876,10 @@ class acp_forums
}
$db->sql_freeresult($result);
- delete_attachments('topic', $topic_ids, false);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $attachment_manager->delete('topic', $topic_ids, false);
+ unset($attachment_manager);
// Delete shadow topics pointing to topics in this forum
delete_topic_shadows($forum_id);
@@ -1915,9 +1971,9 @@ class acp_forums
}
$db->sql_freeresult($result);
- if (sizeof($ids))
+ if (count($ids))
{
- $start += sizeof($ids);
+ $start += count($ids);
foreach ($tables as $table)
{
@@ -1925,7 +1981,7 @@ class acp_forums
}
}
}
- while (sizeof($ids) == $batch_size);
+ while (count($ids) == $batch_size);
}
unset($ids);
@@ -1966,7 +2022,7 @@ class acp_forums
}
// Adjust users post counts
- if (sizeof($post_counts))
+ if (count($post_counts))
{
foreach ($post_counts as $poster_id => $substract)
{
@@ -1994,7 +2050,7 @@ class acp_forums
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('num_posts', (int) $row['stat'], true);
+ $config->set('num_posts', (int) $row['stat'], false);
$sql = 'SELECT COUNT(topic_id) AS stat
FROM ' . TOPICS_TABLE . '
@@ -2003,7 +2059,7 @@ class acp_forums
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('num_topics', (int) $row['stat'], true);
+ $config->set('num_topics', (int) $row['stat'], false);
$sql = 'SELECT COUNT(attach_id) as stat
FROM ' . ATTACHMENTS_TABLE;
@@ -2011,7 +2067,7 @@ class acp_forums
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('num_files', (int) $row['stat'], true);
+ $config->set('num_files', (int) $row['stat'], false);
$sql = 'SELECT SUM(filesize) as stat
FROM ' . ATTACHMENTS_TABLE;
@@ -2019,7 +2075,7 @@ class acp_forums
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('upload_dir_size', (float) $row['stat'], true);
+ $config->set('upload_dir_size', (float) $row['stat'], false);
return array();
}
@@ -2050,7 +2106,7 @@ class acp_forums
}
$db->sql_freeresult($result);
- if (!sizeof($target))
+ if (!count($target))
{
// The forum is already on top or bottom
return false;
diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php
index 0352f6a242..7b1dc706db 100644
--- a/phpBB/includes/acp/acp_groups.php
+++ b/phpBB/includes/acp/acp_groups.php
@@ -26,9 +26,12 @@ class acp_groups
function main($id, $mode)
{
global $config, $db, $user, $auth, $template, $cache;
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx;
global $request, $phpbb_container, $phpbb_dispatcher;
+ /** @var \phpbb\language\language $language Language object */
+ $language = $phpbb_container->get('language');
+
$user->add_lang('acp/groups');
$this->tpl_name = 'acp_groups';
$this->page_title = 'ACP_GROUPS_MANAGE';
@@ -48,15 +51,18 @@ class acp_groups
}
// Check and set some common vars
- $action = (isset($_POST['add'])) ? 'add' : ((isset($_POST['addusers'])) ? 'addusers' : request_var('action', ''));
- $group_id = request_var('g', 0);
- $mark_ary = request_var('mark', array(0));
- $name_ary = request_var('usernames', '', true);
- $leader = request_var('leader', 0);
- $default = request_var('default', 0);
- $start = request_var('start', 0);
+ $action = (isset($_POST['add'])) ? 'add' : ((isset($_POST['addusers'])) ? 'addusers' : $request->variable('action', ''));
+ $group_id = $request->variable('g', 0);
+ $mark_ary = $request->variable('mark', array(0));
+ $name_ary = $request->variable('usernames', '', true);
+ $leader = $request->variable('leader', 0);
+ $default = $request->variable('default', 0);
+ $start = $request->variable('start', 0);
$update = (isset($_POST['update'])) ? true : false;
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
// Clear some vars
$group_row = array();
@@ -101,7 +107,7 @@ class acp_groups
}
// Approve, demote or promote
- $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_name = $group_helper->get_name($group_row['group_name']);
$error = group_user_attributes($action, $group_id, $mark_ary, false, $group_name);
if (!$error)
@@ -142,7 +148,7 @@ class acp_groups
if (confirm_box(true))
{
- $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_name = $group_helper->get_name($group_row['group_name']);
group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id));
}
@@ -161,7 +167,7 @@ class acp_groups
case 'set_default_on_all':
if (confirm_box(true))
{
- $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_name = $group_helper->get_name($group_row['group_name']);
$start = 0;
@@ -184,7 +190,7 @@ class acp_groups
group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
- $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200;
+ $start = (count($mark_ary) < 200) ? 0 : $start + 200;
}
else
{
@@ -220,6 +226,7 @@ class acp_groups
}
else if ($action === 'delete' && $group_row['group_type'] == GROUP_SPECIAL)
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -232,6 +239,7 @@ class acp_groups
case 'delete':
if (!$auth->acl_get('a_groupdel'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -239,7 +247,7 @@ class acp_groups
break;
case 'deleteusers':
- $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_name = $group_helper->get_name($group_row['group_name']);
$error = group_user_del($group_id, $mark_ary, false, $group_name);
break;
}
@@ -283,12 +291,24 @@ class acp_groups
}
$name_ary = array_unique(explode("\n", $name_ary));
- $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_name = $group_helper->get_name($group_row['group_name']);
// Add user/s to group
if ($error = group_user_add($group_id, false, $name_ary, $group_name, $default, $leader, 0, $group_row))
{
- trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id), E_USER_WARNING);
+ $display_message = $language->lang($error);
+
+ if ($error == 'GROUP_USERS_INVALID')
+ {
+ // Find which users don't exist
+ $actual_name_ary = $name_ary;
+ $actual_user_id_ary = [];
+ user_get_id_name($actual_user_id_ary, $actual_name_ary, false, true);
+
+ $display_message = $language->lang('GROUP_USERS_INVALID', implode($language->lang('COMMA_SEPARATOR'), array_udiff($name_ary, $actual_name_ary, 'strcasecmp')));
+ }
+
+ trigger_error($display_message . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id), E_USER_WARNING);
}
$message = ($leader) ? 'GROUP_MODS_ADDED' : 'GROUP_USERS_ADDED';
@@ -303,8 +323,6 @@ class acp_groups
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
- $data = $submit_ary = array();
-
if ($action == 'edit' && !$group_id)
{
trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING);
@@ -312,6 +330,7 @@ class acp_groups
if ($action == 'add' && !$auth->acl_get('a_groupadd'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -369,24 +388,24 @@ class acp_groups
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- $group_name = utf8_normalize_nfc(request_var('group_name', '', true));
- $group_desc = utf8_normalize_nfc(request_var('group_desc', '', true));
- $group_type = request_var('group_type', GROUP_FREE);
+ $group_name = $request->variable('group_name', '', true);
+ $group_desc = $request->variable('group_desc', '', true);
+ $group_type = $request->variable('group_type', GROUP_FREE);
- $allow_desc_bbcode = request_var('desc_parse_bbcode', false);
- $allow_desc_urls = request_var('desc_parse_urls', false);
- $allow_desc_smilies = request_var('desc_parse_smilies', false);
+ $allow_desc_bbcode = $request->variable('desc_parse_bbcode', false);
+ $allow_desc_urls = $request->variable('desc_parse_urls', false);
+ $allow_desc_smilies = $request->variable('desc_parse_smilies', false);
$submit_ary = array(
- 'colour' => request_var('group_colour', ''),
- 'rank' => request_var('group_rank', 0),
+ 'colour' => $request->variable('group_colour', ''),
+ 'rank' => $request->variable('group_rank', 0),
'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 0,
'legend' => isset($_REQUEST['group_legend']) ? 1 : 0,
'teampage' => isset($_REQUEST['group_teampage']) ? 1 : 0,
- 'message_limit' => request_var('group_message_limit', 0),
- 'max_recipients' => request_var('group_max_recipients', 0),
+ 'message_limit' => $request->variable('group_message_limit', 0),
+ 'max_recipients' => $request->variable('group_max_recipients', 0),
'founder_manage' => 0,
- 'skip_auth' => request_var('group_skip_auth', 0),
+ 'skip_auth' => $request->variable('group_skip_auth', 0),
);
if ($user->data['user_type'] == USER_FOUNDER)
@@ -482,7 +501,7 @@ class acp_groups
$error = array_merge($error, $validation_error);
}
- if (!sizeof($error))
+ if (!count($error))
{
// Only set the rank, colour, etc. if it's changed or if we're adding a new
// group. This prevents existing group members being updated if no changes
@@ -555,7 +574,7 @@ class acp_groups
if (!($error = group_create($group_id, $group_type, $group_name, $group_desc, $group_attributes, $allow_desc_bbcode, $allow_desc_urls, $allow_desc_smilies)))
{
- $group_perm_from = request_var('group_perm_from', 0);
+ $group_perm_from = $request->variable('group_perm_from', 0);
// Copy permissions?
// If the user has the a_authgroups permission and at least one additional permission ability set the permissions are fully transferred.
@@ -610,7 +629,7 @@ class acp_groups
}
}
- if (sizeof($error))
+ if (count($error))
{
$error = array_map(array(&$user, 'lang'), $error);
$group_rank = $submit_ary['rank'];
@@ -625,7 +644,7 @@ class acp_groups
}
else if (!$group_id)
{
- $group_name = utf8_normalize_nfc(request_var('group_name', '', true));
+ $group_name = $request->variable('group_name', '', true);
$group_desc_data = array(
'text' => '',
'allow_bbcode' => true,
@@ -710,12 +729,12 @@ class acp_groups
$error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
- $back_link = request_var('back_link', '');
+ $back_link = $request->variable('back_link', '');
switch ($back_link)
{
case 'acp_users_groups':
- $u_back = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=groups&amp;u=' . request_var('u', 0));
+ $u_back = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=groups&amp;u=' . $request->variable('u', 0));
break;
default:
@@ -728,13 +747,13 @@ class acp_groups
'S_ADD_GROUP' => ($action == 'add') ? true : false,
'S_GROUP_PERM' => ($action == 'add' && $auth->acl_get('a_authgroups') && $auth->acl_gets('a_aauth', 'a_fauth', 'a_mauth', 'a_uauth')) ? true : false,
'S_INCLUDE_SWATCH' => true,
- 'S_ERROR' => (sizeof($error)) ? true : false,
+ 'S_ERROR' => (count($error)) ? true : false,
'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false,
'S_USER_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false,
'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
- 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
- 'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
+ 'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '',
+ 'GROUP_NAME' => $group_helper->get_name($group_name),
'GROUP_INTERNAL_NAME' => $group_name,
'GROUP_DESC' => $group_desc_data['text'],
'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '',
@@ -816,8 +835,9 @@ class acp_groups
trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- $this->page_title = 'GROUP_MEMBERS';
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
+ $this->page_title = 'GROUP_MEMBERS';
// Grab the leaders - always, on every page...
$sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_regdate, u.user_colour, u.user_posts, u.group_id, ug.group_leader, ug.user_pending
@@ -868,7 +888,7 @@ class acp_groups
'S_GROUP_SPECIAL' => ($group_row['group_type'] == GROUP_SPECIAL) ? true : false,
'S_ACTION_OPTIONS' => $s_action_options,
- 'GROUP_NAME' => ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'],
+ 'GROUP_NAME' => $group_helper->get_name($group_row['group_name']),
'U_ACTION' => $this->u_action . "&amp;g=$group_id",
'U_BACK' => $this->u_action,
@@ -921,7 +941,7 @@ class acp_groups
);
// Get us all the groups
- $sql = 'SELECT g.group_id, g.group_name, g.group_type
+ $sql = 'SELECT g.group_id, g.group_name, g.group_type, g.group_colour
FROM ' . GROUPS_TABLE . ' g
ORDER BY g.group_type ASC, g.group_name';
$result = $db->sql_query($sql);
@@ -937,11 +957,12 @@ class acp_groups
// used for easy access to the data within a group
$cached_group_data[$type][$row['group_id']] = $row;
$cached_group_data[$type][$row['group_id']]['total_members'] = 0;
+ $cached_group_data[$type][$row['group_id']]['pending_members'] = 0;
}
$db->sql_freeresult($result);
// How many people are in which group?
- $sql = 'SELECT COUNT(ug.user_id) AS total_members, ug.group_id
+ $sql = 'SELECT COUNT(ug.user_id) AS total_members, SUM(ug.user_pending) AS pending_members, ug.group_id
FROM ' . USER_GROUP_TABLE . ' ug
WHERE ' . $db->sql_in_set('ug.group_id', array_keys($lookup)) . '
GROUP BY ug.group_id';
@@ -951,6 +972,7 @@ class acp_groups
{
$type = $lookup[$row['group_id']];
$cached_group_data[$type][$row['group_id']]['total_members'] = $row['total_members'];
+ $cached_group_data[$type][$row['group_id']]['pending_members'] = $row['pending_members'];
}
$db->sql_freeresult($result);
@@ -978,7 +1000,9 @@ class acp_groups
'S_GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL) ? true : false,
'GROUP_NAME' => $group_name,
+ 'GROUP_COLOR' => $row['group_colour'],
'TOTAL_MEMBERS' => $row['total_members'],
+ 'PENDING_MEMBERS' => $row['pending_members']
));
}
}
@@ -997,6 +1021,9 @@ class acp_groups
$teampage_id = $request->variable('t', 0);
$category_id = $request->variable('c', 0);
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
if ($field && !in_array($field, array('legend', 'teampage')))
{
// Invalid mode
@@ -1004,7 +1031,7 @@ class acp_groups
}
else if ($field && in_array($field, array('legend', 'teampage')))
{
-
+ /* @var $group_position \phpbb\groupposition\groupposition_interface */
$group_position = $phpbb_container->get('groupposition.' . $field);
}
@@ -1096,10 +1123,9 @@ class acp_groups
ORDER BY group_legend ASC, group_type DESC, group_name ASC';
$result = $db->sql_query($sql);
- $s_group_select_legend = '';
while ($row = $db->sql_fetchrow($result))
{
- $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $group_name = $group_helper->get_name($row['group_name']);
if ($row['group_legend'])
{
$template->assign_block_vars('legend', array(
@@ -1134,7 +1160,6 @@ class acp_groups
ORDER BY t.teampage_position ASC';
$result = $db->sql_query($sql);
- $category_data = array();
while ($row = $db->sql_fetchrow($result))
{
if ($row['teampage_id'] == $category_id)
@@ -1147,7 +1172,7 @@ class acp_groups
if ($row['group_id'])
{
- $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $group_name = $group_helper->get_name($row['group_name']);
$group_type = $user->lang[\phpbb\groupposition\teampage::group_type_language($row['group_type'])];
}
else
@@ -1177,10 +1202,9 @@ class acp_groups
ORDER BY g.group_type DESC, g.group_name ASC';
$result = $db->sql_query($sql);
- $s_group_select_teampage = '';
while ($row = $db->sql_fetchrow($result))
{
- $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $group_name = $group_helper->get_name($row['group_name']);
$template->assign_block_vars('add_teampage', array(
'GROUP_ID' => (int) $row['group_id'],
'GROUP_NAME' => $group_name,
diff --git a/phpBB/includes/acp/acp_help_phpbb.php b/phpBB/includes/acp/acp_help_phpbb.php
new file mode 100644
index 0000000000..a36b36eddc
--- /dev/null
+++ b/phpBB/includes/acp/acp_help_phpbb.php
@@ -0,0 +1,143 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+class acp_help_phpbb
+{
+ var $u_action;
+
+ function main($id, $mode)
+ {
+ global $config, $request, $template, $user, $phpbb_dispatcher, $phpbb_admin_path, $phpbb_root_path, $phpEx;
+
+ if (!class_exists('phpbb_questionnaire_data_collector'))
+ {
+ include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx);
+ }
+
+ $collect_url = "https://www.phpbb.com/stats/receive_stats.php";
+
+ $this->tpl_name = 'acp_help_phpbb';
+ $this->page_title = 'ACP_HELP_PHPBB';
+
+ $submit = ($request->is_set_post('submit')) ? true : false;
+
+ $form_key = 'acp_help_phpbb';
+ add_form_key($form_key);
+ $error = array();
+
+ if ($submit && !check_form_key($form_key))
+ {
+ $error[] = $user->lang['FORM_INVALID'];
+ }
+ // Do not write values if there is an error
+ if (count($error))
+ {
+ $submit = false;
+ }
+
+ // generate a unique id if necessary
+ if (!isset($config['questionnaire_unique_id']))
+ {
+ $install_id = unique_id();
+ $config->set('questionnaire_unique_id', $install_id);
+ }
+ else
+ {
+ $install_id = $config['questionnaire_unique_id'];
+ }
+
+ $collector = new phpbb_questionnaire_data_collector($install_id);
+
+ // Add data provider
+ $collector->add_data_provider(new phpbb_questionnaire_php_data_provider());
+ $collector->add_data_provider(new phpbb_questionnaire_system_data_provider());
+ $collector->add_data_provider(new phpbb_questionnaire_phpbb_data_provider($config));
+
+ /**
+ * Event to modify ACP help phpBB page and/or listen to submit
+ *
+ * @event core.acp_help_phpbb_submit_before
+ * @var boolean submit Do we display the form or process the submission
+ * @since 3.2.0-RC2
+ */
+ $vars = array('submit');
+ extract($phpbb_dispatcher->trigger_event('core.acp_help_phpbb_submit_before', compact($vars)));
+
+ if ($submit)
+ {
+ $config->set('help_send_statistics', $request->variable('help_send_statistics', false));
+ $response = $request->variable('send_statistics_response', '');
+
+ $config->set('help_send_statistics_time', time());
+
+ if (!empty($response))
+ {
+ if ((strpos($response, 'Thank you') !== false || strpos($response, 'Flood protection') !== false))
+ {
+ trigger_error($user->lang('THANKS_SEND_STATISTICS') . adm_back_link($this->u_action));
+ }
+ else
+ {
+ trigger_error($user->lang('FAIL_SEND_STATISTICS') . adm_back_link($this->u_action));
+ }
+ }
+
+ trigger_error($user->lang('CONFIG_UPDATED') . adm_back_link($this->u_action));
+ }
+
+ $template->assign_vars(array(
+ 'U_COLLECT_STATS' => $collect_url,
+ 'S_COLLECT_STATS' => (!empty($config['help_send_statistics'])) ? true : false,
+ 'RAW_DATA' => $collector->get_data_for_form(),
+ 'U_ACP_MAIN' => append_sid("{$phpbb_admin_path}index.$phpEx"),
+ 'U_ACTION' => $this->u_action,
+ // Pass earliest time we should try to send stats again
+ 'COLLECT_STATS_TIME' => intval($config['help_send_statistics_time']) + 86400,
+ ));
+
+ $raw = $collector->get_data_raw();
+
+ foreach ($raw as $provider => $data)
+ {
+ if ($provider == 'install_id')
+ {
+ $data = array($provider => $data);
+ }
+
+ $template->assign_block_vars('providers', array(
+ 'NAME' => htmlspecialchars($provider),
+ ));
+
+ foreach ($data as $key => $value)
+ {
+ if (is_array($value))
+ {
+ $value = utf8_wordwrap(serialize($value), 75, "\n", true);
+ }
+
+ $template->assign_block_vars('providers.values', array(
+ 'KEY' => utf8_htmlspecialchars($key),
+ 'VALUE' => utf8_htmlspecialchars($value),
+ ));
+ }
+ }
+ }
+}
diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php
index a0ea7dc9b1..2c3948f644 100644
--- a/phpBB/includes/acp/acp_icons.php
+++ b/phpBB/includes/acp/acp_icons.php
@@ -28,18 +28,18 @@ class acp_icons
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $template, $cache;
+ global $config, $phpbb_root_path;
global $request, $phpbb_container;
$user->add_lang('acp/posting');
// Set up general vars
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : $action;
$action = (isset($_POST['edit'])) ? 'edit' : $action;
$action = (isset($_POST['import'])) ? 'import' : $action;
- $icon_id = request_var('id', 0);
+ $icon_id = $request->variable('id', 0);
$submit = $request->is_set_post('submit', false);
$form_key = 'acp_icons';
@@ -166,7 +166,7 @@ class acp_icons
}
$db->sql_freeresult($result);
- if (sizeof($smilies))
+ if (count($smilies))
{
foreach ($smilies as $row)
{
@@ -198,7 +198,6 @@ class acp_icons
$data = array();
$after = false;
- $display = 0;
$order_lists = array('', '');
$add_order_lists = array('', '');
$display_count = 0;
@@ -213,7 +212,6 @@ class acp_icons
if ($row[$fields . '_id'] == $icon_id)
{
$after = true;
- $display = $row['display_on_posting'];
$data[$row[$fields . '_url']] = $row;
}
else
@@ -252,7 +250,7 @@ class acp_icons
$data = $_images;
}
- $colspan = (($mode == 'smilies') ? 7 : 5);
+ $colspan = (($mode == 'smilies') ? 7 : 6);
$colspan += ($icon_id) ? 1 : 0;
$colspan += ($action == 'add') ? 2 : 0;
@@ -296,12 +294,14 @@ class acp_icons
'ID' => (isset($img_row[$fields . '_id'])) ? $img_row[$fields . '_id'] : 0,
'WIDTH' => (!empty($img_row[$fields .'_width'])) ? $img_row[$fields .'_width'] : $img_row['width'],
'HEIGHT' => (!empty($img_row[$fields .'_height'])) ? $img_row[$fields .'_height'] : $img_row['height'],
+ 'TEXT_ALT' => ($mode == 'icons' && !empty($img_row['icons_alt'])) ? $img_row['icons_alt'] : $img,
+ 'ALT' => ($mode == 'icons' && !empty($img_row['icons_alt'])) ? $img_row['icons_alt'] : '',
'POSTING_CHECKED' => (!empty($img_row['display_on_posting']) || $action == 'add') ? ' checked="checked"' : '',
));
}
// Ok, another row for adding an addition code for a pre-existing image...
- if ($action == 'add' && $mode == 'smilies' && sizeof($smilies))
+ if ($action == 'add' && $mode == 'smilies' && count($smilies))
{
$template->assign_vars(array(
'S_ADD_CODE' => true,
@@ -335,24 +335,25 @@ class acp_icons
}
// Get items to create/modify
- $images = (isset($_POST['image'])) ? array_keys(request_var('image', array('' => 0))) : array();
+ $images = (isset($_POST['image'])) ? array_keys($request->variable('image', array('' => 0))) : array();
// Now really get the items
- $image_id = (isset($_POST['id'])) ? request_var('id', array('' => 0)) : array();
- $image_order = (isset($_POST['order'])) ? request_var('order', array('' => 0)) : array();
- $image_width = (isset($_POST['width'])) ? request_var('width', array('' => 0)) : array();
- $image_height = (isset($_POST['height'])) ? request_var('height', array('' => 0)) : array();
- $image_add = (isset($_POST['add_img'])) ? request_var('add_img', array('' => 0)) : array();
- $image_emotion = utf8_normalize_nfc(request_var('emotion', array('' => ''), true));
- $image_code = utf8_normalize_nfc(request_var('code', array('' => ''), true));
- $image_display_on_posting = (isset($_POST['display_on_posting'])) ? request_var('display_on_posting', array('' => 0)) : array();
+ $image_id = (isset($_POST['id'])) ? $request->variable('id', array('' => 0)) : array();
+ $image_order = (isset($_POST['order'])) ? $request->variable('order', array('' => 0)) : array();
+ $image_width = (isset($_POST['width'])) ? $request->variable('width', array('' => 0)) : array();
+ $image_height = (isset($_POST['height'])) ? $request->variable('height', array('' => 0)) : array();
+ $image_add = (isset($_POST['add_img'])) ? $request->variable('add_img', array('' => 0)) : array();
+ $image_emotion = $request->variable('emotion', array('' => ''), true);
+ $image_code = $request->variable('code', array('' => ''), true);
+ $image_alt = ($request->is_set_post('alt')) ? $request->variable('alt', array('' => ''), true) : array();
+ $image_display_on_posting = (isset($_POST['display_on_posting'])) ? $request->variable('display_on_posting', array('' => 0)) : array();
// Ok, add the relevant bits if we are adding new codes to existing emoticons...
if ($request->variable('add_additional_code', false, false, \phpbb\request\request_interface::POST))
{
- $add_image = request_var('add_image', '');
- $add_code = utf8_normalize_nfc(request_var('add_code', '', true));
- $add_emotion = utf8_normalize_nfc(request_var('add_emotion', '', true));
+ $add_image = $request->variable('add_image', '');
+ $add_code = $request->variable('add_code', '', true);
+ $add_emotion = $request->variable('add_emotion', '', true);
if ($add_image && $add_emotion && $add_code)
{
@@ -361,15 +362,15 @@ class acp_icons
$image_code[$add_image] = $add_code;
$image_emotion[$add_image] = $add_emotion;
- $image_width[$add_image] = request_var('add_width', 0);
- $image_height[$add_image] = request_var('add_height', 0);
+ $image_width[$add_image] = $request->variable('add_width', 0);
+ $image_height[$add_image] = $request->variable('add_height', 0);
if ($request->variable('add_display_on_posting', false, false, \phpbb\request\request_interface::POST))
{
$image_display_on_posting[$add_image] = 1;
}
- $image_order[$add_image] = request_var('add_order', 0);
+ $image_order[$add_image] = $request->variable('add_order', 0);
}
}
@@ -377,7 +378,7 @@ class acp_icons
{
$smiley_count = $this->item_count($table);
- $addable_smileys_count = sizeof($images);
+ $addable_smileys_count = count($images);
foreach ($images as $image)
{
if (!isset($image_add[$image]))
@@ -447,6 +448,13 @@ class acp_icons
);
}
+ if ($mode == 'icons')
+ {
+ $img_sql = array_merge($img_sql, array(
+ 'icons_alt' => $image_alt[$image])
+ );
+ }
+
// Image_order holds the 'new' order value
if (!empty($image_order[$image]))
{
@@ -495,6 +503,7 @@ class acp_icons
$cache->destroy('_icons');
$cache->destroy('sql', $table);
+ $phpbb_container->get('text_formatter.cache')->invalidate();
$level = ($icons_updated) ? E_USER_NOTICE : E_USER_WARNING;
$errormsgs = '';
@@ -515,8 +524,8 @@ class acp_icons
case 'import':
- $pak = request_var('pak', '');
- $current = request_var('current', '');
+ $pak = $request->variable('pak', '');
+ $current = $request->variable('current', '');
if ($pak != '')
{
@@ -537,8 +546,8 @@ class acp_icons
{
if (preg_match_all("#'(.*?)', ?#", $pak_entry, $data))
{
- if ((sizeof($data[1]) != 4 && $mode == 'icons') ||
- ((sizeof($data[1]) != 6 || (empty($data[1][4]) || empty($data[1][5]))) && $mode == 'smilies' ))
+ if ((count($data[1]) != 4 && $mode == 'icons') ||
+ ((count($data[1]) != 6 || (empty($data[1][4]) || empty($data[1][5]))) && $mode == 'smilies' ))
{
trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -554,7 +563,6 @@ class acp_icons
{
switch ($db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
$db->sql_query('DELETE FROM ' . $table);
break;
@@ -597,7 +605,7 @@ class acp_icons
if ($mode == 'smilies')
{
$smiley_count = $this->item_count($table);
- if ($smiley_count + sizeof($pak_ary) > SMILEY_LIMIT)
+ if ($smiley_count + count($pak_ary) > SMILEY_LIMIT)
{
trigger_error($user->lang('TOO_MANY_SMILIES', SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -608,8 +616,8 @@ class acp_icons
$data = array();
if (preg_match_all("#'(.*?)', ?#", $pak_entry, $data))
{
- if ((sizeof($data[1]) != 4 && $mode == 'icons') ||
- (sizeof($data[1]) != 6 && $mode == 'smilies'))
+ if ((count($data[1]) != 4 && $mode == 'icons') ||
+ (count($data[1]) != 6 && $mode == 'smilies'))
{
trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -675,6 +683,7 @@ class acp_icons
$cache->destroy('_icons');
$cache->destroy('sql', $table);
+ $phpbb_container->get('text_formatter.cache')->invalidate();
trigger_error($user->lang[$lang . '_IMPORT_SUCCESS'] . adm_back_link($this->u_action));
}
@@ -802,6 +811,7 @@ class acp_icons
$cache->destroy('_icons');
$cache->destroy('sql', $table);
+ $phpbb_container->get('text_formatter.cache')->invalidate();
if ($request->is_ajax())
{
@@ -872,6 +882,7 @@ class acp_icons
$cache->destroy('_icons');
$cache->destroy('sql', $table);
+ $phpbb_container->get('text_formatter.cache')->invalidate();
if ($request->is_ajax())
{
@@ -927,9 +938,10 @@ class acp_icons
)
);
- $spacer = false;
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
- $pagination_start = request_var('start', 0);
+ $pagination_start = $request->variable('start', 0);
+ $spacer = false;
$item_count = $this->item_count($table);
@@ -940,7 +952,7 @@ class acp_icons
while ($row = $db->sql_fetchrow($result))
{
- $alt_text = ($mode == 'smilies') ? $row['code'] : '';
+ $alt_text = ($mode == 'smilies') ? $row['code'] : (($mode == 'icons' && !empty($row['icons_alt'])) ? $row['icons_alt'] : $row['icons_url']);
$template->assign_block_vars('items', array(
'S_SPACER' => (!$spacer && !$row['display_on_posting']) ? true : false,
diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php
index 76c7a1b277..4ee4cd4816 100644
--- a/phpBB/includes/acp/acp_inactive.php
+++ b/phpBB/includes/acp/acp_inactive.php
@@ -24,15 +24,15 @@ class acp_inactive
var $u_action;
var $p_master;
- function acp_inactive(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $phpbb_container;
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix;
+ global $config, $db, $user, $auth, $template, $phpbb_container, $phpbb_log, $request;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx;
if (!function_exists('user_active_flip'))
{
@@ -41,24 +41,26 @@ class acp_inactive
$user->add_lang('memberlist');
- $action = request_var('action', '');
- $mark = (isset($_REQUEST['mark'])) ? request_var('mark', array(0)) : array();
- $start = request_var('start', 0);
+ $action = $request->variable('action', '');
+ $mark = (isset($_REQUEST['mark'])) ? $request->variable('mark', array(0)) : array();
+ $start = $request->variable('start', 0);
$submit = isset($_POST['submit']);
// Sort keys
- $sort_days = request_var('st', 0);
- $sort_key = request_var('sk', 'i');
- $sort_dir = request_var('sd', 'd');
+ $sort_days = $request->variable('st', 0);
+ $sort_key = $request->variable('sk', 'i');
+ $sort_dir = $request->variable('sd', 'd');
$form_key = 'acp_inactive';
add_form_key($form_key);
+
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// We build the sort key and per page settings here, because they may be needed later
// Number of entries to display
- $per_page = request_var('users_per_page', (int) $config['topics_per_page']);
+ $per_page = $request->variable('users_per_page', (int) $config['topics_per_page']);
// Sorting
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
@@ -68,7 +70,7 @@ class acp_inactive
$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
- if ($submit && sizeof($mark))
+ if ($submit && count($mark))
{
if ($action !== 'delete' && !check_form_key($form_key))
{
@@ -141,8 +143,10 @@ class acp_inactive
{
foreach ($inactive_users as $row)
{
- add_log('admin', 'LOG_USER_ACTIVE', $row['username']);
- add_log('user', $row['user_id'], 'LOG_USER_ACTIVE_USER');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_ACTIVE', false, array($row['username']));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_ACTIVE_USER', false, array(
+ 'reportee_id' => $row['user_id']
+ ));
}
trigger_error(sprintf($user->lang['LOG_INACTIVE_ACTIVATE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action)));
@@ -160,12 +164,13 @@ class acp_inactive
{
if (!$auth->acl_get('a_userdel'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
user_delete('retain', $mark, true);
- add_log('admin', 'LOG_INACTIVE_' . strtoupper($action), implode(', ', $user_affected));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_INACTIVE_' . strtoupper($action), false, array(implode(', ', $user_affected)));
trigger_error(sprintf($user->lang['LOG_INACTIVE_DELETE'], implode($user->lang['COMMA_SEPARATOR'], $user_affected) . ' ' . adm_back_link($this->u_action)));
}
@@ -240,7 +245,7 @@ class acp_inactive
WHERE ' . $db->sql_in_set('user_id', $user_ids);
$db->sql_query($sql);
- add_log('admin', 'LOG_INACTIVE_REMIND', implode(', ', $usernames));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_INACTIVE_REMIND', false, array(implode(', ', $usernames)));
trigger_error(sprintf($user->lang['LOG_INACTIVE_REMIND'], implode($user->lang['COMMA_SEPARATOR'], $usernames) . ' ' . adm_back_link($this->u_action)));
}
diff --git a/phpBB/includes/acp/acp_jabber.php b/phpBB/includes/acp/acp_jabber.php
index 3b958c0ea1..07f5dadbff 100644
--- a/phpBB/includes/acp/acp_jabber.php
+++ b/phpBB/includes/acp/acp_jabber.php
@@ -29,8 +29,8 @@ class acp_jabber
function main($id, $mode)
{
- global $db, $user, $auth, $template;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $template, $phpbb_log, $request;
+ global $config, $phpbb_root_path, $phpEx;
$user->add_lang('acp/board');
@@ -39,7 +39,6 @@ class acp_jabber
include($phpbb_root_path . 'includes/functions_jabber.' . $phpEx);
}
- $action = request_var('action', '');
$submit = (isset($_POST['submit'])) ? true : false;
if ($mode != 'settings')
@@ -50,16 +49,16 @@ class acp_jabber
$this->tpl_name = 'acp_jabber';
$this->page_title = 'ACP_JABBER_SETTINGS';
- $jab_enable = request_var('jab_enable', (bool) $config['jab_enable']);
- $jab_host = request_var('jab_host', (string) $config['jab_host']);
- $jab_port = request_var('jab_port', (int) $config['jab_port']);
- $jab_username = request_var('jab_username', (string) $config['jab_username']);
- $jab_password = request_var('jab_password', (string) $config['jab_password']);
- $jab_package_size = request_var('jab_package_size', (int) $config['jab_package_size']);
- $jab_use_ssl = request_var('jab_use_ssl', (bool) $config['jab_use_ssl']);
- $jab_verify_peer = request_var('jab_verify_peer', (bool) $config['jab_verify_peer']);
- $jab_verify_peer_name = request_var('jab_verify_peer_name', (bool) $config['jab_verify_peer_name']);
- $jab_allow_self_signed = request_var('jab_allow_self_signed', (bool) $config['jab_allow_self_signed']);
+ $jab_enable = $request->variable('jab_enable', (bool) $config['jab_enable']);
+ $jab_host = $request->variable('jab_host', (string) $config['jab_host']);
+ $jab_port = $request->variable('jab_port', (int) $config['jab_port']);
+ $jab_username = $request->variable('jab_username', (string) $config['jab_username']);
+ $jab_password = $request->variable('jab_password', (string) $config['jab_password']);
+ $jab_package_size = $request->variable('jab_package_size', (int) $config['jab_package_size']);
+ $jab_use_ssl = $request->variable('jab_use_ssl', (bool) $config['jab_use_ssl']);
+ $jab_verify_peer = $request->variable('jab_verify_peer', (bool) $config['jab_verify_peer']);
+ $jab_verify_peer_name = $request->variable('jab_verify_peer_name', (bool) $config['jab_verify_peer_name']);
+ $jab_allow_self_signed = $request->variable('jab_allow_self_signed', (bool) $config['jab_allow_self_signed']);
$form_name = 'acp_jabber';
add_form_key($form_name);
@@ -71,8 +70,6 @@ class acp_jabber
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
- $error = array();
-
$message = $user->lang['JAB_SETTINGS_CHANGED'];
$log = 'JAB_SETTINGS_CHANGED';
@@ -109,21 +106,21 @@ class acp_jabber
$db->sql_query($sql);
}
- set_config('jab_enable', $jab_enable);
- set_config('jab_host', $jab_host);
- set_config('jab_port', $jab_port);
- set_config('jab_username', $jab_username);
+ $config->set('jab_enable', $jab_enable);
+ $config->set('jab_host', $jab_host);
+ $config->set('jab_port', $jab_port);
+ $config->set('jab_username', $jab_username);
if ($jab_password !== '********')
{
- set_config('jab_password', $jab_password);
+ $config->set('jab_password', $jab_password);
}
- set_config('jab_package_size', $jab_package_size);
- set_config('jab_use_ssl', $jab_use_ssl);
- set_config('jab_verify_peer', $jab_verify_peer);
- set_config('jab_verify_peer_name', $jab_verify_peer_name);
- set_config('jab_allow_self_signed', $jab_allow_self_signed);
+ $config->set('jab_package_size', $jab_package_size);
+ $config->set('jab_use_ssl', $jab_use_ssl);
+ $config->set('jab_verify_peer', $jab_verify_peer);
+ $config->set('jab_verify_peer_name', $jab_verify_peer_name);
+ $config->set('jab_allow_self_signed', $jab_allow_self_signed);
- add_log('admin', 'LOG_' . $log);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_' . $log);
trigger_error($message . adm_back_link($this->u_action));
}
diff --git a/phpBB/includes/acp/acp_language.php b/phpBB/includes/acp/acp_language.php
index bddc2be9cb..8881f624e3 100644
--- a/phpBB/includes/acp/acp_language.php
+++ b/phpBB/includes/acp/acp_language.php
@@ -31,8 +31,8 @@ class acp_language
function main($id, $mode)
{
- global $config, $db, $user, $template;
- global $phpbb_root_path, $phpEx, $request;
+ global $config, $db, $user, $template, $phpbb_log, $phpbb_container;
+ global $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher;
if (!function_exists('validate_language_iso_name'))
{
@@ -44,14 +44,14 @@ class acp_language
$action = (isset($_POST['remove_store'])) ? 'details' : $action;
$submit = (empty($action) && !isset($_POST['update']) && !isset($_POST['test_connection'])) ? false : true;
- $action = (empty($action)) ? request_var('action', '') : $action;
+ $action = (empty($action)) ? $request->variable('action', '') : $action;
$form_name = 'acp_lang';
add_form_key('acp_lang');
- $lang_id = request_var('id', 0);
+ $lang_id = $request->variable('id', 0);
- $selected_lang_file = request_var('language_file', '|common.' . $phpEx);
+ $selected_lang_file = $request->variable('language_file', '|common.' . $phpEx);
list($this->language_directory, $this->language_file) = explode('|', $selected_lang_file);
@@ -84,16 +84,16 @@ class acp_language
$db->sql_freeresult($result);
$sql_ary = array(
- 'lang_english_name' => request_var('lang_english_name', $row['lang_english_name']),
- 'lang_local_name' => utf8_normalize_nfc(request_var('lang_local_name', $row['lang_local_name'], true)),
- 'lang_author' => utf8_normalize_nfc(request_var('lang_author', $row['lang_author'], true)),
+ 'lang_english_name' => $request->variable('lang_english_name', $row['lang_english_name']),
+ 'lang_local_name' => $request->variable('lang_local_name', $row['lang_local_name'], true),
+ 'lang_author' => $request->variable('lang_author', $row['lang_author'], true),
);
$db->sql_query('UPDATE ' . LANG_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE lang_id = ' . $lang_id);
- add_log('admin', 'LOG_LANGUAGE_PACK_UPDATED', $sql_ary['lang_english_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_UPDATED', false, array($sql_ary['lang_english_name']));
trigger_error($user->lang['LANGUAGE_DETAILS_UPDATED'] . adm_back_link($this->u_action));
break;
@@ -227,9 +227,22 @@ class acp_language
$sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE lang_id = ' . $lang_id;
$db->sql_query($sql);
- add_log('admin', 'LOG_LANGUAGE_PACK_DELETED', $row['lang_english_name']);
-
- trigger_error(sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']) . adm_back_link($this->u_action));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_DELETED', false, array($row['lang_english_name']));
+
+ $delete_message = sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']);
+ $lang_iso = $row['lang_iso'];
+ /**
+ * Run code after language deleted
+ *
+ * @event core.acp_language_after_delete
+ * @var string lang_iso Language ISO code
+ * @var string delete_message Delete message appear to user
+ * @since 3.2.2-RC1
+ */
+ $vars = array('lang_iso', 'delete_message');
+ extract($phpbb_dispatcher->trigger_event('core.acp_language_after_delete', compact($vars)));
+
+ trigger_error($delete_message . adm_back_link($this->u_action));
}
else
{
@@ -249,7 +262,7 @@ class acp_language
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- $lang_iso = request_var('iso', '');
+ $lang_iso = $request->variable('iso', '');
$lang_iso = basename($lang_iso);
if (!$lang_iso || !file_exists("{$phpbb_root_path}language/$lang_iso/iso.txt"))
@@ -337,7 +350,7 @@ class acp_language
}
$db->sql_freeresult($result);
- add_log('admin', 'LOG_LANGUAGE_PACK_INSTALLED', $lang_pack['name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_LANGUAGE_PACK_INSTALLED', false, array($lang_pack['name']));
$message = sprintf($user->lang['LANGUAGE_PACK_INSTALLED'], $lang_pack['name']);
$message .= ($notify_cpf_update) ? '<br /><br />' . $user->lang['LANGUAGE_PACK_CPF_UPDATE'] : '';
@@ -385,42 +398,24 @@ class acp_language
$db->sql_freeresult($result);
$new_ary = $iso = array();
- $dp = @opendir("{$phpbb_root_path}language");
- if ($dp)
+ /** @var \phpbb\language\language_file_helper $language_helper */
+ $language_helper = $phpbb_container->get('language.helper.language_file');
+ $iso = $language_helper->get_available_languages();
+
+ foreach ($iso as $lang_array)
{
- while (($file = readdir($dp)) !== false)
- {
- if ($file[0] == '.' || !is_dir($phpbb_root_path . 'language/' . $file))
- {
- continue;
- }
+ $lang_iso = $lang_array['iso'];
- if (file_exists("{$phpbb_root_path}language/$file/iso.txt"))
- {
- if (!in_array($file, $installed))
- {
- if ($iso = file("{$phpbb_root_path}language/$file/iso.txt"))
- {
- if (sizeof($iso) == 3)
- {
- $new_ary[$file] = array(
- 'iso' => $file,
- 'name' => trim($iso[0]),
- 'local_name'=> trim($iso[1]),
- 'author' => trim($iso[2])
- );
- }
- }
- }
- }
+ if (!in_array($lang_iso, $installed))
+ {
+ $new_ary[$lang_iso] = $lang_array;
}
- closedir($dp);
}
unset($installed);
- if (sizeof($new_ary))
+ if (count($new_ary))
{
foreach ($new_ary as $iso => $lang_ary)
{
diff --git a/phpBB/includes/acp/acp_logs.php b/phpBB/includes/acp/acp_logs.php
index 80dee1d620..f9bb35791c 100644
--- a/phpBB/includes/acp/acp_logs.php
+++ b/phpBB/includes/acp/acp_logs.php
@@ -25,28 +25,29 @@ class acp_logs
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $phpbb_container;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $user, $auth, $template, $phpbb_container;
+ global $config;
global $request;
$user->add_lang('mcp');
// Set up general vars
- $action = request_var('action', '');
- $forum_id = request_var('f', 0);
- $topic_id = request_var('t', 0);
- $start = request_var('start', 0);
+ $action = $request->variable('action', '');
+ $forum_id = $request->variable('f', 0);
+ $start = $request->variable('start', 0);
$deletemark = $request->variable('delmarked', false, false, \phpbb\request\request_interface::POST);
$deleteall = $request->variable('delall', false, false, \phpbb\request\request_interface::POST);
- $marked = request_var('mark', array(0));
+ $marked = $request->variable('mark', array(0));
// Sort keys
- $sort_days = request_var('st', 0);
- $sort_key = request_var('sk', 't');
- $sort_dir = request_var('sd', 'd');
+ $sort_days = $request->variable('st', 0);
+ $sort_key = $request->variable('sk', 't');
+ $sort_dir = $request->variable('sd', 'd');
$this->tpl_name = 'acp_logs';
$this->log_type = constant('LOG_' . strtoupper($mode));
+
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// Delete entries if requested and able
@@ -56,7 +57,7 @@ class acp_logs
{
$conditions = array();
- if ($deletemark && sizeof($marked))
+ if ($deletemark && count($marked))
{
$conditions['log_id'] = array('IN' => $marked);
}
@@ -68,10 +69,11 @@ class acp_logs
$conditions['log_time'] = array('>=', time() - ($sort_days * 86400));
}
- $keywords = utf8_normalize_nfc(request_var('keywords', '', true));
+ $keywords = $request->variable('keywords', '', true);
$conditions['keywords'] = $keywords;
}
+ /* @var $phpbb_log \phpbb\log\log_interface */
$phpbb_log = $phpbb_container->get('log');
$phpbb_log->delete($mode, $conditions);
}
@@ -105,7 +107,7 @@ class acp_logs
$sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0;
$sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC');
- $keywords = utf8_normalize_nfc(request_var('keywords', '', true));
+ $keywords = $request->variable('keywords', '', true);
$keywords_param = !empty($keywords) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : '';
$l_title = $user->lang['ACP_' . strtoupper($mode) . '_LOGS'];
@@ -149,7 +151,7 @@ class acp_logs
{
$data = array();
- $checks = array('viewtopic', 'viewlogs', 'viewforum');
+ $checks = array('viewpost', 'viewtopic', 'viewlogs', 'viewforum');
foreach ($checks as $check)
{
if (isset($row[$check]) && $row[$check])
@@ -165,7 +167,7 @@ class acp_logs
'IP' => $row['ip'],
'DATE' => $user->format_date($row['time']),
'ACTION' => $row['action'],
- 'DATA' => (sizeof($data)) ? implode(' | ', $data) : '',
+ 'DATA' => (count($data)) ? implode(' | ', $data) : '',
'ID' => $row['id'],
)
);
diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php
index 6e7bd91a86..8f169d15a7 100644
--- a/phpBB/includes/acp/acp_main.php
+++ b/phpBB/includes/acp/acp_main.php
@@ -25,8 +25,8 @@ class acp_main
function main($id, $mode)
{
- global $config, $db, $cache, $user, $auth, $template, $request;
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
+ global $config, $db, $cache, $user, $auth, $template, $request, $phpbb_log;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container, $phpbb_dispatcher, $phpbb_filesystem;
// Show restore permissions notice
if ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm'))
@@ -53,7 +53,7 @@ class acp_main
return;
}
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
if ($action)
{
@@ -118,12 +118,13 @@ class acp_main
case 'online':
if (!$auth->acl_get('a_board'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- set_config('record_online_users', 1, true);
- set_config('record_online_date', time(), true);
- add_log('admin', 'LOG_RESET_ONLINE');
+ $config->set('record_online_users', 1, false);
+ $config->set('record_online_date', time(), false);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESET_ONLINE');
if ($request->is_ajax())
{
@@ -134,6 +135,7 @@ class acp_main
case 'stats':
if (!$auth->acl_get('a_board'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -141,35 +143,35 @@ class acp_main
FROM ' . POSTS_TABLE . '
WHERE post_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
- set_config('num_posts', (int) $db->sql_fetchfield('stat'), true);
+ $config->set('num_posts', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT COUNT(topic_id) AS stat
FROM ' . TOPICS_TABLE . '
WHERE topic_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
- set_config('num_topics', (int) $db->sql_fetchfield('stat'), true);
+ $config->set('num_topics', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT COUNT(user_id) AS stat
FROM ' . USERS_TABLE . '
WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')';
$result = $db->sql_query($sql);
- set_config('num_users', (int) $db->sql_fetchfield('stat'), true);
+ $config->set('num_users', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT COUNT(attach_id) as stat
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 0';
$result = $db->sql_query($sql);
- set_config('num_files', (int) $db->sql_fetchfield('stat'), true);
+ $config->set('num_files', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT SUM(filesize) as stat
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 0';
$result = $db->sql_query($sql);
- set_config('upload_dir_size', (float) $db->sql_fetchfield('stat'), true);
+ $config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
if (!function_exists('update_last_username'))
@@ -178,7 +180,7 @@ class acp_main
}
update_last_username();
- add_log('admin', 'LOG_RESYNC_STATS');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_STATS');
if ($request->is_ajax())
{
@@ -189,6 +191,7 @@ class acp_main
case 'user':
if (!$auth->acl_get('a_board'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -215,7 +218,7 @@ class acp_main
// Still no maximum post id? Then we are finished
if (!$max_post_id)
{
- add_log('admin', 'LOG_RESYNC_POSTCOUNTS');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS');
break;
}
@@ -245,7 +248,7 @@ class acp_main
$start += $step;
}
- add_log('admin', 'LOG_RESYNC_POSTCOUNTS');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POSTCOUNTS');
if ($request->is_ajax())
{
@@ -256,11 +259,12 @@ class acp_main
case 'date':
if (!$auth->acl_get('a_board'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- set_config('board_startdate', time() - 1);
- add_log('admin', 'LOG_RESET_DATE');
+ $config->set('board_startdate', time() - 1);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESET_DATE');
if ($request->is_ajax())
{
@@ -271,7 +275,6 @@ class acp_main
case 'db_track':
switch ($db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
$db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE);
break;
@@ -334,13 +337,13 @@ class acp_main
}
unset($posted);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
}
}
- add_log('admin', 'LOG_RESYNC_POST_MARKING');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RESYNC_POST_MARKING');
if ($request->is_ajax())
{
@@ -352,11 +355,16 @@ class acp_main
$config->increment('assets_version', 1);
$cache->purge();
+ // Remove old renderers from the text_formatter service. Since this
+ // operation is performed after the cache is purged, there is not "current"
+ // renderer and in effect all renderers will be purged
+ $phpbb_container->get('text_formatter.cache')->tidy();
+
// Clear permissions
$auth->acl_clear_prefetch();
phpbb_cache_moderators($db, $cache, $auth);
- add_log('admin', 'LOG_PURGE_CACHE');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_CACHE');
if ($request->is_ajax())
{
@@ -367,6 +375,7 @@ class acp_main
case 'purge_sessions':
if ((int) $user->data['user_type'] !== USER_FOUNDER)
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -376,7 +385,6 @@ class acp_main
{
switch ($db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
$db->sql_query("DELETE FROM $table");
break;
@@ -407,7 +415,7 @@ class acp_main
$sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $reinsert_ary);
$db->sql_query($sql);
- add_log('admin', 'LOG_PURGE_SESSIONS');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PURGE_SESSIONS');
if ($request->is_ajax())
{
@@ -431,7 +439,6 @@ class acp_main
if ($auth->acl_get('a_board'))
{
- /** @var \phpbb\version_helper $version_helper */
$version_helper = $phpbb_container->get('version_helper');
try
{
@@ -451,9 +458,10 @@ class acp_main
}
catch (\RuntimeException $e)
{
+ $message = call_user_func_array(array($user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
$template->assign_vars(array(
'S_VERSIONCHECK_FAIL' => true,
- 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== $user->lang('VERSIONCHECK_FAIL')) ? $e->getMessage() : '',
+ 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== 'VERSIONCHECK_FAIL') ? $message : '',
));
}
}
@@ -569,6 +577,7 @@ class acp_main
'S_TOTAL_ORPHAN' => ($total_orphan === false) ? false : true,
'GZIP_COMPRESSION' => ($config['gzip_compress'] && @extension_loaded('zlib')) ? $user->lang['ON'] : $user->lang['OFF'],
'DATABASE_INFO' => $db->sql_server_info(),
+ 'PHP_VERSION_INFO' => PHP_VERSION,
'BOARD_VERSION' => $config['version'],
'U_ACTION' => $this->u_action,
@@ -576,6 +585,7 @@ class acp_main
'U_INACTIVE_USERS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=inactive&amp;mode=list'),
'U_VERSIONCHECK' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=update&amp;mode=version_check'),
'U_VERSIONCHECK_FORCE' => append_sid("{$phpbb_admin_path}index.$phpEx", 'versioncheck_force=1'),
+ 'U_ATTACH_ORPHAN' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=acp_attachments&mode=orphan'),
'S_VERSIONCHECK' => ($auth->acl_get('a_board')) ? true : false,
'S_ACTION_OPTIONS' => ($auth->acl_get('a_board')) ? true : false,
@@ -668,7 +678,7 @@ class acp_main
}
}
- if (!defined('PHPBB_DISABLE_CONFIG_CHECK') && file_exists($phpbb_root_path . 'config.' . $phpEx) && phpbb_is_writable($phpbb_root_path . 'config.' . $phpEx))
+ if (!defined('PHPBB_DISABLE_CONFIG_CHECK') && file_exists($phpbb_root_path . 'config.' . $phpEx) && $phpbb_filesystem->is_writable($phpbb_root_path . 'config.' . $phpEx))
{
// World-Writable? (000x)
$template->assign_var('S_WRITABLE_CONFIG', (bool) (@fileperms($phpbb_root_path . 'config.' . $phpEx) & 0x0002));
@@ -688,7 +698,7 @@ class acp_main
// Fill dbms version if not yet filled
if (empty($config['dbms_version']))
{
- set_config('dbms_version', $db->sql_server_info(true));
+ $config->set('dbms_version', $db->sql_server_info(true));
}
$this->tpl_name = 'acp_main';
diff --git a/phpBB/includes/acp/acp_modules.php b/phpBB/includes/acp/acp_modules.php
index 9d14614417..fb0c09055e 100644
--- a/phpBB/includes/acp/acp_modules.php
+++ b/phpBB/includes/acp/acp_modules.php
@@ -19,6 +19,8 @@ if (!defined('IN_PHPBB'))
exit;
}
+use phpbb\module\exception\module_exception;
+
/**
* - Able to check for new module versions (modes changed/adjusted/added/removed)
* Icons for:
@@ -37,8 +39,10 @@ class acp_modules
function main($id, $mode)
{
- global $db, $user, $auth, $template, $module, $request;
- global $config, $phpbb_admin_path, $phpbb_root_path, $phpEx;
+ global $db, $user, $template, $module, $request, $phpbb_log, $phpbb_container;
+
+ /** @var \phpbb\module\module_manager $module_manager */
+ $module_manager = $phpbb_container->get('module.manager');
// Set a global define for modules we might include (the author is able to prevent execution of code by checking this constant)
define('MODULE_INCLUDE', true);
@@ -68,9 +72,9 @@ class acp_modules
$this->page_title = strtoupper($this->module_class);
- $this->parent_id = request_var('parent_id', 0);
- $module_id = request_var('m', 0);
- $action = request_var('action', '');
+ $this->parent_id = $request->variable('parent_id', 0);
+ $module_id = $request->variable('m', 0);
+ $action = $request->variable('action', '');
$errors = array();
switch ($action)
@@ -94,13 +98,20 @@ class acp_modules
$db->sql_freeresult($result);
}
- $errors = $this->delete_module($module_id);
-
- if (!sizeof($errors))
+ try
+ {
+ $row = $module_manager->get_module_row($module_id, $this->module_class);
+ $module_manager->delete_module($module_id, $this->module_class);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_REMOVED', false, array($user->lang($row['module_langname'])));
+ }
+ catch (module_exception $e)
{
- $this->remove_cache_file();
- trigger_error($user->lang['MODULE_DELETED'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
+ $msg = $user->lang($e->getMessage());
+ trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
+
+ $module_manager->remove_cache_file($this->module_class);
+ trigger_error($user->lang['MODULE_DELETED'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
}
else
{
@@ -146,8 +157,8 @@ class acp_modules
AND module_id = $module_id";
$db->sql_query($sql);
- add_log('admin', 'LOG_MODULE_' . strtoupper($action), $this->lang_name($row['module_langname']));
- $this->remove_cache_file();
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_' . strtoupper($action), false, array($user->lang($row['module_langname'])));
+ $module_manager->remove_cache_file($this->module_class);
break;
@@ -176,12 +187,16 @@ class acp_modules
trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
- $move_module_name = $this->move_module_by($row, $action, 1);
+ try
+ {
+ $move_module_name = $module_manager->move_module_by($row, $this->module_class, $action, 1);
- if ($move_module_name !== false)
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_' . strtoupper($action), false, array($user->lang($row['module_langname']), $move_module_name));
+ $module_manager->remove_cache_file($this->module_class);
+ }
+ catch (module_exception $e)
{
- add_log('admin', 'LOG_MODULE_' . strtoupper($action), $this->lang_name($row['module_langname']), $move_module_name);
- $this->remove_cache_file();
+ // Do nothing
}
if ($request->is_ajax())
@@ -195,7 +210,7 @@ class acp_modules
break;
case 'quickadd':
- $quick_install = request_var('quick_install', '');
+ $quick_install = $request->variable('quick_install', '');
if (confirm_box(true))
{
@@ -207,7 +222,7 @@ class acp_modules
list($module_basename, $module_mode) = explode('::', $quick_install);
// Check if module name and mode exist...
- $fileinfo = $this->get_module_infos($module_basename);
+ $fileinfo = $module_manager->get_module_infos($this->module_class, $module_basename);
$fileinfo = $fileinfo[$module_basename];
if (isset($fileinfo['modes'][$module_mode]))
@@ -223,11 +238,20 @@ class acp_modules
'module_auth' => $fileinfo['modes'][$module_mode]['auth'],
);
- $errors = $this->update_module_data($module_data);
+ try
+ {
+ $module_manager->update_module_data($module_data);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_MODULE_ADD', false, array($user->lang($module_data['module_langname'])));
+ }
+ catch (\phpbb\module\exception\module_exception $e)
+ {
+ $msg = $user->lang($e->getMessage());
+ trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
+ }
- if (!sizeof($errors))
+ if (!count($errors))
{
- $this->remove_cache_file();
+ $module_manager->remove_cache_file($this->module_class);
trigger_error($user->lang['MODULE_ADDED'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
}
@@ -253,7 +277,15 @@ class acp_modules
trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
- $module_row = $this->get_module_row($module_id);
+ try
+ {
+ $module_row = $module_manager->get_module_row($module_id, $this->module_class);
+ }
+ catch (\phpbb\module\exception\module_not_found_exception $e)
+ {
+ $msg = $user->lang($e->getMessage());
+ trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
+ }
// no break
@@ -266,7 +298,7 @@ class acp_modules
'module_enabled' => 0,
'module_display' => 1,
'parent_id' => 0,
- 'module_langname' => utf8_normalize_nfc(request_var('module_langname', '', true)),
+ 'module_langname' => $request->variable('module_langname', '', true),
'module_mode' => '',
'module_auth' => '',
);
@@ -274,13 +306,13 @@ class acp_modules
$module_data = array();
- $module_data['module_basename'] = request_var('module_basename', (string) $module_row['module_basename']);
- $module_data['module_enabled'] = request_var('module_enabled', (int) $module_row['module_enabled']);
- $module_data['module_display'] = request_var('module_display', (int) $module_row['module_display']);
- $module_data['parent_id'] = request_var('module_parent_id', (int) $module_row['parent_id']);
+ $module_data['module_basename'] = $request->variable('module_basename', (string) $module_row['module_basename']);
+ $module_data['module_enabled'] = $request->variable('module_enabled', (int) $module_row['module_enabled']);
+ $module_data['module_display'] = $request->variable('module_display', (int) $module_row['module_display']);
+ $module_data['parent_id'] = $request->variable('module_parent_id', (int) $module_row['parent_id']);
$module_data['module_class'] = $this->module_class;
- $module_data['module_langname'] = utf8_normalize_nfc(request_var('module_langname', (string) $module_row['module_langname'], true));
- $module_data['module_mode'] = request_var('module_mode', (string) $module_row['module_mode']);
+ $module_data['module_langname'] = $request->variable('module_langname', (string) $module_row['module_langname'], true);
+ $module_data['module_mode'] = $request->variable('module_mode', (string) $module_row['module_mode']);
$submit = (isset($_POST['submit'])) ? true : false;
@@ -296,7 +328,7 @@ class acp_modules
trigger_error($user->lang['NO_MODULE_LANGNAME'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
- $module_type = request_var('module_type', 'category');
+ $module_type = $request->variable('module_type', 'category');
if ($module_type == 'category')
{
@@ -312,15 +344,29 @@ class acp_modules
// Adjust auth row
if ($module_data['module_basename'] && $module_data['module_mode'])
{
- $fileinfo = $this->get_module_infos($module_data['module_basename']);
+ $fileinfo = $module_manager->get_module_infos($this->module_class, $module_data['module_basename']);
$module_data['module_auth'] = $fileinfo[$module_data['module_basename']]['modes'][$module_data['module_mode']]['auth'];
}
- $errors = $this->update_module_data($module_data);
+ try
+ {
+ $module_manager->update_module_data($module_data);
+ $phpbb_log->add('admin',
+ $user->data['user_id'],
+ $user->ip,
+ ($action === 'edit') ? 'LOG_MODULE_EDIT' : 'LOG_MODULE_ADD',
+ false,
+ array($user->lang($module_data['module_langname']))
+ ); }
+ catch (\phpbb\module\exception\module_exception $e)
+ {
+ $msg = $user->lang($e->getMessage());
+ trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
+ }
- if (!sizeof($errors))
+ if (!count($errors))
{
- $this->remove_cache_file();
+ $module_manager->remove_cache_file($this->module_class);
trigger_error((($action == 'add') ? $user->lang['MODULE_ADDED'] : $user->lang['MODULE_EDITED']) . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
}
@@ -330,7 +376,7 @@ class acp_modules
$is_cat = (!$module_data['module_basename']) ? true : false;
// Get module information
- $module_infos = $this->get_module_infos();
+ $module_infos = $module_manager->get_module_infos($this->module_class);
// Build name options
$s_name_options = $s_mode_options = '';
@@ -342,7 +388,7 @@ class acp_modules
}
// Name options
- $s_name_options .= '<option value="' . $option . '"' . (($option == $module_data['module_basename']) ? ' selected="selected"' : '') . '>' . $this->lang_name($values['title']) . ' [' . $option . ']</option>';
+ $s_name_options .= '<option value="' . $option . '"' . (($option == $module_data['module_basename']) ? ' selected="selected"' : '') . '>' . $user->lang($values['title']) . ' [' . $option . ']</option>';
$template->assign_block_vars('m_names', array('NAME' => $option, 'A_NAME' => addslashes($option)));
@@ -351,14 +397,14 @@ class acp_modules
{
if ($option == $module_data['module_basename'])
{
- $s_mode_options .= '<option value="' . $m_mode . '"' . (($m_mode == $module_data['module_mode']) ? ' selected="selected"' : '') . '>' . $this->lang_name($m_values['title']) . '</option>';
+ $s_mode_options .= '<option value="' . $m_mode . '"' . (($m_mode == $module_data['module_mode']) ? ' selected="selected"' : '') . '>' . $user->lang($m_values['title']) . '</option>';
}
$template->assign_block_vars('m_names.modes', array(
'OPTION' => $m_mode,
- 'VALUE' => $this->lang_name($m_values['title']),
+ 'VALUE' => $user->lang($m_values['title']),
'A_OPTION' => addslashes($m_mode),
- 'A_VALUE' => addslashes($this->lang_name($m_values['title'])))
+ 'A_VALUE' => addslashes($user->lang($m_values['title'])))
);
}
}
@@ -376,7 +422,7 @@ class acp_modules
'L_TITLE' => $user->lang[strtoupper($action) . '_MODULE'],
- 'MODULENAME' => $this->lang_name($module_data['module_langname']),
+ 'MODULENAME' => $user->lang($module_data['module_langname']),
'ACTION' => $action,
'MODULE_ID' => $module_id,
@@ -384,7 +430,7 @@ class acp_modules
array_change_key_case($module_data, CASE_UPPER))
);
- if (sizeof($errors))
+ if (count($errors))
{
$template->assign_vars(array(
'S_ERROR' => true,
@@ -398,7 +444,7 @@ class acp_modules
}
// Default management page
- if (sizeof($errors))
+ if (count($errors))
{
if ($request->is_ajax())
{
@@ -424,11 +470,11 @@ class acp_modules
{
$navigation = '<a href="' . $this->u_action . '">' . strtoupper($this->module_class) . '</a>';
- $modules_nav = $this->get_module_branch($this->parent_id, 'parents', 'descending');
+ $modules_nav = $module_manager->get_module_branch($this->parent_id, $this->module_class, 'parents');
foreach ($modules_nav as $row)
{
- $langname = $this->lang_name($row['module_langname']);
+ $langname = $user->lang($row['module_langname']);
if ($row['module_id'] == $this->parent_id)
{
@@ -455,7 +501,7 @@ class acp_modules
{
do
{
- $langname = $this->lang_name($row['module_langname']);
+ $langname = $user->lang($row['module_langname']);
if (!$row['module_enabled'])
{
@@ -490,7 +536,15 @@ class acp_modules
}
else if ($this->parent_id)
{
- $row = $this->get_module_row($this->parent_id);
+ try
+ {
+ $row = $module_manager->get_module_row($this->parent_id, $this->module_class);
+ }
+ catch (\phpbb\module\exception\module_not_found_exception $e)
+ {
+ $msg = $user->lang($e->getMessage());
+ trigger_error($msg . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
+ }
$url = $this->u_action . '&amp;parent_id=' . $this->parent_id . '&amp;m=' . $row['module_id'];
@@ -509,19 +563,19 @@ class acp_modules
$db->sql_freeresult($result);
// Quick adding module
- $module_infos = $this->get_module_infos();
+ $module_infos = $module_manager->get_module_infos($this->module_class);
// Build quick options
$s_install_options = '';
foreach ($module_infos as $option => $values)
{
// Name options
- $s_install_options .= '<optgroup label="' . $this->lang_name($values['title']) . ' [' . $option . ']">';
+ $s_install_options .= '<optgroup label="' . $user->lang($values['title']) . ' [' . $option . ']">';
// Build module modes
foreach ($values['modes'] as $m_mode => $m_values)
{
- $s_install_options .= '<option value="' . $option . '::' . $m_mode . '">&nbsp; &nbsp;' . $this->lang_name($m_values['title']) . '</option>';
+ $s_install_options .= '<option value="' . $option . '::' . $m_mode . '">&nbsp; &nbsp;' . $user->lang($m_values['title']) . '</option>';
}
$s_install_options .= '</optgroup>';
@@ -539,109 +593,11 @@ class acp_modules
}
/**
- * Get row for specified module
- */
- function get_module_row($module_id)
- {
- global $db, $user;
-
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND module_id = $module_id";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$row)
- {
- trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
- }
-
- return $row;
- }
-
- /**
- * Get available module information from module files
- *
- * @param string $module
- * @param bool|string $module_class
- * @param bool $use_all_available Use all available instead of just all
- * enabled extensions
- * @return array
- */
- function get_module_infos($module = '', $module_class = false, $use_all_available = false)
- {
- global $phpbb_extension_manager, $phpbb_root_path, $phpEx;
-
- $module_class = ($module_class === false) ? $this->module_class : $module_class;
-
- $directory = $phpbb_root_path . 'includes/' . $module_class . '/info/';
- $fileinfo = array();
-
- $finder = $phpbb_extension_manager->get_finder($use_all_available);
-
- $modules = $finder
- ->extension_suffix('_module')
- ->extension_directory("/$module_class")
- ->core_path("includes/$module_class/info/")
- ->core_prefix($module_class . '_')
- ->get_classes(true);
-
- foreach ($modules as $cur_module)
- {
- // Skip entries we do not need if we know the module we are
- // looking for
- if ($module && strpos(str_replace('\\', '_', $cur_module), $module) === false && $module !== $cur_module)
- {
- continue;
- }
-
- $info_class = preg_replace('/_module$/', '_info', $cur_module);
-
- // If the class does not exist it might be following the old
- // format. phpbb_acp_info_acp_foo needs to be turned into
- // acp_foo_info and the respective file has to be included
- // manually because it does not support auto loading
- $old_info_class_file = str_replace("phpbb_{$module_class}_info_", '', $cur_module);
- $old_info_class = $old_info_class_file . '_info';
-
- if (class_exists($old_info_class))
- {
- $info_class = $old_info_class;
- }
- else if (!class_exists($info_class))
- {
- $info_class = $old_info_class;
- // need to check class exists again because previous checks triggered autoloading
- if (!class_exists($info_class) && file_exists($directory . $old_info_class_file . '.' . $phpEx))
- {
- include($directory . $old_info_class_file . '.' . $phpEx);
- }
- }
-
- if (class_exists($info_class))
- {
- $info = new $info_class();
- $module_info = $info->module();
-
- $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $cur_module;
-
- $fileinfo[$main_class] = $module_info;
- }
- }
-
- ksort($fileinfo);
-
- return $fileinfo;
- }
-
- /**
* Simple version of jumpbox, just lists modules
*/
function make_module_select($select_id = false, $ignore_id = false, $ignore_acl = false, $ignore_nonpost = false, $ignore_emptycat = true, $ignore_noncat = false)
{
- global $db, $user, $auth, $config;
+ global $db, $user;
$sql = 'SELECT module_id, module_enabled, module_basename, parent_id, module_langname, left_id, right_id, module_auth
FROM ' . MODULES_TABLE . "
@@ -696,7 +652,7 @@ class acp_modules
$selected = (is_array($select_id)) ? ((in_array($row['module_id'], $select_id)) ? ' selected="selected"' : '') : (($row['module_id'] == $select_id) ? ' selected="selected"' : '');
- $langname = $this->lang_name($row['module_langname']);
+ $langname = $user->lang($row['module_langname']);
$module_list .= '<option value="' . $row['module_id'] . '"' . $selected . ((!$row['module_enabled']) ? ' class="disabled"' : '') . '>' . $padding . $langname . '</option>';
$iteration++;
@@ -707,401 +663,4 @@ class acp_modules
return $module_list;
}
-
- /**
- * Get module branch
- */
- function get_module_branch($module_id, $type = 'all', $order = 'descending', $include_module = true)
- {
- global $db;
-
- switch ($type)
- {
- case 'parents':
- $condition = 'm1.left_id BETWEEN m2.left_id AND m2.right_id';
- break;
-
- case 'children':
- $condition = 'm2.left_id BETWEEN m1.left_id AND m1.right_id';
- break;
-
- default:
- $condition = 'm2.left_id BETWEEN m1.left_id AND m1.right_id OR m1.left_id BETWEEN m2.left_id AND m2.right_id';
- break;
- }
-
- $rows = array();
-
- $sql = 'SELECT m2.*
- FROM ' . MODULES_TABLE . ' m1
- LEFT JOIN ' . MODULES_TABLE . " m2 ON ($condition)
- WHERE m1.module_class = '" . $db->sql_escape($this->module_class) . "'
- AND m2.module_class = '" . $db->sql_escape($this->module_class) . "'
- AND m1.module_id = $module_id
- ORDER BY m2.left_id " . (($order == 'descending') ? 'ASC' : 'DESC');
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- if (!$include_module && $row['module_id'] == $module_id)
- {
- continue;
- }
-
- $rows[] = $row;
- }
- $db->sql_freeresult($result);
-
- return $rows;
- }
-
- /**
- * Remove modules cache file
- */
- function remove_cache_file()
- {
- global $phpbb_container;
-
- // Sanitise for future path use, it's escaped as appropriate for queries
- $p_class = str_replace(array('.', '/', '\\'), '', basename($this->module_class));
-
- $phpbb_container->get('cache.driver')->destroy('_modules_' . $p_class);
-
- // Additionally remove sql cache
- $phpbb_container->get('cache.driver')->destroy('sql', MODULES_TABLE);
- }
-
- /**
- * Return correct language name
- */
- function lang_name($module_langname)
- {
- global $user;
-
- return (!empty($user->lang[$module_langname])) ? $user->lang[$module_langname] : $module_langname;
- }
-
- /**
- * Update/Add module
- *
- * @param array &$module_data The module data
- * @param bool $run_inline if set to true errors will be returned and no logs being written
- */
- function update_module_data(&$module_data, $run_inline = false)
- {
- global $db, $user;
-
- if (!isset($module_data['module_id']))
- {
- // no module_id means we're creating a new category/module
- if ($module_data['parent_id'])
- {
- $sql = 'SELECT left_id, right_id
- FROM ' . MODULES_TABLE . "
- WHERE module_class = '" . $db->sql_escape($module_data['module_class']) . "'
- AND module_id = " . (int) $module_data['parent_id'];
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$row)
- {
- if ($run_inline)
- {
- return 'PARENT_NO_EXIST';
- }
-
- trigger_error($user->lang['PARENT_NO_EXIST'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
- }
-
- // Workaround
- $row['left_id'] = (int) $row['left_id'];
- $row['right_id'] = (int) $row['right_id'];
-
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET left_id = left_id + 2, right_id = right_id + 2
- WHERE module_class = '" . $db->sql_escape($module_data['module_class']) . "'
- AND left_id > {$row['right_id']}";
- $db->sql_query($sql);
-
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET right_id = right_id + 2
- WHERE module_class = '" . $db->sql_escape($module_data['module_class']) . "'
- AND {$row['left_id']} BETWEEN left_id AND right_id";
- $db->sql_query($sql);
-
- $module_data['left_id'] = (int) $row['right_id'];
- $module_data['right_id'] = (int) $row['right_id'] + 1;
- }
- else
- {
- $sql = 'SELECT MAX(right_id) AS right_id
- FROM ' . MODULES_TABLE . "
- WHERE module_class = '" . $db->sql_escape($module_data['module_class']) . "'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $module_data['left_id'] = (int) $row['right_id'] + 1;
- $module_data['right_id'] = (int) $row['right_id'] + 2;
- }
-
- $sql = 'INSERT INTO ' . MODULES_TABLE . ' ' . $db->sql_build_array('INSERT', $module_data);
- $db->sql_query($sql);
-
- $module_data['module_id'] = $db->sql_nextid();
-
- if (!$run_inline)
- {
- add_log('admin', 'LOG_MODULE_ADD', $this->lang_name($module_data['module_langname']));
- }
- }
- else
- {
- $row = $this->get_module_row($module_data['module_id']);
-
- if ($module_data['module_basename'] && !$row['module_basename'])
- {
- // we're turning a category into a module
- $branch = $this->get_module_branch($module_data['module_id'], 'children', 'descending', false);
-
- if (sizeof($branch))
- {
- return array($user->lang['NO_CATEGORY_TO_MODULE']);
- }
- }
-
- if ($row['parent_id'] != $module_data['parent_id'])
- {
- $this->move_module($module_data['module_id'], $module_data['parent_id']);
- }
-
- $update_ary = $module_data;
- unset($update_ary['module_id']);
-
- $sql = 'UPDATE ' . MODULES_TABLE . '
- SET ' . $db->sql_build_array('UPDATE', $update_ary) . "
- WHERE module_class = '" . $db->sql_escape($module_data['module_class']) . "'
- AND module_id = " . (int) $module_data['module_id'];
- $db->sql_query($sql);
-
- if (!$run_inline)
- {
- add_log('admin', 'LOG_MODULE_EDIT', $this->lang_name($module_data['module_langname']));
- }
- }
-
- return array();
- }
-
- /**
- * Move module around the tree
- */
- function move_module($from_module_id, $to_parent_id)
- {
- global $db;
-
- $moved_modules = $this->get_module_branch($from_module_id, 'children', 'descending');
- $from_data = $moved_modules[0];
- $diff = sizeof($moved_modules) * 2;
-
- $moved_ids = array();
- for ($i = 0, $size = sizeof($moved_modules); $i < $size; ++$i)
- {
- $moved_ids[] = $moved_modules[$i]['module_id'];
- }
-
- // Resync parents
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET right_id = right_id - $diff
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND left_id < " . (int) $from_data['right_id'] . '
- AND right_id > ' . (int) $from_data['right_id'];
- $db->sql_query($sql);
-
- // Resync righthand side of tree
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET left_id = left_id - $diff, right_id = right_id - $diff
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND left_id > " . (int) $from_data['right_id'];
- $db->sql_query($sql);
-
- if ($to_parent_id > 0)
- {
- $to_data = $this->get_module_row($to_parent_id);
-
- // Resync new parents
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET right_id = right_id + $diff
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND " . (int) $to_data['right_id'] . ' BETWEEN left_id AND right_id
- AND ' . $db->sql_in_set('module_id', $moved_ids, true);
- $db->sql_query($sql);
-
- // Resync the righthand side of the tree
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET left_id = left_id + $diff, right_id = right_id + $diff
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND left_id > " . (int) $to_data['right_id'] . '
- AND ' . $db->sql_in_set('module_id', $moved_ids, true);
- $db->sql_query($sql);
-
- // Resync moved branch
- $to_data['right_id'] += $diff;
- if ($to_data['right_id'] > $from_data['right_id'])
- {
- $diff = '+ ' . ($to_data['right_id'] - $from_data['right_id'] - 1);
- }
- else
- {
- $diff = '- ' . abs($to_data['right_id'] - $from_data['right_id'] - 1);
- }
- }
- else
- {
- $sql = 'SELECT MAX(right_id) AS right_id
- FROM ' . MODULES_TABLE . "
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND " . $db->sql_in_set('module_id', $moved_ids, true);
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $diff = '+ ' . (int) ($row['right_id'] - $from_data['left_id'] + 1);
- }
-
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET left_id = left_id $diff, right_id = right_id $diff
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND " . $db->sql_in_set('module_id', $moved_ids);
- $db->sql_query($sql);
- }
-
- /**
- * Remove module from tree
- */
- function delete_module($module_id)
- {
- global $db, $user;
-
- $row = $this->get_module_row($module_id);
-
- $branch = $this->get_module_branch($module_id, 'children', 'descending', false);
-
- if (sizeof($branch))
- {
- return array($user->lang['CANNOT_REMOVE_MODULE']);
- }
-
- // If not move
- $diff = 2;
- $sql = 'DELETE FROM ' . MODULES_TABLE . "
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND module_id = $module_id";
- $db->sql_query($sql);
-
- $row['right_id'] = (int) $row['right_id'];
- $row['left_id'] = (int) $row['left_id'];
-
- // Resync tree
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET right_id = right_id - $diff
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND left_id < {$row['right_id']} AND right_id > {$row['right_id']}";
- $db->sql_query($sql);
-
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET left_id = left_id - $diff, right_id = right_id - $diff
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND left_id > {$row['right_id']}";
- $db->sql_query($sql);
-
- add_log('admin', 'LOG_MODULE_REMOVED', $this->lang_name($row['module_langname']));
-
- return array();
-
- }
-
- /**
- * Move module position by $steps up/down
- */
- function move_module_by($module_row, $action = 'move_up', $steps = 1)
- {
- global $db;
-
- /**
- * Fetch all the siblings between the module's current spot
- * and where we want to move it to. If there are less than $steps
- * siblings between the current spot and the target then the
- * module will move as far as possible
- */
- $sql = 'SELECT module_id, left_id, right_id, module_langname
- FROM ' . MODULES_TABLE . "
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND parent_id = " . (int) $module_row['parent_id'] . '
- AND ' . (($action == 'move_up') ? 'right_id < ' . (int) $module_row['right_id'] . ' ORDER BY right_id DESC' : 'left_id > ' . (int) $module_row['left_id'] . ' ORDER BY left_id ASC');
- $result = $db->sql_query_limit($sql, $steps);
-
- $target = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $target = $row;
- }
- $db->sql_freeresult($result);
-
- if (!sizeof($target))
- {
- // The module is already on top or bottom
- return false;
- }
-
- /**
- * $left_id and $right_id define the scope of the nodes that are affected by the move.
- * $diff_up and $diff_down are the values to substract or add to each node's left_id
- * and right_id in order to move them up or down.
- * $move_up_left and $move_up_right define the scope of the nodes that are moving
- * up. Other nodes in the scope of ($left_id, $right_id) are considered to move down.
- */
- if ($action == 'move_up')
- {
- $left_id = (int) $target['left_id'];
- $right_id = (int) $module_row['right_id'];
-
- $diff_up = (int) ($module_row['left_id'] - $target['left_id']);
- $diff_down = (int) ($module_row['right_id'] + 1 - $module_row['left_id']);
-
- $move_up_left = (int) $module_row['left_id'];
- $move_up_right = (int) $module_row['right_id'];
- }
- else
- {
- $left_id = (int) $module_row['left_id'];
- $right_id = (int) $target['right_id'];
-
- $diff_up = (int) ($module_row['right_id'] + 1 - $module_row['left_id']);
- $diff_down = (int) ($target['right_id'] - $module_row['right_id']);
-
- $move_up_left = (int) ($module_row['right_id'] + 1);
- $move_up_right = (int) $target['right_id'];
- }
-
- // Now do the dirty job
- $sql = 'UPDATE ' . MODULES_TABLE . "
- SET left_id = left_id + CASE
- WHEN left_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
- ELSE {$diff_down}
- END,
- right_id = right_id + CASE
- WHEN right_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
- ELSE {$diff_down}
- END
- WHERE module_class = '" . $db->sql_escape($this->module_class) . "'
- AND left_id BETWEEN {$left_id} AND {$right_id}
- AND right_id BETWEEN {$left_id} AND {$right_id}";
- $db->sql_query($sql);
-
- $this->remove_cache_file();
-
- return $this->lang_name($target['module_langname']);
- }
}
diff --git a/phpBB/includes/acp/acp_permission_roles.php b/phpBB/includes/acp/acp_permission_roles.php
index 0796b36fef..80cad9915d 100644
--- a/phpBB/includes/acp/acp_permission_roles.php
+++ b/phpBB/includes/acp/acp_permission_roles.php
@@ -26,9 +26,9 @@ class acp_permission_roles
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $phpbb_container;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
- global $request;
+ global $db, $user, $template, $phpbb_container;
+ global $phpbb_root_path, $phpEx;
+ global $request, $phpbb_log;
if (!function_exists('user_get_id_name'))
{
@@ -48,8 +48,8 @@ class acp_permission_roles
$this->tpl_name = 'acp_permission_roles';
$submit = (isset($_POST['submit'])) ? true : false;
- $role_id = request_var('role_id', 0);
- $action = request_var('action', '');
+ $role_id = $request->variable('role_id', 0);
+ $action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : $action;
$form_name = 'acp_permissions';
@@ -116,7 +116,7 @@ class acp_permission_roles
$this->remove_role($role_id, $permission_type);
$role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
- add_log('admin', 'LOG_' . strtoupper($permission_type) . 'ROLE_REMOVED', $role_name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_' . strtoupper($permission_type) . 'ROLE_REMOVED', false, array($role_name));
trigger_error($user->lang['ROLE_DELETED'] . adm_back_link($this->u_action));
}
else
@@ -155,9 +155,9 @@ class acp_permission_roles
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
- $role_name = utf8_normalize_nfc(request_var('role_name', '', true));
- $role_description = utf8_normalize_nfc(request_var('role_description', '', true));
- $auth_settings = request_var('setting', array('' => 0));
+ $role_name = $request->variable('role_name', '', true);
+ $role_description = $request->variable('role_description', '', true);
+ $auth_settings = $request->variable('setting', array('' => 0));
if (!$role_name)
{
@@ -219,7 +219,7 @@ class acp_permission_roles
$this->auth_admin->acl_set_role($role_id, $auth_settings);
$role_name = (!empty($user->lang[$role_name])) ? $user->lang[$role_name] : $role_name;
- add_log('admin', 'LOG_' . strtoupper($permission_type) . 'ROLE_' . strtoupper($action), $role_name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_' . strtoupper($permission_type) . 'ROLE_' . strtoupper($action), false, array($role_name));
trigger_error($user->lang['ROLE_' . strtoupper($action) . '_SUCCESS'] . adm_back_link($this->u_action));
@@ -232,11 +232,11 @@ class acp_permission_roles
{
case 'add':
- $options_from = request_var('options_from', 0);
+ $options_from = $request->variable('options_from', 0);
$role_row = array(
- 'role_name' => utf8_normalize_nfc(request_var('role_name', '', true)),
- 'role_description' => utf8_normalize_nfc(request_var('role_description', '', true)),
+ 'role_name' => $request->variable('role_name', '', true),
+ 'role_description' => $request->variable('role_description', '', true),
'role_type' => $permission_type,
);
@@ -306,6 +306,7 @@ class acp_permission_roles
trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
+ /* @var $phpbb_permissions \phpbb\permissions */
$phpbb_permissions = $phpbb_container->get('acl.permissions');
$template->assign_vars(array(
@@ -347,7 +348,7 @@ class acp_permission_roles
{
$hold_ary = $this->auth_admin->get_role_mask($role_id);
- if (sizeof($hold_ary))
+ if (count($hold_ary))
{
$role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
@@ -425,7 +426,7 @@ class acp_permission_roles
$db->sql_freeresult($result);
// Display assigned items?
- $display_item = request_var('display_item', 0);
+ $display_item = $request->variable('display_item', 0);
// Select existing roles
$sql = 'SELECT *
@@ -481,8 +482,9 @@ class acp_permission_roles
*/
function display_auth_options($auth_options)
{
- global $template, $user, $phpbb_container;
+ global $template, $phpbb_container;
+ /* @var $phpbb_permissions \phpbb\permissions */
$phpbb_permissions = $phpbb_container->get('acl.permissions');
$content_array = $categories = array();
@@ -494,7 +496,7 @@ class acp_permission_roles
$content_array = $content_array[0];
- $template->assign_var('S_NUM_PERM_COLS', sizeof($categories));
+ $template->assign_var('S_NUM_PERM_COLS', count($categories));
// Assign to template
foreach ($content_array as $cat => $cat_array)
diff --git a/phpBB/includes/acp/acp_permissions.php b/phpBB/includes/acp/acp_permissions.php
index 62e75a2db7..e683b1972e 100644
--- a/phpBB/includes/acp/acp_permissions.php
+++ b/phpBB/includes/acp/acp_permissions.php
@@ -23,12 +23,16 @@ class acp_permissions
{
var $u_action;
var $permission_dropdown;
+
+ /**
+ * @var $phpbb_permissions \phpbb\permissions
+ */
protected $permissions;
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $phpbb_container;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $auth, $template, $phpbb_container, $request;
+ global $config, $phpbb_root_path, $phpEx;
if (!function_exists('user_get_id_name'))
{
@@ -52,9 +56,9 @@ class acp_permissions
// Trace has other vars
if ($mode == 'trace')
{
- $user_id = request_var('u', 0);
- $forum_id = request_var('f', 0);
- $permission = request_var('auth', '');
+ $user_id = $request->variable('u', 0);
+ $forum_id = $request->variable('f', 0);
+ $permission = $request->variable('auth', '');
$this->tpl_name = 'permission_trace';
@@ -83,20 +87,20 @@ class acp_permissions
}
// Set some vars
- $action = request_var('action', array('' => 0));
+ $action = $request->variable('action', array('' => 0));
$action = key($action);
$action = (isset($_POST['psubmit'])) ? 'apply_permissions' : $action;
- $all_forums = request_var('all_forums', 0);
- $subforum_id = request_var('subforum_id', 0);
- $forum_id = request_var('forum_id', array(0));
+ $all_forums = $request->variable('all_forums', 0);
+ $subforum_id = $request->variable('subforum_id', 0);
+ $forum_id = $request->variable('forum_id', array(0));
- $username = request_var('username', array(''), true);
- $usernames = request_var('usernames', '', true);
- $user_id = request_var('user_id', array(0));
+ $username = $request->variable('username', array(''), true);
+ $usernames = $request->variable('usernames', '', true);
+ $user_id = $request->variable('user_id', array(0));
- $group_id = request_var('group_id', array(0));
- $select_all_groups = request_var('select_all_groups', 0);
+ $group_id = $request->variable('group_id', array(0));
+ $select_all_groups = $request->variable('select_all_groups', 0);
$form_name = 'acp_permissions';
add_form_key($form_name);
@@ -127,11 +131,11 @@ class acp_permissions
}
unset($usernames);
- if (sizeof($username) && !sizeof($user_id))
+ if (count($username) && !count($user_id))
{
user_get_id_name($user_id, $username);
- if (!sizeof($user_id))
+ if (!count($user_id))
{
trigger_error($user->lang['SELECTED_USER_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -163,8 +167,6 @@ class acp_permissions
}
// Define some common variables for every mode
- $error = array();
-
$permission_scope = (strpos($mode, '_global') !== false) ? 'global' : 'local';
// Showing introductionary page?
@@ -235,7 +237,7 @@ class acp_permissions
);
// Get permission type
- $permission_type = request_var('type', $this->permission_dropdown[0]);
+ $permission_type = $request->variable('type', $this->permission_dropdown[0]);
if (!in_array($permission_type, $this->permission_dropdown))
{
@@ -258,17 +260,17 @@ class acp_permissions
{
$items = $this->retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type);
- if ($all_users && sizeof($items['user_ids']))
+ if ($all_users && count($items['user_ids']))
{
$user_id = $items['user_ids'];
}
- else if ($all_groups && sizeof($items['group_ids']))
+ else if ($all_groups && count($items['group_ids']))
{
$group_id = $items['group_ids'];
}
}
- if (sizeof($user_id) || sizeof($group_id))
+ if (count($user_id) || count($group_id))
{
$this->remove_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id, $forum_id);
}
@@ -313,6 +315,7 @@ class acp_permissions
case 'apply_permissions':
if (!isset($_POST['setting']))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_SETTING_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (!check_form_key($form_name))
@@ -326,6 +329,7 @@ class acp_permissions
case 'apply_all_permissions':
if (!isset($_POST['setting']))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_SETTING_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if (!check_form_key($form_name))
@@ -345,7 +349,7 @@ class acp_permissions
{
case 'forum_dropdown':
- if (sizeof($forum_id))
+ if (count($forum_id))
{
$this->check_existence('forum', $forum_id);
continue 2;
@@ -360,7 +364,7 @@ class acp_permissions
case 'forums':
- if (sizeof($forum_id))
+ if (count($forum_id))
{
$this->check_existence('forum', $forum_id);
continue 2;
@@ -390,7 +394,7 @@ class acp_permissions
case 'user':
- if (sizeof($user_id))
+ if (count($user_id))
{
$this->check_existence('user', $user_id);
continue 2;
@@ -405,7 +409,7 @@ class acp_permissions
case 'group':
- if (sizeof($group_id))
+ if (count($group_id))
{
$this->check_existence('group', $group_id);
continue 2;
@@ -424,14 +428,14 @@ class acp_permissions
$all_users = (isset($_POST['all_users'])) ? true : false;
$all_groups = (isset($_POST['all_groups'])) ? true : false;
- if ((sizeof($user_id) && !$all_users) || (sizeof($group_id) && !$all_groups))
+ if ((count($user_id) && !$all_users) || (count($group_id) && !$all_groups))
{
- if (sizeof($user_id))
+ if (count($user_id))
{
$this->check_existence('user', $user_id);
}
- if (sizeof($group_id))
+ if (count($group_id))
{
$this->check_existence('group', $group_id);
}
@@ -442,13 +446,13 @@ class acp_permissions
// Now we check the users... because the "all"-selection is different here (all defined users/groups)
$items = $this->retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type);
- if ($all_users && sizeof($items['user_ids']))
+ if ($all_users && count($items['user_ids']))
{
$user_id = $items['user_ids'];
continue 2;
}
- if ($all_groups && sizeof($items['group_ids']))
+ if ($all_groups && count($items['group_ids']))
{
$group_id = $items['group_ids'];
continue 2;
@@ -483,14 +487,14 @@ class acp_permissions
'ANONYMOUS_USER_ID' => ANONYMOUS,
'S_SELECT_VICTIM' => true,
- 'S_ALLOW_ALL_SELECT' => (sizeof($forum_id) > 5) ? false : true,
+ 'S_ALLOW_ALL_SELECT' => (count($forum_id) > 5) ? false : true,
'S_CAN_SELECT_USER' => ($auth->acl_get('a_authusers')) ? true : false,
'S_CAN_SELECT_GROUP' => ($auth->acl_get('a_authgroups')) ? true : false,
'S_HIDDEN_FIELDS' => $s_hidden_fields)
);
// Let the forum names being displayed
- if (sizeof($forum_id))
+ if (count($forum_id))
{
$sql = 'SELECT forum_name
FROM ' . FORUMS_TABLE . '
@@ -506,7 +510,7 @@ class acp_permissions
$db->sql_freeresult($result);
$template->assign_vars(array(
- 'S_FORUM_NAMES' => (sizeof($forum_names)) ? true : false,
+ 'S_FORUM_NAMES' => (count($forum_names)) ? true : false,
'FORUM_NAMES' => implode($user->lang['COMMA_SEPARATOR'], $forum_names))
);
}
@@ -523,13 +527,13 @@ class acp_permissions
));
// Do not allow forum_ids being set and no other setting defined (will bog down the server too much)
- if (sizeof($forum_id) && !sizeof($user_id) && !sizeof($group_id))
+ if (count($forum_id) && !count($user_id) && !count($group_id))
{
trigger_error($user->lang['ONLY_FORUM_DEFINED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$template->assign_vars(array(
- 'S_PERMISSION_DROPDOWN' => (sizeof($this->permission_dropdown) > 1) ? $this->build_permission_dropdown($this->permission_dropdown, $permission_type, $permission_scope) : false,
+ 'S_PERMISSION_DROPDOWN' => (count($this->permission_dropdown) > 1) ? $this->build_permission_dropdown($this->permission_dropdown, $permission_type, $permission_scope) : false,
'L_PERMISSION_TYPE' => $this->permissions->get_type_lang($permission_type),
'U_ACTION' => $this->u_action,
@@ -542,8 +546,8 @@ class acp_permissions
'S_SETTING_PERMISSIONS' => true)
);
- $hold_ary = $auth_admin->get_mask('set', (sizeof($user_id)) ? $user_id : false, (sizeof($group_id)) ? $group_id : false, (sizeof($forum_id)) ? $forum_id : false, $permission_type, $permission_scope, ACL_NO);
- $auth_admin->display_mask('set', $permission_type, $hold_ary, ((sizeof($user_id)) ? 'user' : 'group'), (($permission_scope == 'local') ? true : false));
+ $hold_ary = $auth_admin->get_mask('set', (count($user_id)) ? $user_id : false, (count($group_id)) ? $group_id : false, (count($forum_id)) ? $forum_id : false, $permission_type, $permission_scope, ACL_NO);
+ $auth_admin->display_mask('set', $permission_type, $hold_ary, ((count($user_id)) ? 'user' : 'group'), (($permission_scope == 'local') ? true : false));
}
else
{
@@ -551,8 +555,8 @@ class acp_permissions
'S_VIEWING_PERMISSIONS' => true)
);
- $hold_ary = $auth_admin->get_mask('view', (sizeof($user_id)) ? $user_id : false, (sizeof($group_id)) ? $group_id : false, (sizeof($forum_id)) ? $forum_id : false, $permission_type, $permission_scope, ACL_NEVER);
- $auth_admin->display_mask('view', $permission_type, $hold_ary, ((sizeof($user_id)) ? 'user' : 'group'), (($permission_scope == 'local') ? true : false));
+ $hold_ary = $auth_admin->get_mask('view', (count($user_id)) ? $user_id : false, (count($group_id)) ? $group_id : false, (count($forum_id)) ? $forum_id : false, $permission_type, $permission_scope, ACL_NEVER);
+ $auth_admin->display_mask('view', $permission_type, $hold_ary, ((count($user_id)) ? 'user' : 'group'), (($permission_scope == 'local') ? true : false));
}
}
@@ -648,7 +652,7 @@ class acp_permissions
break;
}
- if (sizeof($ids))
+ if (count($ids))
{
$sql = "SELECT $sql_id
FROM $table
@@ -663,7 +667,7 @@ class acp_permissions
$db->sql_freeresult($result);
}
- if (!sizeof($ids))
+ if (!count($ids))
{
trigger_error($user->lang['SELECTED_' . strtoupper($mode) . '_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -672,24 +676,23 @@ class acp_permissions
/**
* Apply permissions
*/
- function set_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id)
+ function set_permissions($mode, $permission_type, $auth_admin, &$user_id, &$group_id)
{
global $db, $cache, $user, $auth;
global $request;
- $psubmit = request_var('psubmit', array(0 => array(0 => 0)));
+ $psubmit = $request->variable('psubmit', array(0 => array(0 => 0)));
// User or group to be set?
- $ug_type = (sizeof($user_id)) ? 'user' : 'group';
+ $ug_type = (count($user_id)) ? 'user' : 'group';
// Check the permission setting again
if (!$auth->acl_get('a_' . str_replace('_', '', $permission_type) . 'auth') || !$auth->acl_get('a_auth' . $ug_type . 's'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- $ug_id = $forum_id = 0;
-
// We loop through the auth settings defined in our submit
list($ug_id, ) = each($psubmit);
list($forum_id, ) = each($psubmit[$ug_id]);
@@ -707,12 +710,12 @@ class acp_permissions
$assigned_role = (isset($roles[$ug_id][$forum_id])) ? (int) $roles[$ug_id][$forum_id] : 0;
// Do the admin want to set these permissions to other items too?
- $inherit = request_var('inherit', array(0 => array(0)));
+ $inherit = $request->variable('inherit', array(0 => array(0)));
$ug_id = array($ug_id);
$forum_id = array($forum_id);
- if (sizeof($inherit))
+ if (count($inherit))
{
foreach ($inherit as $_ug_id => $forum_id_ary)
{
@@ -762,17 +765,18 @@ class acp_permissions
/**
* Apply all permissions
*/
- function set_all_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id)
+ function set_all_permissions($mode, $permission_type, $auth_admin, &$user_id, &$group_id)
{
global $db, $cache, $user, $auth;
global $request;
// User or group to be set?
- $ug_type = (sizeof($user_id)) ? 'user' : 'group';
+ $ug_type = (count($user_id)) ? 'user' : 'group';
// Check the permission setting again
if (!$auth->acl_get('a_' . str_replace('_', '', $permission_type) . 'auth') || !$auth->acl_get('a_auth' . $ug_type . 's'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -866,7 +870,7 @@ class acp_permissions
}
}
- if (sizeof(array_diff_assoc($auth_settings, $test_auth_settings)))
+ if (count(array_diff_assoc($auth_settings, $test_auth_settings)))
{
return false;
}
@@ -877,20 +881,21 @@ class acp_permissions
/**
* Remove permissions
*/
- function remove_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id, &$forum_id)
+ function remove_permissions($mode, $permission_type, $auth_admin, &$user_id, &$group_id, &$forum_id)
{
global $user, $db, $cache, $auth;
// User or group to be set?
- $ug_type = (sizeof($user_id)) ? 'user' : 'group';
+ $ug_type = (count($user_id)) ? 'user' : 'group';
// Check the permission setting again
if (!$auth->acl_get('a_' . str_replace('_', '', $permission_type) . 'auth') || !$auth->acl_get('a_auth' . $ug_type . 's'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- $auth_admin->acl_delete($ug_type, (($ug_type == 'user') ? $user_id : $group_id), (sizeof($forum_id) ? $forum_id : false), $permission_type);
+ $auth_admin->acl_delete($ug_type, (($ug_type == 'user') ? $user_id : $group_id), (count($forum_id) ? $forum_id : false), $permission_type);
// Do we need to recache the moderator lists?
if ($permission_type == 'm_')
@@ -898,7 +903,7 @@ class acp_permissions
phpbb_cache_moderators($db, $cache, $auth);
}
- $this->log_action($mode, 'del', $permission_type, $ug_type, (($ug_type == 'user') ? $user_id : $group_id), (sizeof($forum_id) ? $forum_id : array(0 => 0)));
+ $this->log_action($mode, 'del', $permission_type, $ug_type, (($ug_type == 'user') ? $user_id : $group_id), (count($forum_id) ? $forum_id : array(0 => 0)));
if ($mode == 'setting_forum_local' || $mode == 'setting_mod_local')
{
@@ -917,7 +922,7 @@ class acp_permissions
*/
function log_action($mode, $action, $permission_type, $ug_type, $ug_id, $forum_id)
{
- global $db, $user;
+ global $db, $user, $phpbb_log, $phpbb_container;
if (!is_array($ug_id))
{
@@ -934,10 +939,14 @@ class acp_permissions
$sql .= $db->sql_in_set(($ug_type == 'group') ? 'group_id' : 'user_id', array_map('intval', $ug_id));
$result = $db->sql_query($sql);
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
$l_ug_list = '';
while ($row = $db->sql_fetchrow($result))
{
- $l_ug_list .= (($l_ug_list != '') ? ', ' : '') . ((isset($row['group_type']) && $row['group_type'] == GROUP_SPECIAL) ? '<span class="sep">' . $user->lang['G_' . $row['name']] . '</span>' : $row['name']);
+ $group_name = $group_helper->get_name($row['name']);
+ $l_ug_list .= (($l_ug_list != '') ? ', ' : '') . ((isset($row['group_type']) && $row['group_type'] == GROUP_SPECIAL) ? '<span class="sep">' . $group_name . '</span>' : $group_name);
}
$db->sql_freeresult($result);
@@ -945,7 +954,7 @@ class acp_permissions
if ($forum_id[0] == 0)
{
- add_log('admin', 'LOG_ACL_' . strtoupper($action) . '_' . strtoupper($mode) . '_' . strtoupper($permission_type), $l_ug_list);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ACL_' . strtoupper($action) . '_' . strtoupper($mode) . '_' . strtoupper($permission_type), false, array($l_ug_list));
}
else
{
@@ -962,7 +971,7 @@ class acp_permissions
}
$db->sql_freeresult($result);
- add_log('admin', 'LOG_ACL_' . strtoupper($action) . '_' . strtoupper($mode) . '_' . strtoupper($permission_type), $l_forum_list, $l_ug_list);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ACL_' . strtoupper($action) . '_' . strtoupper($mode) . '_' . strtoupper($permission_type), false, array($l_forum_list, $l_ug_list));
}
}
@@ -971,7 +980,7 @@ class acp_permissions
*/
function permission_trace($user_id, $forum_id, $permission)
{
- global $db, $template, $user, $auth;
+ global $db, $template, $user, $auth, $request, $phpbb_container;
if ($user_id != $user->data['user_id'])
{
@@ -987,6 +996,9 @@ class acp_permissions
trigger_error('NO_USERS', E_USER_ERROR);
}
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
$forum_name = false;
if ($forum_id)
@@ -999,7 +1011,7 @@ class acp_permissions
$db->sql_freeresult($result);
}
- $back = request_var('back', 0);
+ $back = $request->variable('back', 0);
$template->assign_vars(array(
'PERMISSION' => $this->permissions->get_permission_lang($permission),
@@ -1033,7 +1045,7 @@ class acp_permissions
{
$groups[$row['group_id']] = array(
'auth_setting' => ACL_NO,
- 'group_name' => ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']
+ 'group_name' => $group_helper->get_name($row['group_name']),
);
}
$db->sql_freeresult($result);
@@ -1041,7 +1053,7 @@ class acp_permissions
$total = ACL_NO;
$add_key = (($forum_id) ? '_LOCAL' : '');
- if (sizeof($groups))
+ if (count($groups))
{
// Get group auth settings
$hold_ary = $auth->acl_group_raw_data(array_keys($groups), $permission, $forum_id);
@@ -1087,7 +1099,7 @@ class acp_permissions
// Get user specific permission... globally or for this forum
$hold_ary = $auth->acl_user_raw_data($user_id, $permission, $forum_id);
- $auth_setting = (!sizeof($hold_ary)) ? ACL_NO : $hold_ary[$user_id][$forum_id][$permission];
+ $auth_setting = (!count($hold_ary)) ? ACL_NO : $hold_ary[$user_id][$forum_id][$permission];
switch ($auth_setting)
{
@@ -1190,7 +1202,7 @@ class acp_permissions
*/
function copy_forum_permissions()
{
- global $db, $auth, $cache, $template, $user;
+ global $db, $auth, $cache, $template, $user, $request;
$user->add_lang('acp/forums');
@@ -1198,8 +1210,8 @@ class acp_permissions
if ($submit)
{
- $src = request_var('src_forum_id', 0);
- $dest = request_var('dest_forum_ids', array(0));
+ $src = $request->variable('src_forum_id', 0);
+ $dest = $request->variable('dest_forum_ids', array(0));
if (confirm_box(true))
{
@@ -1241,9 +1253,12 @@ class acp_permissions
*/
function retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type)
{
- global $db, $user;
+ global $db, $phpbb_container;
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
- $sql_forum_id = ($permission_scope == 'global') ? 'AND a.forum_id = 0' : ((sizeof($forum_id)) ? 'AND ' . $db->sql_in_set('a.forum_id', $forum_id) : 'AND a.forum_id <> 0');
+ $sql_forum_id = ($permission_scope == 'global') ? 'AND a.forum_id = 0' : ((count($forum_id)) ? 'AND ' . $db->sql_in_set('a.forum_id', $forum_id) : 'AND a.forum_id <> 0');
// Permission options are only able to be a permission set... therefore we will pre-fetch the possible options and also the possible roles
$option_ids = $role_ids = array();
@@ -1259,7 +1274,7 @@ class acp_permissions
}
$db->sql_freeresult($result);
- if (sizeof($option_ids))
+ if (count($option_ids))
{
$sql = 'SELECT DISTINCT role_id
FROM ' . ACL_ROLES_DATA_TABLE . '
@@ -1273,15 +1288,15 @@ class acp_permissions
$db->sql_freeresult($result);
}
- if (sizeof($option_ids) && sizeof($role_ids))
+ if (count($option_ids) && count($role_ids))
{
$sql_where = 'AND (' . $db->sql_in_set('a.auth_option_id', $option_ids) . ' OR ' . $db->sql_in_set('a.auth_role_id', $role_ids) . ')';
}
- else if (sizeof($role_ids))
+ else if (count($role_ids))
{
$sql_where = 'AND ' . $db->sql_in_set('a.auth_role_id', $role_ids);
}
- else if (sizeof($option_ids))
+ else if (count($option_ids))
{
$sql_where = 'AND ' . $db->sql_in_set('a.auth_option_id', $option_ids);
}
@@ -1316,7 +1331,7 @@ class acp_permissions
$defined_group_ids = array();
while ($row = $db->sql_fetchrow($result))
{
- $s_defined_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '">' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>';
+ $s_defined_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '">' . $group_helper->get_name($row['group_name']) . '</option>';
$defined_group_ids[] = $row['group_id'];
}
$db->sql_freeresult($result);
diff --git a/phpBB/includes/acp/acp_php_info.php b/phpBB/includes/acp/acp_php_info.php
index 810a111edb..2a1afe80d4 100644
--- a/phpBB/includes/acp/acp_php_info.php
+++ b/phpBB/includes/acp/acp_php_info.php
@@ -25,8 +25,7 @@ class acp_php_info
function main($id, $mode)
{
- global $db, $user, $auth, $template;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $template;
if ($mode != 'info')
{
diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php
index 9e6cc49522..49da7d84a4 100644
--- a/phpBB/includes/acp/acp_profile.php
+++ b/phpBB/includes/acp/acp_profile.php
@@ -25,13 +25,17 @@ class acp_profile
var $edit_lang_id;
var $lang_defs;
+
+ /**
+ * @var \phpbb\di\service_collection
+ */
protected $type_collection;
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $cache;
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix;
- global $request, $phpbb_container, $phpbb_dispatcher;
+ global $config, $db, $user, $template;
+ global $phpbb_root_path, $phpEx;
+ global $request, $phpbb_container, $phpbb_log, $phpbb_dispatcher;
if (!function_exists('generate_smilies'))
{
@@ -48,10 +52,9 @@ class acp_profile
$this->page_title = 'ACP_CUSTOM_PROFILE_FIELDS';
$field_id = $request->variable('field_id', 0);
- $action = (isset($_POST['create'])) ? 'create' : request_var('action', '');
+ $action = (isset($_POST['create'])) ? 'create' : $request->variable('action', '');
$error = array();
- $s_hidden_fields = '';
$form_key = 'acp_profile';
add_form_key($form_key);
@@ -61,6 +64,7 @@ class acp_profile
trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING);
}
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$this->type_collection = $phpbb_container->get('profilefields.type_collection');
@@ -122,6 +126,7 @@ class acp_profile
$db->sql_query('DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . " WHERE field_id = $field_id");
$db->sql_query('DELETE FROM ' . PROFILE_LANG_TABLE . " WHERE field_id = $field_id");
+ /* @var $db_tools \phpbb\db\tools\tools_interface */
$db_tools = $phpbb_container->get('dbal.tools');
$db_tools->sql_column_remove(PROFILE_FIELDS_DATA_TABLE, 'pf_' . $field_ident);
@@ -147,7 +152,7 @@ class acp_profile
$db->sql_transaction('commit');
- add_log('admin', 'LOG_PROFILE_FIELD_REMOVED', $field_ident);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PROFILE_FIELD_REMOVED', false, array($field_ident));
trigger_error($user->lang['REMOVED_PROFILE_FIELD'] . adm_back_link($this->u_action));
}
else
@@ -193,7 +198,7 @@ class acp_profile
$field_ident = (string) $db->sql_fetchfield('field_ident');
$db->sql_freeresult($result);
- add_log('admin', 'LOG_PROFILE_FIELD_ACTIVATE', $field_ident);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PROFILE_FIELD_ACTIVATE', false, array($field_ident));
if ($request->is_ajax())
{
@@ -234,7 +239,7 @@ class acp_profile
));
}
- add_log('admin', 'LOG_PROFILE_FIELD_DEACTIVATE', $field_ident);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PROFILE_FIELD_DEACTIVATE', false, array($field_ident));
trigger_error($user->lang['PROFILE_FIELD_DEACTIVATED'] . adm_back_link($this->u_action));
@@ -280,7 +285,7 @@ class acp_profile
case 'create':
case 'edit':
- $step = request_var('step', 1);
+ $step = $request->variable('step', 1);
$submit = (isset($_REQUEST['next']) || isset($_REQUEST['prev'])) ? true : false;
$save = (isset($_REQUEST['save'])) ? true : false;
@@ -344,7 +349,7 @@ class acp_profile
// We are adding a new field, define basic params
$lang_options = $field_row = array();
- $field_type = request_var('field_type', '');
+ $field_type = $request->variable('field_type', '');
if (!isset($this->type_collection[$field_type]))
{
@@ -353,7 +358,7 @@ class acp_profile
$profile_field = $this->type_collection[$field_type];
$field_row = array_merge($profile_field->get_default_option_values(), array(
- 'field_ident' => str_replace(' ', '_', utf8_clean_string(request_var('field_ident', '', true))),
+ 'field_ident' => str_replace(' ', '_', utf8_clean_string($request->variable('field_ident', '', true))),
'field_required' => 0,
'field_show_novalue'=> 0,
'field_hide' => 0,
@@ -366,7 +371,7 @@ class acp_profile
'field_is_contact' => 0,
'field_contact_desc'=> '',
'field_contact_url' => '',
- 'lang_name' => utf8_normalize_nfc(request_var('field_ident', '', true)),
+ 'lang_name' => $request->variable('field_ident', '', true),
'lang_explain' => '',
'lang_default_value'=> '')
);
@@ -422,7 +427,7 @@ class acp_profile
$options = $profile_field->prepare_options_form($exclude, $visibility_ary);
- $cp->vars['field_ident'] = ($action == 'create' && $step == 1) ? utf8_clean_string(request_var('field_ident', $field_row['field_ident'], true)) : request_var('field_ident', $field_row['field_ident']);
+ $cp->vars['field_ident'] = ($action == 'create' && $step == 1) ? utf8_clean_string($request->variable('field_ident', $field_row['field_ident'], true)) : $request->variable('field_ident', $field_row['field_ident']);
$cp->vars['lang_name'] = $request->variable('lang_name', $field_row['lang_name'], true);
$cp->vars['lang_explain'] = $request->variable('lang_explain', $field_row['lang_explain'], true);
$cp->vars['lang_default_value'] = $request->variable('lang_default_value', $field_row['lang_default_value'], true);
@@ -441,7 +446,7 @@ class acp_profile
{
$exploded_options = (is_array($options)) ? $options : explode("\n", $options);
- if (sizeof($exploded_options) == sizeof($lang_options) || $action == 'create')
+ if (count($exploded_options) == count($lang_options) || $action == 'create')
{
// The number of options in the field is equal to the number of options already in the database
// Or we are creating a new dropdown list.
@@ -461,7 +466,7 @@ class acp_profile
// step 2
foreach ($exclude[2] as $key)
{
- $var = utf8_normalize_nfc(request_var($key, $field_row[$key], true));
+ $var = $request->variable($key, $field_row[$key], true);
$field_data = $cp->vars;
$var = $profile_field->get_excluded_options($key, $action, $var, $field_data, 2);
@@ -507,7 +512,7 @@ class acp_profile
foreach ($exclude[3] as $key)
{
- $cp->vars[$key] = utf8_normalize_nfc(request_var($key, array(0 => ''), true));
+ $cp->vars[$key] = $request->variable($key, array(0 => ''), true);
if (!$cp->vars[$key] && $action == 'edit')
{
@@ -562,7 +567,7 @@ class acp_profile
}
}
- if (sizeof($error))
+ if (count($error))
{
$submit = false;
}
@@ -595,9 +600,9 @@ class acp_profile
$s_hidden_fields .= build_hidden_fields($_new_key_ary);
}
- if (!sizeof($error))
+ if (!count($error))
{
- if (($step == 3 && (sizeof($this->lang_defs['iso']) == 1 || $save)) || ($action == 'edit' && $save))
+ if (($step == 3 && (count($this->lang_defs['iso']) == 1 || $save)) || ($action == 'edit' && $save))
{
if (!check_form_key($form_key))
{
@@ -611,7 +616,7 @@ class acp_profile
$template->assign_vars(array(
'S_EDIT' => true,
'S_EDIT_MODE' => ($action == 'edit') ? true : false,
- 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '',
'L_TITLE' => $user->lang['STEP_' . $step . '_TITLE_' . strtoupper($action)],
'L_EXPLAIN' => $user->lang['STEP_' . $step . '_EXPLAIN_' . strtoupper($action)],
@@ -659,7 +664,7 @@ class acp_profile
$template->assign_vars(array(
'S_STEP_TWO' => true,
- 'L_NEXT_STEP' => (sizeof($this->lang_defs['iso']) == 1) ? $user->lang['SAVE'] : $user->lang['PROFILE_LANG_OPTIONS'])
+ 'L_NEXT_STEP' => (count($this->lang_defs['iso']) == 1) ? $user->lang['SAVE'] : $user->lang['PROFILE_LANG_OPTIONS'])
);
// Build options based on profile type
@@ -733,6 +738,32 @@ class acp_profile
break;
}
+ $tpl_name = $this->tpl_name;
+ $page_title = $this->page_title;
+ $u_action = $this->u_action;
+
+ /**
+ * Event to handle actions on the ACP profile fields page
+ *
+ * @event core.acp_profile_action
+ * @var string action Action that is being performed
+ * @var string tpl_name Template file to load
+ * @var string page_title Page title
+ * @var string u_action The URL we are at, read only
+ * @since 3.2.2-RC1
+ */
+ $vars = array(
+ 'action',
+ 'tpl_name',
+ 'page_title',
+ 'u_action',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.acp_profile_action', compact($vars)));
+
+ $this->tpl_name = $tpl_name;
+ $this->page_title = $page_title;
+ unset($u_action);
+
$sql = 'SELECT *
FROM ' . PROFILE_FIELDS_TABLE . '
ORDER BY field_order';
@@ -745,7 +776,7 @@ class acp_profile
$active_value = (!$row['field_active']) ? 'activate' : 'deactivate';
$id = $row['field_id'];
- $s_need_edit = (sizeof($this->lang_defs['diff'][$row['field_id']])) ? true : false;
+ $s_need_edit = (count($this->lang_defs['diff'][$row['field_id']])) ? true : false;
if ($s_need_edit)
{
@@ -757,7 +788,8 @@ class acp_profile
continue;
}
$profile_field = $this->type_collection[$row['field_type']];
- $template->assign_block_vars('fields', array(
+
+ $field_block = array(
'FIELD_IDENT' => $row['field_ident'],
'FIELD_TYPE' => $profile_field->get_name(),
@@ -769,8 +801,26 @@ class acp_profile
'U_MOVE_UP' => $this->u_action . "&amp;action=move_up&amp;field_id=$id" . '&amp;hash=' . generate_link_hash('acp_profile'),
'U_MOVE_DOWN' => $this->u_action . "&amp;action=move_down&amp;field_id=$id" . '&amp;hash=' . generate_link_hash('acp_profile'),
- 'S_NEED_EDIT' => $s_need_edit)
+ 'S_NEED_EDIT' => $s_need_edit,
+ );
+
+ /**
+ * Event to modify profile field data before it is assigned to the template
+ *
+ * @event core.acp_profile_modify_profile_row
+ * @var array row Array with data for the current profile field
+ * @var array field_block Template data that is being assigned to the 'fields' block
+ * @var object profile_field A profile field instance, implements \phpbb\profilefields\type\type_base
+ * @since 3.2.2-RC1
+ */
+ $vars = array(
+ 'row',
+ 'field_block',
+ 'profile_field',
);
+ extract($phpbb_dispatcher->trigger_event('core.acp_profile_modify_profile_row', compact($vars)));
+
+ $template->assign_block_vars('fields', $field_block);
}
$db->sql_freeresult($result);
@@ -795,9 +845,9 @@ class acp_profile
/**
* Build all Language specific options
*/
- function build_language_options(&$cp, $field_type, $action = 'create')
+ function build_language_options($cp, $field_type, $action = 'create')
{
- global $user, $config, $db, $phpbb_container;
+ global $user, $config, $db, $request;
$default_lang_id = (!empty($this->edit_lang_id)) ? $this->edit_lang_id : $this->lang_defs['iso'][$config['default_lang']];
@@ -838,7 +888,7 @@ class acp_profile
$lang_options[$lang_id]['lang_iso'] = $lang_iso;
foreach ($options as $field => $field_type)
{
- $value = ($action == 'create') ? utf8_normalize_nfc(request_var('l_' . $field, array(0 => ''), true)) : $cp->vars['l_' . $field];
+ $value = ($action == 'create') ? $request->variable('l_' . $field, array(0 => ''), true) : $cp->vars['l_' . $field];
if ($field == 'lang_options')
{
$var = (!isset($cp->vars['l_lang_options'][$lang_id]) || !is_array($cp->vars['l_lang_options'][$lang_id])) ? $cp->vars['lang_options'] : $cp->vars['l_lang_options'][$lang_id];
@@ -892,11 +942,11 @@ class acp_profile
/**
* Save Profile Field
*/
- function save_profile_field(&$cp, $field_type, $action = 'create')
+ function save_profile_field($cp, $field_type, $action = 'create')
{
- global $db, $config, $user, $phpbb_container, $phpbb_dispatcher;
+ global $db, $config, $user, $phpbb_container, $phpbb_log, $request, $phpbb_dispatcher;
- $field_id = request_var('field_id', 0);
+ $field_id = $request->variable('field_id', 0);
// Collect all information, if something is going wrong, abort the operation
$profile_sql = $profile_lang = $empty_lang = $profile_lang_fields = array();
@@ -983,7 +1033,7 @@ class acp_profile
if ($action == 'create')
{
$field_ident = 'pf_' . $field_ident;
-
+ /* @var $db_tools \phpbb\db\tools\tools_interface */
$db_tools = $phpbb_container->get('dbal.tools');
$db_tools->sql_column_add(PROFILE_FIELDS_DATA_TABLE, $field_ident, array($profile_field->get_database_column_type(), null));
}
@@ -1006,7 +1056,7 @@ class acp_profile
$this->update_insert(PROFILE_LANG_TABLE, $sql_ary, array('field_id' => $field_id, 'lang_id' => $default_lang_id));
}
- if (is_array($cp->vars['l_lang_name']) && sizeof($cp->vars['l_lang_name']))
+ if (is_array($cp->vars['l_lang_name']) && count($cp->vars['l_lang_name']))
{
foreach ($cp->vars['l_lang_name'] as $lang_id => $data)
{
@@ -1082,7 +1132,7 @@ class acp_profile
}
}
- if (is_array($cp->vars['l_lang_options']) && sizeof($cp->vars['l_lang_options']))
+ if (is_array($cp->vars['l_lang_options']) && count($cp->vars['l_lang_options']))
{
$empty_lang = array();
@@ -1093,7 +1143,7 @@ class acp_profile
$lang_ary = explode("\n", $lang_ary);
}
- if (sizeof($lang_ary) != sizeof($cp->vars['lang_options']))
+ if (count($lang_ary) != count($cp->vars['lang_options']))
{
$empty_lang[$lang_id] = true;
}
@@ -1145,7 +1195,7 @@ class acp_profile
}
}
- if (sizeof($profile_lang_fields))
+ if (count($profile_lang_fields))
{
foreach ($profile_lang_fields as $sql)
{
@@ -1182,12 +1232,12 @@ class acp_profile
if ($action == 'edit')
{
- add_log('admin', 'LOG_PROFILE_FIELD_EDIT', $cp->vars['field_ident'] . ':' . $cp->vars['lang_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PROFILE_FIELD_EDIT', false, array($cp->vars['field_ident'] . ':' . $cp->vars['lang_name']));
trigger_error($user->lang['CHANGED_PROFILE_FIELD'] . adm_back_link($this->u_action));
}
else
{
- add_log('admin', 'LOG_PROFILE_FIELD_CREATE', substr($field_ident, 3) . ':' . $cp->vars['lang_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PROFILE_FIELD_CREATE', false, array(substr($field_ident, 3) . ':' . $cp->vars['lang_name']));
trigger_error($user->lang['ADDED_PROFILE_FIELD'] . adm_back_link($this->u_action));
}
}
@@ -1208,7 +1258,7 @@ class acp_profile
$where_sql[] = $key . ' = ' . ((is_string($value)) ? "'" . $db->sql_escape($value) . "'" : (int) $value);
}
- if (!sizeof($where_sql))
+ if (!count($where_sql))
{
return;
}
@@ -1224,14 +1274,14 @@ class acp_profile
{
$sql_ary = array_merge($where_fields, $sql_ary);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_query("INSERT INTO $table " . $db->sql_build_array('INSERT', $sql_ary));
}
}
else
{
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$sql = "UPDATE $table SET " . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE ' . implode(' AND ', $where_sql);
diff --git a/phpBB/includes/acp/acp_prune.php b/phpBB/includes/acp/acp_prune.php
index 98d9caabdd..c5f7789de8 100644
--- a/phpBB/includes/acp/acp_prune.php
+++ b/phpBB/includes/acp/acp_prune.php
@@ -25,7 +25,7 @@ class acp_prune
function main($id, $mode)
{
- global $user, $phpEx, $phpbb_admin_path, $phpbb_root_path;
+ global $user, $phpEx, $phpbb_root_path;
$user->add_lang('acp/prune');
@@ -55,11 +55,10 @@ class acp_prune
*/
function prune_forums($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $auth, $template, $phpbb_log, $request, $phpbb_dispatcher;
- $all_forums = request_var('all_forums', 0);
- $forum_id = request_var('f', array(0));
+ $all_forums = $request->variable('all_forums', 0);
+ $forum_id = $request->variable('f', array(0));
$submit = (isset($_POST['submit'])) ? true : false;
if ($all_forums)
@@ -81,14 +80,14 @@ class acp_prune
{
if (confirm_box(true))
{
- $prune_posted = request_var('prune_days', 0);
- $prune_viewed = request_var('prune_vieweddays', 0);
+ $prune_posted = $request->variable('prune_days', 0);
+ $prune_viewed = $request->variable('prune_vieweddays', 0);
$prune_all = (!$prune_posted && !$prune_viewed) ? true : false;
$prune_flags = 0;
- $prune_flags += (request_var('prune_old_polls', 0)) ? 2 : 0;
- $prune_flags += (request_var('prune_announce', 0)) ? 4 : 0;
- $prune_flags += (request_var('prune_sticky', 0)) ? 8 : 0;
+ $prune_flags += ($request->variable('prune_old_polls', 0)) ? 2 : 0;
+ $prune_flags += ($request->variable('prune_announce', 0)) ? 4 : 0;
+ $prune_flags += ($request->variable('prune_sticky', 0)) ? 8 : 0;
// Convert days to seconds for timestamp functions...
$prunedate_posted = time() - ($prune_posted * 86400);
@@ -98,7 +97,7 @@ class acp_prune
'S_PRUNED' => true)
);
- $sql_forum = (sizeof($forum_id)) ? ' AND ' . $db->sql_in_set('forum_id', $forum_id) : '';
+ $sql_forum = (count($forum_id)) ? ' AND ' . $db->sql_in_set('forum_id', $forum_id) : '';
// Get a list of forum's or the data for the forum that we are pruning.
$sql = 'SELECT forum_id, forum_name
@@ -157,7 +156,8 @@ class acp_prune
// Sync all pruned forums at once
sync('forum', 'forum_id', $prune_ids, true, true);
- add_log('admin', 'LOG_PRUNE', $log_data);
+
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_PRUNE', false, array($log_data));
}
$db->sql_freeresult($result);
@@ -165,25 +165,37 @@ class acp_prune
}
else
{
- confirm_box(false, $user->lang['PRUNE_FORUM_CONFIRM'], build_hidden_fields(array(
+ $hidden_fields = array(
'i' => $id,
'mode' => $mode,
'submit' => 1,
'all_forums' => $all_forums,
'f' => $forum_id,
- 'prune_days' => request_var('prune_days', 0),
- 'prune_vieweddays' => request_var('prune_vieweddays', 0),
- 'prune_old_polls' => request_var('prune_old_polls', 0),
- 'prune_announce' => request_var('prune_announce', 0),
- 'prune_sticky' => request_var('prune_sticky', 0),
- )));
+ 'prune_days' => $request->variable('prune_days', 0),
+ 'prune_vieweddays' => $request->variable('prune_vieweddays', 0),
+ 'prune_old_polls' => $request->variable('prune_old_polls', 0),
+ 'prune_announce' => $request->variable('prune_announce', 0),
+ 'prune_sticky' => $request->variable('prune_sticky', 0),
+ );
+
+ /**
+ * Use this event to pass data from the prune form to the confirmation screen
+ *
+ * @event core.prune_forums_settings_confirm
+ * @var array hidden_fields Hidden fields that are passed through the confirm screen
+ * @since 3.2.2-RC1
+ */
+ $vars = array('hidden_fields');
+ extract($phpbb_dispatcher->trigger_event('core.prune_forums_settings_confirm', compact($vars)));
+
+ confirm_box(false, $user->lang['PRUNE_FORUM_CONFIRM'], build_hidden_fields($hidden_fields));
}
}
// If they haven't selected a forum for pruning yet then
// display a select box to use for pruning.
- if (!sizeof($forum_id))
+ if (!count($forum_id))
{
$template->assign_vars(array(
'U_ACTION' => $this->u_action,
@@ -215,15 +227,27 @@ class acp_prune
$db->sql_freeresult($result);
- $l_selected_forums = (sizeof($forum_id) == 1) ? 'SELECTED_FORUM' : 'SELECTED_FORUMS';
+ $l_selected_forums = (count($forum_id) == 1) ? 'SELECTED_FORUM' : 'SELECTED_FORUMS';
- $template->assign_vars(array(
+ $template_data = array(
'L_SELECTED_FORUMS' => $user->lang[$l_selected_forums],
'U_ACTION' => $this->u_action,
'U_BACK' => $this->u_action,
'FORUM_LIST' => $forum_list,
- 'S_HIDDEN_FIELDS' => $s_hidden_fields)
+ 'S_HIDDEN_FIELDS' => $s_hidden_fields,
);
+
+ /**
+ * Event to add/modify prune forums settings template data
+ *
+ * @event core.prune_forums_settings_template_data
+ * @var array template_data Array with form template data
+ * @since 3.2.2-RC1
+ */
+ $vars = array('template_data');
+ extract($phpbb_dispatcher->trigger_event('core.prune_forums_settings_template_data', compact($vars)));
+
+ $template->assign_vars($template_data);
}
}
@@ -232,8 +256,11 @@ class acp_prune
*/
function prune_users($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $auth, $template, $phpbb_log, $request;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx, $phpbb_container;
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
$user->add_lang('memberlist');
@@ -241,15 +268,15 @@ class acp_prune
if ($prune)
{
- $action = request_var('action', 'deactivate');
- $deleteposts = request_var('deleteposts', 0);
+ $action = $request->variable('action', 'deactivate');
+ $deleteposts = $request->variable('deleteposts', 0);
if (confirm_box(true))
{
$user_ids = $usernames = array();
$this->get_prune_users($user_ids, $usernames);
- if (sizeof($user_ids))
+ if (count($user_ids))
{
if ($action == 'deactivate')
{
@@ -272,7 +299,7 @@ class acp_prune
}
}
- add_log('admin', $l_log, implode(', ', $usernames));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $l_log, false, array(implode(', ', $usernames)));
$msg = $user->lang['USER_' . strtoupper($action) . '_SUCCESS'];
}
else
@@ -288,7 +315,7 @@ class acp_prune
$user_ids = $usernames = array();
$this->get_prune_users($user_ids, $usernames);
- if (!sizeof($user_ids))
+ if (!count($user_ids))
{
trigger_error($user->lang['USER_PRUNE_FAILURE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
@@ -314,8 +341,8 @@ class acp_prune
'mode' => $mode,
'prune' => 1,
- 'deleteposts' => request_var('deleteposts', 0),
- 'action' => request_var('action', ''),
+ 'deleteposts' => $request->variable('deleteposts', 0),
+ 'action' => $request->variable('action', ''),
)), 'confirm_body_prune.html');
}
}
@@ -345,7 +372,7 @@ class acp_prune
$s_group_list = '';
while ($row = $db->sql_fetchrow($result))
{
- $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</option>';
+ $s_group_list .= '<option value="' . $row['group_id'] . '">' . $group_helper->get_name($row['group_name']) . '</option>';
}
$db->sql_freeresult($result);
@@ -372,9 +399,9 @@ class acp_prune
{
global $user, $db, $request;
- $users_by_name = request_var('users', '', true);
- $users_by_id = request_var('user_ids', array(0));
- $group_id = request_var('group_id', 0);
+ $users_by_name = $request->variable('users', '', true);
+ $users_by_id = $request->variable('user_ids', array(0));
+ $group_id = $request->variable('group_id', 0);
$posts_on_queue = (trim($request->variable('posts_on_queue', '')) === '') ? false : $request->variable('posts_on_queue', 0);
if ($users_by_name)
@@ -391,15 +418,15 @@ class acp_prune
}
else
{
- $username = request_var('username', '', true);
- $email = request_var('email', '');
+ $username = $request->variable('username', '', true);
+ $email = $request->variable('email', '');
- $active_select = request_var('active_select', 'lt');
- $count_select = request_var('count_select', 'eq');
- $queue_select = request_var('queue_select', 'gt');
- $joined_before = request_var('joined_before', '');
- $joined_after = request_var('joined_after', '');
- $active = request_var('active', '');
+ $active_select = $request->variable('active_select', 'lt');
+ $count_select = $request->variable('count_select', 'eq');
+ $queue_select = $request->variable('queue_select', 'gt');
+ $joined_before = $request->variable('joined_before', '');
+ $joined_after = $request->variable('joined_after', '');
+ $active = $request->variable('active', '');
$count = ($request->variable('count', '') === '') ? false : $request->variable('count', 0);
@@ -431,13 +458,12 @@ class acp_prune
}
// implicit else when both arrays are empty do nothing
- if ((sizeof($active) && sizeof($active) != 3) || (sizeof($joined_before) && sizeof($joined_before) != 3) || (sizeof($joined_after) && sizeof($joined_after) != 3))
+ if ((count($active) && count($active) != 3) || (count($joined_before) && count($joined_before) != 3) || (count($joined_after) && count($joined_after) != 3))
{
trigger_error($user->lang['WRONG_ACTIVE_JOINED_DATE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
$key_match = array('lt' => '<', 'gt' => '>', 'eq' => '=');
- $sort_by_types = array('username', 'user_email', 'user_posts', 'user_regdate', 'user_lastvisit');
$where_sql = '';
$where_sql .= ($username) ? ' AND username_clean ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($username))) : '';
@@ -446,15 +472,15 @@ class acp_prune
$where_sql .= ($count !== false) ? " AND user_posts " . $key_match[$count_select] . ' ' . (int) $count . ' ' : '';
// First handle pruning of users who never logged in, last active date is 0000-00-00
- if (sizeof($active) && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0)
+ if (count($active) && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0)
{
$where_sql .= ' AND user_lastvisit = 0';
}
- else if (sizeof($active) && $active_select != 'lt')
+ else if (count($active) && $active_select != 'lt')
{
$where_sql .= ' AND user_lastvisit ' . $key_match[$active_select] . ' ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]);
}
- else if (sizeof($active))
+ else if (count($active))
{
$where_sql .= ' AND (user_lastvisit > 0 AND user_lastvisit < ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]) . ')';
}
@@ -511,6 +537,7 @@ class acp_prune
AND ug.user_id <> ' . ANONYMOUS . '
AND u.user_type <> ' . USER_FOUNDER . '
AND ug.user_pending = 0
+ AND ug.group_leader = 0
AND u.user_id = ug.user_id
' . (!empty($user_ids) ? ' AND ' . $db->sql_in_set('ug.user_id', $user_ids) : '');
$result = $db->sql_query($sql);
diff --git a/phpBB/includes/acp/acp_ranks.php b/phpBB/includes/acp/acp_ranks.php
index 5885de57ec..4d2b64d74c 100644
--- a/phpBB/includes/acp/acp_ranks.php
+++ b/phpBB/includes/acp/acp_ranks.php
@@ -25,16 +25,16 @@ class acp_ranks
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $request, $phpbb_dispatcher;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $template, $cache, $request, $phpbb_dispatcher;
+ global $config, $phpbb_root_path, $phpbb_admin_path, $phpbb_log;
$user->add_lang('acp/posting');
// Set up general vars
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : $action;
$action = (isset($_POST['save'])) ? 'save' : $action;
- $rank_id = request_var('id', 0);
+ $rank_id = $request->variable('id', 0);
$this->tpl_name = 'acp_ranks';
$this->page_title = 'ACP_MANAGE_RANKS';
@@ -50,10 +50,10 @@ class acp_ranks
{
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
- $rank_title = utf8_normalize_nfc(request_var('title', '', true));
- $special_rank = request_var('special_rank', 0);
- $min_posts = ($special_rank) ? 0 : max(0, request_var('min_posts', 0));
- $rank_image = request_var('rank_image', '');
+ $rank_title = $request->variable('title', '', true);
+ $special_rank = $request->variable('special_rank', 0);
+ $min_posts = ($special_rank) ? 0 : max(0, $request->variable('min_posts', 0));
+ $rank_image = $request->variable('rank_image', '');
// The rank image has to be a jpg, gif or png
if ($rank_image != '' && !preg_match('#(\.gif|\.png|\.jpg|\.jpeg)$#i', $rank_image))
@@ -89,14 +89,14 @@ class acp_ranks
$sql = 'UPDATE ' . RANKS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " WHERE rank_id = $rank_id";
$message = $user->lang['RANK_UPDATED'];
- add_log('admin', 'LOG_RANK_UPDATED', $rank_title);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RANK_UPDATED', false, array($rank_title));
}
else
{
$sql = 'INSERT INTO ' . RANKS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
$message = $user->lang['RANK_ADDED'];
- add_log('admin', 'LOG_RANK_ADDED', $rank_title);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RANK_ADDED', false, array($rank_title));
}
$db->sql_query($sql);
@@ -133,7 +133,7 @@ class acp_ranks
$cache->destroy('_ranks');
- add_log('admin', 'LOG_RANK_REMOVED', $rank_title);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_RANK_REMOVED', false, array($rank_title));
if ($request->is_ajax())
{
@@ -162,7 +162,7 @@ class acp_ranks
case 'edit':
case 'add':
- $data = $ranks = $existing_imgs = array();
+ $ranks = $existing_imgs = array();
$sql = 'SELECT *
FROM ' . RANKS_TABLE . '
diff --git a/phpBB/includes/acp/acp_reasons.php b/phpBB/includes/acp/acp_reasons.php
index bd40a88138..dfb2ccbfd3 100644
--- a/phpBB/includes/acp/acp_reasons.php
+++ b/phpBB/includes/acp/acp_reasons.php
@@ -25,16 +25,15 @@ class acp_reasons
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
- global $request;
+ global $db, $user, $template;
+ global $request, $phpbb_log;
$user->add_lang(array('mcp', 'acp/posting'));
// Set up general vars
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$submit = (isset($_POST['submit'])) ? true : false;
- $reason_id = request_var('id', 0);
+ $reason_id = $request->variable('id', 0);
$this->tpl_name = 'acp_reasons';
$this->page_title = 'ACP_REASONS';
@@ -50,8 +49,8 @@ class acp_reasons
case 'edit':
$reason_row = array(
- 'reason_title' => utf8_normalize_nfc(request_var('reason_title', '', true)),
- 'reason_description' => utf8_normalize_nfc(request_var('reason_description', '', true)),
+ 'reason_title' => $request->variable('reason_title', '', true),
+ 'reason_description' => $request->variable('reason_description', '', true),
);
if ($submit)
@@ -104,7 +103,7 @@ class acp_reasons
}
}
- if (!sizeof($error))
+ if (!count($error))
{
// New reason?
if ($action == 'add')
@@ -139,7 +138,7 @@ class acp_reasons
$log = 'UPDATED';
}
- add_log('admin', 'LOG_REASON_' . $log, $reason_row['reason_title']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_REASON_' . $log, false, array($reason_row['reason_title']));
trigger_error($user->lang['REASON_' . $log] . adm_back_link($this->u_action));
}
}
@@ -172,7 +171,7 @@ class acp_reasons
'L_TITLE' => $user->lang['REASON_' . $l_title],
'U_ACTION' => $this->u_action . "&amp;id=$reason_id&amp;action=$action",
'U_BACK' => $this->u_action,
- 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '',
'REASON_TITLE' => $reason_row['reason_title'],
'REASON_DESCRIPTION' => $reason_row['reason_description'],
@@ -183,7 +182,7 @@ class acp_reasons
'S_AVAILABLE_TITLES' => implode($user->lang['COMMA_SEPARATOR'], array_map('htmlspecialchars', array_keys($user->lang['report_reasons']['TITLE']))),
'S_EDIT_REASON' => true,
'S_TRANSLATED' => $translated,
- 'S_ERROR' => (sizeof($error)) ? true : false,
+ 'S_ERROR' => (count($error)) ? true : false,
)
);
@@ -232,7 +231,6 @@ class acp_reasons
break;
// Standard? What's that?
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
// Change the reports using this reason to 'other'
@@ -252,7 +250,6 @@ class acp_reasons
// Teh standard
case 'postgres':
case 'oracle':
- case 'sqlite':
case 'sqlite3':
// Change the reports using this reason to 'other'
$sql = 'UPDATE ' . REPORTS_TABLE . '
@@ -264,7 +261,7 @@ class acp_reasons
$db->sql_query('DELETE FROM ' . REPORTS_REASONS_TABLE . ' WHERE reason_id = ' . $reason_id);
- add_log('admin', 'LOG_REASON_REMOVED', $reason_row['reason_title']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_REASON_REMOVED', false, array($reason_row['reason_title']));
trigger_error($user->lang['REASON_REMOVED'] . adm_back_link($this->u_action));
}
else
diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php
index cc1e5df084..538a28a926 100644
--- a/phpBB/includes/acp/acp_search.php
+++ b/phpBB/includes/acp/acp_search.php
@@ -50,8 +50,8 @@ class acp_search
function settings($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $request;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $user, $template, $phpbb_log, $request;
+ global $config, $phpbb_admin_path, $phpEx;
$submit = (isset($_POST['submit'])) ? true : false;
@@ -109,8 +109,8 @@ class acp_search
unset($search);
unset($error);
- $cfg_array = (isset($_REQUEST['config'])) ? request_var('config', array('' => ''), true) : array();
- $updated = request_var('updated', false);
+ $cfg_array = (isset($_REQUEST['config'])) ? $request->variable('config', array('' => ''), true) : array();
+ $updated = $request->variable('updated', false);
foreach ($settings as $config_name => $var_type)
{
@@ -138,7 +138,7 @@ class acp_search
// only change config if anything was actually changed
if ($submit && ($config[$config_name] != $config_value))
{
- set_config($config_name, $config_value);
+ $config->set($config_name, $config_value);
$updated = true;
}
}
@@ -148,7 +148,7 @@ class acp_search
$extra_message = '';
if ($updated)
{
- add_log('admin', 'LOG_CONFIG_SEARCH');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_SEARCH');
}
if (isset($cfg_array['search_type']) && in_array($cfg_array['search_type'], $search_types, true) && ($cfg_array['search_type'] != $config['search_type']))
@@ -162,11 +162,11 @@ class acp_search
{
if (!method_exists($search, 'init') || !($error = $search->init()))
{
- set_config('search_type', $cfg_array['search_type']);
+ $config->set('search_type', $cfg_array['search_type']);
if (!$updated)
{
- add_log('admin', 'LOG_CONFIG_SEARCH');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_SEARCH');
}
$extra_message = '<br />' . $user->lang['SWITCHED_SEARCH_BACKEND'] . '<br /><a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=search&amp;mode=index') . '">&raquo; ' . $user->lang['GO_TO_SEARCH_INDEX'] . '</a>';
}
@@ -237,10 +237,10 @@ class acp_search
function index($id, $mode)
{
- global $db, $user, $auth, $template, $cache, $request;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $template, $phpbb_log, $request;
+ global $config, $phpbb_admin_path, $phpEx;
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$this->state = explode(',', $config['search_indexing_state']);
if (isset($_POST['cancel']))
@@ -261,7 +261,7 @@ class acp_search
switch ($action)
{
case 'progress_bar':
- $type = request_var('type', '');
+ $type = $request->variable('type', '');
$this->display_progress_bar($type);
break;
@@ -280,7 +280,7 @@ class acp_search
if (empty($this->state[0]))
{
- $this->state[0] = request_var('search_type', '');
+ $this->state[0] = $request->variable('search_type', '');
}
$this->search = null;
@@ -314,8 +314,7 @@ class acp_search
}
else
{
- $starttime = explode(' ', microtime());
- $starttime = $starttime[1] + $starttime[0];
+ $starttime = microtime(true);
$row_count = 0;
while (still_on_time() && $post_counter <= $this->max_post_id)
{
@@ -333,9 +332,9 @@ class acp_search
$forum_ids[] = $row['forum_id'];
}
$db->sql_freeresult($result);
- $row_count += sizeof($ids);
+ $row_count += count($ids);
- if (sizeof($ids))
+ if (count($ids))
{
$this->search->index_remove($ids, $posters, $forum_ids);
}
@@ -347,11 +346,10 @@ class acp_search
if ($post_counter <= $this->max_post_id)
{
- $mtime = explode(' ', microtime());
- $totaltime = $mtime[0] + $mtime[1] - $starttime;
+ $totaltime = microtime(true) - $starttime;
$rows_per_second = $row_count / $totaltime;
meta_refresh(1, append_sid($this->u_action . '&amp;action=delete&amp;skip_rows=' . $post_counter . '&amp;hash=' . generate_link_hash('acp_search')));
- trigger_error($user->lang('SEARCH_INDEX_DELETE_REDIRECT', (int) $row_count, $post_counter, $rows_per_second));
+ trigger_error($user->lang('SEARCH_INDEX_DELETE_REDIRECT', (int) $row_count, $post_counter) . $user->lang('SEARCH_INDEX_DELETE_REDIRECT_RATE', $rows_per_second));
}
}
@@ -360,7 +358,7 @@ class acp_search
$this->state = array('');
$this->save_state();
- add_log('admin', 'LOG_SEARCH_INDEX_REMOVED', $name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_SEARCH_INDEX_REMOVED', false, array($name));
trigger_error($user->lang['SEARCH_INDEX_REMOVED'] . adm_back_link($this->u_action) . $this->close_popup_js());
break;
@@ -387,8 +385,7 @@ class acp_search
}
$db->sql_freeresult($result);
- $starttime = explode(' ', microtime());
- $starttime = $starttime[1] + $starttime[0];
+ $starttime = microtime(true);
$row_count = 0;
while (still_on_time() && $post_counter <= $this->max_post_id)
{
@@ -437,8 +434,7 @@ class acp_search
if ($post_counter <= $this->max_post_id)
{
- $mtime = explode(' ', microtime());
- $totaltime = $mtime[0] + $mtime[1] - $starttime;
+ $totaltime = microtime(true) - $starttime;
$rows_per_second = $row_count / $totaltime;
meta_refresh(1, append_sid($this->u_action . '&amp;action=create&amp;skip_rows=' . $post_counter . '&amp;hash=' . generate_link_hash('acp_search')));
trigger_error($user->lang('SEARCH_INDEX_CREATE_REDIRECT', (int) $row_count, $post_counter) . $user->lang('SEARCH_INDEX_CREATE_REDIRECT_RATE', $rows_per_second));
@@ -450,7 +446,7 @@ class acp_search
$this->state = array('');
$this->save_state();
- add_log('admin', 'LOG_SEARCH_INDEX_CREATED', $name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_SEARCH_INDEX_CREATED', false, array($name));
trigger_error($user->lang['SEARCH_INDEX_CREATED'] . adm_back_link($this->u_action) . $this->close_popup_js());
break;
}
@@ -478,8 +474,8 @@ class acp_search
$statistics = array();
foreach ($data as $statistic => $value)
{
- $n = sizeof($statistics);
- if ($n && sizeof($statistics[$n - 1]) < 3)
+ $n = count($statistics);
+ if ($n && count($statistics[$n - 1]) < 3)
{
$statistics[$n - 1] += array('statistic_2' => $statistic, 'value_2' => $value);
}
@@ -496,7 +492,7 @@ class acp_search
'S_ACTIVE' => ($type == $config['search_type']) ? true : false,
'S_HIDDEN_FIELDS' => build_hidden_fields(array('search_type' => $type)),
'S_INDEXED' => (bool) $search->index_created(),
- 'S_STATS' => (bool) sizeof($statistics))
+ 'S_STATS' => (bool) count($statistics))
);
foreach ($statistics as $statistic)
@@ -566,7 +562,7 @@ class acp_search
function get_search_types()
{
- global $phpbb_root_path, $phpEx, $phpbb_extension_manager;
+ global $phpbb_extension_manager;
$finder = $phpbb_extension_manager->get_finder();
@@ -592,6 +588,8 @@ class acp_search
function save_state($state = false)
{
+ global $config;
+
if ($state)
{
$this->state = $state;
@@ -599,7 +597,7 @@ class acp_search
ksort($this->state);
- set_config('search_indexing_state', implode(',', $this->state), true);
+ $config->set('search_indexing_state', implode(',', $this->state), true);
}
/**
diff --git a/phpBB/includes/acp/acp_send_statistics.php b/phpBB/includes/acp/acp_send_statistics.php
deleted file mode 100644
index 7c9e9cf78e..0000000000
--- a/phpBB/includes/acp/acp_send_statistics.php
+++ /dev/null
@@ -1,91 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-class acp_send_statistics
-{
- var $u_action;
-
- function main($id, $mode)
- {
- global $config, $template, $phpbb_admin_path, $phpbb_root_path, $phpEx;
-
- if (!class_exists('phpbb_questionnaire_data_collector'))
- {
- include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx);
- }
-
- $collect_url = "https://www.phpbb.com/stats/receive_stats.php";
-
- $this->tpl_name = 'acp_send_statistics';
- $this->page_title = 'ACP_SEND_STATISTICS';
-
- // generate a unique id if necessary
- if (!isset($config['questionnaire_unique_id']))
- {
- $install_id = unique_id();
- set_config('questionnaire_unique_id', $install_id);
- }
- else
- {
- $install_id = $config['questionnaire_unique_id'];
- }
-
- $collector = new phpbb_questionnaire_data_collector($install_id);
-
- // Add data provider
- $collector->add_data_provider(new phpbb_questionnaire_php_data_provider());
- $collector->add_data_provider(new phpbb_questionnaire_system_data_provider());
- $collector->add_data_provider(new phpbb_questionnaire_phpbb_data_provider($config));
-
- $template->assign_vars(array(
- 'U_COLLECT_STATS' => $collect_url,
- 'RAW_DATA' => $collector->get_data_for_form(),
- 'U_ACP_MAIN' => append_sid("{$phpbb_admin_path}index.$phpEx"),
- ));
-
- $raw = $collector->get_data_raw();
-
- foreach ($raw as $provider => $data)
- {
- if ($provider == 'install_id')
- {
- $data = array($provider => $data);
- }
-
- $template->assign_block_vars('providers', array(
- 'NAME' => htmlspecialchars($provider),
- ));
-
- foreach ($data as $key => $value)
- {
- if (is_array($value))
- {
- $value = utf8_wordwrap(serialize($value), 75, "\n", true);
- }
-
- $template->assign_block_vars('providers.values', array(
- 'KEY' => utf8_htmlspecialchars($key),
- 'VALUE' => utf8_htmlspecialchars($value),
- ));
- }
- }
- }
-}
diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php
index c29fb062d8..87c8d88f52 100644
--- a/phpBB/includes/acp/acp_styles.php
+++ b/phpBB/includes/acp/acp_styles.php
@@ -32,6 +32,9 @@ class acp_styles
protected $styles_list_cols = 0;
protected $reserved_style_names = array('adm', 'admin', 'all');
+ /** @var \phpbb\config\config */
+ protected $config;
+
/** @var \phpbb\db\driver\driver_interface */
protected $db;
@@ -50,6 +53,9 @@ class acp_styles
/** @var \phpbb\auth\auth */
protected $auth;
+ /** @var \phpbb\textformatter\cache_interface */
+ protected $text_formatter_cache;
+
/** @var string */
protected $phpbb_root_path;
@@ -61,7 +67,7 @@ class acp_styles
public function main($id, $mode)
{
- global $db, $user, $phpbb_admin_path, $phpbb_root_path, $phpEx, $template, $request, $cache, $auth, $config, $phpbb_dispatcher;
+ global $db, $user, $phpbb_admin_path, $phpbb_root_path, $phpEx, $template, $request, $cache, $auth, $config, $phpbb_dispatcher, $phpbb_container;
$this->db = $db;
$this->user = $user;
@@ -69,6 +75,7 @@ class acp_styles
$this->request = $request;
$this->cache = $cache;
$this->auth = $auth;
+ $this->text_formatter_cache = $phpbb_container->get('text_formatter.cache');
$this->config = $config;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $phpEx;
@@ -194,7 +201,6 @@ class acp_styles
$messages = array();
$installed_names = array();
$installed_dirs = array();
- $last_installed = false;
foreach ($dirs as $dir)
{
if (in_array($dir, $this->reserved_style_names))
@@ -217,7 +223,6 @@ class acp_styles
$style['style_id'] = $this->install_style($style);
$style['_installed'] = true;
$found = true;
- $last_installed = $style['style_id'];
$installed_names[] = $style['style_name'];
$installed_dirs[] = $style['style_path'];
$messages[] = sprintf($this->user->lang['STYLE_INSTALLED'], htmlspecialchars($style['style_name']));
@@ -229,6 +234,12 @@ class acp_styles
}
}
+ // Invalidate the text formatter's cache for the new styles to take effect
+ if (!empty($installed_names))
+ {
+ $this->text_formatter_cache->invalidate();
+ }
+
// Show message
if (!count($messages))
{
@@ -248,6 +259,19 @@ class acp_styles
// Get list of styles to uninstall
$ids = $this->request_vars('id', 0, true);
+ // Don't remove prosilver, you can still deactivate it.
+ $sql = 'SELECT style_id
+ FROM ' . STYLES_TABLE . "
+ WHERE style_name = '" . $this->db->sql_escape('prosilver') . "'";
+ $result = $this->db->sql_query($sql);
+ $prosilver_id = (int) $this->db->sql_fetchfield('style_id');
+ $this->db->sql_freeresult($result);
+
+ if ($prosilver_id && in_array($prosilver_id, $ids))
+ {
+ trigger_error($this->user->lang('UNINSTALL_PROSILVER') . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+
// Check if confirmation box was submitted
if (confirm_box(true))
{
@@ -276,6 +300,8 @@ class acp_styles
*/
protected function action_uninstall_confirmed($ids, $delete_files)
{
+ global $user, $phpbb_log;
+
$default = $this->default_style;
$uninstalled = array();
$messages = array();
@@ -335,7 +361,7 @@ class acp_styles
// Log action
if (count($uninstalled))
{
- add_log('admin', 'LOG_STYLE_DELETE', implode(', ', $uninstalled));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_DELETE', false, array(implode(', ', $uninstalled)));
}
// Clear cache
@@ -385,7 +411,7 @@ class acp_styles
// Reset default style for users who use selected styles
$sql = 'UPDATE ' . USERS_TABLE . '
- SET user_style = 0
+ SET user_style = ' . (int) $this->default_style . '
WHERE user_style IN (' . implode(', ', $ids) . ')';
$this->db->sql_query($sql);
@@ -407,6 +433,8 @@ class acp_styles
*/
protected function action_details()
{
+ global $user, $phpbb_log;
+
$id = $this->request->variable('id', 0);
if (!$id)
{
@@ -541,7 +569,8 @@ class acp_styles
$this->cache->purge();
}
}
- add_log('admin', 'LOG_STYLE_EDIT_DETAILS', $style['style_name']);
+
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_EDIT_DETAILS', false, array($style['style_name']));
}
// Update default style
@@ -552,7 +581,7 @@ class acp_styles
{
trigger_error($this->user->lang['STYLE_DEFAULT_CHANGE_INACTIVE'] . adm_back_link($update_action), E_USER_WARNING);
}
- set_config('default_style', $id);
+ $this->config->set('default_style', $id);
$this->cache->purge();
}
@@ -936,6 +965,7 @@ class acp_styles
// Style data
'STYLE_ID' => $style['style_id'],
'STYLE_NAME' => htmlspecialchars($style['style_name']),
+ 'STYLE_PHPBB_VERSION' => $this->read_style_cfg($style['style_path'])['phpbb_version'],
'STYLE_PATH' => htmlspecialchars($style['style_path']),
'STYLE_COPYRIGHT' => strip_tags($style['style_copyright']),
'STYLE_ACTIVE' => $style['style_active'],
@@ -981,11 +1011,14 @@ class acp_styles
'L_ACTION' => $this->user->lang['EXPORT']
); */
- // Uninstall
- $actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=uninstall&amp;hash=' . generate_link_hash('uninstall') . '&amp;id=' . $style['style_id'],
- 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL']
- );
+ if ($style['style_name'] !== 'prosilver')
+ {
+ // Uninstall
+ $actions[] = array(
+ 'U_ACTION' => $this->u_action . '&amp;action=uninstall&amp;hash=' . generate_link_hash('uninstall') . '&amp;id=' . $style['style_id'],
+ 'L_ACTION' => $this->user->lang['STYLE_UNINSTALL']
+ );
+ }
// Preview
$actions[] = array(
@@ -1106,7 +1139,14 @@ class acp_styles
*/
protected function read_style_cfg($dir)
{
+ // This should never happen, we give them a red warning because of its relevance.
+ if (!file_exists($this->styles_path . $dir . '/style.cfg'))
+ {
+ trigger_error($this->user->lang('NO_STYLE_CFG', $dir), E_USER_WARNING);
+ }
+
static $required = array('name', 'phpbb_version', 'copyright');
+
$cfg = parse_cfg_file($this->styles_path . $dir . '/style.cfg');
// Check if it is a valid file
@@ -1139,6 +1179,8 @@ class acp_styles
*/
protected function install_style($style)
{
+ global $user, $phpbb_log;
+
// Generate row
$sql_ary = array();
foreach ($style as $key => $value)
@@ -1160,7 +1202,7 @@ class acp_styles
$this->db->sql_transaction('commit');
- add_log('admin', 'LOG_STYLE_ADD', $sql_ary['style_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_STYLE_ADD', false, array($sql_ary['style_name']));
return $id;
}
@@ -1231,7 +1273,7 @@ class acp_styles
// Change default style for users
$sql = 'UPDATE ' . USERS_TABLE . '
- SET user_style = 0
+ SET user_style = ' . (int) $this->default_style . '
WHERE user_style = ' . $id;
$this->db->sql_query($sql);
@@ -1337,18 +1379,18 @@ class acp_styles
}
// Hardcoded template bitfield to add for new templates
+ $default_bitfield = '1111111111111';
+
$bitfield = new bitfield();
- $bitfield->set(0);
- $bitfield->set(1);
- $bitfield->set(2);
- $bitfield->set(3);
- $bitfield->set(4);
- $bitfield->set(8);
- $bitfield->set(9);
- $bitfield->set(11);
- $bitfield->set(12);
- $value = $bitfield->get_base64();
- return $value;
+ for ($i = 0; $i < strlen($default_bitfield); $i++)
+ {
+ if ($default_bitfield[$i] == '1')
+ {
+ $bitfield->set($i);
+ }
+ }
+
+ return $bitfield->get_base64();
}
}
diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php
index cee2ce222e..fa3afa6ce3 100644
--- a/phpBB/includes/acp/acp_update.php
+++ b/phpBB/includes/acp/acp_update.php
@@ -33,6 +33,7 @@ class acp_update
$this->tpl_name = 'acp_update';
$this->page_title = 'ACP_VERSION_CHECK';
+ /* @var $version_helper \phpbb\version_helper */
$version_helper = $phpbb_container->get('version_helper');
try
{
@@ -51,26 +52,31 @@ class acp_update
$updates_available = array();
}
- $template->assign_block_vars('updates_available', $updates_available);
+ if (!empty($updates_available))
+ {
+ $template->assign_block_vars('updates_available', $updates_available);
+ }
- $update_link = append_sid($phpbb_root_path . 'install/');
+ $update_link = $phpbb_root_path . 'install/app.' . $phpEx;
- $template->assign_vars(array(
- 'S_UP_TO_DATE' => empty($updates_available),
- 'U_ACTION' => $this->u_action,
- 'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&amp;versioncheck_force=1'),
+ $template_ary = [
+ 'S_UP_TO_DATE' => empty($updates_available),
+ 'U_ACTION' => $this->u_action,
+ 'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&amp;versioncheck_force=1'),
- 'CURRENT_VERSION' => $config['version'],
+ 'CURRENT_VERSION' => $config['version'],
- 'UPDATE_INSTRUCTIONS' => sprintf($user->lang['UPDATE_INSTRUCTIONS'], $update_link),
+ 'UPDATE_INSTRUCTIONS' => $user->lang('UPDATE_INSTRUCTIONS', $update_link),
'S_VERSION_UPGRADEABLE' => !empty($upgrades_available),
'UPGRADE_INSTRUCTIONS' => !empty($upgrades_available) ? $user->lang('UPGRADE_INSTRUCTIONS', $upgrades_available['current'], $upgrades_available['announcement']) : false,
- ));
+ ];
+
+ $template->assign_vars($template_ary);
// Incomplete update?
if (phpbb_version_compare($config['version'], PHPBB_VERSION, '<'))
{
- $database_update_link = append_sid($phpbb_root_path . 'install/database_update.' . $phpEx);
+ $database_update_link = $phpbb_root_path . 'install/app.php/update';
$template->assign_vars(array(
'S_UPDATE_INCOMPLETE' => true,
diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php
index cd44800af8..fd4b5e8c24 100644
--- a/phpBB/includes/acp/acp_users.php
+++ b/phpBB/includes/acp/acp_users.php
@@ -24,28 +24,28 @@ class acp_users
var $u_action;
var $p_master;
- function acp_users(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $cache;
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
+ global $config, $db, $user, $auth, $template;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx;
global $phpbb_dispatcher, $request;
- global $phpbb_container;
+ global $phpbb_container, $phpbb_log;
$user->add_lang(array('posting', 'ucp', 'acp/users'));
$this->tpl_name = 'acp_users';
$error = array();
- $username = utf8_normalize_nfc(request_var('username', '', true));
- $user_id = request_var('u', 0);
- $action = request_var('action', '');
+ $username = $request->variable('username', '', true);
+ $user_id = $request->variable('u', 0);
+ $action = $request->variable('action', '');
// Get referer to redirect user to the appropriate page after delete action
- $redirect = request_var('redirect', '');
+ $redirect = $request->variable('redirect', '');
$redirect_tag = "redirect=$redirect";
$redirect_url = append_sid("{$phpbb_admin_path}index.$phpEx", "i=$redirect");
@@ -65,7 +65,7 @@ class acp_users
$this->page_title = 'WHOIS';
$this->tpl_name = 'simple_body';
- $user_ip = phpbb_ip_normalise(request_var('user_ip', ''));
+ $user_ip = phpbb_ip_normalise($request->variable('user_ip', ''));
$domain = gethostbyaddr($user_ip);
$ipwhois = user_ipwhois($user_ip);
@@ -180,9 +180,9 @@ class acp_users
$user->add_lang('acp/ban');
- $delete = request_var('delete', 0);
- $delete_type = request_var('delete_type', '');
- $ip = request_var('ip', 'ip');
+ $delete = $request->variable('delete', 0);
+ $delete_type = $request->variable('delete_type', '');
+ $ip = $request->variable('ip', 'ip');
/**
* Run code at beginning of ACP users overview
@@ -205,6 +205,7 @@ class acp_users
{
if (!$auth->acl_get('a_userdel'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action . '&amp;u=' . $user_id), E_USER_WARNING);
}
@@ -231,7 +232,7 @@ class acp_users
{
user_delete($delete_type, $user_id, $user_row['username']);
- add_log('admin', 'LOG_USER_DELETED', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DELETED', false, array($user_row['username']));
trigger_error($user->lang['USER_DELETED'] . adm_back_link(
(empty($redirect)) ? $this->u_action : $redirect_url
)
@@ -298,13 +299,11 @@ class acp_users
case 'banuser':
$ban[] = $user_row['username'];
$reason = 'USER_ADMIN_BAN_NAME_REASON';
- $log = 'LOG_USER_BAN_USER';
break;
case 'banemail':
$ban[] = $user_row['user_email'];
$reason = 'USER_ADMIN_BAN_EMAIL_REASON';
- $log = 'LOG_USER_BAN_EMAIL';
break;
case 'banip':
@@ -322,12 +321,11 @@ class acp_users
$db->sql_freeresult($result);
$reason = 'USER_ADMIN_BAN_IP_REASON';
- $log = 'LOG_USER_BAN_IP';
break;
}
- $ban_reason = utf8_normalize_nfc(request_var('ban_reason', $user->lang[$reason], true));
- $ban_give_reason = utf8_normalize_nfc(request_var('ban_give_reason', '', true));
+ $ban_reason = $request->variable('ban_reason', $user->lang[$reason], true);
+ $ban_give_reason = $request->variable('ban_give_reason', '', true);
// Log not used at the moment, we simply utilize the ban function.
$result = user_ban(substr($action, 3), $ban, 0, 0, 0, $ban_reason, $ban_give_reason);
@@ -411,8 +409,10 @@ class acp_users
$messenger->send(NOTIFY_EMAIL);
- add_log('admin', 'LOG_USER_REACTIVATE', $user_row['username']);
- add_log('user', $user_id, 'LOG_USER_REACTIVATE_USER');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_REACTIVATE', false, array($user_row['username']));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_REACTIVATE_USER', false, array(
+ 'reportee_id' => $user_id
+ ));
trigger_error($user->lang['FORCE_REACTIVATION_SUCCESS'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
@@ -448,6 +448,7 @@ class acp_users
{
if ($config['require_activation'] == USER_ACTIVATION_ADMIN)
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']);
@@ -475,8 +476,10 @@ class acp_users
$message = ($user_row['user_type'] == USER_INACTIVE) ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED';
$log = ($user_row['user_type'] == USER_INACTIVE) ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE';
- add_log('admin', $log, $user_row['username']);
- add_log('user', $user_id, $log . '_USER');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log, false, array($user_row['username']));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, $log . '_USER', false, array(
+ 'reportee_id' => $user_id
+ ));
trigger_error($user->lang[$message] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
@@ -499,8 +502,10 @@ class acp_users
WHERE user_id = $user_id";
$db->sql_query($sql);
- add_log('admin', 'LOG_USER_DEL_SIG', $user_row['username']);
- add_log('user', $user_id, 'LOG_USER_DEL_SIG_USER');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_SIG', false, array($user_row['username']));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_SIG_USER', false, array(
+ 'reportee_id' => $user_id
+ ));
trigger_error($user->lang['USER_ADMIN_SIG_REMOVED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
@@ -514,11 +519,14 @@ class acp_users
}
// Delete old avatar if present
+ /* @var $phpbb_avatar_manager \phpbb\avatar\manager */
$phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
$phpbb_avatar_manager->handle_avatar_delete($db, $user, $phpbb_avatar_manager->clean_row($user_row, 'user'), USERS_TABLE, 'user_');
- add_log('admin', 'LOG_USER_DEL_AVATAR', $user_row['username']);
- add_log('user', $user_id, 'LOG_USER_DEL_AVATAR_USER');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_AVATAR', false, array($user_row['username']));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_AVATAR_USER', false, array(
+ 'reportee_id' => $user_id
+ ));
trigger_error($user->lang['USER_ADMIN_AVATAR_REMOVED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
break;
@@ -530,7 +538,7 @@ class acp_users
// Delete posts, attachments, etc.
delete_posts('poster_id', $user_id);
- add_log('admin', 'LOG_USER_DEL_POSTS', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_POSTS', false, array($user_row['username']));
trigger_error($user->lang['USER_POSTS_DELETED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
else
@@ -550,9 +558,12 @@ class acp_users
if (confirm_box(true))
{
- delete_attachments('user', $user_id);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $attachment_manager->delete('user', $user_id);
+ unset($attachment_manager);
- add_log('admin', 'LOG_USER_DEL_ATTACH', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_ATTACH', false, array($user_row['username']));
trigger_error($user->lang['USER_ATTACHMENTS_REMOVED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
else
@@ -598,7 +609,7 @@ class acp_users
delete_pm($user_id, $msg_ids, PRIVMSGS_OUTBOX);
- add_log('admin', 'LOG_USER_DEL_OUTBOX', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_DEL_OUTBOX', false, array($user_row['username']));
$lang = 'EMPTIED';
}
@@ -627,7 +638,7 @@ class acp_users
$user->add_lang('acp/forums');
- $new_forum_id = request_var('new_f', 0);
+ $new_forum_id = $request->variable('new_f', 0);
if (!$new_forum_id)
{
@@ -679,7 +690,7 @@ class acp_users
}
$db->sql_freeresult($result);
- if (sizeof($topic_id_ary))
+ if (count($topic_id_ary))
{
$sql = 'SELECT topic_id, forum_id, topic_title, topic_posts_approved, topic_posts_unapproved, topic_posts_softdeleted, topic_attachment
FROM ' . TOPICS_TABLE . '
@@ -707,12 +718,12 @@ class acp_users
}
// Entire topic comprises posts by this user, move these topics
- if (sizeof($move_topic_ary))
+ if (count($move_topic_ary))
{
move_topics($move_topic_ary, $new_forum_id, false);
}
- if (sizeof($move_post_ary))
+ if (count($move_post_ary))
{
// Create new topic
// Update post_ids, report_ids, attachment_ids
@@ -758,19 +769,22 @@ class acp_users
$forum_id_ary = array_unique($forum_id_ary);
$topic_id_ary = array_unique(array_merge(array_keys($topic_id_ary), $new_topic_id_ary));
- if (sizeof($topic_id_ary))
+ if (count($topic_id_ary))
{
sync('topic_reported', 'topic_id', $topic_id_ary);
sync('topic', 'topic_id', $topic_id_ary);
}
- if (sizeof($forum_id_ary))
+ if (count($forum_id_ary))
{
sync('forum', 'forum_id', $forum_id_ary, false, true);
}
- add_log('admin', 'LOG_USER_MOVE_POSTS', $user_row['username'], $forum_info['forum_name']);
- add_log('user', $user_id, 'LOG_USER_MOVE_POSTS_USER', $forum_info['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_MOVE_POSTS', false, array($user_row['username'], $forum_info['forum_name']));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_MOVE_POSTS_USER', false, array(
+ 'reportee_id' => $user_id,
+ $forum_info['forum_name']
+ ));
trigger_error($user->lang['USER_POSTS_MOVED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
@@ -782,7 +796,7 @@ class acp_users
{
remove_newly_registered($user_id, $user_row);
- add_log('admin', 'LOG_USER_REMOVED_NR', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_REMOVED_NR', false, array($user_row['username']));
trigger_error($user->lang['USER_LIFTED_NR'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
else
@@ -799,24 +813,30 @@ class acp_users
break;
default:
+ $u_action = $this->u_action;
+
/**
* Run custom quicktool code
*
* @event core.acp_users_overview_run_quicktool
- * @var array user_row Current user data
* @var string action Quick tool that should be run
+ * @var array user_row Current user data
+ * @var string u_action The u_action link
* @since 3.1.0-a1
+ * @changed 3.2.2-RC1 Added u_action
*/
- $vars = array('action', 'user_row');
+ $vars = array('action', 'user_row', 'u_action');
extract($phpbb_dispatcher->trigger_event('core.acp_users_overview_run_quicktool', compact($vars)));
+
+ unset($u_action);
break;
}
// Handle registration info updates
$data = array(
- 'username' => utf8_normalize_nfc(request_var('user', $user_row['username'], true)),
- 'user_founder' => request_var('user_founder', ($user_row['user_type'] == USER_FOUNDER) ? 1 : 0),
- 'email' => strtolower(request_var('user_email', $user_row['user_email'])),
+ 'username' => $request->variable('user', $user_row['username'], true),
+ 'user_founder' => $request->variable('user_founder', ($user_row['user_type'] == USER_FOUNDER) ? 1 : 0),
+ 'email' => strtolower($request->variable('user_email', $user_row['user_email'])),
'new_password' => $request->variable('new_password', '', true),
'password_confirm' => $request->variable('password_confirm', '', true),
);
@@ -835,7 +855,7 @@ class acp_users
$check_ary += array(
'username' => array(
array('string', false, $config['min_name_chars'], $config['max_name_chars']),
- array('username', $user_row['username'])
+ array('username', $user_row['username'], true)
),
);
}
@@ -864,6 +884,7 @@ class acp_users
}
// Instantiate passwords manager
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
// Which updates do we need to do?
@@ -871,7 +892,7 @@ class acp_users
$update_password = $data['new_password'] && !$passwords_manager->check($data['new_password'], $user_row['user_password']);
$update_email = ($data['email'] != $user_row['user_email']) ? $data['email'] : false;
- if (!sizeof($error))
+ if (!count($error))
{
$sql_ary = array();
@@ -936,7 +957,11 @@ class acp_users
$sql_ary['username'] = $update_username;
$sql_ary['username_clean'] = utf8_clean_string($update_username);
- add_log('user', $user_id, 'LOG_USER_UPDATE_NAME', $user_row['username'], $update_username);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_UPDATE_NAME', false, array(
+ 'reportee_id' => $user_id,
+ $user_row['username'],
+ $update_username
+ ));
}
if ($update_email !== false)
@@ -946,7 +971,12 @@ class acp_users
'user_email_hash' => phpbb_email_hash($update_email),
);
- add_log('user', $user_id, 'LOG_USER_UPDATE_EMAIL', $user_row['username'], $user_row['user_email'], $update_email);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_UPDATE_EMAIL', false, array(
+ 'reportee_id' => $user_id,
+ $user_row['username'],
+ $user_row['user_email'],
+ $update_email
+ ));
}
if ($update_password)
@@ -957,10 +987,14 @@ class acp_users
);
$user->reset_login_keys($user_id);
- add_log('user', $user_id, 'LOG_USER_NEW_PASSWORD', $user_row['username']);
+
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_NEW_PASSWORD', false, array(
+ 'reportee_id' => $user_id,
+ $user_row['username']
+ ));
}
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
@@ -976,7 +1010,7 @@ class acp_users
// Let the users permissions being updated
$auth->acl_clear_prefetch($user_id);
- add_log('admin', 'LOG_USER_USER_UPDATE', $data['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_USER_UPDATE', false, array($data['username']));
trigger_error($user->lang['USER_OVERVIEW_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
@@ -1133,17 +1167,19 @@ class acp_users
$user->add_lang('mcp');
// Set up general vars
- $start = request_var('start', 0);
+ $start = $request->variable('start', 0);
$deletemark = (isset($_POST['delmarked'])) ? true : false;
$deleteall = (isset($_POST['delall'])) ? true : false;
- $marked = request_var('mark', array(0));
- $message = utf8_normalize_nfc(request_var('message', '', true));
+ $marked = $request->variable('mark', array(0));
+ $message = $request->variable('message', '', true);
+
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// Sort keys
- $sort_days = request_var('st', 0);
- $sort_key = request_var('sk', 't');
- $sort_dir = request_var('sd', 'd');
+ $sort_days = $request->variable('st', 0);
+ $sort_key = $request->variable('sk', 't');
+ $sort_dir = $request->variable('sd', 'd');
// Delete entries if requested and able
if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs'))
@@ -1173,7 +1209,7 @@ class acp_users
$where_sql";
$db->sql_query($sql);
- add_log('admin', 'LOG_CLEAR_USER', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CLEAR_USER', false, array($user_row['username']));
}
}
@@ -1184,9 +1220,16 @@ class acp_users
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;u=' . $user_id), E_USER_WARNING);
}
- add_log('admin', 'LOG_USER_FEEDBACK', $user_row['username']);
- add_log('mod', 0, 0, 'LOG_USER_FEEDBACK', $user_row['username']);
- add_log('user', $user_id, 'LOG_USER_GENERAL', $message);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_FEEDBACK', false, array($user_row['username']));
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_USER_FEEDBACK', false, array(
+ 'forum_id' => 0,
+ 'topic_id' => 0,
+ $user_row['username']
+ ));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_GENERAL', false, array(
+ 'reportee_id' => $user_id,
+ $message
+ ));
trigger_error($user->lang['USER_FEEDBACK_ADDED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
@@ -1237,17 +1280,10 @@ class acp_users
$user->add_lang('mcp');
// Set up general vars
- $start = request_var('start', 0);
$deletemark = (isset($_POST['delmarked'])) ? true : false;
$deleteall = (isset($_POST['delall'])) ? true : false;
$confirm = (isset($_POST['confirm'])) ? true : false;
- $marked = request_var('mark', array(0));
- $message = utf8_normalize_nfc(request_var('message', '', true));
-
- // Sort keys
- $sort_days = request_var('st', 0);
- $sort_key = request_var('sk', 't');
- $sort_dir = request_var('sd', 'd');
+ $marked = $request->variable('mark', array(0));
// Delete entries if requested and able
if ($deletemark || $deleteall || $confirm)
@@ -1255,8 +1291,8 @@ class acp_users
if (confirm_box(true))
{
$where_sql = '';
- $deletemark = request_var('delmarked', 0);
- $deleteall = request_var('delall', 0);
+ $deletemark = $request->variable('delmarked', 0);
+ $deleteall = $request->variable('delall', 0);
if ($deletemark && $marked)
{
$where_sql = ' AND ' . $db->sql_in_set('warning_id', array_values($marked));
@@ -1287,11 +1323,11 @@ class acp_users
if ($log_warnings)
{
- add_log('admin', 'LOG_WARNINGS_DELETED', $user_row['username'], $num_warnings);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WARNINGS_DELETED', false, array($user_row['username'], $num_warnings));
}
else
{
- add_log('admin', 'LOG_WARNINGS_DELETED_ALL', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WARNINGS_DELETED_ALL', false, array($user_row['username']));
}
}
}
@@ -1311,7 +1347,7 @@ class acp_users
{
$s_hidden_fields['delall'] = 1;
}
- if (isset($_POST['delall']) || (isset($_POST['delmarked']) && sizeof($marked)))
+ if (isset($_POST['delall']) || (isset($_POST['delmarked']) && count($marked)))
{
confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields));
}
@@ -1347,9 +1383,9 @@ class acp_users
{
// Check if there are more occurrences of % than arguments, if there are we fill out the arguments array
// It doesn't matter if we add more arguments than placeholders
- if ((substr_count($row['action'], '%') - sizeof($log_data_ary)) > 0)
+ if ((substr_count($row['action'], '%') - count($log_data_ary)) > 0)
{
- $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($row['action'], '%') - sizeof($log_data_ary), ''));
+ $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($row['action'], '%') - count($log_data_ary), ''));
}
$row['action'] = vsprintf($row['action'], $log_data_ary);
$row['action'] = bbcode_nl2br(censor_text($row['action']));
@@ -1383,6 +1419,7 @@ class acp_users
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$cp_data = $cp_error = array();
@@ -1397,7 +1434,7 @@ class acp_users
$user_row['iso_lang_id'] = $row['lang_id'];
$data = array(
- 'jabber' => utf8_normalize_nfc(request_var('jabber', $user_row['user_jabber'], true)),
+ 'jabber' => $request->variable('jabber', $user_row['user_jabber'], true),
'bday_day' => 0,
'bday_month' => 0,
'bday_year' => 0,
@@ -1408,9 +1445,9 @@ class acp_users
list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user_row['user_birthday']);
}
- $data['bday_day'] = request_var('bday_day', $data['bday_day']);
- $data['bday_month'] = request_var('bday_month', $data['bday_month']);
- $data['bday_year'] = request_var('bday_year', $data['bday_year']);
+ $data['bday_day'] = $request->variable('bday_day', $data['bday_day']);
+ $data['bday_month'] = $request->variable('bday_month', $data['bday_month']);
+ $data['bday_year'] = $request->variable('bday_year', $data['bday_year']);
$data['user_birthday'] = sprintf('%2d-%2d-%4d', $data['bday_day'], $data['bday_month'], $data['bday_year']);
/**
@@ -1441,7 +1478,7 @@ class acp_users
// validate custom profile fields
$cp->submit_cp_field('profile', $user_row['iso_lang_id'], $cp_data, $cp_error);
- if (sizeof($cp_error))
+ if (count($cp_error))
{
$error = array_merge($error, $cp_error);
}
@@ -1454,15 +1491,17 @@ class acp_users
* Validate profile data in ACP before submitting to the database
*
* @event core.acp_users_profile_validate
- * @var bool submit Flag indicating if submit button has been pressed
* @var array data Array with user profile data
+ * @var int user_id The user id
+ * @var array user_row Array with the full user data
* @var array error Array with the form errors
* @since 3.1.4-RC1
+ * @changed 3.1.12-RC1 Removed submit, added user_id, user_row
*/
- $vars = array('submit', 'data', 'error');
+ $vars = array('data', 'user_id', 'user_row', 'error');
extract($phpbb_dispatcher->trigger_event('core.acp_users_profile_validate', compact($vars)));
- if (!sizeof($error))
+ if (!count($error))
{
$sql_ary = array(
'user_jabber' => $data['jabber'],
@@ -1511,7 +1550,6 @@ class acp_users
$selected = ($i == $data['bday_month']) ? ' selected="selected"' : '';
$s_birthday_month_options .= "<option value=\"$i\"$selected>$i</option>";
}
- $s_birthday_year_options = '';
$now = getdate();
$s_birthday_year_options = '<option value="0"' . ((!$data['bday_year']) ? ' selected="selected"' : '') . '>--</option>';
@@ -1546,36 +1584,36 @@ class acp_users
}
$data = array(
- 'dateformat' => utf8_normalize_nfc(request_var('dateformat', $user_row['user_dateformat'], true)),
- 'lang' => basename(request_var('lang', $user_row['user_lang'])),
- 'tz' => request_var('tz', $user_row['user_timezone']),
- 'style' => request_var('style', $user_row['user_style']),
- 'viewemail' => request_var('viewemail', $user_row['user_allow_viewemail']),
- 'massemail' => request_var('massemail', $user_row['user_allow_massemail']),
- 'hideonline' => request_var('hideonline', !$user_row['user_allow_viewonline']),
- 'notifymethod' => request_var('notifymethod', $user_row['user_notify_type']),
- 'notifypm' => request_var('notifypm', $user_row['user_notify_pm']),
- 'allowpm' => request_var('allowpm', $user_row['user_allow_pm']),
-
- 'topic_sk' => request_var('topic_sk', ($user_row['user_topic_sortby_type']) ? $user_row['user_topic_sortby_type'] : 't'),
- 'topic_sd' => request_var('topic_sd', ($user_row['user_topic_sortby_dir']) ? $user_row['user_topic_sortby_dir'] : 'd'),
- 'topic_st' => request_var('topic_st', ($user_row['user_topic_show_days']) ? $user_row['user_topic_show_days'] : 0),
-
- 'post_sk' => request_var('post_sk', ($user_row['user_post_sortby_type']) ? $user_row['user_post_sortby_type'] : 't'),
- 'post_sd' => request_var('post_sd', ($user_row['user_post_sortby_dir']) ? $user_row['user_post_sortby_dir'] : 'a'),
- 'post_st' => request_var('post_st', ($user_row['user_post_show_days']) ? $user_row['user_post_show_days'] : 0),
-
- 'view_images' => request_var('view_images', $this->optionget($user_row, 'viewimg')),
- 'view_flash' => request_var('view_flash', $this->optionget($user_row, 'viewflash')),
- 'view_smilies' => request_var('view_smilies', $this->optionget($user_row, 'viewsmilies')),
- 'view_sigs' => request_var('view_sigs', $this->optionget($user_row, 'viewsigs')),
- 'view_avatars' => request_var('view_avatars', $this->optionget($user_row, 'viewavatars')),
- 'view_wordcensor' => request_var('view_wordcensor', $this->optionget($user_row, 'viewcensors')),
-
- 'bbcode' => request_var('bbcode', $this->optionget($user_row, 'bbcode')),
- 'smilies' => request_var('smilies', $this->optionget($user_row, 'smilies')),
- 'sig' => request_var('sig', $this->optionget($user_row, 'attachsig')),
- 'notify' => request_var('notify', $user_row['user_notify']),
+ 'dateformat' => $request->variable('dateformat', $user_row['user_dateformat'], true),
+ 'lang' => basename($request->variable('lang', $user_row['user_lang'])),
+ 'tz' => $request->variable('tz', $user_row['user_timezone']),
+ 'style' => $request->variable('style', $user_row['user_style']),
+ 'viewemail' => $request->variable('viewemail', $user_row['user_allow_viewemail']),
+ 'massemail' => $request->variable('massemail', $user_row['user_allow_massemail']),
+ 'hideonline' => $request->variable('hideonline', !$user_row['user_allow_viewonline']),
+ 'notifymethod' => $request->variable('notifymethod', $user_row['user_notify_type']),
+ 'notifypm' => $request->variable('notifypm', $user_row['user_notify_pm']),
+ 'allowpm' => $request->variable('allowpm', $user_row['user_allow_pm']),
+
+ 'topic_sk' => $request->variable('topic_sk', ($user_row['user_topic_sortby_type']) ? $user_row['user_topic_sortby_type'] : 't'),
+ 'topic_sd' => $request->variable('topic_sd', ($user_row['user_topic_sortby_dir']) ? $user_row['user_topic_sortby_dir'] : 'd'),
+ 'topic_st' => $request->variable('topic_st', ($user_row['user_topic_show_days']) ? $user_row['user_topic_show_days'] : 0),
+
+ 'post_sk' => $request->variable('post_sk', ($user_row['user_post_sortby_type']) ? $user_row['user_post_sortby_type'] : 't'),
+ 'post_sd' => $request->variable('post_sd', ($user_row['user_post_sortby_dir']) ? $user_row['user_post_sortby_dir'] : 'a'),
+ 'post_st' => $request->variable('post_st', ($user_row['user_post_show_days']) ? $user_row['user_post_show_days'] : 0),
+
+ 'view_images' => $request->variable('view_images', $this->optionget($user_row, 'viewimg')),
+ 'view_flash' => $request->variable('view_flash', $this->optionget($user_row, 'viewflash')),
+ 'view_smilies' => $request->variable('view_smilies', $this->optionget($user_row, 'viewsmilies')),
+ 'view_sigs' => $request->variable('view_sigs', $this->optionget($user_row, 'viewsigs')),
+ 'view_avatars' => $request->variable('view_avatars', $this->optionget($user_row, 'viewavatars')),
+ 'view_wordcensor' => $request->variable('view_wordcensor', $this->optionget($user_row, 'viewcensors')),
+
+ 'bbcode' => $request->variable('bbcode', $this->optionget($user_row, 'bbcode')),
+ 'smilies' => $request->variable('smilies', $this->optionget($user_row, 'smilies')),
+ 'sig' => $request->variable('sig', $this->optionget($user_row, 'attachsig')),
+ 'notify' => $request->variable('notify', $user_row['user_notify']),
);
/**
@@ -1607,7 +1645,7 @@ class acp_users
$error[] = 'FORM_INVALID';
}
- if (!sizeof($error))
+ if (!count($error))
{
$this->optionset($user_row, 'viewimg', $data['view_images']);
$this->optionset($user_row, 'viewflash', $data['view_flash']);
@@ -1658,7 +1696,7 @@ class acp_users
$vars = array('data', 'user_row', 'sql_ary', 'error');
extract($phpbb_dispatcher->trigger_event('core.acp_users_prefs_modify_sql', compact($vars)));
- if (!sizeof($error))
+ if (!count($error))
{
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
@@ -1845,6 +1883,17 @@ class acp_users
'user_avatar_height' => $result['avatar_height'],
);
+ /**
+ * Modify users preferences data before assigning it to the template
+ *
+ * @event core.acp_users_avatar_sql
+ * @var array user_row Array with user data
+ * @var array result Array with user avatar data to be updated in the DB
+ * @since 3.2.4-RC1
+ */
+ $vars = array('user_row', 'result');
+ extract($phpbb_dispatcher->trigger_event('core.acp_users_avatar_sql', compact($vars)));
+
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $result) . '
WHERE user_id = ' . (int) $user_id;
@@ -1945,7 +1994,7 @@ class acp_users
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;u=' . $user_id), E_USER_WARNING);
}
- $rank_id = request_var('user_rank', 0);
+ $rank_id = $request->variable('user_rank', 0);
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_rank = $rank_id
@@ -1979,62 +2028,85 @@ class acp_users
case 'sig':
- if (!function_exists('generate_smilies'))
- {
- include($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
- }
-
if (!function_exists('display_custom_bbcodes'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
- $enable_bbcode = ($config['allow_sig_bbcode']) ? (bool) $this->optionget($user_row, 'sig_bbcode') : false;
- $enable_smilies = ($config['allow_sig_smilies']) ? (bool) $this->optionget($user_row, 'sig_smilies') : false;
- $enable_urls = ($config['allow_sig_links']) ? (bool) $this->optionget($user_row, 'sig_links') : false;
- $signature = utf8_normalize_nfc(request_var('signature', (string) $user_row['user_sig'], true));
+ $enable_bbcode = ($config['allow_sig_bbcode']) ? $this->optionget($user_row, 'sig_bbcode') : false;
+ $enable_smilies = ($config['allow_sig_smilies']) ? $this->optionget($user_row, 'sig_smilies') : false;
+ $enable_urls = ($config['allow_sig_links']) ? $this->optionget($user_row, 'sig_links') : false;
- $preview = (isset($_POST['preview'])) ? true : false;
+ $bbcode_flags = ($enable_bbcode ? OPTION_FLAG_BBCODE : 0) + ($enable_smilies ? OPTION_FLAG_SMILIES : 0) + ($enable_urls ? OPTION_FLAG_LINKS : 0);
- if ($submit || $preview)
- {
- if (!class_exists('messenger'))
- {
- include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
- }
+ $decoded_message = generate_text_for_edit($user_row['user_sig'], $user_row['user_sig_bbcode_uid'], $bbcode_flags);
+ $signature = $request->variable('signature', $decoded_message['text'], true);
+ $signature_preview = '';
- $enable_bbcode = ($config['allow_sig_bbcode']) ? ((request_var('disable_bbcode', false)) ? false : true) : false;
- $enable_smilies = ($config['allow_sig_smilies']) ? ((request_var('disable_smilies', false)) ? false : true) : false;
- $enable_urls = ($config['allow_sig_links']) ? ((request_var('disable_magic_url', false)) ? false : true) : false;
-
- $message_parser = new parse_message($signature);
-
- // Allowing Quote BBCode
- $message_parser->parse($enable_bbcode, $enable_urls, $enable_smilies, $config['allow_sig_img'], $config['allow_sig_flash'], true, $config['allow_sig_links'], true, 'sig');
-
- if (sizeof($message_parser->warn_msg))
- {
- $error[] = implode('<br />', $message_parser->warn_msg);
- }
+ if ($submit || $request->is_set_post('preview'))
+ {
+ $enable_bbcode = ($config['allow_sig_bbcode']) ? !$request->variable('disable_bbcode', false) : false;
+ $enable_smilies = ($config['allow_sig_smilies']) ? !$request->variable('disable_smilies', false) : false;
+ $enable_urls = ($config['allow_sig_links']) ? !$request->variable('disable_magic_url', false) : false;
if (!check_form_key($form_name))
{
- $error = 'FORM_INVALID';
+ $error[] = 'FORM_INVALID';
}
+ }
+
+ $bbcode_uid = $bbcode_bitfield = $bbcode_flags = '';
+ $warn_msg = generate_text_for_storage(
+ $signature,
+ $bbcode_uid,
+ $bbcode_bitfield,
+ $bbcode_flags,
+ $enable_bbcode,
+ $enable_urls,
+ $enable_smilies,
+ $config['allow_sig_img'],
+ $config['allow_sig_flash'],
+ true,
+ $config['allow_sig_links'],
+ 'sig'
+ );
+
+ if (count($warn_msg))
+ {
+ $error += $warn_msg;
+ }
- if (!sizeof($error) && $submit)
+ if (!$submit)
+ {
+ // Parse it for displaying
+ $signature_preview = generate_text_for_display($signature, $bbcode_uid, $bbcode_bitfield, $bbcode_flags);
+ }
+ else
+ {
+ if (!count($error))
{
$this->optionset($user_row, 'sig_bbcode', $enable_bbcode);
$this->optionset($user_row, 'sig_smilies', $enable_smilies);
$this->optionset($user_row, 'sig_links', $enable_urls);
$sql_ary = array(
- 'user_sig' => (string) $message_parser->message,
+ 'user_sig' => $signature,
'user_options' => $user_row['user_options'],
- 'user_sig_bbcode_uid' => (string) $message_parser->bbcode_uid,
- 'user_sig_bbcode_bitfield' => (string) $message_parser->bbcode_bitfield
+ 'user_sig_bbcode_uid' => $bbcode_uid,
+ 'user_sig_bbcode_bitfield' => $bbcode_bitfield,
);
+ /**
+ * Modify user signature before it is stored in the DB
+ *
+ * @event core.acp_users_modify_signature_sql_ary
+ * @var array user_row Array with user data
+ * @var array sql_ary Array with user signature data to be updated in the DB
+ * @since 3.2.4-RC1
+ */
+ $vars = array('user_row', 'sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.acp_users_modify_signature_sql_ary', compact($vars)));
+
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE user_id = ' . $user_id;
@@ -2042,33 +2114,30 @@ class acp_users
trigger_error($user->lang['USER_SIG_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
-
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $error);
}
- $signature_preview = '';
+ // Replace "error" strings with their real, localised form
+ $error = array_map(array($user, 'lang'), $error);
- if ($preview)
+ if ($request->is_set_post('preview'))
{
- // Now parse it for displaying
- $signature_preview = $message_parser->format_display($enable_bbcode, $enable_urls, $enable_smilies, false);
- unset($message_parser);
+ $decoded_message = generate_text_for_edit($signature, $bbcode_uid, $bbcode_flags);
}
- decode_message($signature, $user_row['user_sig_bbcode_uid']);
+ /** @var \phpbb\controller\helper $controller_helper */
+ $controller_helper = $phpbb_container->get('controller.helper');
$template->assign_vars(array(
'S_SIGNATURE' => true,
- 'SIGNATURE' => $signature,
+ 'SIGNATURE' => $decoded_message['text'],
'SIGNATURE_PREVIEW' => $signature_preview,
'S_BBCODE_CHECKED' => (!$enable_bbcode) ? ' checked="checked"' : '',
'S_SMILIES_CHECKED' => (!$enable_smilies) ? ' checked="checked"' : '',
'S_MAGIC_URL_CHECKED' => (!$enable_urls) ? ' checked="checked"' : '',
- 'BBCODE_STATUS' => ($config['allow_sig_bbcode']) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'),
+ 'BBCODE_STATUS' => $user->lang(($config['allow_sig_bbcode'] ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '<a href="' . $controller_helper->route('phpbb_help_bbcode_controller') . '">', '</a>'),
'SMILIES_STATUS' => ($config['allow_sig_smilies']) ? $user->lang['SMILIES_ARE_ON'] : $user->lang['SMILIES_ARE_OFF'],
'IMG_STATUS' => ($config['allow_sig_img']) ? $user->lang['IMAGES_ARE_ON'] : $user->lang['IMAGES_ARE_OFF'],
'FLASH_STATUS' => ($config['allow_sig_flash']) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'],
@@ -2089,17 +2158,18 @@ class acp_users
break;
case 'attach':
+ /* @var $pagination \phpbb\pagination */
+ $pagination = $phpbb_container->get('pagination');
- $start = request_var('start', 0);
+ $start = $request->variable('start', 0);
$deletemark = (isset($_POST['delmarked'])) ? true : false;
- $marked = request_var('mark', array(0));
- $pagination = $phpbb_container->get('pagination');
+ $marked = $request->variable('mark', array(0));
// Sort keys
- $sort_key = request_var('sk', 'a');
- $sort_dir = request_var('sd', 'd');
+ $sort_key = $request->variable('sk', 'a');
+ $sort_dir = $request->variable('sd', 'd');
- if ($deletemark && sizeof($marked))
+ if ($deletemark && count($marked))
{
$sql = 'SELECT attach_id
FROM ' . ATTACHMENTS_TABLE . '
@@ -2116,7 +2186,7 @@ class acp_users
$db->sql_freeresult($result);
}
- if ($deletemark && sizeof($marked))
+ if ($deletemark && count($marked))
{
if (confirm_box(true))
{
@@ -2132,11 +2202,14 @@ class acp_users
}
$db->sql_freeresult($result);
- delete_attachments('attach', $marked);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $attachment_manager->delete('attach', $marked);
+ unset($attachment_manager);
- $message = (sizeof($log_attachments) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED'];
+ $message = (count($log_attachments) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED'];
- add_log('admin', 'LOG_ATTACHMENTS_DELETED', implode($user->lang['COMMA_SEPARATOR'], $log_attachments));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ATTACHMENTS_DELETED', false, array(implode($user->lang['COMMA_SEPARATOR'], $log_attachments)));
trigger_error($message . adm_back_link($this->u_action . '&amp;u=' . $user_id));
}
else
@@ -2248,7 +2321,7 @@ class acp_users
}
$user->add_lang(array('groups', 'acp/groups'));
- $group_id = request_var('g', 0);
+ $group_id = $request->variable('g', 0);
if ($group_id)
{
@@ -2265,10 +2338,6 @@ class acp_users
trigger_error($user->lang['NOT_ALLOWED_MANAGE_GROUP'] . adm_back_link($this->u_action . '&amp;u=' . $user_id), E_USER_WARNING);
}
}
- else
- {
- $founder_manage = 0;
- }
switch ($action)
{
@@ -2379,6 +2448,9 @@ class acp_users
$error = array();
}
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
$sql = 'SELECT ug.*, g.*
FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . " ug
WHERE ug.user_id = $user_id
@@ -2405,7 +2477,7 @@ class acp_users
// Select box for other groups
$sql = 'SELECT group_id, group_name, group_type, group_founder_manage
FROM ' . GROUPS_TABLE . '
- ' . ((sizeof($id_ary)) ? 'WHERE ' . $db->sql_in_set('group_id', $id_ary, true) : '') . '
+ ' . ((count($id_ary)) ? 'WHERE ' . $db->sql_in_set('group_id', $id_ary, true) : '') . '
ORDER BY group_type DESC, group_name ASC';
$result = $db->sql_query($sql);
@@ -2423,7 +2495,7 @@ class acp_users
continue;
}
- $s_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '">' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>';
+ $s_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '">' . $group_helper->get_name($row['group_name']) . '</option>';
}
$db->sql_freeresult($result);
@@ -2447,7 +2519,7 @@ class acp_users
'U_DELETE' => $this->u_action . "&amp;action=delete&amp;u=$user_id&amp;g=" . $data['group_id'],
'U_APPROVE' => ($group_type == 'pending') ? $this->u_action . "&amp;action=approve&amp;u=$user_id&amp;g=" . $data['group_id'] : '',
- 'GROUP_NAME' => ($group_type == 'special') ? $user->lang['G_' . $data['group_name']] : $data['group_name'],
+ 'GROUP_NAME' => $group_helper->get_name($data['group_name']),
'L_DEMOTE_PROMOTE' => ($data['group_leader']) ? $user->lang['GROUP_DEMOTE'] : $user->lang['GROUP_PROMOTE'],
'S_IS_MEMBER' => ($group_type != 'pending') ? true : false,
@@ -2477,7 +2549,7 @@ class acp_users
$user->add_lang('acp/permissions');
add_permission_language();
- $forum_id = request_var('f', 0);
+ $forum_id = $request->variable('f', 0);
// Global Permissions
if (!$forum_id)
@@ -2534,12 +2606,28 @@ class acp_users
break;
+ default:
+
+ /**
+ * Additional modes provided by extensions
+ *
+ * @event core.acp_users_mode_add
+ * @var string mode New mode
+ * @var int user_id User id of the user to manage
+ * @var array user_row Array with user data
+ * @var array error Array with errors data
+ * @since 3.2.2-RC1
+ */
+ $vars = array('mode', 'user_id', 'user_row', 'error');
+ extract($phpbb_dispatcher->trigger_event('core.acp_users_mode_add', compact($vars)));
+
+ break;
}
// Assign general variables
$template->assign_vars(array(
- 'S_ERROR' => (sizeof($error)) ? true : false,
- 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '')
+ 'S_ERROR' => (count($error)) ? true : false,
+ 'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '')
);
}
diff --git a/phpBB/includes/acp/acp_words.php b/phpBB/includes/acp/acp_words.php
index 272d38bcc8..e5eeb7ab07 100644
--- a/phpBB/includes/acp/acp_words.php
+++ b/phpBB/includes/acp/acp_words.php
@@ -28,13 +28,12 @@ class acp_words
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $user, $template, $cache, $phpbb_log, $request, $phpbb_container;
$user->add_lang('acp/posting');
// Set up general vars
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
$action = (isset($_POST['add'])) ? 'add' : ((isset($_POST['save'])) ? 'save' : $action);
$s_hidden_fields = '';
@@ -50,7 +49,7 @@ class acp_words
{
case 'edit':
- $word_id = request_var('id', 0);
+ $word_id = $request->variable('id', 0);
if (!$word_id)
{
@@ -88,9 +87,9 @@ class acp_words
trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING);
}
- $word_id = request_var('id', 0);
- $word = utf8_normalize_nfc(request_var('word', '', true));
- $replacement = utf8_normalize_nfc(request_var('replacement', '', true));
+ $word_id = $request->variable('id', 0);
+ $word = $request->variable('word', '', true);
+ $replacement = $request->variable('replacement', '', true);
if ($word === '' || $replacement === '')
{
@@ -115,9 +114,11 @@ class acp_words
}
$cache->destroy('_word_censors');
+ $phpbb_container->get('text_formatter.cache')->invalidate();
$log_action = ($word_id) ? 'LOG_WORD_EDIT' : 'LOG_WORD_ADD';
- add_log('admin', $log_action, $word);
+
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log_action, false, array($word));
$message = ($word_id) ? $user->lang['WORD_UPDATED'] : $user->lang['WORD_ADDED'];
trigger_error($message . adm_back_link($this->u_action));
@@ -126,7 +127,7 @@ class acp_words
case 'delete':
- $word_id = request_var('id', 0);
+ $word_id = $request->variable('id', 0);
if (!$word_id)
{
@@ -147,8 +148,9 @@ class acp_words
$db->sql_query($sql);
$cache->destroy('_word_censors');
+ $phpbb_container->get('text_formatter.cache')->invalidate();
- add_log('admin', 'LOG_WORD_DELETE', $deleted_word);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_WORD_DELETE', false, array($deleted_word));
trigger_error($user->lang['WORD_REMOVED'] . adm_back_link($this->u_action));
}
diff --git a/phpBB/includes/acp/auth.php b/phpBB/includes/acp/auth.php
index 52c45499b2..b414a3121a 100644
--- a/phpBB/includes/acp/auth.php
+++ b/phpBB/includes/acp/auth.php
@@ -27,7 +27,7 @@ class auth_admin extends \phpbb\auth\auth
/**
* Init auth settings
*/
- function auth_admin()
+ function __construct()
{
global $db, $cache;
@@ -107,7 +107,7 @@ class auth_admin extends \phpbb\auth\auth
$compare_options = array_diff(preg_replace('/^((?!' . $auth_option . ').+)|(' . $auth_option . ')$/', '', array_keys($this->acl_options[$scope])), array(''));
// If forum_ids is false and the scope is local we actually want to have all forums within the array
- if ($scope == 'local' && !sizeof($forum_ids))
+ if ($scope == 'local' && !count($forum_ids))
{
$sql = 'SELECT forum_id
FROM ' . FORUMS_TABLE;
@@ -177,9 +177,9 @@ class auth_admin extends \phpbb\auth\auth
// Now, we need to fill the gaps with $acl_fill. ;)
// Now switch back to keys
- if (sizeof($compare_options))
+ if (count($compare_options))
{
- $compare_options = array_combine($compare_options, array_fill(1, sizeof($compare_options), $acl_fill));
+ $compare_options = array_combine($compare_options, array_fill(1, count($compare_options), $acl_fill));
}
// Defining the user-function here to save some memory
@@ -189,7 +189,7 @@ class auth_admin extends \phpbb\auth\auth
};
// Actually fill the gaps
- if (sizeof($hold_ary))
+ if (count($hold_ary))
{
foreach ($hold_ary as $ug_id => $row)
{
@@ -266,9 +266,14 @@ class auth_admin extends \phpbb\auth\auth
*/
function display_mask($mode, $permission_type, &$hold_ary, $user_mode = 'user', $local = false, $group_display = true)
{
- global $template, $user, $db, $phpbb_root_path, $phpEx, $phpbb_container;
+ global $template, $user, $db, $phpbb_container;
+
+ /* @var $phpbb_permissions \phpbb\permissions */
$phpbb_permissions = $phpbb_container->get('acl.permissions');
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
// Define names for template loops, might be able to be set
$tpl_pmask = 'p_mask';
$tpl_fmask = 'f_mask';
@@ -300,7 +305,7 @@ class auth_admin extends \phpbb\auth\auth
$ug_names_ary = array();
while ($row = $db->sql_fetchrow($result))
{
- $ug_names_ary[$row['ug_id']] = ($user_mode == 'user') ? $row['ug_name'] : (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['ug_name']] : $row['ug_name']);
+ $ug_names_ary[$row['ug_id']] = ($user_mode == 'user') ? $row['ug_name'] : $group_helper->get_name($row['ug_name']);
}
$db->sql_freeresult($result);
@@ -351,7 +356,7 @@ class auth_admin extends \phpbb\auth\auth
// Build js roles array (role data assignments)
$s_role_js_array = '';
- if (sizeof($roles))
+ if (count($roles))
{
$s_role_js_array = array();
@@ -408,14 +413,7 @@ class auth_admin extends \phpbb\auth\auth
{
foreach ($memberships as $row)
{
- if ($groups[$row['group_id']]['group_type'] == GROUP_SPECIAL)
- {
- $user_groups_default[$row['user_id']][] = $user->lang['G_' . $groups[$row['group_id']]['group_name']];
- }
- else
- {
- $user_groups_custom[$row['user_id']][] = $groups[$row['group_id']]['group_name'];
- }
+ $user_groups_default[$row['user_id']][] = $group_helper->get_name($groups[$row['group_id']]['group_name']);
}
}
unset($memberships, $groups);
@@ -424,7 +422,7 @@ class auth_admin extends \phpbb\auth\auth
// If we only have one forum id to display or being in local mode and more than one user/group to display,
// we switch the complete interface to group by user/usergroup instead of grouping by forum
// To achieve this, we need to switch the array a bit
- if (sizeof($forum_ids) == 1 || ($local && sizeof($ug_names_ary) > 1))
+ if (count($forum_ids) == 1 || ($local && count($ug_names_ary) > 1))
{
$hold_ary_temp = $hold_ary;
$hold_ary = array();
@@ -455,9 +453,9 @@ class auth_admin extends \phpbb\auth\auth
'S_LOCAL' => ($local) ? true : false,
'S_GLOBAL' => (!$local) ? true : false,
- 'S_NUM_CATS' => sizeof($categories),
+ 'S_NUM_CATS' => count($categories),
'S_VIEW' => ($mode == 'view') ? true : false,
- 'S_NUM_OBJECTS' => sizeof($content_array),
+ 'S_NUM_OBJECTS' => count($content_array),
'S_USER_MODE' => ($user_mode == 'user') ? true : false,
'S_GROUP_MODE' => ($user_mode == 'group') ? true : false)
);
@@ -468,7 +466,10 @@ class auth_admin extends \phpbb\auth\auth
// Build role dropdown options
$current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
+ $role_options = array();
+
$s_role_options = '';
+ $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
@reset($roles);
while (list($role_id, $role_row) = each($roles))
@@ -478,6 +479,13 @@ class auth_admin extends \phpbb\auth\auth
$title = ($role_description) ? ' title="' . $role_description . '"' : '';
$s_role_options .= '<option value="' . $role_id . '"' . (($role_id == $current_role_id) ? ' selected="selected"' : '') . $title . '>' . $role_name . '</option>';
+
+ $role_options[] = array(
+ 'ID' => $role_id,
+ 'ROLE_NAME' => $role_name,
+ 'TITLE' => $role_description,
+ 'SELECTED' => $role_id == $current_role_id,
+ );
}
if ($s_role_options)
@@ -505,11 +513,14 @@ class auth_admin extends \phpbb\auth\auth
$template->assign_block_vars($tpl_pmask . '.' . $tpl_fmask, array(
'NAME' => $ug_names_ary[$ug_id],
- 'S_ROLE_OPTIONS' => $s_role_options,
'UG_ID' => $ug_id,
+ 'S_ROLE_OPTIONS' => $s_role_options,
'S_CUSTOM' => $s_custom_permissions,
- 'FORUM_ID' => $forum_id)
- );
+ 'FORUM_ID' => $forum_id,
+ 'S_ROLE_ID' => $current_role_id,
+ ));
+
+ $template->assign_block_vars_array($tpl_pmask . '.' . $tpl_fmask . '.role_options', $role_options);
$this->assign_cat_array($ug_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace);
@@ -535,15 +546,15 @@ class auth_admin extends \phpbb\auth\auth
'NAME' => $ug_name,
'CATEGORIES' => implode('</th><th>', $categories),
- 'USER_GROUPS_DEFAULT' => ($user_mode == 'user' && isset($user_groups_default[$ug_id]) && sizeof($user_groups_default[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_default[$ug_id]) : '',
- 'USER_GROUPS_CUSTOM' => ($user_mode == 'user' && isset($user_groups_custom[$ug_id]) && sizeof($user_groups_custom[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_custom[$ug_id]) : '',
+ 'USER_GROUPS_DEFAULT' => ($user_mode == 'user' && isset($user_groups_default[$ug_id]) && count($user_groups_default[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_default[$ug_id]) : '',
+ 'USER_GROUPS_CUSTOM' => ($user_mode == 'user' && isset($user_groups_custom[$ug_id]) && count($user_groups_custom[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_custom[$ug_id]) : '',
'L_ACL_TYPE' => $l_acl_type,
'S_LOCAL' => ($local) ? true : false,
'S_GLOBAL' => (!$local) ? true : false,
- 'S_NUM_CATS' => sizeof($categories),
+ 'S_NUM_CATS' => count($categories),
'S_VIEW' => ($mode == 'view') ? true : false,
- 'S_NUM_OBJECTS' => sizeof($content_array),
+ 'S_NUM_OBJECTS' => count($content_array),
'S_USER_MODE' => ($user_mode == 'user') ? true : false,
'S_GROUP_MODE' => ($user_mode == 'group') ? true : false)
);
@@ -554,6 +565,9 @@ class auth_admin extends \phpbb\auth\auth
// Build role dropdown options
$current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
+ $role_options = array();
+
+ $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
$s_role_options = '';
@reset($roles);
@@ -564,6 +578,13 @@ class auth_admin extends \phpbb\auth\auth
$title = ($role_description) ? ' title="' . $role_description . '"' : '';
$s_role_options .= '<option value="' . $role_id . '"' . (($role_id == $current_role_id) ? ' selected="selected"' : '') . $title . '>' . $role_name . '</option>';
+
+ $role_options[] = array(
+ 'ID' => $role_id,
+ 'ROLE_NAME' => $role_name,
+ 'TITLE' => $role_description,
+ 'SELECTED' => $role_id == $current_role_id,
+ );
}
if ($s_role_options)
@@ -592,12 +613,14 @@ class auth_admin extends \phpbb\auth\auth
$template->assign_block_vars($tpl_pmask . '.' . $tpl_fmask, array(
'NAME' => ($forum_id == 0) ? $forum_names_ary[0] : $forum_names_ary[$forum_id]['forum_name'],
'PADDING' => ($forum_id == 0) ? '' : $forum_names_ary[$forum_id]['padding'],
- 'S_ROLE_OPTIONS' => $s_role_options,
'S_CUSTOM' => $s_custom_permissions,
'UG_ID' => $ug_id,
+ 'S_ROLE_OPTIONS' => $s_role_options,
'FORUM_ID' => $forum_id)
);
+ $template->assign_block_vars_array($tpl_pmask . '.' . $tpl_fmask . '.role_options', $role_options);
+
$this->assign_cat_array($forum_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace);
}
@@ -611,13 +634,17 @@ class auth_admin extends \phpbb\auth\auth
*/
function display_role_mask(&$hold_ary)
{
- global $db, $template, $user, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $template, $user, $phpbb_root_path, $phpEx;
+ global $phpbb_container;
- if (!sizeof($hold_ary))
+ if (!count($hold_ary))
{
return;
}
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
// Get forum names
$sql = 'SELECT forum_id, forum_name
FROM ' . FORUMS_TABLE . '
@@ -642,7 +669,7 @@ class auth_admin extends \phpbb\auth\auth
'FORUM_ID' => $forum_id)
);
- if (isset($auth_ary['users']) && sizeof($auth_ary['users']))
+ if (isset($auth_ary['users']) && count($auth_ary['users']))
{
$sql = 'SELECT user_id, username
FROM ' . USERS_TABLE . '
@@ -661,7 +688,7 @@ class auth_admin extends \phpbb\auth\auth
$db->sql_freeresult($result);
}
- if (isset($auth_ary['groups']) && sizeof($auth_ary['groups']))
+ if (isset($auth_ary['groups']) && count($auth_ary['groups']))
{
$sql = 'SELECT group_id, group_name, group_type
FROM ' . GROUPS_TABLE . '
@@ -673,7 +700,7 @@ class auth_admin extends \phpbb\auth\auth
{
$template->assign_block_vars('role_mask.groups', array(
'GROUP_ID' => $row['group_id'],
- 'GROUP_NAME' => ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'],
+ 'GROUP_NAME' => $group_helper->get_name($row['group_name']),
'U_PROFILE' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=group&amp;g={$row['group_id']}"))
);
}
@@ -792,7 +819,7 @@ class auth_admin extends \phpbb\auth\auth
// Because we just changed the options and also purged the options cache, we instantly update/regenerate it for later calls to succeed.
$this->acl_options = array();
- $this->auth_admin();
+ $this->__construct();
return true;
}
@@ -863,7 +890,7 @@ class auth_admin extends \phpbb\auth\auth
}
$db->sql_freeresult($result);
- if (sizeof($role_ids))
+ if (count($role_ids))
{
$sql = "DELETE FROM $table
WHERE $forum_sql
@@ -973,7 +1000,7 @@ class auth_admin extends \phpbb\auth\auth
}
// If no data is there, we set the any-flag to ACL_NEVER...
- if (!sizeof($sql_ary))
+ if (!count($sql_ary))
{
$sql_ary[] = array(
'role_id' => (int) $role_id,
@@ -1056,7 +1083,7 @@ class auth_admin extends \phpbb\auth\auth
$db->sql_freeresult($result);
// Get role data for resetting data
- if (sizeof($cur_role_auth))
+ if (count($cur_role_auth))
{
$sql = 'SELECT ao.auth_option, rd.role_id, rd.auth_setting
FROM ' . ACL_OPTIONS_TABLE . ' ao, ' . ACL_ROLES_DATA_TABLE . ' rd
@@ -1106,8 +1133,9 @@ class auth_admin extends \phpbb\auth\auth
*/
function assign_cat_array(&$category_array, $tpl_cat, $tpl_mask, $ug_id, $forum_id, $s_view, $show_trace = false)
{
- global $template, $user, $phpbb_admin_path, $phpEx, $phpbb_container;
+ global $template, $phpbb_admin_path, $phpEx, $phpbb_container;
+ /* @var $phpbb_permissions \phpbb\permissions */
$phpbb_permissions = $phpbb_container->get('acl.permissions');
@reset($category_array);
@@ -1194,8 +1222,9 @@ class auth_admin extends \phpbb\auth\auth
*/
function build_permission_array(&$permission_row, &$content_array, &$categories, $key_sort_array)
{
- global $user, $phpbb_container;
+ global $phpbb_container;
+ /* @var $phpbb_permissions \phpbb\permissions */
$phpbb_permissions = $phpbb_container->get('acl.permissions');
foreach ($key_sort_array as $forum_id)
diff --git a/phpBB/includes/acp/info/acp_attachments.php b/phpBB/includes/acp/info/acp_attachments.php
index ff6e342f77..057f08201e 100644
--- a/phpBB/includes/acp/info/acp_attachments.php
+++ b/phpBB/includes/acp/info/acp_attachments.php
@@ -18,7 +18,6 @@ class acp_attachments_info
return array(
'filename' => 'acp_attachments',
'title' => 'ACP_ATTACHMENTS',
- 'version' => '1.0.0',
'modes' => array(
'attach' => array('title' => 'ACP_ATTACHMENT_SETTINGS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_BOARD_CONFIGURATION', 'ACP_ATTACHMENTS')),
'extensions' => array('title' => 'ACP_MANAGE_EXTENSIONS', 'auth' => 'acl_a_attach', 'cat' => array('ACP_ATTACHMENTS')),
diff --git a/phpBB/includes/acp/info/acp_ban.php b/phpBB/includes/acp/info/acp_ban.php
index 4959f4da41..c88f4c2ebb 100644
--- a/phpBB/includes/acp/info/acp_ban.php
+++ b/phpBB/includes/acp/info/acp_ban.php
@@ -18,7 +18,6 @@ class acp_ban_info
return array(
'filename' => 'acp_ban',
'title' => 'ACP_BAN',
- 'version' => '1.0.0',
'modes' => array(
'email' => array('title' => 'ACP_BAN_EMAILS', 'auth' => 'acl_a_ban', 'cat' => array('ACP_USER_SECURITY')),
'ip' => array('title' => 'ACP_BAN_IPS', 'auth' => 'acl_a_ban', 'cat' => array('ACP_USER_SECURITY')),
diff --git a/phpBB/includes/acp/info/acp_bbcodes.php b/phpBB/includes/acp/info/acp_bbcodes.php
index 2bca319cc3..dfcd43a8ac 100644
--- a/phpBB/includes/acp/info/acp_bbcodes.php
+++ b/phpBB/includes/acp/info/acp_bbcodes.php
@@ -18,7 +18,6 @@ class acp_bbcodes_info
return array(
'filename' => 'acp_bbcodes',
'title' => 'ACP_BBCODES',
- 'version' => '1.0.0',
'modes' => array(
'bbcodes' => array('title' => 'ACP_BBCODES', 'auth' => 'acl_a_bbcode', 'cat' => array('ACP_MESSAGES')),
),
diff --git a/phpBB/includes/acp/info/acp_board.php b/phpBB/includes/acp/info/acp_board.php
index 6838b4f8ba..1a3ee7b6be 100644
--- a/phpBB/includes/acp/info/acp_board.php
+++ b/phpBB/includes/acp/info/acp_board.php
@@ -18,7 +18,6 @@ class acp_board_info
return array(
'filename' => 'acp_board',
'title' => 'ACP_BOARD_MANAGEMENT',
- 'version' => '1.0.0',
'modes' => array(
'settings' => array('title' => 'ACP_BOARD_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'features' => array('title' => 'ACP_BOARD_FEATURES', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
diff --git a/phpBB/includes/acp/info/acp_bots.php b/phpBB/includes/acp/info/acp_bots.php
index 9aa24927af..26782d8c0b 100644
--- a/phpBB/includes/acp/info/acp_bots.php
+++ b/phpBB/includes/acp/info/acp_bots.php
@@ -18,7 +18,6 @@ class acp_bots_info
return array(
'filename' => 'acp_bots',
'title' => 'ACP_BOTS',
- 'version' => '1.0.0',
'modes' => array(
'bots' => array('title' => 'ACP_BOTS', 'auth' => 'acl_a_bots', 'cat' => array('ACP_GENERAL_TASKS')),
),
diff --git a/phpBB/includes/acp/info/acp_captcha.php b/phpBB/includes/acp/info/acp_captcha.php
index 99dc5ce0e5..3f7bf0351d 100644
--- a/phpBB/includes/acp/info/acp_captcha.php
+++ b/phpBB/includes/acp/info/acp_captcha.php
@@ -18,7 +18,6 @@ class acp_captcha_info
return array(
'filename' => 'acp_captcha',
'title' => 'ACP_CAPTCHA',
- 'version' => '1.0.0',
'modes' => array(
'visual' => array('title' => 'ACP_VC_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')),
'img' => array('title' => 'ACP_VC_CAPTCHA_DISPLAY', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION'), 'display' => false)
diff --git a/phpBB/includes/acp/info/acp_database.php b/phpBB/includes/acp/info/acp_database.php
index 5cf9da24fb..815db53b67 100644
--- a/phpBB/includes/acp/info/acp_database.php
+++ b/phpBB/includes/acp/info/acp_database.php
@@ -18,7 +18,6 @@ class acp_database_info
return array(
'filename' => 'acp_database',
'title' => 'ACP_DATABASE',
- 'version' => '1.0.0',
'modes' => array(
'backup' => array('title' => 'ACP_BACKUP', 'auth' => 'acl_a_backup', 'cat' => array('ACP_CAT_DATABASE')),
'restore' => array('title' => 'ACP_RESTORE', 'auth' => 'acl_a_backup', 'cat' => array('ACP_CAT_DATABASE')),
diff --git a/phpBB/includes/acp/info/acp_disallow.php b/phpBB/includes/acp/info/acp_disallow.php
index ebd44b515c..df4765b6bb 100644
--- a/phpBB/includes/acp/info/acp_disallow.php
+++ b/phpBB/includes/acp/info/acp_disallow.php
@@ -18,7 +18,6 @@ class acp_disallow_info
return array(
'filename' => 'acp_disallow',
'title' => 'ACP_DISALLOW',
- 'version' => '1.0.0',
'modes' => array(
'usernames' => array('title' => 'ACP_DISALLOW_USERNAMES', 'auth' => 'acl_a_names', 'cat' => array('ACP_USER_SECURITY')),
),
diff --git a/phpBB/includes/acp/info/acp_email.php b/phpBB/includes/acp/info/acp_email.php
index 2f77fc617c..e85ef0923a 100644
--- a/phpBB/includes/acp/info/acp_email.php
+++ b/phpBB/includes/acp/info/acp_email.php
@@ -18,7 +18,6 @@ class acp_email_info
return array(
'filename' => 'acp_email',
'title' => 'ACP_MASS_EMAIL',
- 'version' => '1.0.0',
'modes' => array(
'email' => array('title' => 'ACP_MASS_EMAIL', 'auth' => 'acl_a_email && cfg_email_enable', 'cat' => array('ACP_GENERAL_TASKS')),
),
diff --git a/phpBB/includes/acp/info/acp_extensions.php b/phpBB/includes/acp/info/acp_extensions.php
index d4cf1b0ed5..9adcd543b9 100644
--- a/phpBB/includes/acp/info/acp_extensions.php
+++ b/phpBB/includes/acp/info/acp_extensions.php
@@ -18,7 +18,6 @@ class acp_extensions_info
return array(
'filename' => 'acp_extensions',
'title' => 'ACP_EXTENSION_MANAGEMENT',
- 'version' => '1.0.0',
'modes' => array(
'main' => array('title' => 'ACP_EXTENSIONS', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_EXTENSION_MANAGEMENT')),
),
diff --git a/phpBB/includes/acp/info/acp_forums.php b/phpBB/includes/acp/info/acp_forums.php
index 647090c8c3..8b5ce7edc2 100644
--- a/phpBB/includes/acp/info/acp_forums.php
+++ b/phpBB/includes/acp/info/acp_forums.php
@@ -18,7 +18,6 @@ class acp_forums_info
return array(
'filename' => 'acp_forums',
'title' => 'ACP_FORUM_MANAGEMENT',
- 'version' => '1.0.0',
'modes' => array(
'manage' => array('title' => 'ACP_MANAGE_FORUMS', 'auth' => 'acl_a_forum', 'cat' => array('ACP_MANAGE_FORUMS')),
),
diff --git a/phpBB/includes/acp/info/acp_groups.php b/phpBB/includes/acp/info/acp_groups.php
index 6c5ad70d97..e0aafeca0d 100644
--- a/phpBB/includes/acp/info/acp_groups.php
+++ b/phpBB/includes/acp/info/acp_groups.php
@@ -18,7 +18,6 @@ class acp_groups_info
return array(
'filename' => 'acp_groups',
'title' => 'ACP_GROUPS_MANAGEMENT',
- 'version' => '1.0.0',
'modes' => array(
'manage' => array('title' => 'ACP_GROUPS_MANAGE', 'auth' => 'acl_a_group', 'cat' => array('ACP_GROUPS')),
'position' => array('title' => 'ACP_GROUPS_POSITION', 'auth' => 'acl_a_group', 'cat' => array('ACP_GROUPS')),
diff --git a/phpBB/includes/acp/info/acp_help_phpbb.php b/phpBB/includes/acp/info/acp_help_phpbb.php
new file mode 100644
index 0000000000..dee8ef41d7
--- /dev/null
+++ b/phpBB/includes/acp/info/acp_help_phpbb.php
@@ -0,0 +1,34 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class acp_help_phpbb_info
+{
+ function module()
+ {
+ return array(
+ 'filename' => 'acp_help_phpbb',
+ 'title' => 'ACP_HELP_PHPBB',
+ 'modes' => array(
+ 'help_phpbb' => array('title' => 'ACP_HELP_PHPBB', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')),
+ ),
+ );
+ }
+
+ function install()
+ {
+ }
+
+ function uninstall()
+ {
+ }
+}
diff --git a/phpBB/includes/acp/info/acp_icons.php b/phpBB/includes/acp/info/acp_icons.php
index 001d6cb402..87eadddd8d 100644
--- a/phpBB/includes/acp/info/acp_icons.php
+++ b/phpBB/includes/acp/info/acp_icons.php
@@ -18,7 +18,6 @@ class acp_icons_info
return array(
'filename' => 'acp_icons',
'title' => 'ACP_ICONS_SMILIES',
- 'version' => '1.0.0',
'modes' => array(
'icons' => array('title' => 'ACP_ICONS', 'auth' => 'acl_a_icons', 'cat' => array('ACP_MESSAGES')),
'smilies' => array('title' => 'ACP_SMILIES', 'auth' => 'acl_a_icons', 'cat' => array('ACP_MESSAGES')),
diff --git a/phpBB/includes/acp/info/acp_inactive.php b/phpBB/includes/acp/info/acp_inactive.php
index 442eb13c30..38cb964735 100644
--- a/phpBB/includes/acp/info/acp_inactive.php
+++ b/phpBB/includes/acp/info/acp_inactive.php
@@ -18,7 +18,6 @@ class acp_inactive_info
return array(
'filename' => 'acp_inactive',
'title' => 'ACP_INACTIVE_USERS',
- 'version' => '1.0.0',
'modes' => array(
'list' => array('title' => 'ACP_INACTIVE_USERS', 'auth' => 'acl_a_user', 'cat' => array('ACP_CAT_USERS')),
),
diff --git a/phpBB/includes/acp/info/acp_jabber.php b/phpBB/includes/acp/info/acp_jabber.php
index c1dfb2aca7..660299a12d 100644
--- a/phpBB/includes/acp/info/acp_jabber.php
+++ b/phpBB/includes/acp/info/acp_jabber.php
@@ -18,7 +18,6 @@ class acp_jabber_info
return array(
'filename' => 'acp_jabber',
'title' => 'ACP_JABBER_SETTINGS',
- 'version' => '1.0.0',
'modes' => array(
'settings' => array('title' => 'ACP_JABBER_SETTINGS', 'auth' => 'acl_a_jabber', 'cat' => array('ACP_CLIENT_COMMUNICATION')),
),
diff --git a/phpBB/includes/acp/info/acp_language.php b/phpBB/includes/acp/info/acp_language.php
index b9efbbbd9a..1a5a2b6ba8 100644
--- a/phpBB/includes/acp/info/acp_language.php
+++ b/phpBB/includes/acp/info/acp_language.php
@@ -18,7 +18,6 @@ class acp_language_info
return array(
'filename' => 'acp_language',
'title' => 'ACP_LANGUAGE',
- 'version' => '1.0.0',
'modes' => array(
'lang_packs' => array('title' => 'ACP_LANGUAGE_PACKS', 'auth' => 'acl_a_language', 'cat' => array('ACP_LANGUAGE')),
),
diff --git a/phpBB/includes/acp/info/acp_logs.php b/phpBB/includes/acp/info/acp_logs.php
index 3b2764c4dc..1be7b2883d 100644
--- a/phpBB/includes/acp/info/acp_logs.php
+++ b/phpBB/includes/acp/info/acp_logs.php
@@ -38,7 +38,6 @@ class acp_logs_info
return array(
'filename' => 'acp_logs',
'title' => 'ACP_LOGGING',
- 'version' => '1.0.0',
'modes' => $modes,
);
}
diff --git a/phpBB/includes/acp/info/acp_main.php b/phpBB/includes/acp/info/acp_main.php
index 51259e3bd9..48d35da585 100644
--- a/phpBB/includes/acp/info/acp_main.php
+++ b/phpBB/includes/acp/info/acp_main.php
@@ -18,7 +18,6 @@ class acp_main_info
return array(
'filename' => 'acp_main',
'title' => 'ACP_INDEX',
- 'version' => '1.0.0',
'modes' => array(
'main' => array('title' => 'ACP_INDEX', 'auth' => '', 'cat' => array('ACP_CAT_GENERAL')),
),
diff --git a/phpBB/includes/acp/info/acp_modules.php b/phpBB/includes/acp/info/acp_modules.php
index a47cd4ad83..073e69c6a8 100644
--- a/phpBB/includes/acp/info/acp_modules.php
+++ b/phpBB/includes/acp/info/acp_modules.php
@@ -18,7 +18,6 @@ class acp_modules_info
return array(
'filename' => 'acp_modules',
'title' => 'ACP_MODULE_MANAGEMENT',
- 'version' => '1.0.0',
'modes' => array(
'acp' => array('title' => 'ACP', 'auth' => 'acl_a_modules', 'cat' => array('ACP_MODULE_MANAGEMENT')),
'ucp' => array('title' => 'UCP', 'auth' => 'acl_a_modules', 'cat' => array('ACP_MODULE_MANAGEMENT')),
diff --git a/phpBB/includes/acp/info/acp_permission_roles.php b/phpBB/includes/acp/info/acp_permission_roles.php
index e8aa13375d..34af693b7b 100644
--- a/phpBB/includes/acp/info/acp_permission_roles.php
+++ b/phpBB/includes/acp/info/acp_permission_roles.php
@@ -18,7 +18,6 @@ class acp_permission_roles_info
return array(
'filename' => 'acp_permission_roles',
'title' => 'ACP_PERMISSION_ROLES',
- 'version' => '1.0.0',
'modes' => array(
'admin_roles' => array('title' => 'ACP_ADMIN_ROLES', 'auth' => 'acl_a_roles && acl_a_aauth', 'cat' => array('ACP_PERMISSION_ROLES')),
'user_roles' => array('title' => 'ACP_USER_ROLES', 'auth' => 'acl_a_roles && acl_a_uauth', 'cat' => array('ACP_PERMISSION_ROLES')),
diff --git a/phpBB/includes/acp/info/acp_permissions.php b/phpBB/includes/acp/info/acp_permissions.php
index 3ec592a300..3d415f2b72 100644
--- a/phpBB/includes/acp/info/acp_permissions.php
+++ b/phpBB/includes/acp/info/acp_permissions.php
@@ -18,7 +18,6 @@ class acp_permissions_info
return array(
'filename' => 'acp_permissions',
'title' => 'ACP_PERMISSIONS',
- 'version' => '1.0.0',
'modes' => array(
'intro' => array('title' => 'ACP_PERMISSIONS', 'auth' => 'acl_a_authusers || acl_a_authgroups || acl_a_viewauth', 'cat' => array('ACP_CAT_PERMISSIONS')),
'trace' => array('title' => 'ACP_PERMISSION_TRACE', 'auth' => 'acl_a_viewauth', 'display' => false, 'cat' => array('ACP_PERMISSION_MASKS')),
diff --git a/phpBB/includes/acp/info/acp_php_info.php b/phpBB/includes/acp/info/acp_php_info.php
index af978e0daa..c5e60c7e66 100644
--- a/phpBB/includes/acp/info/acp_php_info.php
+++ b/phpBB/includes/acp/info/acp_php_info.php
@@ -18,7 +18,6 @@ class acp_php_info_info
return array(
'filename' => 'acp_php_info',
'title' => 'ACP_PHP_INFO',
- 'version' => '1.0.0',
'modes' => array(
'info' => array('title' => 'ACP_PHP_INFO', 'auth' => 'acl_a_phpinfo', 'cat' => array('ACP_GENERAL_TASKS')),
),
diff --git a/phpBB/includes/acp/info/acp_profile.php b/phpBB/includes/acp/info/acp_profile.php
index 307e711eee..ede34204b4 100644
--- a/phpBB/includes/acp/info/acp_profile.php
+++ b/phpBB/includes/acp/info/acp_profile.php
@@ -18,7 +18,6 @@ class acp_profile_info
return array(
'filename' => 'acp_profile',
'title' => 'ACP_CUSTOM_PROFILE_FIELDS',
- 'version' => '1.0.0',
'modes' => array(
'profile' => array('title' => 'ACP_CUSTOM_PROFILE_FIELDS', 'auth' => 'acl_a_profile', 'cat' => array('ACP_CAT_USERS')),
),
diff --git a/phpBB/includes/acp/info/acp_prune.php b/phpBB/includes/acp/info/acp_prune.php
index 58cb1ba9ab..74e5248aa9 100644
--- a/phpBB/includes/acp/info/acp_prune.php
+++ b/phpBB/includes/acp/info/acp_prune.php
@@ -18,7 +18,6 @@ class acp_prune_info
return array(
'filename' => 'acp_prune',
'title' => 'ACP_PRUNING',
- 'version' => '1.0.0',
'modes' => array(
'forums' => array('title' => 'ACP_PRUNE_FORUMS', 'auth' => 'acl_a_prune', 'cat' => array('ACP_MANAGE_FORUMS')),
'users' => array('title' => 'ACP_PRUNE_USERS', 'auth' => 'acl_a_userdel', 'cat' => array('ACP_CAT_USERS')),
diff --git a/phpBB/includes/acp/info/acp_ranks.php b/phpBB/includes/acp/info/acp_ranks.php
index 3cc9b4a428..9bf51eba3c 100644
--- a/phpBB/includes/acp/info/acp_ranks.php
+++ b/phpBB/includes/acp/info/acp_ranks.php
@@ -18,7 +18,6 @@ class acp_ranks_info
return array(
'filename' => 'acp_ranks',
'title' => 'ACP_RANKS',
- 'version' => '1.0.0',
'modes' => array(
'ranks' => array('title' => 'ACP_MANAGE_RANKS', 'auth' => 'acl_a_ranks', 'cat' => array('ACP_CAT_USERS')),
),
diff --git a/phpBB/includes/acp/info/acp_reasons.php b/phpBB/includes/acp/info/acp_reasons.php
index c48fd1aacd..55a0495d0f 100644
--- a/phpBB/includes/acp/info/acp_reasons.php
+++ b/phpBB/includes/acp/info/acp_reasons.php
@@ -18,7 +18,6 @@ class acp_reasons_info
return array(
'filename' => 'acp_reasons',
'title' => 'ACP_REASONS',
- 'version' => '1.0.0',
'modes' => array(
'main' => array('title' => 'ACP_MANAGE_REASONS', 'auth' => 'acl_a_reasons', 'cat' => array('ACP_GENERAL_TASKS')),
),
diff --git a/phpBB/includes/acp/info/acp_search.php b/phpBB/includes/acp/info/acp_search.php
index 5d681a7174..0635dd9edd 100644
--- a/phpBB/includes/acp/info/acp_search.php
+++ b/phpBB/includes/acp/info/acp_search.php
@@ -18,7 +18,6 @@ class acp_search_info
return array(
'filename' => 'acp_search',
'title' => 'ACP_SEARCH',
- 'version' => '1.0.0',
'modes' => array(
'settings' => array('title' => 'ACP_SEARCH_SETTINGS', 'auth' => 'acl_a_search', 'cat' => array('ACP_SERVER_CONFIGURATION')),
'index' => array('title' => 'ACP_SEARCH_INDEX', 'auth' => 'acl_a_search', 'cat' => array('ACP_CAT_DATABASE')),
diff --git a/phpBB/includes/acp/info/acp_send_statistics.php b/phpBB/includes/acp/info/acp_send_statistics.php
deleted file mode 100644
index a4f2ddc420..0000000000
--- a/phpBB/includes/acp/info/acp_send_statistics.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-class acp_send_statistics_info
-{
- function module()
- {
- return array(
- 'filename' => 'acp_send_statistics',
- 'title' => 'ACP_SEND_STATISTICS',
- 'version' => '1.0.0',
- 'modes' => array(
- 'send_statistics' => array('title' => 'ACP_SEND_STATISTICS', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')),
- ),
- );
- }
-
- function install()
- {
- }
-
- function uninstall()
- {
- }
-}
diff --git a/phpBB/includes/acp/info/acp_styles.php b/phpBB/includes/acp/info/acp_styles.php
index c0ab005502..59b0a64899 100644
--- a/phpBB/includes/acp/info/acp_styles.php
+++ b/phpBB/includes/acp/info/acp_styles.php
@@ -18,7 +18,6 @@ class acp_styles_info
return array(
'filename' => 'acp_styles',
'title' => 'ACP_CAT_STYLES',
- 'version' => '2.0.0',
'modes' => array(
'style' => array('title' => 'ACP_STYLES', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_MANAGEMENT')),
'install' => array('title' => 'ACP_STYLES_INSTALL', 'auth' => 'acl_a_styles', 'cat' => array('ACP_STYLE_MANAGEMENT')),
diff --git a/phpBB/includes/acp/info/acp_update.php b/phpBB/includes/acp/info/acp_update.php
index ca00f6d305..7806fb4891 100644
--- a/phpBB/includes/acp/info/acp_update.php
+++ b/phpBB/includes/acp/info/acp_update.php
@@ -18,7 +18,6 @@ class acp_update_info
return array(
'filename' => 'acp_update',
'title' => 'ACP_UPDATE',
- 'version' => '1.0.0',
'modes' => array(
'version_check' => array('title' => 'ACP_VERSION_CHECK', 'auth' => 'acl_a_board', 'cat' => array('ACP_AUTOMATION')),
),
diff --git a/phpBB/includes/acp/info/acp_users.php b/phpBB/includes/acp/info/acp_users.php
index ab69523cde..cb59d24293 100644
--- a/phpBB/includes/acp/info/acp_users.php
+++ b/phpBB/includes/acp/info/acp_users.php
@@ -18,7 +18,6 @@ class acp_users_info
return array(
'filename' => 'acp_users',
'title' => 'ACP_USER_MANAGEMENT',
- 'version' => '1.0.0',
'modes' => array(
'overview' => array('title' => 'ACP_MANAGE_USERS', 'auth' => 'acl_a_user', 'cat' => array('ACP_CAT_USERS')),
'feedback' => array('title' => 'ACP_USER_FEEDBACK', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')),
diff --git a/phpBB/includes/acp/info/acp_words.php b/phpBB/includes/acp/info/acp_words.php
index 3c8c79f25f..8a6d0d7f20 100644
--- a/phpBB/includes/acp/info/acp_words.php
+++ b/phpBB/includes/acp/info/acp_words.php
@@ -18,7 +18,6 @@ class acp_words_info
return array(
'filename' => 'acp_words',
'title' => 'ACP_WORDS',
- 'version' => '1.0.0',
'modes' => array(
'words' => array('title' => 'ACP_WORDS', 'auth' => 'acl_a_words', 'cat' => array('ACP_MESSAGES')),
),
diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php
index 86390c0901..c31b63a403 100644
--- a/phpBB/includes/bbcode.php
+++ b/phpBB/includes/bbcode.php
@@ -35,9 +35,18 @@ class bbcode
/**
* Constructor
+ */
+ function __construct($bitfield = '')
+ {
+ $this->bbcode_set_bitfield($bitfield);
+ }
+
+ /**
* Init bbcode cache entries if bitfield is specified
+ *
+ * @param string $bbcode_bitfield The bbcode bitfield
*/
- function bbcode($bitfield = '')
+ function bbcode_set_bitfield($bitfield = '')
{
if ($bitfield)
{
@@ -94,13 +103,13 @@ class bbcode
${$type}['replace'][] = $replace;
}
- if (sizeof($str['search']))
+ if (count($str['search']))
{
$message = str_replace($str['search'], $str['replace'], $message);
$str = array('search' => array(), 'replace' => array());
}
- if (sizeof($preg['search']))
+ if (count($preg['search']))
{
// we need to turn the entities back into their original form to allow the
// search patterns to work properly
@@ -110,7 +119,18 @@ class bbcode
$undid_bbcode_specialchars = true;
}
- $message = preg_replace($preg['search'], $preg['replace'], $message);
+ foreach ($preg['search'] as $key => $search)
+ {
+ if (is_callable($preg['replace'][$key]))
+ {
+ $message = preg_replace_callback($search, $preg['replace'][$key], $message);
+ }
+ else
+ {
+ $message = preg_replace($search, $preg['replace'][$key], $message);
+ }
+ }
+
$preg = array('search' => array(), 'replace' => array());
}
}
@@ -129,13 +149,32 @@ class bbcode
*/
function bbcode_cache_init()
{
- global $phpbb_root_path, $phpEx, $config, $user, $phpbb_dispatcher, $phpbb_extension_manager, $phpbb_path_helper;
+ global $user, $phpbb_dispatcher, $phpbb_extension_manager, $phpbb_container, $phpbb_filesystem;
if (empty($this->template_filename))
{
$this->template_bitfield = new bitfield($user->style['bbcode_bitfield']);
- $template = new phpbb\template\twig\twig($phpbb_path_helper, $config, $user, new phpbb\template\context(), $phpbb_extension_manager);
+ $template = new \phpbb\template\twig\twig(
+ $phpbb_container->get('path_helper'),
+ $phpbb_container->get('config'),
+ new \phpbb\template\context(),
+ new \phpbb\template\twig\environment(
+ $phpbb_container->get('config'),
+ $phpbb_container->get('filesystem'),
+ $phpbb_container->get('path_helper'),
+ $phpbb_container->getParameter('core.cache_dir'),
+ $phpbb_container->get('ext.manager'),
+ new \phpbb\template\twig\loader(
+ $phpbb_filesystem
+ )
+ ),
+ $phpbb_container->getParameter('core.cache_dir'),
+ $phpbb_container->get('user'),
+ $phpbb_container->get('template.twig.extensions.collection'),
+ $phpbb_extension_manager
+ );
+
$template->set_style();
$template->set_filenames(array('bbcode.html' => 'bbcode.html'));
$this->template_filename = $template->get_source_file_for_handle('bbcode.html');
@@ -161,7 +200,7 @@ class bbcode
}
}
- if (sizeof($sql))
+ if (count($sql))
{
global $db;
@@ -188,18 +227,25 @@ class bbcode
{
switch ($bbcode_id)
{
- case 0:
+ case BBCODE_ID_QUOTE:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[/quote:$uid]' => $this->bbcode_tpl('quote_close', $bbcode_id)
),
'preg' => array(
- '#\[quote(?:=&quot;(.*?)&quot;)?:$uid\]((?!\[quote(?:=&quot;.*?&quot;)?:$uid\]).)?#ise' => "\$this->bbcode_second_pass_quote('\$1', '\$2')"
+ '#\[quote(?:=&quot;(.*?)&quot;)?:$uid\]((?!\[quote(?:=&quot;.*?&quot;)?:$uid\]).)?#is' => function ($match) {
+ if (!isset($match[2]))
+ {
+ $match[2] = '';
+ }
+
+ return $this->bbcode_second_pass_quote($match[1], $match[2]);
+ },
)
);
break;
- case 1:
+ case BBCODE_ID_B:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[b:$uid]' => $this->bbcode_tpl('b_open', $bbcode_id),
@@ -208,7 +254,7 @@ class bbcode
);
break;
- case 2:
+ case BBCODE_ID_I:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[i:$uid]' => $this->bbcode_tpl('i_open', $bbcode_id),
@@ -217,7 +263,7 @@ class bbcode
);
break;
- case 3:
+ case BBCODE_ID_URL:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[url:$uid\]((.*?))\[/url:$uid\]#s' => $this->bbcode_tpl('url', $bbcode_id),
@@ -226,7 +272,7 @@ class bbcode
);
break;
- case 4:
+ case BBCODE_ID_IMG:
if ($user->optionget('viewimg'))
{
$this->bbcode_cache[$bbcode_id] = array(
@@ -245,7 +291,7 @@ class bbcode
}
break;
- case 5:
+ case BBCODE_ID_SIZE:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[size=([\-\+]?\d+):$uid\](.*?)\[/size:$uid\]#s' => $this->bbcode_tpl('size', $bbcode_id),
@@ -253,7 +299,7 @@ class bbcode
);
break;
- case 6:
+ case BBCODE_ID_COLOR:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+):$uid\](.*?)\[/color:$uid\]!is' => $this->bbcode_tpl('color', $bbcode_id),
@@ -261,7 +307,7 @@ class bbcode
);
break;
- case 7:
+ case BBCODE_ID_U:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[u:$uid]' => $this->bbcode_tpl('u_open', $bbcode_id),
@@ -270,20 +316,24 @@ class bbcode
);
break;
- case 8:
+ case BBCODE_ID_CODE:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
- '#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#ise' => "\$this->bbcode_second_pass_code('\$1', '\$2')",
+ '#\[code(?:=([a-z]+))?:$uid\](.*?)\[/code:$uid\]#is' => function ($match) {
+ return $this->bbcode_second_pass_code($match[1], $match[2]);
+ },
)
);
break;
- case 9:
+ case BBCODE_ID_LIST:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#(\[\/?(list|\*):[mou]?:?$uid\])[\n]{1}#' => "\$1",
'#(\[list=([^\[]+):$uid\])[\n]{1}#' => "\$1",
- '#\[list=([^\[]+):$uid\]#e' => "\$this->bbcode_list('\$1')",
+ '#\[list=([^\[]+):$uid\]#' => function ($match) {
+ return $this->bbcode_list($match[1]);
+ },
),
'str' => array(
'[list:$uid]' => $this->bbcode_tpl('ulist_open_default', $bbcode_id),
@@ -296,7 +346,7 @@ class bbcode
);
break;
- case 10:
+ case BBCODE_ID_EMAIL:
$this->bbcode_cache[$bbcode_id] = array(
'preg' => array(
'#\[email:$uid\]((.*?))\[/email:$uid\]#is' => $this->bbcode_tpl('email', $bbcode_id),
@@ -305,7 +355,7 @@ class bbcode
);
break;
- case 11:
+ case BBCODE_ID_FLASH:
if ($user->optionget('viewflash'))
{
$this->bbcode_cache[$bbcode_id] = array(
@@ -324,7 +374,7 @@ class bbcode
}
break;
- case 12:
+ case BBCODE_ID_ATTACH:
$this->bbcode_cache[$bbcode_id] = array(
'str' => array(
'[/attachment:$uid]' => $this->bbcode_tpl('inline_attachment_close', $bbcode_id)
@@ -367,7 +417,9 @@ class bbcode
}
// Replace {L_*} lang strings
- $bbcode_tpl = preg_replace('/{L_([A-Z0-9_]+)}/e', "(!empty(\$user->lang['\$1'])) ? \$user->lang['\$1'] : ucwords(strtolower(str_replace('_', ' ', '\$1')))", $bbcode_tpl);
+ $bbcode_tpl = preg_replace_callback('/{L_([A-Z0-9_]+)}/', function ($match) use ($user) {
+ return (!empty($user->lang[$match[1]])) ? $user->lang($match[1]) : ucwords(strtolower(str_replace('_', ' ', $match[1])));
+ }, $bbcode_tpl);
if (!empty($rowset[$bbcode_id]['second_pass_replace']))
{
@@ -458,7 +510,10 @@ class bbcode
// Turn template blocks into PHP assignment statements for the values of $bbcode_tpl..
$this->bbcode_template = array();
- $matches = preg_match_all('#<!-- BEGIN (.*?) -->(.*?)<!-- END (?:.*?) -->#', $tpl, $match);
+ // Capture the BBCode template matches
+ // Allow phpBB template or the Twig syntax
+ $matches = (preg_match_all('#<!-- BEGIN (.*?) -->(.*?)<!-- END (?:.*?) -->#', $tpl, $match)) ?:
+ preg_match_all('#{% for (.*?) in .*? %}(.*?){% endfor %}#s', $tpl, $match);
for ($i = 0; $i < $matches; $i++)
{
@@ -491,7 +546,9 @@ class bbcode
'email' => array('{EMAIL}' => '$1', '{DESCRIPTION}' => '$2')
);
- $tpl = preg_replace('/{L_([A-Z0-9_]+)}/e', "(!empty(\$user->lang['\$1'])) ? \$user->lang['\$1'] : ucwords(strtolower(str_replace('_', ' ', '\$1')))", $tpl);
+ $tpl = preg_replace_callback('/{L_([A-Z0-9_]+)}/', function ($match) use ($user) {
+ return (!empty($user->lang[$match[1]])) ? $user->lang($match[1]) : ucwords(strtolower(str_replace('_', ' ', $match[1])));
+ }, $tpl);
if (!empty($replacements[$tpl_name]))
{
diff --git a/phpBB/includes/compatibility_globals.php b/phpBB/includes/compatibility_globals.php
index 54c9287c96..ad394e3782 100644
--- a/phpBB/includes/compatibility_globals.php
+++ b/phpBB/includes/compatibility_globals.php
@@ -18,30 +18,67 @@ if (!defined('IN_PHPBB'))
exit;
}
-// set up caching
-$cache = $phpbb_container->get('cache');
+/**
+ * Sets compatibility globals in the global scope
+ *
+ * This function registers compatibility variables to the global
+ * variable scope. This is required to make it possible to include this file
+ * in a service.
+ */
+function register_compatibility_globals()
+{
+ global $phpbb_container;
+
+ global $cache, $phpbb_dispatcher, $request, $user, $auth, $db, $config, $language, $phpbb_log;
+ global $symfony_request, $phpbb_filesystem, $phpbb_path_helper, $phpbb_extension_manager, $template;
+
+ // set up caching
+ /* @var $cache \phpbb\cache\service */
+ $cache = $phpbb_container->get('cache');
+
+ // Instantiate some basic classes
+ /* @var $phpbb_dispatcher \phpbb\event\dispatcher */
+ $phpbb_dispatcher = $phpbb_container->get('dispatcher');
+
+ /* @var $request \phpbb\request\request_interface */
+ $request = $phpbb_container->get('request');
+ // Inject request instance, so only this instance is used with request_var
+ request_var('', 0, false, false, $request);
-// Instantiate some basic classes
-$phpbb_dispatcher = $phpbb_container->get('dispatcher');
-$request = $phpbb_container->get('request');
-$user = $phpbb_container->get('user');
-$auth = $phpbb_container->get('auth');
-$db = $phpbb_container->get('dbal.conn');
+ /* @var $user \phpbb\user */
+ $user = $phpbb_container->get('user');
-// make sure request_var uses this request instance
-request_var('', 0, false, false, $request); // "dependency injection" for a function
+ /* @var \phpbb\language\language $language */
+ $language = $phpbb_container->get('language');
-// Grab global variables, re-cache if necessary
-$config = $phpbb_container->get('config');
-set_config(null, null, null, $config);
-set_config_count(null, null, null, $config);
+ /* @var $auth \phpbb\auth\auth */
+ $auth = $phpbb_container->get('auth');
-$phpbb_log = $phpbb_container->get('log');
-$symfony_request = $phpbb_container->get('symfony_request');
-$phpbb_filesystem = $phpbb_container->get('filesystem');
-$phpbb_path_helper = $phpbb_container->get('path_helper');
+ /* @var $db \phpbb\db\driver\driver_interface */
+ $db = $phpbb_container->get('dbal.conn');
-// load extensions
-$phpbb_extension_manager = $phpbb_container->get('ext.manager');
+ // Grab global variables, re-cache if necessary
+ /* @var $config phpbb\config\db */
+ $config = $phpbb_container->get('config');
+ set_config('', '', false, $config);
+ set_config_count('', 0, false, $config);
-$template = $phpbb_container->get('template');
+ /* @var $phpbb_log \phpbb\log\log_interface */
+ $phpbb_log = $phpbb_container->get('log');
+
+ /* @var $symfony_request \phpbb\symfony_request */
+ $symfony_request = $phpbb_container->get('symfony_request');
+
+ /* @var $phpbb_filesystem \phpbb\filesystem\filesystem_interface */
+ $phpbb_filesystem = $phpbb_container->get('filesystem');
+
+ /* @var $phpbb_path_helper \phpbb\path_helper */
+ $phpbb_path_helper = $phpbb_container->get('path_helper');
+
+ // load extensions
+ /* @var $phpbb_extension_manager \phpbb\extension\manager */
+ $phpbb_extension_manager = $phpbb_container->get('ext.manager');
+
+ /* @var $template \phpbb\template\template */
+ $template = $phpbb_container->get('template');
+}
diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index a24ebaf9de..ff3bbbc543 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -28,7 +28,7 @@ if (!defined('IN_PHPBB'))
*/
// phpBB Version
-define('PHPBB_VERSION', '3.1.11');
+@define('PHPBB_VERSION', '3.2.9');
// QA-related
// define('PHPBB_QA', 1);
@@ -171,17 +171,33 @@ define('CONFIRM_REPORT', 4);
// Categories - Attachments
define('ATTACHMENT_CATEGORY_NONE', 0);
define('ATTACHMENT_CATEGORY_IMAGE', 1); // Inline Images
-define('ATTACHMENT_CATEGORY_WM', 2); // Windows Media Files - Streaming
-define('ATTACHMENT_CATEGORY_RM', 3); // Real Media Files - Streaming
+define('ATTACHMENT_CATEGORY_WM', 2); // Windows Media Files - Streaming - @deprecated 3.2
+define('ATTACHMENT_CATEGORY_RM', 3); // Real Media Files - Streaming - @deprecated 3.2
define('ATTACHMENT_CATEGORY_THUMB', 4); // Not used within the database, only while displaying posts
define('ATTACHMENT_CATEGORY_FLASH', 5); // Flash/SWF files
-define('ATTACHMENT_CATEGORY_QUICKTIME', 6); // Quicktime/Mov files
+define('ATTACHMENT_CATEGORY_QUICKTIME', 6); // Quicktime/Mov files - @deprecated 3.2
// BBCode UID length
define('BBCODE_UID_LEN', 8);
// Number of core BBCodes
define('NUM_CORE_BBCODES', 12);
+define('NUM_PREDEFINED_BBCODES', 22);
+
+// BBCode IDs
+define('BBCODE_ID_QUOTE', 0);
+define('BBCODE_ID_B', 1);
+define('BBCODE_ID_I', 2);
+define('BBCODE_ID_URL', 3);
+define('BBCODE_ID_IMG', 4);
+define('BBCODE_ID_SIZE', 5);
+define('BBCODE_ID_COLOR', 6);
+define('BBCODE_ID_U', 7);
+define('BBCODE_ID_CODE', 8);
+define('BBCODE_ID_LIST', 9);
+define('BBCODE_ID_EMAIL', 10);
+define('BBCODE_ID_FLASH', 11);
+define('BBCODE_ID_ATTACH', 12);
// BBCode hard limit
define('BBCODE_LIMIT', 1511);
@@ -221,6 +237,9 @@ define('CAPTCHA_MAX_CHARS', 7);
// Additional constants
define('VOTE_CONVERTED', 127);
+// BC global FTW
+global $table_prefix;
+
// Table names
define('ACL_GROUPS_TABLE', $table_prefix . 'acl_groups');
define('ACL_OPTIONS_TABLE', $table_prefix . 'acl_options');
@@ -232,7 +251,7 @@ define('BANLIST_TABLE', $table_prefix . 'banlist');
define('BBCODES_TABLE', $table_prefix . 'bbcodes');
define('BOOKMARKS_TABLE', $table_prefix . 'bookmarks');
define('BOTS_TABLE', $table_prefix . 'bots');
-define('CONFIG_TABLE', $table_prefix . 'config');
+@define('CONFIG_TABLE', $table_prefix . 'config');
define('CONFIG_TEXT_TABLE', $table_prefix . 'config_text');
define('CONFIRM_TABLE', $table_prefix . 'confirm');
define('DISALLOW_TABLE', $table_prefix . 'disallow');
diff --git a/phpBB/includes/diff/diff.php b/phpBB/includes/diff/diff.php
index d307880c4b..d8ae9d77ac 100644
--- a/phpBB/includes/diff/diff.php
+++ b/phpBB/includes/diff/diff.php
@@ -50,7 +50,7 @@ class diff
* @param array &$to_content An array of strings.
* @param bool $preserve_cr If true, \r is replaced by a new line in the diff output
*/
- function diff(&$from_content, &$to_content, $preserve_cr = true)
+ function __construct(&$from_content, &$to_content, $preserve_cr = true)
{
$diff_engine = new diff_engine();
$this->_edits = $diff_engine->diff($from_content, $to_content, $preserve_cr);
@@ -75,7 +75,7 @@ class diff
{
$count = 0;
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -98,7 +98,7 @@ class diff
{
$count = 0;
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -136,7 +136,7 @@ class diff
$rev->_edits = array();
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
$rev->_edits[] = $edit->reverse();
@@ -152,7 +152,7 @@ class diff
*/
function is_empty()
{
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -168,8 +168,8 @@ class diff
$final = $edit->final;
// We can simplify one case where the array is usually supposed to be empty...
- if (sizeof($orig) == 1 && trim($orig[0]) === '') $orig = array();
- if (sizeof($final) == 1 && trim($final[0]) === '') $final = array();
+ if (count($orig) == 1 && trim($orig[0]) === '') $orig = array();
+ if (count($final) == 1 && trim($final[0]) === '') $final = array();
if (!$orig && !$final)
{
@@ -196,13 +196,13 @@ class diff
{
$lcs = 0;
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
if (is_a($edit, 'diff_op_copy'))
{
- $lcs += sizeof($edit->orig);
+ $lcs += count($edit->orig);
}
}
return $lcs;
@@ -219,13 +219,13 @@ class diff
{
$lines = array();
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
if ($edit->orig)
{
- array_splice($lines, sizeof($lines), 0, $edit->orig);
+ array_splice($lines, count($lines), 0, $edit->orig);
}
}
return $lines;
@@ -242,13 +242,13 @@ class diff
{
$lines = array();
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
if ($edit->final)
{
- array_splice($lines, sizeof($lines), 0, $edit->final);
+ array_splice($lines, count($lines), 0, $edit->final);
}
}
return $lines;
@@ -296,7 +296,7 @@ class diff
$prevtype = null;
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -330,30 +330,30 @@ class mapped_diff extends diff
* compared when computing the diff.
* @param array $mapped_to_lines This array should have the same number of elements as $to_lines.
*/
- function mapped_diff(&$from_lines, &$to_lines, &$mapped_from_lines, &$mapped_to_lines)
+ function __construct(&$from_lines, &$to_lines, &$mapped_from_lines, &$mapped_to_lines)
{
- if (sizeof($from_lines) != sizeof($mapped_from_lines) || sizeof($to_lines) != sizeof($mapped_to_lines))
+ if (count($from_lines) != count($mapped_from_lines) || count($to_lines) != count($mapped_to_lines))
{
return false;
}
- parent::diff($mapped_from_lines, $mapped_to_lines);
+ parent::__construct($mapped_from_lines, $mapped_to_lines);
$xi = $yi = 0;
- for ($i = 0; $i < sizeof($this->_edits); $i++)
+ for ($i = 0; $i < count($this->_edits); $i++)
{
$orig = &$this->_edits[$i]->orig;
if (is_array($orig))
{
- $orig = array_slice($from_lines, $xi, sizeof($orig));
- $xi += sizeof($orig);
+ $orig = array_slice($from_lines, $xi, count($orig));
+ $xi += count($orig);
}
$final = &$this->_edits[$i]->final;
if (is_array($final))
{
- $final = array_slice($to_lines, $yi, sizeof($final));
- $yi += sizeof($final);
+ $final = array_slice($to_lines, $yi, count($final));
+ $yi += count($final);
}
}
}
@@ -377,12 +377,12 @@ class diff_op
function norig()
{
- return ($this->orig) ? sizeof($this->orig) : 0;
+ return ($this->orig) ? count($this->orig) : 0;
}
function nfinal()
{
- return ($this->final) ? sizeof($this->final) : 0;
+ return ($this->final) ? count($this->final) : 0;
}
}
@@ -394,7 +394,7 @@ class diff_op
*/
class diff_op_copy extends diff_op
{
- function diff_op_copy($orig, $final = false)
+ function __construct($orig, $final = false)
{
if (!is_array($final))
{
@@ -419,7 +419,7 @@ class diff_op_copy extends diff_op
*/
class diff_op_delete extends diff_op
{
- function diff_op_delete($lines)
+ function __construct($lines)
{
$this->orig = $lines;
$this->final = false;
@@ -440,7 +440,7 @@ class diff_op_delete extends diff_op
*/
class diff_op_add extends diff_op
{
- function diff_op_add($lines)
+ function __construct($lines)
{
$this->final = $lines;
$this->orig = false;
@@ -461,7 +461,7 @@ class diff_op_add extends diff_op
*/
class diff_op_change extends diff_op
{
- function diff_op_change($orig, $final)
+ function __construct($orig, $final)
{
$this->orig = $orig;
$this->final = $final;
@@ -498,7 +498,7 @@ class diff3 extends diff
* @param bool $preserve_cr If true, \r\n and bare \r are replaced by a new line
* in the diff output
*/
- function diff3(&$orig, &$final1, &$final2, $preserve_cr = true)
+ function __construct(&$orig, &$final1, &$final2, $preserve_cr = true)
{
$diff_engine = new diff_engine();
@@ -517,7 +517,7 @@ class diff3 extends diff
{
$conflicts = 0;
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -550,7 +550,7 @@ class diff3 extends diff
$lines = array();
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -590,7 +590,7 @@ class diff3 extends diff
{
$lines = array();
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -614,7 +614,7 @@ class diff3 extends diff
{
$lines = array();
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -638,7 +638,7 @@ class diff3 extends diff
{
$conflicts = array();
- for ($i = 0, $size = sizeof($this->_edits); $i < $size; $i++)
+ for ($i = 0, $size = count($this->_edits); $i < $size; $i++)
{
$edit = $this->_edits[$i];
@@ -754,7 +754,7 @@ class diff3 extends diff
*/
class diff3_op
{
- function diff3_op($orig = false, $final1 = false, $final2 = false)
+ function __construct($orig = false, $final1 = false, $final2 = false)
{
$this->orig = $orig ? $orig : array();
$this->final1 = $final1 ? $final1 : array();
@@ -803,9 +803,9 @@ class diff3_op
function solve_prepare()
{
// We can simplify one case where the array is usually supposed to be empty...
- if (sizeof($this->orig) == 1 && trim($this->orig[0]) === '') $this->orig = array();
- if (sizeof($this->final1) == 1 && trim($this->final1[0]) === '') $this->final1 = array();
- if (sizeof($this->final2) == 1 && trim($this->final2[0]) === '') $this->final2 = array();
+ if (count($this->orig) == 1 && trim($this->orig[0]) === '') $this->orig = array();
+ if (count($this->final1) == 1 && trim($this->final1[0]) === '') $this->final1 = array();
+ if (count($this->final2) == 1 && trim($this->final2[0]) === '') $this->final2 = array();
// Now we only can have the case where the only difference between arrays are newlines, so compare all cases
@@ -848,10 +848,10 @@ class diff3_op
$_final1 = &$this->$final1;
// Ok, we basically search for $orig in $final1
- $compare_seq = sizeof($_orig);
+ $compare_seq = count($_orig);
// Go through the conflict code
- for ($i = 0, $j = 0, $size = sizeof($_final1); $i < $size; $i++, $j = $i)
+ for ($i = 0, $j = 0, $size = count($_final1); $i < $size; $i++, $j = $i)
{
$line = $_final1[$i];
$skip = 0;
@@ -895,7 +895,7 @@ class diff3_op
// CASE ONE: orig changed into final2, but modified/unknown code in final1.
// IF orig is found "as is" in final1 we replace the code directly in final1 and populate this as final2/merge
- if (sizeof($this->orig) && sizeof($this->final2))
+ if (count($this->orig) && count($this->final2))
{
$result = $this->_compare_conflict_seq('orig', 'final1', 'final2');
@@ -915,7 +915,7 @@ class diff3_op
}
// Try to solve $Id$ issues. ;)
- if (sizeof($this->orig) == 1 && sizeof($this->final1) == 1 && sizeof($this->final2) == 1)
+ if (count($this->orig) == 1 && count($this->final1) == 1 && count($this->final2) == 1)
{
$match = '#^' . preg_quote('* @version $Id: ', '#') . '[a-z\._\- ]+[0-9]+ [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9\:Z]+ [a-z0-9_\- ]+\$$#';
@@ -939,9 +939,9 @@ class diff3_op
}
// The same is true for a line at the end. ;)
- if (sizeof($this->orig) && sizeof($this->final2) && sizeof($this->orig) === sizeof($this->final2) && trim($this->orig[sizeof($this->orig)-1]) === '' && trim($this->final2[sizeof($this->final2)-1]) === '')
+ if (count($this->orig) && count($this->final2) && count($this->orig) === count($this->final2) && trim($this->orig[count($this->orig)-1]) === '' && trim($this->final2[count($this->final2)-1]) === '')
{
- unset($this->orig[sizeof($this->orig)-1], $this->final2[sizeof($this->final2)-1]);
+ unset($this->orig[count($this->orig)-1], $this->final2[count($this->final2)-1]);
$this->orig = array_values($this->orig);
$this->final2 = array_values($this->final2);
@@ -972,7 +972,7 @@ class diff3_op
}
// CASE TWO: Added lines from orig to final2 but final1 had added lines too. Just merge them.
- if (!sizeof($this->orig) && $this->final1 !== $this->final2 && sizeof($this->final1) && sizeof($this->final2))
+ if (!count($this->orig) && $this->final1 !== $this->final2 && count($this->final1) && count($this->final2))
{
$result = $this->_compare_conflict_seq('final2', 'final1');
@@ -1001,7 +1001,7 @@ class diff3_op
}
// CASE THREE: Removed lines (orig has the to-remove line(s), but final1 has additional lines which does not need to be removed). Just remove orig from final1 and then use final1 as final2/merge
- if (!sizeof($this->final2) && sizeof($this->orig) && sizeof($this->final1) && $this->orig !== $this->final1)
+ if (!count($this->final2) && count($this->orig) && count($this->final1) && $this->orig !== $this->final1)
{
$result = $this->_compare_conflict_seq('orig', 'final1');
@@ -1011,11 +1011,11 @@ class diff3_op
}
// First of all, try to find the code in orig in final1. ;)
- $compare_seq = sizeof($this->orig);
+ $compare_seq = count($this->orig);
$begin = $end = -1;
$j = 0;
- for ($i = 0, $size = sizeof($this->final1); $i < $size; $i++)
+ for ($i = 0, $size = count($this->final1); $i < $size; $i++)
{
$line = $this->final1[$i];
@@ -1066,7 +1066,7 @@ class diff3_op
*/
class diff3_op_copy extends diff3_op
{
- function diff3_op_copy($lines = false)
+ function __construct($lines = false)
{
$this->orig = $lines ? $lines : array();
$this->final1 = &$this->orig;
@@ -1092,7 +1092,7 @@ class diff3_op_copy extends diff3_op
*/
class diff3_block_builder
{
- function diff3_block_builder()
+ function __construct()
{
$this->_init();
}
@@ -1147,6 +1147,6 @@ class diff3_block_builder
function _append(&$array, $lines)
{
- array_splice($array, sizeof($array), 0, $lines);
+ array_splice($array, count($array), 0, $lines);
}
}
diff --git a/phpBB/includes/diff/engine.php b/phpBB/includes/diff/engine.php
index bc21b3b9ba..757fdadde9 100644
--- a/phpBB/includes/diff/engine.php
+++ b/phpBB/includes/diff/engine.php
@@ -84,8 +84,8 @@ class diff_engine
$to_lines = explode("\n", preg_replace('#[\n\r]+#', "\n", $to_lines));
}
- $n_from = sizeof($from_lines);
- $n_to = sizeof($to_lines);
+ $n_from = count($from_lines);
+ $n_to = count($to_lines);
$this->xchanged = $this->ychanged = $this->xv = $this->yv = $this->xind = $this->yind = array();
unset($this->seq, $this->in_seq, $this->lcs);
@@ -145,7 +145,7 @@ class diff_engine
}
// Find the LCS.
- $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
+ $this->_compareseq(0, count($this->xv), 0, count($this->yv));
// Merge edits when possible.
if ($this->skip_whitespace_changes)
@@ -444,8 +444,8 @@ class diff_engine
$i = 0;
$j = 0;
- $len = sizeof($lines);
- $other_len = sizeof($other_changed);
+ $len = count($lines);
+ $other_len = count($other_changed);
while (1)
{
diff --git a/phpBB/includes/diff/renderer.php b/phpBB/includes/diff/renderer.php
index 6b7f07cf9c..8a8b0c295e 100644
--- a/phpBB/includes/diff/renderer.php
+++ b/phpBB/includes/diff/renderer.php
@@ -56,7 +56,7 @@ class diff_renderer
/**
* Constructor.
*/
- function diff_renderer($params = array())
+ function __construct($params = array())
{
foreach ($params as $param => $value)
{
@@ -128,8 +128,8 @@ class diff_renderer
if (is_array($block))
{
// How many lines to keep as context from the copy block.
- $keep = ($i == sizeof($diffs) - 1) ? $ntrail : $nlead + $ntrail;
- if (sizeof($edit->orig) <= $keep)
+ $keep = ($i == count($diffs) - 1) ? $ntrail : $nlead + $ntrail;
+ if (count($edit->orig) <= $keep)
{
// We have less lines in the block than we want for context => keep the whole block.
$block[] = $edit;
@@ -156,9 +156,9 @@ class diff_renderer
if (!is_array($block))
{
// Extract context lines from the preceding copy block.
- $context = array_slice($context, sizeof($context) - $nlead);
- $x0 = $xi - sizeof($context);
- $y0 = $yi - sizeof($context);
+ $context = array_slice($context, count($context) - $nlead);
+ $x0 = $xi - count($context);
+ $y0 = $yi - count($context);
$block = array();
if ($context)
@@ -169,8 +169,8 @@ class diff_renderer
$block[] = $edit;
}
- $xi += ($edit->orig) ? sizeof($edit->orig) : 0;
- $yi += ($edit->final) ? sizeof($edit->final) : 0;
+ $xi += ($edit->orig) ? count($edit->orig) : 0;
+ $yi += ($edit->final) ? count($edit->final) : 0;
}
if (is_array($block))
@@ -433,7 +433,7 @@ class diff_renderer_inline extends diff_renderer
{
array_walk($lines, array(&$this, '_encode'));
$lines[0] = $this->_ins_prefix . $lines[0];
- $lines[sizeof($lines) - 1] .= $this->_ins_suffix;
+ $lines[count($lines) - 1] .= $this->_ins_suffix;
return $this->_lines($lines, ' ', false);
}
@@ -441,7 +441,7 @@ class diff_renderer_inline extends diff_renderer
{
array_walk($lines, array(&$this, '_encode'));
$lines[0] = $this->_del_prefix . $lines[0];
- $lines[sizeof($lines) - 1] .= $this->_del_suffix;
+ $lines[count($lines) - 1] .= $this->_del_suffix;
return $this->_lines($lines, ' ', false);
}
@@ -617,7 +617,7 @@ class diff_renderer_side_by_side extends diff_renderer
$this->render($diff);
// Is the diff empty?
- if (!sizeof($this->lines))
+ if (!count($this->lines))
{
$output .= '<tr><th colspan="2">' . $user->lang['NO_VISIBLE_CHANGES'] . '</th></tr>';
}
@@ -672,8 +672,8 @@ class diff_renderer_side_by_side extends diff_renderer
case 'change':
// Pop the old/new stacks one by one, until both are empty.
- $oldsize = sizeof($change['old']);
- $newsize = sizeof($change['new']);
+ $oldsize = count($change['old']);
+ $newsize = count($change['new']);
$left = $right = '';
for ($row = 0, $row_max = max($oldsize, $newsize); $row < $row_max; ++$row)
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index 84178f74e4..c9f589c174 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -64,183 +64,58 @@ function set_var(&$result, $var, $type, $multibyte = false)
}
/**
-* Wrapper function of \phpbb\request\request::variable which exists for backwards compatability.
-* See {@link \phpbb\request\request_interface::variable \phpbb\request\request_interface::variable} for
-* documentation of this function's use.
-*
-* @deprecated
-* @param mixed $var_name The form variable's name from which data shall be retrieved.
-* If the value is an array this may be an array of indizes which will give
-* direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
-* then specifying array("var", 1) as the name will return "a".
-* If you pass an instance of {@link \phpbb\request\request_interface phpbb_request_interface}
-* as this parameter it will overwrite the current request class instance. If you do
-* not do so, it will create its own instance (but leave superglobals enabled).
-* @param mixed $default A default value that is returned if the variable was not set.
-* This function will always return a value of the same type as the default.
-* @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
-* Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
-* @param bool $cookie This param is mapped to \phpbb\request\request_interface::COOKIE as the last param for
-* \phpbb\request\request_interface::variable for backwards compatability reasons.
-* @param \phpbb\request\request_interface|null|false If an instance of \phpbb\request\request_interface is given the instance is stored in
-* a static variable and used for all further calls where this parameters is null. Until
-* the function is called with an instance it automatically creates a new \phpbb\request\request
-* instance on every call. By passing false this per-call instantiation can be restored
-* after having passed in a \phpbb\request\request_interface instance.
-*
-* @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
-* the same as that of $default. If the variable is not set $default is returned.
-*/
-function request_var($var_name, $default, $multibyte = false, $cookie = false, $request = null)
-{
- // This is all just an ugly hack to add "Dependency Injection" to a function
- // the only real code is the function call which maps this function to a method.
- static $static_request = null;
-
- if ($request instanceof \phpbb\request\request_interface)
- {
- $static_request = $request;
-
- if (empty($var_name))
- {
- return;
- }
- }
- else if ($request === false)
- {
- $static_request = null;
-
- if (empty($var_name))
- {
- return;
- }
- }
-
- $tmp_request = $static_request;
-
- // no request class set, create a temporary one ourselves to keep backwards compatability
- if ($tmp_request === null)
- {
- // false param: enable super globals, so the created request class does not
- // make super globals inaccessible everywhere outside this function.
- $tmp_request = new \phpbb\request\request(new \phpbb\request\type_cast_helper(), false);
- }
-
- return $tmp_request->variable($var_name, $default, $multibyte, ($cookie) ? \phpbb\request\request_interface::COOKIE : \phpbb\request\request_interface::REQUEST);
-}
-
-/**
-* Sets a configuration option's value.
-*
-* Please note that this function does not update the is_dynamic value for
-* an already existing config option.
-*
-* @param string $config_name The configuration option's name
-* @param string $config_value New configuration value
-* @param bool $is_dynamic Whether this variable should be cached (false) or
-* if it changes too frequently (true) to be
-* efficiently cached.
-*
-* @return null
-*
-* @deprecated
-*/
-function set_config($config_name, $config_value, $is_dynamic = false, \phpbb\config\config $set_config = null)
-{
- static $config = null;
-
- if ($set_config !== null)
- {
- $config = $set_config;
-
- if (empty($config_name))
- {
- return;
- }
- }
-
- $config->set($config_name, $config_value, !$is_dynamic);
-}
-
-/**
-* Increments an integer config value directly in the database.
+* Generates an alphanumeric random string of given length
*
-* @param string $config_name The configuration option's name
-* @param int $increment Amount to increment by
-* @param bool $is_dynamic Whether this variable should be cached (false) or
-* if it changes too frequently (true) to be
-* efficiently cached.
+* @param int $num_chars Length of random string, defaults to 8.
+* This number should be less or equal than 64.
*
-* @return null
-*
-* @deprecated
+* @return string
*/
-function set_config_count($config_name, $increment, $is_dynamic = false, \phpbb\config\config $set_config = null)
+function gen_rand_string($num_chars = 8)
{
- static $config = null;
+ $range = array_merge(range('A', 'Z'), range(0, 9));
+ $size = count($range);
- if ($set_config !== null)
+ $output = '';
+ for ($i = 0; $i < $num_chars; $i++)
{
- $config = $set_config;
-
- if (empty($config_name))
- {
- return;
- }
+ $rand = random_int(0, $size-1);
+ $output .= $range[$rand];
}
- $config->increment($config_name, $increment, !$is_dynamic);
-}
-
-/**
-* Generates an alphanumeric random string of given length
-*
-* @return string
-*/
-function gen_rand_string($num_chars = 8)
-{
- // [a, z] + [0, 9] = 36
- return substr(strtoupper(base_convert(unique_id(), 16, 36)), 0, $num_chars);
+ return $output;
}
/**
* Generates a user-friendly alphanumeric random string of given length
* We remove 0 and O so users cannot confuse those in passwords etc.
*
+* @param int $num_chars Length of random string, defaults to 8.
+* This number should be less or equal than 64.
+*
* @return string
*/
function gen_rand_string_friendly($num_chars = 8)
{
- $rand_str = unique_id();
+ $range = array_merge(range('A', 'N'), range('P', 'Z'), range(1, 9));
+ $size = count($range);
- // Remove Z and Y from the base_convert(), replace 0 with Z and O with Y
- // [a, z] + [0, 9] - {z, y} = [a, z] + [0, 9] - {0, o} = 34
- $rand_str = str_replace(array('0', 'O'), array('Z', 'Y'), strtoupper(base_convert($rand_str, 16, 34)));
+ $output = '';
+ for ($i = 0; $i < $num_chars; $i++)
+ {
+ $rand = random_int(0, $size-1);
+ $output .= $range[$rand];
+ }
- return substr($rand_str, 0, $num_chars);
+ return $output;
}
/**
* Return unique id
-* @param string $extra additional entropy
*/
-function unique_id($extra = 'c')
+function unique_id()
{
- static $dss_seeded = false;
- global $config;
-
- $val = $config['rand_seed'] . microtime();
- $val = md5($val);
- $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra);
-
- if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10)))
- {
- set_config('rand_seed_last_update', time(), true);
- set_config('rand_seed', $config['rand_seed'], true);
- $dss_seeded = true;
- }
-
- return substr($val, 4, 16);
+ return strtolower(gen_rand_string(16));
}
/**
@@ -376,8 +251,7 @@ function still_on_time($extra_time = 15)
{
static $max_execution_time, $start_time;
- $time = explode(' ', microtime());
- $current_time = $time[0] + $time[1];
+ $current_time = microtime(true);
if (empty($max_execution_time))
{
@@ -441,448 +315,6 @@ function phpbb_version_compare($version1, $version2, $operator = null)
}
}
-/**
-* Global function for chmodding directories and files for internal use
-*
-* This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
-* The function determines owner and group from common.php file and sets the same to the provided file.
-* The function uses bit fields to build the permissions.
-* The function sets the appropiate execute bit on directories.
-*
-* Supported constants representing bit fields are:
-*
-* CHMOD_ALL - all permissions (7)
-* CHMOD_READ - read permission (4)
-* CHMOD_WRITE - write permission (2)
-* CHMOD_EXECUTE - execute permission (1)
-*
-* NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions.
-*
-* @param string $filename The file/directory to be chmodded
-* @param int $perms Permissions to set
-*
-* @return bool true on success, otherwise false
-*/
-function phpbb_chmod($filename, $perms = CHMOD_READ)
-{
- static $_chmod_info;
-
- // Return if the file no longer exists.
- if (!file_exists($filename))
- {
- return false;
- }
-
- // Determine some common vars
- if (empty($_chmod_info))
- {
- if (!function_exists('fileowner') || !function_exists('filegroup'))
- {
- // No need to further determine owner/group - it is unknown
- $_chmod_info['process'] = false;
- }
- else
- {
- global $phpbb_root_path, $phpEx;
-
- // Determine owner/group of common.php file and the filename we want to change here
- $common_php_owner = @fileowner($phpbb_root_path . 'common.' . $phpEx);
- $common_php_group = @filegroup($phpbb_root_path . 'common.' . $phpEx);
-
- // And the owner and the groups PHP is running under.
- $php_uid = (function_exists('posix_getuid')) ? @posix_getuid() : false;
- $php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false;
-
- // If we are unable to get owner/group, then do not try to set them by guessing
- if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group)
- {
- $_chmod_info['process'] = false;
- }
- else
- {
- $_chmod_info = array(
- 'process' => true,
- 'common_owner' => $common_php_owner,
- 'common_group' => $common_php_group,
- 'php_uid' => $php_uid,
- 'php_gids' => $php_gids,
- );
- }
- }
- }
-
- if ($_chmod_info['process'])
- {
- $file_uid = @fileowner($filename);
- $file_gid = @filegroup($filename);
-
- // Change owner
- if (@chown($filename, $_chmod_info['common_owner']))
- {
- clearstatcache();
- $file_uid = @fileowner($filename);
- }
-
- // Change group
- if (@chgrp($filename, $_chmod_info['common_group']))
- {
- clearstatcache();
- $file_gid = @filegroup($filename);
- }
-
- // If the file_uid/gid now match the one from common.php we can process further, else we are not able to change something
- if ($file_uid != $_chmod_info['common_owner'] || $file_gid != $_chmod_info['common_group'])
- {
- $_chmod_info['process'] = false;
- }
- }
-
- // Still able to process?
- if ($_chmod_info['process'])
- {
- if ($file_uid == $_chmod_info['php_uid'])
- {
- $php = 'owner';
- }
- else if (in_array($file_gid, $_chmod_info['php_gids']))
- {
- $php = 'group';
- }
- else
- {
- // Since we are setting the everyone bit anyway, no need to do expensive operations
- $_chmod_info['process'] = false;
- }
- }
-
- // We are not able to determine or change something
- if (!$_chmod_info['process'])
- {
- $php = 'other';
- }
-
- // Owner always has read/write permission
- $owner = CHMOD_READ | CHMOD_WRITE;
- if (is_dir($filename))
- {
- $owner |= CHMOD_EXECUTE;
-
- // Only add execute bit to the permission if the dir needs to be readable
- if ($perms & CHMOD_READ)
- {
- $perms |= CHMOD_EXECUTE;
- }
- }
-
- switch ($php)
- {
- case 'owner':
- $result = @chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0));
-
- clearstatcache();
-
- if (is_readable($filename) && phpbb_is_writable($filename))
- {
- break;
- }
-
- case 'group':
- $result = @chmod($filename, ($owner << 6) + ($perms << 3) + (0 << 0));
-
- clearstatcache();
-
- if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename)))
- {
- break;
- }
-
- case 'other':
- $result = @chmod($filename, ($owner << 6) + ($perms << 3) + ($perms << 0));
-
- clearstatcache();
-
- if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename)))
- {
- break;
- }
-
- default:
- return false;
- break;
- }
-
- return $result;
-}
-
-/**
-* Test if a file/directory is writable
-*
-* This function calls the native is_writable() when not running under
-* Windows and it is not disabled.
-*
-* @param string $file Path to perform write test on
-* @return bool True when the path is writable, otherwise false.
-*/
-function phpbb_is_writable($file)
-{
- if (strtolower(substr(PHP_OS, 0, 3)) === 'win' || !function_exists('is_writable'))
- {
- if (file_exists($file))
- {
- // Canonicalise path to absolute path
- $file = phpbb_realpath($file);
-
- if (is_dir($file))
- {
- // Test directory by creating a file inside the directory
- $result = @tempnam($file, 'i_w');
-
- if (is_string($result) && file_exists($result))
- {
- unlink($result);
-
- // Ensure the file is actually in the directory (returned realpathed)
- return (strpos($result, $file) === 0) ? true : false;
- }
- }
- else
- {
- $handle = @fopen($file, 'r+');
-
- if (is_resource($handle))
- {
- fclose($handle);
- return true;
- }
- }
- }
- else
- {
- // file does not exist test if we can write to the directory
- $dir = dirname($file);
-
- if (file_exists($dir) && is_dir($dir) && phpbb_is_writable($dir))
- {
- return true;
- }
- }
-
- return false;
- }
- else
- {
- return is_writable($file);
- }
-}
-
-/**
-* Checks if a path ($path) is absolute or relative
-*
-* @param string $path Path to check absoluteness of
-* @return boolean
-*/
-function phpbb_is_absolute($path)
-{
- return (isset($path[0]) && $path[0] == '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false;
-}
-
-/**
-* @author Chris Smith <chris@project-minerva.org>
-* @copyright 2006 Project Minerva Team
-* @param string $path The path which we should attempt to resolve.
-* @return mixed
-*/
-function phpbb_own_realpath($path)
-{
- global $request;
-
- // Now to perform funky shizzle
-
- // Switch to use UNIX slashes
- $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
- $path_prefix = '';
-
- // Determine what sort of path we have
- if (phpbb_is_absolute($path))
- {
- $absolute = true;
-
- if ($path[0] == '/')
- {
- // Absolute path, *NIX style
- $path_prefix = '';
- }
- else
- {
- // Absolute path, Windows style
- // Remove the drive letter and colon
- $path_prefix = $path[0] . ':';
- $path = substr($path, 2);
- }
- }
- else
- {
- // Relative Path
- // Prepend the current working directory
- if (function_exists('getcwd'))
- {
- // This is the best method, hopefully it is enabled!
- $path = str_replace(DIRECTORY_SEPARATOR, '/', getcwd()) . '/' . $path;
- $absolute = true;
- if (preg_match('#^[a-z]:#i', $path))
- {
- $path_prefix = $path[0] . ':';
- $path = substr($path, 2);
- }
- else
- {
- $path_prefix = '';
- }
- }
- else if ($request->server('SCRIPT_FILENAME'))
- {
- // Warning: If chdir() has been used this will lie!
- // Warning: This has some problems sometime (CLI can create them easily)
- $filename = htmlspecialchars_decode($request->server('SCRIPT_FILENAME'));
- $path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($filename)) . '/' . $path;
- $absolute = true;
- $path_prefix = '';
- }
- else
- {
- // We have no way of getting the absolute path, just run on using relative ones.
- $absolute = false;
- $path_prefix = '.';
- }
- }
-
- // Remove any repeated slashes
- $path = preg_replace('#/{2,}#', '/', $path);
-
- // Remove the slashes from the start and end of the path
- $path = trim($path, '/');
-
- // Break the string into little bits for us to nibble on
- $bits = explode('/', $path);
-
- // Remove any . in the path, renumber array for the loop below
- $bits = array_values(array_diff($bits, array('.')));
-
- // Lets get looping, run over and resolve any .. (up directory)
- for ($i = 0, $max = sizeof($bits); $i < $max; $i++)
- {
- // @todo Optimise
- if ($bits[$i] == '..' )
- {
- if (isset($bits[$i - 1]))
- {
- if ($bits[$i - 1] != '..')
- {
- // We found a .. and we are able to traverse upwards, lets do it!
- unset($bits[$i]);
- unset($bits[$i - 1]);
- $i -= 2;
- $max -= 2;
- $bits = array_values($bits);
- }
- }
- else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute
- {
- // We have an absolute path trying to descend above the root of the filesystem
- // ... Error!
- return false;
- }
- }
- }
-
- // Prepend the path prefix
- array_unshift($bits, $path_prefix);
-
- $resolved = '';
-
- $max = sizeof($bits) - 1;
-
- // Check if we are able to resolve symlinks, Windows cannot.
- $symlink_resolve = (function_exists('readlink')) ? true : false;
-
- foreach ($bits as $i => $bit)
- {
- if (@is_dir("$resolved/$bit") || ($i == $max && @is_file("$resolved/$bit")))
- {
- // Path Exists
- if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit")))
- {
- // Resolved a symlink.
- $resolved = $link . (($i == $max) ? '' : '/');
- continue;
- }
- }
- else
- {
- // Something doesn't exist here!
- // This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic
- // return false;
- }
- $resolved .= $bit . (($i == $max) ? '' : '/');
- }
-
- // @todo If the file exists fine and open_basedir only has one path we should be able to prepend it
- // because we must be inside that basedir, the question is where...
- // @internal The slash in is_dir() gets around an open_basedir restriction
- if (!@file_exists($resolved) || (!@is_dir($resolved . '/') && !is_file($resolved)))
- {
- return false;
- }
-
- // Put the slashes back to the native operating systems slashes
- $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved);
-
- // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
- if (substr($resolved, -1) == DIRECTORY_SEPARATOR)
- {
- return substr($resolved, 0, -1);
- }
-
- return $resolved; // We got here, in the end!
-}
-
-if (!function_exists('realpath'))
-{
- /**
- * A wrapper for realpath
- * @ignore
- */
- function phpbb_realpath($path)
- {
- return phpbb_own_realpath($path);
- }
-}
-else
-{
- /**
- * A wrapper for realpath
- */
- function phpbb_realpath($path)
- {
- $realpath = realpath($path);
-
- // Strangely there are provider not disabling realpath but returning strange values. :o
- // We at least try to cope with them.
- if ($realpath === $path || $realpath === false)
- {
- return phpbb_own_realpath($path);
- }
-
- // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
- if (substr($realpath, -1) == DIRECTORY_SEPARATOR)
- {
- $realpath = substr($realpath, 0, -1);
- }
-
- return $realpath;
- }
-}
-
// functions used for building option fields
/**
@@ -1189,14 +621,14 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
if ($mode == 'all')
{
- if ($forum_id === false || !sizeof($forum_id))
+ if (empty($forum_id))
{
// Mark all forums read (index page)
-
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
// Mark all topic notifications read for this user
- $phpbb_notifications->mark_notifications_read(array(
+ $phpbb_notifications->mark_notifications(array(
'notification.type.topic',
'notification.type.quote',
'notification.type.bookmark',
@@ -1248,8 +680,6 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
}
}
}
-
- return;
}
else if ($mode == 'topics')
{
@@ -1263,9 +693,10 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
$forum_id = array_unique($forum_id);
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
- $phpbb_notifications->mark_notifications_read_by_parent(array(
+ $phpbb_notifications->mark_notifications_by_parent(array(
'notification.type.topic',
'notification.type.approve_topic',
), $forum_id, $user->data['user_id'], $post_time);
@@ -1282,7 +713,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
}
$db->sql_freeresult($result);
- $phpbb_notifications->mark_notifications_read_by_parent(array(
+ $phpbb_notifications->mark_notifications_by_parent(array(
'notification.type.quote',
'notification.type.bookmark',
'notification.type.post',
@@ -1313,7 +744,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
}
$db->sql_freeresult($result);
- if (sizeof($sql_update))
+ if (count($sql_update))
{
$sql = 'UPDATE ' . FORUMS_TRACK_TABLE . "
SET mark_time = $post_time
@@ -1375,8 +806,6 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
unset($tracking);
}
-
- return;
}
else if ($mode == 'topic')
{
@@ -1385,15 +814,16 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
return;
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
// Mark post notifications read for this user in this topic
- $phpbb_notifications->mark_notifications_read(array(
+ $phpbb_notifications->mark_notifications(array(
'notification.type.topic',
'notification.type.approve_topic',
), $topic_id, $user->data['user_id'], $post_time);
- $phpbb_notifications->mark_notifications_read_by_parent(array(
+ $phpbb_notifications->mark_notifications_by_parent(array(
'notification.type.quote',
'notification.type.bookmark',
'notification.type.post',
@@ -1438,7 +868,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
$tracking['tf'][$forum_id][$topic_id36] = true;
}
- $tracking['t'][$topic_id36] = base_convert($post_time - $config['board_startdate'], 10, 36);
+ $tracking['t'][$topic_id36] = base_convert($post_time - (int) $config['board_startdate'], 10, 36);
// If the cookie grows larger than 10000 characters we will remove the smallest value
// This can result in old topics being unread - but most of the time it should be accurate...
@@ -1448,7 +878,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
// We get the ten most minimum stored time offsets and its associated topic ids
$time_keys = array();
- for ($i = 0; $i < 10 && sizeof($tracking['t']); $i++)
+ for ($i = 0; $i < 10 && count($tracking['t']); $i++)
{
$min_value = min($tracking['t']);
$m_tkey = array_search($min_value, $tracking['t']);
@@ -1489,8 +919,6 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
$user->set_cookie('track', tracking_serialize($tracking), $post_time + 31536000);
$request->overwrite($config['cookie_name'] . '_track', tracking_serialize($tracking), \phpbb\request\request_interface::COOKIE);
}
-
- return;
}
else if ($mode == 'post')
{
@@ -1515,9 +943,28 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
$db->sql_return_on_error(false);
}
-
- return;
}
+
+ /**
+ * This event is used for performing actions directly after forums,
+ * topics or posts have been marked as read.
+ *
+ * @event core.markread_after
+ * @var string mode Variable containing marking mode value
+ * @var mixed forum_id Variable containing forum id, or false
+ * @var mixed topic_id Variable containing topic id, or false
+ * @var int post_time Variable containing post time
+ * @var int user_id Variable containing the user id
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'forum_id',
+ 'topic_id',
+ 'post_time',
+ 'user_id',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.markread_after', compact($vars)));
}
/**
@@ -1525,7 +972,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
*/
function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $global_announce_list = false)
{
- global $config, $user;
+ global $user;
$last_read = array();
@@ -1544,7 +991,7 @@ function get_topic_tracking($forum_id, $topic_ids, &$rowset, $forum_mark_time, $
$topic_ids = array_diff($topic_ids, array_keys($last_read));
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$mark_time = array();
@@ -1596,7 +1043,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis
$topic_ids = array_diff($topic_ids, array_keys($last_read));
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$sql = 'SELECT forum_id, mark_time
FROM ' . FORUMS_TRACK_TABLE . "
@@ -1623,7 +1070,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis
{
global $tracking_topics;
- if (!isset($tracking_topics) || !sizeof($tracking_topics))
+ if (!isset($tracking_topics) || !count($tracking_topics))
{
$tracking_topics = $request->variable($config['cookie_name'] . '_track', '', true, \phpbb\request\request_interface::COOKIE);
$tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
@@ -1650,7 +1097,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis
$topic_ids = array_diff($topic_ids, array_keys($last_read));
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$mark_time = array();
@@ -1684,7 +1131,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis
*/
function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $sql_limit = 1001, $sql_limit_offset = 0)
{
- global $config, $db, $user;
+ global $config, $db, $user, $request;
global $phpbb_dispatcher;
$user_id = ($user_id === false) ? (int) $user->data['user_id'] : (int) $user_id;
@@ -1763,7 +1210,7 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s
if (empty($tracking_topics))
{
- $tracking_topics = request_var($config['cookie_name'] . '_track', '', false, true);
+ $tracking_topics = $request->variable($config['cookie_name'] . '_track', '', false, \phpbb\request\request_interface::COOKIE);
$tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array();
}
@@ -1830,7 +1277,7 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s
*/
function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false)
{
- global $db, $tracking_topics, $user, $config, $auth, $request, $phpbb_container;
+ global $db, $tracking_topics, $user, $config, $request, $phpbb_container;
// Determine the users last forum mark time if not given.
if ($mark_time_forum === false)
@@ -1855,6 +1302,7 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti
// Handle update of unapproved topics info.
// Only update for moderators having m_approve permission for the forum.
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
// Check the forum for any left unread topics.
@@ -1887,8 +1335,6 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti
else if ($config['load_anon_lastread'] || $user->data['is_registered'])
{
// Get information from cookie
- $row = false;
-
if (!isset($tracking_topics['tf'][$forum_id]))
{
// We do not need to mark read, this happened before. Therefore setting this to true
@@ -1993,7 +1439,7 @@ function tracking_unserialize($string, $max_depth = 3)
switch ($string[$i])
{
case '(':
- if (sizeof($stack) >= $max_depth)
+ if (count($stack) >= $max_depth)
{
die('Invalid data supplied');
}
@@ -2047,7 +1493,7 @@ function tracking_unserialize($string, $max_depth = 3)
}
}
- if (sizeof($stack) != 0 || ($mode != 0 && $mode != 3))
+ if (count($stack) != 0 || ($mode != 0 && $mode != 3))
{
die('Invalid data supplied');
}
@@ -2230,7 +1676,7 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false,
*/
function generate_board_url($without_script_path = false)
{
- global $config, $user, $request;
+ global $config, $user, $request, $symfony_request;
$server_name = $user->host;
@@ -2247,7 +1693,8 @@ function generate_board_url($without_script_path = false)
}
else
{
- $server_port = $request->server('SERVER_PORT', 0);
+ $server_port = (int) $symfony_request->getPort();
+
$forwarded_proto = $request->server('HTTP_X_FORWARDED_PROTO');
if (!empty($forwarded_proto) && $forwarded_proto === 'https')
@@ -2294,11 +1741,9 @@ function generate_board_url($without_script_path = false)
*/
function redirect($url, $return = false, $disable_cd_check = false)
{
- global $db, $cache, $config, $user, $phpbb_root_path, $phpbb_filesystem, $phpbb_path_helper, $phpEx, $phpbb_dispatcher;
+ global $user, $phpbb_path_helper, $phpbb_dispatcher;
- $failover_flag = false;
-
- if (empty($user->lang))
+ if (!$user->is_setup())
{
$user->add_lang('common');
}
@@ -2311,15 +1756,15 @@ function redirect($url, $return = false, $disable_cd_check = false)
if ($url_parts === false)
{
- // Malformed url, redirect to current page...
- $url = generate_board_url() . '/' . $user->page['page'];
+ // Malformed url
+ trigger_error('INSECURE_REDIRECT', E_USER_WARNING);
}
else if (!empty($url_parts['scheme']) && !empty($url_parts['host']))
{
// Attention: only able to redirect within the same domain if $disable_cd_check is false (yourdomain.com -> www.yourdomain.com will not work)
if (!$disable_cd_check && $url_parts['host'] !== $user->host)
{
- trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_WARNING);
}
}
else if ($url[0] == '/')
@@ -2359,13 +1804,13 @@ function redirect($url, $return = false, $disable_cd_check = false)
if (!$disable_cd_check && strpos($url, generate_board_url(true) . '/') !== 0)
{
- trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_WARNING);
}
// Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2
if (strpos(urldecode($url), "\n") !== false || strpos(urldecode($url), "\r") !== false || strpos($url, ';') !== false)
{
- trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_WARNING);
}
// Now, also check the protocol and for a valid url the last time...
@@ -2374,7 +1819,7 @@ function redirect($url, $return = false, $disable_cd_check = false)
if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols))
{
- trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_WARNING);
}
/**
@@ -2398,27 +1843,6 @@ function redirect($url, $return = false, $disable_cd_check = false)
garbage_collection();
}
- // Redirect via an HTML form for PITA webservers
- if (@preg_match('#WebSTAR|Xitami#', getenv('SERVER_SOFTWARE')))
- {
- header('Refresh: 0; URL=' . $url);
-
- echo '<!DOCTYPE html>';
- echo '<html dir="' . $user->lang['DIRECTION'] . '" lang="' . $user->lang['USER_LANG'] . '">';
- echo '<head>';
- echo '<meta charset="utf-8">';
- echo '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
- echo '<meta http-equiv="refresh" content="0; url=' . str_replace('&', '&amp;', $url) . '" />';
- echo '<title>' . $user->lang['REDIRECT'] . '</title>';
- echo '</head>';
- echo '<body>';
- echo '<div style="text-align: center;">' . sprintf($user->lang['URL_REDIRECT'], '<a href="' . str_replace('&', '&amp;', $url) . '">', '</a>') . '</div>';
- echo '</body>';
- echo '</html>';
-
- exit;
- }
-
// Behave as per HTTP/1.1 spec for others
header('Location: ' . $url);
exit;
@@ -2427,7 +1851,7 @@ function redirect($url, $return = false, $disable_cd_check = false)
/**
* Re-Apply session id after page reloads
*/
-function reapply_sid($url)
+function reapply_sid($url, $is_route = false)
{
global $phpEx, $phpbb_root_path;
@@ -2449,7 +1873,7 @@ function reapply_sid($url)
$url = preg_replace("/$phpEx(&amp;|&)+?/", "$phpEx?", $url);
}
- return append_sid($url);
+ return append_sid($url, false, true, false, $is_route);
}
/**
@@ -2698,31 +2122,35 @@ function check_form_key($form_name, $timespan = false)
/**
* Build Confirm box
* @param boolean $check True for checking if confirmed (without any additional parameters) and false for displaying the confirm box
-* @param string $title Title/Message used for confirm box.
+* @param string|array $title Title/Message used for confirm box.
* message text is _CONFIRM appended to title.
* If title cannot be found in user->lang a default one is displayed
* If title_CONFIRM cannot be found in user->lang the text given is used.
+* If title is an array, the first array value is used as explained per above,
+* all other array values are sent as parameters to the language function.
* @param string $hidden Hidden variables
* @param string $html_body Template used for confirm box
* @param string $u_action Custom form action
+*
+* @return bool True if confirmation was successful, false if not
*/
function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_body.html', $u_action = '')
{
global $user, $template, $db, $request;
- global $config, $phpbb_path_helper;
+ global $config, $language, $phpbb_path_helper, $phpbb_dispatcher;
if (isset($_POST['cancel']))
{
return false;
}
- $confirm = ($user->lang['YES'] === $request->variable('confirm', '', true, \phpbb\request\request_interface::POST));
+ $confirm = ($language->lang('YES') === $request->variable('confirm', '', true, \phpbb\request\request_interface::POST));
if ($check && $confirm)
{
- $user_id = request_var('confirm_uid', 0);
- $session_id = request_var('sess', '');
- $confirm_key = request_var('confirm_key', '');
+ $user_id = $request->variable('confirm_uid', 0);
+ $session_id = $request->variable('sess', '');
+ $confirm_key = $request->variable('confirm_key', '');
if ($user_id != $user->data['user_id'] || $session_id != $user->session_id || !$confirm_key || !$user->data['user_last_confirm_key'] || $confirm_key != $user->data['user_last_confirm_key'])
{
@@ -2750,13 +2178,27 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
// generate activation key
$confirm_key = gen_rand_string(10);
+ // generate language strings
+ if (is_array($title))
+ {
+ $key = array_shift($title);
+ $count = array_shift($title);
+ $confirm_title = $language->is_set($key) ? $language->lang($key, $count, $title) : $language->lang('CONFIRM');
+ $confirm_text = $language->is_set($key . '_CONFIRM') ? $language->lang($key . '_CONFIRM', $count, $title) : $key;
+ }
+ else
+ {
+ $confirm_title = $language->is_set($title) ? $language->lang($title) : $language->lang('CONFIRM');
+ $confirm_text = $language->is_set($title . '_CONFIRM') ? $language->lang($title . '_CONFIRM') : $title;
+ }
+
if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
{
- adm_page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]);
+ adm_page_header($confirm_title);
}
else
{
- page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]);
+ page_header($confirm_title);
}
$template->set_filenames(array(
@@ -2764,7 +2206,7 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
);
// If activation key already exist, we better do not re-use the key (something very strange is going on...)
- if (request_var('confirm_key', ''))
+ if ($request->variable('confirm_key', ''))
{
// This should not occur, therefore we cancel the operation to safe the user
return false;
@@ -2776,10 +2218,10 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
$u_action .= ((strpos($u_action, '?') === false) ? '?' : '&amp;') . 'confirm_key=' . $confirm_key;
$template->assign_vars(array(
- 'MESSAGE_TITLE' => (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang($title, 1),
- 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
+ 'MESSAGE_TITLE' => $confirm_title,
+ 'MESSAGE_TEXT' => $confirm_text,
- 'YES_VALUE' => $user->lang['YES'],
+ 'YES_VALUE' => $language->lang('YES'),
'S_CONFIRM_ACTION' => $u_action,
'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields,
'S_AJAX_REQUEST' => $request->is_ajax(),
@@ -2792,16 +2234,36 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
if ($request->is_ajax())
{
$u_action .= '&confirm_uid=' . $user->data['user_id'] . '&sess=' . $user->session_id . '&sid=' . $user->session_id;
- $json_response = new \phpbb\json_response;
- $json_response->send(array(
+ $data = array(
'MESSAGE_BODY' => $template->assign_display('body'),
- 'MESSAGE_TITLE' => (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title],
- 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
+ 'MESSAGE_TITLE' => $confirm_title,
+ 'MESSAGE_TEXT' => $confirm_text,
- 'YES_VALUE' => $user->lang['YES'],
+ 'YES_VALUE' => $language->lang('YES'),
'S_CONFIRM_ACTION' => str_replace('&amp;', '&', $u_action), //inefficient, rewrite whole function
'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields
- ));
+ );
+
+ /**
+ * This event allows an extension to modify the ajax output of confirm box.
+ *
+ * @event core.confirm_box_ajax_before
+ * @var string u_action Action of the form
+ * @var array data Data to be sent
+ * @var string hidden Hidden fields generated by caller
+ * @var string s_hidden_fields Hidden fields generated by this function
+ * @since 3.2.8-RC1
+ */
+ $vars = array(
+ 'u_action',
+ 'data',
+ 'hidden',
+ 's_hidden_fields',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.confirm_box_ajax_before', compact($vars)));
+
+ $json_response = new \phpbb\json_response;
+ $json_response->send($data);
}
if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
@@ -2812,6 +2274,8 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
{
page_footer();
}
+
+ exit; // unreachable, page_footer() above will call exit()
}
/**
@@ -2819,13 +2283,14 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
*/
function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = false, $s_display = true)
{
- global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config;
- global $request, $phpbb_container, $phpbb_dispatcher;
+ global $user, $template, $auth, $phpEx, $phpbb_root_path, $config;
+ global $request, $phpbb_container, $phpbb_dispatcher, $phpbb_log;
$err = '';
+ $form_name = 'login';
// Make sure user->setup() has been called
- if (empty($user->lang))
+ if (!$user->is_setup())
{
$user->setup();
}
@@ -2852,8 +2317,9 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
// anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
if ($user->data['is_registered'])
{
- add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL');
}
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_ADMIN');
}
@@ -2862,14 +2328,15 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
// Get credential
if ($admin)
{
- $credential = request_var('credential', '');
+ $credential = $request->variable('credential', '');
if (strspn($credential, 'abcdef0123456789') !== strlen($credential) || strlen($credential) != 32)
{
if ($user->data['is_registered'])
{
- add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL');
}
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_ADMIN');
}
@@ -2880,7 +2347,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
$password = $request->untrimmed_variable('password', '', true);
}
- $username = request_var('username', '', true);
+ $username = $request->variable('username', '', true);
$autologin = $request->is_set_post('autologin');
$viewonline = (int) !$request->is_set_post('viewonline');
$admin = ($admin) ? 1 : 0;
@@ -2890,12 +2357,25 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
if ($admin && utf8_clean_string($username) != utf8_clean_string($user->data['username']))
{
// We log the attempt to use a different username...
- add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL');
+
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_ADMIN_USER_DIFFER');
}
- // If authentication is successful we redirect user to previous page
- $result = $auth->login($username, $password, $autologin, $viewonline, $admin);
+ // Check form key
+ if ($password && !defined('IN_CHECK_BAN') && !check_form_key($form_name))
+ {
+ $result = array(
+ 'status' => false,
+ 'error_msg' => 'FORM_INVALID',
+ );
+ }
+ else
+ {
+ // If authentication is successful we redirect user to previous page
+ $result = $auth->login($username, $password, $autologin, $viewonline, $admin);
+ }
// If admin authentication and login, we will log if it was a success or not...
// We also break the operation on the first non-success login - it could be argued that the user already knows
@@ -2903,7 +2383,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
{
if ($result['status'] == LOGIN_SUCCESS)
{
- add_log('admin', 'LOG_ADMIN_AUTH_SUCCESS');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_SUCCESS');
}
else
{
@@ -2911,7 +2391,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
// anonymous/inactive users are never able to go to the ACP even if they have the relevant permissions
if ($user->data['is_registered'])
{
- add_log('admin', 'LOG_ADMIN_AUTH_FAIL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ADMIN_AUTH_FAIL');
}
}
}
@@ -2919,7 +2399,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
// The result parameter is always an array, holding the relevant information...
if ($result['status'] == LOGIN_SUCCESS)
{
- $redirect = request_var('redirect', "{$phpbb_root_path}index.$phpEx");
+ $redirect = $request->variable('redirect', "{$phpbb_root_path}index.$phpEx");
/**
* This event allows an extension to modify the redirection when a user successfully logs in
@@ -2927,10 +2407,12 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
* @event core.login_box_redirect
* @var string redirect Redirect string
* @var bool admin Is admin?
+ * @var array result Result from auth provider
* @since 3.1.0-RC5
* @changed 3.1.9-RC1 Removed undefined return variable
+ * @changed 3.2.4-RC1 Added result
*/
- $vars = array('redirect', 'admin');
+ $vars = array('redirect', 'admin', 'result');
extract($phpbb_dispatcher->trigger_event('core.login_box_redirect', compact($vars)));
// append/replace SID (may change during the session for AOL users)
@@ -3019,6 +2501,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
$s_hidden_fields['credential'] = $credential;
}
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$auth_provider = $provider_collection->get_provider();
@@ -3045,7 +2528,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
$s_hidden_fields = build_hidden_fields($s_hidden_fields);
- $template->assign_vars(array(
+ $login_box_template_data = array(
'LOGIN_ERROR' => $err,
'LOGIN_EXPLAIN' => $l_explain,
@@ -3053,6 +2536,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
'U_RESEND_ACTIVATION' => ($config['require_activation'] == USER_ACTIVATION_SELF && $config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '',
'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'),
'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'),
+ 'UA_PRIVACY' => addslashes(append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy')),
'S_DISPLAY_FULL_LOGIN' => ($s_display) ? true : false,
'S_HIDDEN_FIELDS' => $s_hidden_fields,
@@ -3062,7 +2546,29 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
'USERNAME_CREDENTIAL' => 'username',
'PASSWORD_CREDENTIAL' => ($admin) ? 'password_' . $credential : 'password',
- ));
+ );
+
+ /**
+ * Event to add/modify login box template data
+ *
+ * @event core.login_box_modify_template_data
+ * @var int admin Flag whether user is admin
+ * @var string username User name
+ * @var int autologin Flag whether autologin is enabled
+ * @var string redirect Redirect URL
+ * @var array login_box_template_data Array with the login box template data
+ * @since 3.2.3-RC2
+ */
+ $vars = array(
+ 'admin',
+ 'username',
+ 'autologin',
+ 'redirect',
+ 'login_box_template_data',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.login_box_modify_template_data', compact($vars)));
+
+ $template->assign_vars($login_box_template_data);
page_header($user->lang['LOGIN']);
@@ -3079,7 +2585,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
*/
function login_forum_box($forum_data)
{
- global $db, $phpbb_container, $request, $template, $user, $phpbb_dispatcher;
+ global $db, $phpbb_container, $request, $template, $user, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
$password = $request->variable('password', '', true);
@@ -3122,6 +2628,7 @@ function login_forum_box($forum_data)
}
$db->sql_freeresult($result);
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
if ($passwords_manager->check($password, $forum_data['forum_password']))
@@ -3163,6 +2670,8 @@ function login_forum_box($forum_data)
'body' => 'login_forum.html')
);
+ make_jumpbox(append_sid("{$phpbb_root_path}viewforum.$phpEx"), $forum_data['forum_id']);
+
page_footer();
}
@@ -3257,9 +2766,9 @@ function parse_cfg_file($filename, $lines = false)
{
$value = '';
}
- else if (($value[0] == "'" && $value[sizeof($value) - 1] == "'") || ($value[0] == '"' && $value[sizeof($value) - 1] == '"'))
+ else if (($value[0] == "'" && $value[strlen($value) - 1] == "'") || ($value[0] == '"' && $value[strlen($value) - 1] == '"'))
{
- $value = htmlspecialchars(substr($value, 1, sizeof($value)-2));
+ $value = htmlspecialchars(substr($value, 1, strlen($value)-2));
}
else
{
@@ -3278,52 +2787,6 @@ function parse_cfg_file($filename, $lines = false)
}
/**
-* Add log entry
-*
-* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
-* @param int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise
-* @param int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise
-* @param int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise
-* @param string $log_operation Name of the operation
-* @param array $additional_data More arguments can be added, depending on the log_type
-*
-* @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
-*
-* @deprecated Use $phpbb_log->add() instead
-*/
-function add_log()
-{
- global $phpbb_log, $user;
-
- $args = func_get_args();
- $mode = array_shift($args);
-
- // This looks kind of dirty, but add_log has some additional data before the log_operation
- $additional_data = array();
- switch ($mode)
- {
- case 'admin':
- case 'critical':
- break;
- case 'mod':
- $additional_data['forum_id'] = array_shift($args);
- $additional_data['topic_id'] = array_shift($args);
- break;
- case 'user':
- $additional_data['reportee_id'] = array_shift($args);
- break;
- }
-
- $log_operation = array_shift($args);
- $additional_data = array_merge($additional_data, $args);
-
- $user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id'];
- $user_ip = (empty($user->ip)) ? '' : $user->ip;
-
- return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data);
-}
-
-/**
* Return a nicely formatted backtrace.
*
* Turns the array returned by debug_backtrace() into HTML markup.
@@ -3386,6 +2849,7 @@ function get_preg_expression($mode)
return array(
'#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#',
'#<!\-\- l \-\-><a (?:class="[\w-]+" )?href="(.*?)(?:(&amp;|\?)sid=[0-9a-f]{32})?">.*?</a><!\-\- l \-\->#',
+ '#<!\-\- ([mw]) \-\-><a (?:class="[\w-]+" )?href="http://(.*?)">\2</a><!\-\- \1 \-\->#',
'#<!\-\- ([mw]) \-\-><a (?:class="[\w-]+" )?href="(.*?)">.*?</a><!\-\- \1 \-\->#',
'#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#',
'#<!\-\- .*? \-\->#s',
@@ -3406,12 +2870,17 @@ function get_preg_expression($mode)
case 'url':
// generated with regex_idn.php file in the develop folder
- return "[a-z][a-z\d+\-.]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?";
+ return "[a-z][a-z\d+\-.]*(?<!javascript):/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?";
+ break;
+
+ case 'url_http':
+ // generated with regex_idn.php file in the develop folder
+ return "http[s]?:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?";
break;
case 'url_inline':
// generated with regex_idn.php file in the develop folder
- return "[a-z][a-z\d+]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?";
+ return "[a-z][a-z\d+]*(?<!javascript):/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?";
break;
case 'www_url':
@@ -3457,31 +2926,19 @@ function get_preg_expression($mode)
* Depends on whether installed PHP version supports unicode properties
*
* @param string $word word template to be replaced
-* @param bool $use_unicode whether or not to take advantage of PCRE supporting unicode
*
* @return string $preg_expr regex to use with word censor
*/
-function get_censor_preg_expression($word, $use_unicode = true)
+function get_censor_preg_expression($word)
{
// Unescape the asterisk to simplify further conversions
$word = str_replace('\*', '*', preg_quote($word, '#'));
- if ($use_unicode && phpbb_pcre_utf8_support())
- {
- // Replace asterisk(s) inside the pattern, at the start and at the end of it with regexes
- $word = preg_replace(array('#(?<=[\p{Nd}\p{L}_])\*+(?=[\p{Nd}\p{L}_])#iu', '#^\*+#', '#\*+$#'), array('([\x20]*?|[\p{Nd}\p{L}_-]*?)', '[\p{Nd}\p{L}_-]*?', '[\p{Nd}\p{L}_-]*?'), $word);
+ // Replace asterisk(s) inside the pattern, at the start and at the end of it with regexes
+ $word = preg_replace(array('#(?<=[\p{Nd}\p{L}_])\*+(?=[\p{Nd}\p{L}_])#iu', '#^\*+#', '#\*+$#'), array('([\x20]*?|[\p{Nd}\p{L}_-]*?)', '[\p{Nd}\p{L}_-]*?', '[\p{Nd}\p{L}_-]*?'), $word);
- // Generate the final substitution
- $preg_expr = '#(?<![\p{Nd}\p{L}_-])(' . $word . ')(?![\p{Nd}\p{L}_-])#iu';
- }
- else
- {
- // Replace the asterisk inside the pattern, at the start and at the end of it with regexes
- $word = preg_replace(array('#(?<=\S)\*+(?=\S)#iu', '#^\*+#', '#\*+$#'), array('(\x20*?\S*?)', '\S*?', '\S*?'), $word);
-
- // Generate the final substitution
- $preg_expr = '#(?<!\S)(' . $word . ')(?!\S)#iu';
- }
+ // Generate the final substitution
+ $preg_expr = '#(?<![\p{Nd}\p{L}_-])(' . $word . ')(?![\p{Nd}\p{L}_-])#iu';
return $preg_expr;
}
@@ -3645,7 +3102,7 @@ function phpbb_inet_pton($address)
if (preg_match(get_preg_expression('ipv6'), $address))
{
$parts = explode(':', $address);
- $missing_parts = 8 - sizeof($parts) + 1;
+ $missing_parts = 8 - count($parts) + 1;
if (substr($address, 0, 2) === '::')
{
@@ -3662,7 +3119,7 @@ function phpbb_inet_pton($address)
if (preg_match(get_preg_expression('ipv4'), $last_part))
{
- $parts[sizeof($parts) - 1] = '';
+ $parts[count($parts) - 1] = '';
$last_part = phpbb_inet_pton($last_part);
$embedded_ipv4 = true;
--$missing_parts;
@@ -3674,7 +3131,7 @@ function phpbb_inet_pton($address)
{
$ret .= str_pad($part, 4, '0', STR_PAD_LEFT);
}
- else if ($i && $i < sizeof($parts) - 1)
+ else if ($i && $i < count($parts) - 1)
{
$ret .= str_repeat('0000', $missing_parts);
}
@@ -3729,38 +3186,12 @@ function phpbb_checkdnsrr($host, $type = 'MX')
return (@gethostbyname($host_fqdn) == $host_fqdn) ? false : true;
}
- // checkdnsrr() is available on Windows since PHP 5.3,
- // but until 5.3.3 it only works for MX records
- // See: http://bugs.php.net/bug.php?id=51844
-
- // Call checkdnsrr() if
- // we're looking for an MX record or
- // we're not on Windows or
- // we're running a PHP version where #51844 has been fixed
-
- // checkdnsrr() supports AAAA since 5.0.0
- // checkdnsrr() supports TXT since 5.2.4
- if (
- ($type == 'MX' || DIRECTORY_SEPARATOR != '\\' || version_compare(PHP_VERSION, '5.3.3', '>=')) &&
- ($type != 'AAAA' || version_compare(PHP_VERSION, '5.0.0', '>=')) &&
- ($type != 'TXT' || version_compare(PHP_VERSION, '5.2.4', '>=')) &&
- function_exists('checkdnsrr')
- )
+ if (function_exists('checkdnsrr'))
{
return checkdnsrr($host_fqdn, $type);
}
- // dns_get_record() is available since PHP 5; since PHP 5.3 also on Windows,
- // but on Windows it does not work reliable for AAAA records before PHP 5.3.1
-
- // Call dns_get_record() if
- // we're not looking for an AAAA record or
- // we're not on Windows or
- // we're running a PHP version where AAAA lookups work reliable
- if (
- ($type != 'AAAA' || DIRECTORY_SEPARATOR != '\\' || version_compare(PHP_VERSION, '5.3.1', '>=')) &&
- function_exists('dns_get_record')
- )
+ if (function_exists('dns_get_record'))
{
// dns_get_record() expects an integer as second parameter
// We have to convert the string $type to the corresponding integer constant.
@@ -3893,7 +3324,7 @@ function phpbb_checkdnsrr($host, $type = 'MX')
function msg_handler($errno, $msg_text, $errfile, $errline)
{
global $cache, $db, $auth, $template, $config, $user, $request;
- global $phpEx, $phpbb_root_path, $msg_title, $msg_long_text;
+ global $phpbb_root_path, $msg_title, $msg_long_text, $phpbb_log;
// Do not display notices if we suppress them via @
if (error_reporting() == 0 && $errno != E_USER_ERROR && $errno != E_USER_WARNING && $errno != E_USER_NOTICE)
@@ -3907,11 +3338,6 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
$msg_text = $msg_long_text;
}
- if (!defined('E_DEPRECATED'))
- {
- define('E_DEPRECATED', 8192);
- }
-
switch ($errno)
{
case E_NOTICE:
@@ -3934,7 +3360,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
// we are writing an image - the user won't see the debug, so let's place it in the log
if (defined('IMAGE_OUTPUT') || defined('IN_CRON'))
{
- add_log('critical', 'LOG_IMAGE_GENERATION_ERROR', $errfile, $errline, $msg_text);
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_IMAGE_GENERATION_ERROR', false, array($errfile, $errline, $msg_text));
}
// echo '<br /><br />BACKTRACE<br />' . get_backtrace() . '<br />' . "\n";
}
@@ -3945,7 +3371,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
case E_USER_ERROR:
- if (!empty($user) && !empty($user->lang))
+ if (!empty($user) && $user->is_setup())
{
$msg_text = (!empty($user->lang[$msg_text])) ? $user->lang[$msg_text] : $msg_text;
$msg_title = (!isset($msg_title)) ? $user->lang['GENERAL_ERROR'] : ((!empty($user->lang[$msg_title])) ? $user->lang[$msg_title] : $msg_title);
@@ -3996,7 +3422,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
{
// let's avoid loops
$db->sql_return_on_error(true);
- add_log('critical', 'LOG_GENERAL_ERROR', $msg_title, $log_text);
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_GENERAL_ERROR', false, array($msg_title, $log_text));
$db->sql_return_on_error(false);
}
@@ -4066,7 +3492,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
// We re-init the auth array to get correct results on login/logout
$auth->acl($user->data);
- if (empty($user->lang))
+ if (!$user->is_setup())
{
$user->setup();
}
@@ -4155,11 +3581,21 @@ function msg_handler($errno, $msg_text, $errfile, $errline)
*/
function phpbb_filter_root_path($errfile)
{
+ global $phpbb_filesystem;
+
static $root_path;
if (empty($root_path))
{
- $root_path = phpbb_realpath(dirname(__FILE__) . '/../');
+ if ($phpbb_filesystem)
+ {
+ $root_path = $phpbb_filesystem->realpath(dirname(__FILE__) . '/../');
+ }
+ else
+ {
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $root_path = $filesystem->realpath(dirname(__FILE__) . '/../');
+ }
}
return str_replace(array($root_path, '\\'), array('[ROOT]', '/'), $errfile);
@@ -4187,7 +3623,7 @@ function obtain_guest_count($item_id = 0, $item = 'forum')
// Get number of online guests
- if ($db->get_sql_layer() === 'sqlite' || $db->get_sql_layer() === 'sqlite3')
+ if ($db->get_sql_layer() === 'sqlite3')
{
$sql = 'SELECT COUNT(session_ip) as num_guests
FROM (
@@ -4221,7 +3657,7 @@ function obtain_guest_count($item_id = 0, $item = 'forum')
*/
function obtain_users_online($item_id = 0, $item = 'forum')
{
- global $db, $config, $user;
+ global $db, $config;
$reading_sql = '';
if ($item_id !== 0)
@@ -4287,12 +3723,11 @@ function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum'
{
global $config, $db, $user, $auth, $phpbb_dispatcher;
- $guests_online = $hidden_online = $l_online_users = $online_userlist = $visible_online = '';
$user_online_link = $rowset = array();
// Need caps version of $item for language-strings
$item_caps = strtoupper($item);
- if (sizeof($online_users['online_users']))
+ if (count($online_users['online_users']))
{
$sql_ary = array(
'SELECT' => 'u.username, u.username_clean, u.user_id, u.user_type, u.user_allow_viewonline, u.user_colour',
@@ -4467,178 +3902,6 @@ function phpbb_optionset($bit, $set, $data)
}
/**
-* Determine which plural form we should use.
-* For some languages this is not as simple as for English.
-*
-* @param $rule int ID of the plural rule we want to use, see http://wiki.phpbb.com/Plural_Rules#Plural_Rules
-* @param $number int|float The number we want to get the plural case for. Float numbers are floored.
-* @return int The plural-case we need to use for the number plural-rule combination
-*/
-function phpbb_get_plural_form($rule, $number)
-{
- $number = (int) $number;
-
- if ($rule > 15 || $rule < 0)
- {
- trigger_error('INVALID_PLURAL_RULE');
- }
-
- /**
- * The following plural rules are based on a list published by the Mozilla Developer Network
- * https://developer.mozilla.org/en/Localization_and_Plurals
- */
- switch ($rule)
- {
- case 0:
- /**
- * Families: Asian (Chinese, Japanese, Korean, Vietnamese), Persian, Turkic/Altaic (Turkish), Thai, Lao
- * 1 - everything: 0, 1, 2, ...
- */
- return 1;
-
- case 1:
- /**
- * Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan)
- * 1 - 1
- * 2 - everything else: 0, 2, 3, ...
- */
- return ($number == 1) ? 1 : 2;
-
- case 2:
- /**
- * Families: Romanic (French, Brazilian Portuguese)
- * 1 - 0, 1
- * 2 - everything else: 2, 3, ...
- */
- return (($number == 0) || ($number == 1)) ? 1 : 2;
-
- case 3:
- /**
- * Families: Baltic (Latvian)
- * 1 - 0
- * 2 - ends in 1, not 11: 1, 21, ... 101, 121, ...
- * 3 - everything else: 2, 3, ... 10, 11, 12, ... 20, 22, ...
- */
- return ($number == 0) ? 1 : ((($number % 10 == 1) && ($number % 100 != 11)) ? 2 : 3);
-
- case 4:
- /**
- * Families: Celtic (Scottish Gaelic)
- * 1 - is 1 or 11: 1, 11
- * 2 - is 2 or 12: 2, 12
- * 3 - others between 3 and 19: 3, 4, ... 10, 13, ... 18, 19
- * 4 - everything else: 0, 20, 21, ...
- */
- return ($number == 1 || $number == 11) ? 1 : (($number == 2 || $number == 12) ? 2 : (($number >= 3 && $number <= 19) ? 3 : 4));
-
- case 5:
- /**
- * Families: Romanic (Romanian)
- * 1 - 1
- * 2 - is 0 or ends in 01-19: 0, 2, 3, ... 19, 101, 102, ... 119, 201, ...
- * 3 - everything else: 20, 21, ...
- */
- return ($number == 1) ? 1 : ((($number == 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 2 : 3);
-
- case 6:
- /**
- * Families: Baltic (Lithuanian)
- * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
- * 2 - ends in 0 or ends in 10-20: 0, 10, 11, 12, ... 19, 20, 30, 40, ...
- * 3 - everything else: 2, 3, ... 8, 9, 22, 23, ... 29, 32, 33, ...
- */
- return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 < 2) || (($number % 100 >= 10) && ($number % 100 < 20))) ? 2 : 3);
-
- case 7:
- /**
- * Families: Slavic (Croatian, Serbian, Russian, Ukrainian)
- * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
- * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ...
- * 3 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26, ...
- */
- return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 2 : 3);
-
- case 8:
- /**
- * Families: Slavic (Slovak, Czech)
- * 1 - 1
- * 2 - 2, 3, 4
- * 3 - everything else: 0, 5, 6, 7, ...
- */
- return ($number == 1) ? 1 : ((($number >= 2) && ($number <= 4)) ? 2 : 3);
-
- case 9:
- /**
- * Families: Slavic (Polish)
- * 1 - 1
- * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... 104, 122, ...
- * 3 - everything else: 0, 5, 6, ... 11, 12, 13, 14, 15, ... 20, 21, 25, ...
- */
- return ($number == 1) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 2 : 3);
-
- case 10:
- /**
- * Families: Slavic (Slovenian, Sorbian)
- * 1 - ends in 01: 1, 101, 201, ...
- * 2 - ends in 02: 2, 102, 202, ...
- * 3 - ends in 03-04: 3, 4, 103, 104, 203, 204, ...
- * 4 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, ...
- */
- return ($number % 100 == 1) ? 1 : (($number % 100 == 2) ? 2 : ((($number % 100 == 3) || ($number % 100 == 4)) ? 3 : 4));
-
- case 11:
- /**
- * Families: Celtic (Irish Gaeilge)
- * 1 - 1
- * 2 - 2
- * 3 - is 3-6: 3, 4, 5, 6
- * 4 - is 7-10: 7, 8, 9, 10
- * 5 - everything else: 0, 11, 12, ...
- */
- return ($number == 1) ? 1 : (($number == 2) ? 2 : (($number >= 3 && $number <= 6) ? 3 : (($number >= 7 && $number <= 10) ? 4 : 5)));
-
- case 12:
- /**
- * Families: Semitic (Arabic)
- * 1 - 1
- * 2 - 2
- * 3 - ends in 03-10: 3, 4, ... 10, 103, 104, ... 110, 203, 204, ...
- * 4 - ends in 11-99: 11, ... 99, 111, 112, ...
- * 5 - everything else: 100, 101, 102, 200, 201, 202, ...
- * 6 - 0
- */
- return ($number == 1) ? 1 : (($number == 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : (($number != 0) ? 5 : 6))));
-
- case 13:
- /**
- * Families: Semitic (Maltese)
- * 1 - 1
- * 2 - is 0 or ends in 01-10: 0, 2, 3, ... 9, 10, 101, 102, ...
- * 3 - ends in 11-19: 11, 12, ... 18, 19, 111, 112, ...
- * 4 - everything else: 20, 21, ...
- */
- return ($number == 1) ? 1 : ((($number == 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 2 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 3 : 4));
-
- case 14:
- /**
- * Families: Slavic (Macedonian)
- * 1 - ends in 1: 1, 11, 21, ...
- * 2 - ends in 2: 2, 12, 22, ...
- * 3 - everything else: 0, 3, 4, ... 10, 13, 14, ... 20, 23, ...
- */
- return ($number % 10 == 1) ? 1 : (($number % 10 == 2) ? 2 : 3);
-
- case 15:
- /**
- * Families: Icelandic
- * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, 131, ...
- * 2 - everything else: 0, 2, 3, ... 10, 11, 12, ... 20, 22, ...
- */
- return (($number % 10 == 1) && ($number % 100 != 11)) ? 1 : 2;
- }
-}
-
-/**
* Login using http authenticate.
*
* @param array $param Parameter array, see $param_defaults array.
@@ -4862,9 +4125,9 @@ function phpbb_get_user_avatar($user_row, $alt = 'USER_AVATAR', $ignore_config =
*
* @return string Avatar html
*/
-function phpbb_get_group_avatar($user_row, $alt = 'GROUP_AVATAR', $ignore_config = false, $lazy = false)
+function phpbb_get_group_avatar($group_row, $alt = 'GROUP_AVATAR', $ignore_config = false, $lazy = false)
{
- $row = \phpbb\avatar\manager::clean_row($user_row, 'group');
+ $row = \phpbb\avatar\manager::clean_row($group_row, 'group');
return phpbb_get_avatar($row, $alt, $ignore_config, $lazy);
}
@@ -4880,8 +4143,7 @@ function phpbb_get_group_avatar($user_row, $alt = 'GROUP_AVATAR', $ignore_config
*/
function phpbb_get_avatar($row, $alt, $ignore_config = false, $lazy = false)
{
- global $user, $config, $cache, $phpbb_root_path, $phpEx;
- global $request;
+ global $user, $config;
global $phpbb_container, $phpbb_dispatcher;
if (!$config['allow_avatar'] && !$ignore_config)
@@ -4895,6 +4157,7 @@ function phpbb_get_avatar($row, $alt, $ignore_config = false, $lazy = false)
'height' => $row['avatar_height'],
);
+ /* @var $phpbb_avatar_manager \phpbb\avatar\manager */
$phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
$driver = $phpbb_avatar_manager->get_driver($row['avatar_type'], !$ignore_config);
$html = '';
@@ -4902,11 +4165,6 @@ function phpbb_get_avatar($row, $alt, $ignore_config = false, $lazy = false)
if ($driver)
{
$html = $driver->get_custom_html($user, $row, $alt);
- if (!empty($html))
- {
- return $html;
- }
-
$avatar_data = $driver->get_data($row);
}
else
@@ -4914,7 +4172,7 @@ function phpbb_get_avatar($row, $alt, $ignore_config = false, $lazy = false)
$avatar_data['src'] = '';
}
- if (!empty($avatar_data['src']))
+ if (empty($html) && !empty($avatar_data['src']))
{
if ($lazy)
{
@@ -5060,8 +4318,8 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
if ($total_online_users > $config['record_online_users'])
{
- set_config('record_online_users', $total_online_users, true);
- set_config('record_online_date', time(), true);
+ $config->set('record_online_users', $total_online_users, false);
+ $config->set('record_online_date', time(), false);
}
$l_online_record = $user->lang('RECORD_ONLINE_USERS', (int) $config['record_online_users'], $user->format_date($config['record_online_date'], false, true));
@@ -5096,8 +4354,8 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
}
}
- $forum_id = request_var('f', 0);
- $topic_id = request_var('t', 0);
+ $forum_id = $request->variable('f', 0);
+ $topic_id = $request->variable('t', 0);
$s_feed_news = false;
@@ -5117,6 +4375,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
// This path is sent with the base template paths in the assign_vars()
// call below. We need to correct it in case we are accessing from a
// controller because the web paths will be incorrect otherwise.
+ /* @var $phpbb_path_helper \phpbb\path_helper */
$phpbb_path_helper = $phpbb_container->get('path_helper');
$corrected_path = $phpbb_path_helper->get_web_root_path();
$web_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? $board_url : $corrected_path;
@@ -5153,11 +4412,12 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
// Output the notifications
$notifications = false;
- if ($config['load_notifications'] && $user->data['user_id'] != ANONYMOUS && $user->data['user_type'] != USER_IGNORE)
+ if ($config['load_notifications'] && $config['allow_board_notifications'] && $user->data['user_id'] != ANONYMOUS && $user->data['user_type'] != USER_IGNORE)
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
- $notifications = $phpbb_notifications->load_notifications(array(
+ $notifications = $phpbb_notifications->load_notifications('notification.method.board', array(
'all_unread' => true,
'limit' => 5,
));
@@ -5168,8 +4428,27 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
}
}
+ /** @var \phpbb\controller\helper $controller_helper */
+ $controller_helper = $phpbb_container->get('controller.helper');
$notification_mark_hash = generate_link_hash('mark_all_notifications_read');
+ $s_login_redirect = build_hidden_fields(array('redirect' => $phpbb_path_helper->remove_web_root_path(build_url())));
+
+ // Add form token for login box, in case page is presenting a login form.
+ add_form_key('login', '_LOGIN');
+
+ /**
+ * Workaround for missing template variable in pre phpBB 3.2.6 styles.
+ * @deprecated 3.2.7 (To be removed: 3.3.0-a1)
+ */
+ $form_token_login = $template->retrieve_var('S_FORM_TOKEN_LOGIN');
+ if (!empty($form_token_login))
+ {
+ $s_login_redirect .= $form_token_login;
+ // Remove S_FORM_TOKEN_LOGIN as it's already appended to S_LOGIN_REDIRECT
+ $template->assign_var('S_FORM_TOKEN_LOGIN', '');
+ }
+
// The following assigns all _common_ variables that may be used at any point in a template.
$template->assign_vars(array(
'SITENAME' => $config['sitename'],
@@ -5192,7 +4471,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
'U_VIEW_ALL_NOTIFICATIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications'),
'U_MARK_ALL_NOTIFICATIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&amp;mode=notification_list&amp;mark=all&amp;token=' . $notification_mark_hash),
'U_NOTIFICATION_SETTINGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&amp;mode=notification_options'),
- 'S_NOTIFICATIONS_DISPLAY' => $config['load_notifications'],
+ 'S_NOTIFICATIONS_DISPLAY' => $config['load_notifications'] && $config['allow_board_notifications'],
'S_USER_NEW_PRIVMSG' => $user->data['user_new_privmsg'],
'S_USER_UNREAD_PRIVMSG' => $user->data['user_unread_privmsg'],
@@ -5221,7 +4500,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
'U_PROFILE' => append_sid("{$phpbb_root_path}ucp.$phpEx"),
'U_USER_PROFILE' => get_username_string('profile', $user->data['user_id'], $user->data['username'], $user->data['user_colour']),
'U_MODCP' => append_sid("{$phpbb_root_path}mcp.$phpEx", false, true, $user->session_id),
- 'U_FAQ' => append_sid("{$phpbb_root_path}faq.$phpEx"),
+ 'U_FAQ' => $controller_helper->route('phpbb_help_faq_controller'),
'U_SEARCH_SELF' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=egosearch'),
'U_SEARCH_NEW' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=newposts'),
'U_SEARCH_UNANSWERED' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unanswered'),
@@ -5229,11 +4508,12 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'),
'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'),
'U_CONTACT_US' => ($config['contact_admin_form_enable'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=contactadmin') : '',
- 'U_TEAM' => ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=team'),
+ 'U_TEAM' => (!$auth->acl_get('u_viewprofile')) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=team'),
'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'),
'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'),
+ 'UA_PRIVACY' => addslashes(append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy')),
'U_RESTORE_PERMISSIONS' => ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '',
- 'U_FEED' => generate_board_url() . "/feed.$phpEx",
+ 'U_FEED' => $controller_helper->route('phpbb_feed_index'),
'S_USER_LOGGED_IN' => ($user->data['user_id'] != ANONYMOUS) ? true : false,
'S_AUTOLOGIN_ENABLED' => ($config['allow_autologin']) ? true : false,
@@ -5258,7 +4538,7 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
'S_TOPIC_ID' => $topic_id,
'S_LOGIN_ACTION' => ((!defined('ADMIN_START')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("{$phpbb_admin_path}index.$phpEx", false, true, $user->session_id)),
- 'S_LOGIN_REDIRECT' => build_hidden_fields(array('redirect' => $phpbb_path_helper->remove_web_root_path(build_url()))),
+ 'S_LOGIN_REDIRECT' => $s_login_redirect,
'S_ENABLE_FEEDS' => ($config['feed_enable']) ? true : false,
'S_ENABLE_FEEDS_OVERALL' => ($config['feed_overall']) ? true : false,
@@ -5284,12 +4564,14 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/",
'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/",
'T_STYLESHEET_LINK' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/stylesheet.css?assets_version=' . $config['assets_version'],
- 'T_STYLESHEET_LANG_LINK' => "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/' . $user->lang_name . '/stylesheet.css?assets_version=' . $config['assets_version'],
+ 'T_STYLESHEET_LANG_LINK'=> "{$web_path}styles/" . rawurlencode($user->style['style_path']) . '/theme/' . $user->lang_name . '/stylesheet.css?assets_version=' . $config['assets_version'],
+ 'T_FONT_AWESOME_LINK' => !empty($config['allow_cdn']) && !empty($config['load_font_awesome_url']) ? $config['load_font_awesome_url'] : "{$web_path}assets/css/font-awesome.min.css?assets_version=" . $config['assets_version'],
'T_JQUERY_LINK' => !empty($config['allow_cdn']) && !empty($config['load_jquery_url']) ? $config['load_jquery_url'] : "{$web_path}assets/javascript/jquery.min.js?assets_version=" . $config['assets_version'],
'S_ALLOW_CDN' => !empty($config['allow_cdn']),
+ 'S_COOKIE_NOTICE' => !empty($config['cookie_notice']),
'T_THEME_NAME' => rawurlencode($user->style['style_path']),
- 'T_THEME_LANG_NAME' => $user->data['user_lang'],
+ 'T_THEME_LANG_NAME' => $user->lang_name,
'T_TEMPLATE_NAME' => $user->style['style_path'],
'T_SUPER_TEMPLATE_NAME' => rawurlencode((isset($user->style['style_parent_tree']) && $user->style['style_parent_tree']) ? $user->style['style_parent_tree'] : $user->style['style_path']),
'T_IMAGES' => 'images',
@@ -5307,12 +4589,13 @@ function page_header($page_title = '', $display_online_list = false, $item_id =
if ($send_headers)
{
- // An array of http headers that phpbb will set. The following event may override these.
+ // An array of http headers that phpBB will set. The following event may override these.
$http_headers += array(
// application/xhtml+xml not used because of IE
'Content-type' => 'text/html; charset=UTF-8',
'Cache-Control' => 'private, no-cache="set-cookie"',
'Expires' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
+ 'Referrer-Policy' => 'strict-origin-when-cross-origin',
);
if (!empty($user->data['is_bot']))
{
@@ -5381,10 +4664,10 @@ function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \php
if (isset($GLOBALS['starttime']))
{
$totaltime = microtime(true) - $GLOBALS['starttime'];
- $debug_info[] = sprintf('<abbr title="SQL time: %.3fs / PHP time: %.3fs">Time: %.3fs</abbr>', $db->get_sql_time(), ($totaltime - $db->get_sql_time()), $totaltime);
+ $debug_info[] = sprintf('<span title="SQL time: %.3fs / PHP time: %.3fs">Time: %.3fs</span>', $db->get_sql_time(), ($totaltime - $db->get_sql_time()), $totaltime);
}
- $debug_info[] = sprintf('<abbr title="Cached: %d">Queries: %d</abbr>', $db->sql_num_queries(true), $db->sql_num_queries());
+ $debug_info[] = sprintf('<span title="Cached: %d">Queries: %d</span>', $db->sql_num_queries(true), $db->sql_num_queries());
$memory_usage = memory_get_peak_usage();
if ($memory_usage)
@@ -5433,7 +4716,7 @@ function phpbb_generate_debug_output(\phpbb\db\driver\driver_interface $db, \php
*/
function page_footer($run_cron = true, $display_template = true, $exit_handler = true)
{
- global $db, $config, $template, $user, $auth, $cache, $starttime, $phpbb_root_path, $phpEx;
+ global $db, $config, $template, $user, $auth, $cache, $phpEx;
global $request, $phpbb_dispatcher, $phpbb_admin_path;
// A listener can set this variable to `true` when it overrides this function
@@ -5490,6 +4773,8 @@ function page_footer($run_cron = true, $display_template = true, $exit_handler =
if ($call_cron)
{
global $phpbb_container;
+
+ /* @var $cron \phpbb\cron\manager */
$cron = $phpbb_container->get('cron.manager');
$task = $cron->find_one_ready_task();
@@ -5570,7 +4855,7 @@ function garbage_collection()
*/
function exit_handler()
{
- global $phpbb_hook, $config;
+ global $phpbb_hook;
if (!empty($phpbb_hook) && $phpbb_hook->call_hook(__FUNCTION__))
{
@@ -5606,22 +4891,6 @@ function phpbb_user_session_handler()
}
/**
-* Check if PCRE has UTF-8 support
-* PHP may not be linked with the bundled PCRE lib and instead with an older version
-*
-* @return bool Returns true if PCRE (the regular expressions library) supports UTF-8 encoding
-*/
-function phpbb_pcre_utf8_support()
-{
- static $utf8_pcre_properties = null;
- if (is_null($utf8_pcre_properties))
- {
- $utf8_pcre_properties = (@preg_match('/\p{L}/u', 'a') !== false);
- }
- return $utf8_pcre_properties;
-}
-
-/**
* Casts a numeric string $input to an appropriate numeric type (i.e. integer or float)
*
* @param string $input A numeric string.
diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php
index c4afb39ff0..a2014a7d5b 100644
--- a/phpBB/includes/functions_acp.php
+++ b/phpBB/includes/functions_acp.php
@@ -24,9 +24,9 @@ if (!defined('IN_PHPBB'))
*/
function adm_page_header($page_title)
{
- global $config, $db, $user, $template;
+ global $config, $user, $template;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $SID, $_SID;
- global $phpbb_dispatcher;
+ global $phpbb_dispatcher, $phpbb_container;
if (defined('HEADER_INC'))
{
@@ -88,6 +88,7 @@ function adm_page_header($page_title)
'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/",
'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/",
'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/",
+ 'T_FONT_AWESOME_LINK' => !empty($config['allow_cdn']) && !empty($config['load_font_awesome_url']) ? $config['load_font_awesome_url'] : "{$phpbb_root_path}assets/css/font-awesome.min.css?assets_version=" . $config['assets_version'],
'T_ASSETS_VERSION' => $config['assets_version'],
@@ -107,14 +108,17 @@ function adm_page_header($page_title)
'S_CONTENT_ENCODING' => 'UTF-8',
'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
+
+ 'CONTAINER_EXCEPTION' => $phpbb_container->hasParameter('container_exception') ? $phpbb_container->getParameter('container_exception') : false,
));
- // An array of http headers that phpbb will set. The following event may override these.
+ // An array of http headers that phpBB will set. The following event may override these.
$http_headers = array(
// application/xhtml+xml not used because of IE
'Content-type' => 'text/html; charset=UTF-8',
'Cache-Control' => 'private, no-cache="set-cookie"',
'Expires' => gmdate('D, d M Y H:i:s', time()) . ' GMT',
+ 'Referrer-Policy' => 'strict-origin-when-cross-origin',
);
/**
@@ -142,8 +146,8 @@ function adm_page_header($page_title)
*/
function adm_page_footer($copyright_html = true)
{
- global $db, $config, $template, $user, $auth, $cache;
- global $starttime, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $db, $config, $template, $user, $auth;
+ global $phpbb_root_path;
global $request, $phpbb_dispatcher;
// A listener can set this variable to `true` when it overrides this function
@@ -232,7 +236,7 @@ function h_radio($name, $input_ary, $input_default = false, $id = false, $key =
/**
* Build configuration template for acp configuration pages
*/
-function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
+function build_cfg_template($tpl_type, $key, &$new_ary, $config_key, $vars)
{
global $user, $module, $phpbb_dispatcher;
@@ -240,18 +244,18 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
$name = 'config[' . $config_key . ']';
// Make sure there is no notice printed out for non-existent config options (we simply set them)
- if (!isset($new[$config_key]))
+ if (!isset($new_ary[$config_key]))
{
- $new[$config_key] = '';
+ $new_ary[$config_key] = '';
}
switch ($tpl_type[0])
{
case 'password':
- if ($new[$config_key] !== '')
+ if ($new_ary[$config_key] !== '')
{
// replace passwords with asterixes
- $new[$config_key] = '********';
+ $new_ary[$config_key] = '********';
}
case 'text':
case 'url':
@@ -263,7 +267,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
$size = (int) $tpl_type[1];
$maxlength = (int) $tpl_type[2];
- $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new[$config_key] . '"' . (($tpl_type[0] === 'password') ? ' autocomplete="off"' : '') . ' />';
+ $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new_ary[$config_key] . '"' . (($tpl_type[0] === 'password') ? ' autocomplete="off"' : '') . ' />';
break;
case 'color':
@@ -271,7 +275,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
case 'datetime-local':
case 'month':
case 'week':
- $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '" name="' . $name . '" value="' . $new[$config_key] . '" />';
+ $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '" name="' . $name . '" value="' . $new_ary[$config_key] . '" />';
break;
case 'date':
@@ -285,7 +289,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
$max = (int) $tpl_type[2];
}
- $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (( $min != '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="' . $name . '" value="' . $new[$config_key] . '" />';
+ $tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (( $min != '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="' . $name . '" value="' . $new_ary[$config_key] . '" />';
break;
case 'dimension':
@@ -298,19 +302,19 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
$max = (int) $tpl_type[2];
}
- $tpl = '<input id="' . $key . '" type="number"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_width]" value="' . $new[$config_key . '_width'] . '" /> x <input type="number"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_height]" value="' . $new[$config_key . '_height'] . '" />';
+ $tpl = '<input id="' . $key . '" type="number"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_width]" value="' . $new_ary[$config_key . '_width'] . '" /> x <input type="number"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_height]" value="' . $new_ary[$config_key . '_height'] . '" />';
break;
case 'textarea':
$rows = (int) $tpl_type[1];
$cols = (int) $tpl_type[2];
- $tpl = '<textarea id="' . $key . '" name="' . $name . '" rows="' . $rows . '" cols="' . $cols . '">' . $new[$config_key] . '</textarea>';
+ $tpl = '<textarea id="' . $key . '" name="' . $name . '" rows="' . $rows . '" cols="' . $cols . '">' . $new_ary[$config_key] . '</textarea>';
break;
case 'radio':
- $key_yes = ($new[$config_key]) ? ' checked="checked"' : '';
- $key_no = (!$new[$config_key]) ? ' checked="checked"' : '';
+ $key_yes = ($new_ary[$config_key]) ? ' checked="checked"' : '';
+ $key_no = (!$new_ary[$config_key]) ? ' checked="checked"' : '';
$tpl_type_cond = explode('_', $tpl_type[1]);
$type_no = ($tpl_type_cond[0] == 'disabled' || $tpl_type_cond[0] == 'enabled') ? false : true;
@@ -324,8 +328,6 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
case 'select':
case 'custom':
- $return = '';
-
if (isset($vars['method']))
{
$call = array($module->module, $vars['method']);
@@ -347,7 +349,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
switch ($value)
{
case '{CONFIG_VALUE}':
- $value = $new[$config_key];
+ $value = $new_ary[$config_key];
break;
case '{KEY}':
@@ -360,7 +362,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
}
else
{
- $args = array($new[$config_key], $key);
+ $args = array($new_ary[$config_key], $key);
}
$return = call_user_func_array($call, $args);
@@ -388,6 +390,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
$tpl .= $vars['append'];
}
+ $new = $new_ary;
/**
* Overwrite the html code we display for the config value
*
@@ -405,6 +408,8 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
*/
$vars = array('tpl_type', 'key', 'new', 'name', 'vars', 'tpl');
extract($phpbb_dispatcher->trigger_event('core.build_config_template', compact($vars)));
+ $new_ary = $new;
+ unset($new);
return $tpl;
}
@@ -415,7 +420,7 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
*/
function validate_config_vars($config_vars, &$cfg_array, &$error)
{
- global $phpbb_root_path, $user, $phpbb_dispatcher;
+ global $phpbb_root_path, $user, $phpbb_dispatcher, $phpbb_filesystem, $language;
$type = 0;
$min = 1;
@@ -438,6 +443,16 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)
// Validate a bit. ;) (0 = type, 1 = min, 2= max)
switch ($validator[$type])
{
+ case 'url':
+ $cfg_array[$config_name] = trim($cfg_array[$config_name]);
+
+ if (!empty($cfg_array[$config_name]) && !preg_match('#^' . get_preg_expression('url') . '$#iu', $cfg_array[$config_name]))
+ {
+ $error[] = $language->lang('URL_INVALID', $language->lang($config_definition['lang']));
+ }
+
+ // no break here
+
case 'string':
$length = utf8_strlen($cfg_array[$config_name]);
@@ -560,9 +575,6 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)
$cfg_array[$config_name] = trim($destination);
- // Absolute file path
- case 'absolute_path':
- case 'absolute_path_writable':
// Path being relative (still prefixed by phpbb_root_path), but with the ability to escape the root dir...
case 'path':
case 'wpath':
@@ -581,7 +593,7 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)
break;
}
- $path = in_array($config_definition['validate'], array('wpath', 'path', 'rpath', 'rwpath')) ? $phpbb_root_path . $cfg_array[$config_name] : $cfg_array[$config_name];
+ $path = $phpbb_root_path . $cfg_array[$config_name];
if (!file_exists($path))
{
@@ -594,9 +606,9 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)
}
// Check if the path is writable
- if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath' || $config_definition['validate'] === 'absolute_path_writable')
+ if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath')
{
- if (file_exists($path) && !phpbb_is_writable($path))
+ if (file_exists($path) && !$phpbb_filesystem->is_writable($path))
{
$error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]);
}
@@ -652,8 +664,6 @@ function validate_range($value_ary, &$error)
foreach ($value_ary as $value)
{
$column = explode(':', $value['column_type']);
- $max = $min = 0;
- $type = 0;
if (!isset($column_types[$column[0]]))
{
continue;
diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php
index 4bac718999..cc82fdbda3 100644
--- a/phpBB/includes/functions_admin.php
+++ b/phpBB/includes/functions_admin.php
@@ -65,7 +65,7 @@ function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = ar
*/
function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl = false, $ignore_nonpost = false, $ignore_emptycat = true, $only_acl_post = false, $return_array = false)
{
- global $db, $user, $auth, $phpbb_dispatcher;
+ global $db, $auth, $phpbb_dispatcher;
// This query is identical to the jumpbox one
$sql = 'SELECT forum_id, forum_name, parent_id, forum_type, forum_flags, forum_options, left_id, right_id
@@ -167,7 +167,7 @@ function size_select_options($size_compare)
$s_size_options = '';
- for ($i = 0, $size = sizeof($size_types_text); $i < $size; $i++)
+ for ($i = 0, $size = count($size_types_text); $i < $size; $i++)
{
$selected = ($size_compare == $size_types[$i]) ? ' selected="selected"' : '';
$s_size_options .= '<option value="' . $size_types[$i] . '"' . $selected . '>' . $size_types_text[$i] . '</option>';
@@ -187,9 +187,12 @@ function size_select_options($size_compare)
*/
function group_select_options($group_id, $exclude_ids = false, $manage_founder = false)
{
- global $db, $user, $config;
+ global $db, $config, $phpbb_container;
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
- $exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : '';
+ $exclude_sql = ($exclude_ids !== false && count($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : '';
$sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : '';
$sql_founder = ($manage_founder !== false) ? (($exclude_sql || $sql_and) ? ' AND ' : ' WHERE ') . 'group_founder_manage = ' . (int) $manage_founder : '';
@@ -205,7 +208,7 @@ function group_select_options($group_id, $exclude_ids = false, $manage_founder =
while ($row = $db->sql_fetchrow($result))
{
$selected = ($row['group_id'] == $group_id) ? ' selected="selected"' : '';
- $s_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '"' . $selected . '>' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>';
+ $s_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '"' . $selected . '>' . $group_helper->get_name($row['group_name']) . '</option>';
}
$db->sql_freeresult($result);
@@ -342,7 +345,7 @@ function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $incl
*/
function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true)
{
- global $db;
+ global $db, $user, $phpbb_log;
// Only one forum id specified
if (!is_array($dest_forum_ids))
@@ -465,7 +468,7 @@ function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perm
if ($add_log)
{
- add_log('admin', 'LOG_FORUM_COPIED_PERMISSIONS', $src_forum_name, implode(', ', $dest_forum_names));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_FORUM_COPIED_PERMISSIONS', false, array($src_forum_name, implode(', ', $dest_forum_names)));
}
$db->sql_transaction('commit');
@@ -540,6 +543,20 @@ function move_topics($topic_ids, $forum_id, $auto_sync = true)
$topic_ids = array($topic_ids);
}
+ /**
+ * Perform additional actions before topics move
+ *
+ * @event core.move_topics_before
+ * @var array topic_ids Array of the moved topic ids
+ * @var string forum_id The forum id from where the topics are moved
+ * @since 3.2.9-RC1
+ */
+ $vars = array(
+ 'topic_ids',
+ 'forum_id',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.move_topics_before', compact($vars)));
+
$sql = 'DELETE FROM ' . TOPICS_TABLE . '
WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids) . '
AND forum_id = ' . $forum_id;
@@ -590,6 +607,22 @@ function move_topics($topic_ids, $forum_id, $auto_sync = true)
}
unset($table_ary);
+ /**
+ * Perform additional actions after topics move
+ *
+ * @event core.move_topics_after
+ * @var array topic_ids Array of the moved topic ids
+ * @var string forum_id The forum id from where the topics were moved
+ * @var array forum_ids Array of the forums where the topics were moved (includes also forum_id)
+ * @since 3.2.9-RC1
+ */
+ $vars = array(
+ 'topic_ids',
+ 'forum_id',
+ 'forum_ids',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.move_topics_after', compact($vars)));
+
if ($auto_sync)
{
sync('forum', 'forum_id', $forum_ids, true, true);
@@ -744,7 +777,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
{
$where_ids = (is_array($where_ids)) ? array_unique($where_ids) : array($where_ids);
- if (!sizeof($where_ids))
+ if (!count($where_ids))
{
return array('topics' => 0, 'posts' => 0);
}
@@ -774,9 +807,9 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
}
$db->sql_freeresult($result);
- $return['topics'] = sizeof($topic_ids);
+ $return['topics'] = count($topic_ids);
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
return $return;
}
@@ -834,7 +867,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
}
$db->sql_freeresult($result);
- if (sizeof($moved_topic_ids))
+ if (count($moved_topic_ids))
{
$sql = 'DELETE FROM ' . TOPICS_TABLE . '
WHERE ' . $db->sql_in_set('topic_id', $moved_topic_ids);
@@ -851,9 +884,10 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
if ($approved_topics)
{
- set_config_count('num_topics', $approved_topics * (-1), true);
+ $config->increment('num_topics', $approved_topics * (-1), false);
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->delete_notifications(array(
@@ -919,7 +953,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
$where_ids = array($where_ids);
}
- if (!sizeof($where_ids))
+ if (!count($where_ids))
{
return false;
}
@@ -927,7 +961,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
$where_ids = array_map('intval', $where_ids);
/* Possible code for splitting post deletion
- if (sizeof($where_ids) >= 1001)
+ if (count($where_ids) >= 1001)
{
// Split into chunks of 1000
$chunks = array_chunk($where_ids, 1000);
@@ -970,7 +1004,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
}
$db->sql_freeresult($result);
- if (!sizeof($post_ids))
+ if (!count($post_ids))
{
return false;
}
@@ -1014,7 +1048,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
unset($table_ary);
// Adjust users post counts
- if (sizeof($post_counts) && $post_count_sync)
+ if (count($post_counts) && $post_count_sync)
{
foreach ($post_counts as $poster_id => $substract)
{
@@ -1033,7 +1067,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
}
// Remove topics now having no posts?
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$sql = 'SELECT topic_id
FROM ' . POSTS_TABLE . '
@@ -1069,7 +1103,10 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
$search->index_remove($post_ids, $poster_ids, $forum_ids);
- delete_attachments('post', $post_ids, false);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $attachment_manager->delete('post', $post_ids, false);
+ unset($attachment_manager);
/**
* Perform additional actions during post(s) deletion
@@ -1136,348 +1173,41 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
if ($approved_posts && $post_count_sync)
{
- set_config_count('num_posts', $approved_posts * (-1), true);
+ $config->increment('num_posts', $approved_posts * (-1), false);
}
// We actually remove topics now to not be inconsistent (the delete_topics function calls this function too)
- if (sizeof($remove_topics) && $call_delete_topics)
+ if (count($remove_topics) && $call_delete_topics)
{
delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false);
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->delete_notifications($delete_notifications_types, $post_ids);
- return sizeof($post_ids);
+ return count($post_ids);
}
/**
* Delete Attachments
*
+* @deprecated 3.2.0-a1 (To be removed: 3.4.0)
+*
* @param string $mode can be: post|message|topic|attach|user
* @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
* @param bool $resync set this to false if you are deleting posts or topics
*/
function delete_attachments($mode, $ids, $resync = true)
{
- global $db, $config, $phpbb_dispatcher;
-
- // 0 is as bad as an empty array
- if (empty($ids))
- {
- return false;
- }
-
- if (is_array($ids))
- {
- $ids = array_unique($ids);
- $ids = array_map('intval', $ids);
- }
- else
- {
- $ids = array((int) $ids);
- }
-
- $sql_where = '';
-
- switch ($mode)
- {
- case 'post':
- case 'message':
- $sql_id = 'post_msg_id';
- $sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
- break;
-
- case 'topic':
- $sql_id = 'topic_id';
- break;
-
- case 'user':
- $sql_id = 'poster_id';
- break;
-
- case 'attach':
- default:
- $sql_id = 'attach_id';
- $mode = 'attach';
- break;
- }
-
- $post_ids = $message_ids = $topic_ids = $physical = array();
-
- /**
- * Perform additional actions before collecting data for attachment(s) deletion
- *
- * @event core.delete_attachments_collect_data_before
- * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
- * @var mixed ids Array or comma separated list of ids corresponding to the mode
- * @var bool resync Flag indicating if posts/messages/topics should be synchronized
- * @var string sql_id The field name to collect/delete data for depending on the mode
- * @since 3.1.7-RC1
- */
- $vars = array(
- 'mode',
- 'ids',
- 'resync',
- 'sql_id',
- );
- extract($phpbb_dispatcher->trigger_event('core.delete_attachments_collect_data_before', compact($vars)));
-
- // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
- $sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
- FROM ' . ATTACHMENTS_TABLE . '
- WHERE ' . $db->sql_in_set($sql_id, $ids);
-
- $sql .= $sql_where;
-
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- // We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
- if ($resync && !$row['is_orphan'])
- {
- if (!$row['in_message'])
- {
- $post_ids[] = $row['post_msg_id'];
- $topic_ids[] = $row['topic_id'];
- }
- else
- {
- $message_ids[] = $row['post_msg_id'];
- }
- }
-
- $physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
- }
- $db->sql_freeresult($result);
-
- /**
- * Perform additional actions before attachment(s) deletion
- *
- * @event core.delete_attachments_before
- * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
- * @var mixed ids Array or comma separated list of ids corresponding to the mode
- * @var bool resync Flag indicating if posts/messages/topics should be synchronized
- * @var string sql_id The field name to collect/delete data for depending on the mode
- * @var array post_ids Array with post ids for deleted attachment(s)
- * @var array topic_ids Array with topic ids for deleted attachment(s)
- * @var array message_ids Array with private message ids for deleted attachment(s)
- * @var array physical Array with deleted attachment(s) physical file(s) data
- * @since 3.1.7-RC1
- */
- $vars = array(
- 'mode',
- 'ids',
- 'resync',
- 'sql_id',
- 'post_ids',
- 'topic_ids',
- 'message_ids',
- 'physical',
- );
- extract($phpbb_dispatcher->trigger_event('core.delete_attachments_before', compact($vars)));
-
- // Delete attachments
- $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
- WHERE ' . $db->sql_in_set($sql_id, $ids);
-
- $sql .= $sql_where;
-
- $db->sql_query($sql);
- $num_deleted = $db->sql_affectedrows();
-
- /**
- * Perform additional actions after attachment(s) deletion from the database
- *
- * @event core.delete_attachments_from_database_after
- * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
- * @var mixed ids Array or comma separated list of ids corresponding to the mode
- * @var bool resync Flag indicating if posts/messages/topics should be synchronized
- * @var string sql_id The field name to collect/delete data for depending on the mode
- * @var array post_ids Array with post ids for deleted attachment(s)
- * @var array topic_ids Array with topic ids for deleted attachment(s)
- * @var array message_ids Array with private message ids for deleted attachment(s)
- * @var array physical Array with deleted attachment(s) physical file(s) data
- * @var int num_deleted The number of deleted attachment(s) from the database
- * @since 3.1.7-RC1
- */
- $vars = array(
- 'mode',
- 'ids',
- 'resync',
- 'sql_id',
- 'post_ids',
- 'topic_ids',
- 'message_ids',
- 'physical',
- 'num_deleted',
- );
- extract($phpbb_dispatcher->trigger_event('core.delete_attachments_from_database_after', compact($vars)));
-
- if (!$num_deleted)
- {
- return 0;
- }
-
- // Delete attachments from filesystem
- $space_removed = $files_removed = 0;
- foreach ($physical as $file_ary)
- {
- if (phpbb_unlink($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
- {
- // Only non-orphaned files count to the file size
- $space_removed += $file_ary['filesize'];
- $files_removed++;
- }
-
- if ($file_ary['thumbnail'])
- {
- phpbb_unlink($file_ary['filename'], 'thumbnail', true);
- }
- }
-
- /**
- * Perform additional actions after attachment(s) deletion from the filesystem
- *
- * @event core.delete_attachments_from_filesystem_after
- * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
- * @var mixed ids Array or comma separated list of ids corresponding to the mode
- * @var bool resync Flag indicating if posts/messages/topics should be synchronized
- * @var string sql_id The field name to collect/delete data for depending on the mode
- * @var array post_ids Array with post ids for deleted attachment(s)
- * @var array topic_ids Array with topic ids for deleted attachment(s)
- * @var array message_ids Array with private message ids for deleted attachment(s)
- * @var array physical Array with deleted attachment(s) physical file(s) data
- * @var int num_deleted The number of deleted attachment(s) from the database
- * @var int space_removed The size of deleted files(s) from the filesystem
- * @var int files_removed The number of deleted file(s) from the filesystem
- * @since 3.1.7-RC1
- */
- $vars = array(
- 'mode',
- 'ids',
- 'resync',
- 'sql_id',
- 'post_ids',
- 'topic_ids',
- 'message_ids',
- 'physical',
- 'num_deleted',
- 'space_removed',
- 'files_removed',
- );
- extract($phpbb_dispatcher->trigger_event('core.delete_attachments_from_filesystem_after', compact($vars)));
-
- if ($space_removed || $files_removed)
- {
- set_config_count('upload_dir_size', $space_removed * (-1), true);
- set_config_count('num_files', $files_removed * (-1), true);
- }
-
- // If we do not resync, we do not need to adjust any message, post, topic or user entries
- if (!$resync)
- {
- return $num_deleted;
- }
-
- // No more use for the original ids
- unset($ids);
-
- // Now, we need to resync posts, messages, topics. We go through every one of them
- $post_ids = array_unique($post_ids);
- $message_ids = array_unique($message_ids);
- $topic_ids = array_unique($topic_ids);
-
- // Update post indicators for posts now no longer having attachments
- if (sizeof($post_ids))
- {
- // Just check which posts are still having an assigned attachment not orphaned by querying the attachments table
- $sql = 'SELECT post_msg_id
- FROM ' . ATTACHMENTS_TABLE . '
- WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . '
- AND in_message = 0
- AND is_orphan = 0';
- $result = $db->sql_query($sql);
-
- $remaining_ids = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $remaining_ids[] = $row['post_msg_id'];
- }
- $db->sql_freeresult($result);
-
- // Now only unset those ids remaining
- $post_ids = array_diff($post_ids, $remaining_ids);
-
- if (sizeof($post_ids))
- {
- $sql = 'UPDATE ' . POSTS_TABLE . '
- SET post_attachment = 0
- WHERE ' . $db->sql_in_set('post_id', $post_ids);
- $db->sql_query($sql);
- }
- }
-
- // Update message table if messages are affected
- if (sizeof($message_ids))
- {
- // Just check which messages are still having an assigned attachment not orphaned by querying the attachments table
- $sql = 'SELECT post_msg_id
- FROM ' . ATTACHMENTS_TABLE . '
- WHERE ' . $db->sql_in_set('post_msg_id', $message_ids) . '
- AND in_message = 1
- AND is_orphan = 0';
- $result = $db->sql_query($sql);
-
- $remaining_ids = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $remaining_ids[] = $row['post_msg_id'];
- }
- $db->sql_freeresult($result);
-
- // Now only unset those ids remaining
- $message_ids = array_diff($message_ids, $remaining_ids);
-
- if (sizeof($message_ids))
- {
- $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
- SET message_attachment = 0
- WHERE ' . $db->sql_in_set('msg_id', $message_ids);
- $db->sql_query($sql);
- }
- }
-
- // Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
- if (sizeof($topic_ids))
- {
- // Just check which topics are still having an assigned attachment not orphaned by querying the attachments table (much less entries expected)
- $sql = 'SELECT topic_id
- FROM ' . ATTACHMENTS_TABLE . '
- WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
- AND is_orphan = 0';
- $result = $db->sql_query($sql);
-
- $remaining_ids = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $remaining_ids[] = $row['topic_id'];
- }
- $db->sql_freeresult($result);
+ global $phpbb_container;
- // Now only unset those ids remaining
- $topic_ids = array_diff($topic_ids, $remaining_ids);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $num_deleted = $attachment_manager->delete($mode, $ids, $resync);
- if (sizeof($topic_ids))
- {
- $sql = 'UPDATE ' . TOPICS_TABLE . '
- SET topic_attachment = 0
- WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
- $db->sql_query($sql);
- }
- }
+ unset($attachment_manager);
return $num_deleted;
}
@@ -1532,7 +1262,7 @@ function delete_topic_shadows($forum_id, $sql_more = '', $auto_sync = true)
$db->sql_query($sql);
}
}
- while (sizeof($topic_ids) == $batch_size);
+ while (count($topic_ids) == $batch_size);
if ($auto_sync)
{
@@ -1595,27 +1325,19 @@ function update_posted_info(&$topic_ids)
/**
* Delete attached file
+*
+* @deprecated 3.2.0-a1 (To be removed: 3.4.0)
*/
function phpbb_unlink($filename, $mode = 'file', $entry_removed = false)
{
- global $db, $phpbb_root_path, $config;
+ global $phpbb_container;
- // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
- $sql = 'SELECT COUNT(attach_id) AS num_entries
- FROM ' . ATTACHMENTS_TABLE . "
- WHERE physical_filename = '" . $db->sql_escape(utf8_basename($filename)) . "'";
- $result = $db->sql_query($sql);
- $num_entries = (int) $db->sql_fetchfield('num_entries');
- $db->sql_freeresult($result);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $unlink = $attachment_manager->unlink($filename, $mode, $entry_removed);
+ unset($attachment_manager);
- // Do not remove file if at least one additional entry with the same name exist.
- if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
- {
- return false;
- }
-
- $filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
- return @unlink($phpbb_root_path . $config['upload_path'] . '/' . $filename);
+ return $unlink;
}
/**
@@ -1671,7 +1393,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
// Do not sync the "global forum"
$where_ids = array_diff($where_ids, array(0));
- if (!sizeof($where_ids))
+ if (!count($where_ids))
{
// Empty array with IDs. This means that we don't have any work to do. Just return.
return;
@@ -1685,7 +1407,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
else
{
- if (!sizeof($where_ids))
+ if (!count($where_ids))
{
return;
}
@@ -1724,7 +1446,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
$db->sql_freeresult($result);
- if (!sizeof($topic_id_ary))
+ if (!count($topic_id_ary))
{
return;
}
@@ -1841,7 +1563,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$post_ids[] = $post_id;
}
- if (sizeof($post_ids))
+ if (count($post_ids))
{
$sql = 'UPDATE ' . POSTS_TABLE . '
SET post_reported = 1 - post_reported
@@ -1887,7 +1609,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
$db->sql_freeresult($result);
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET topic_reported = 1 - topic_reported
@@ -1946,7 +1668,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$post_ids[] = $post_id;
}
- if (sizeof($post_ids))
+ if (count($post_ids))
{
$sql = 'UPDATE ' . POSTS_TABLE . '
SET post_attachment = 1 - post_attachment
@@ -1992,7 +1714,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
$db->sql_freeresult($result);
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET topic_attachment = 1 - topic_attachment
@@ -2044,7 +1766,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
$db->sql_freeresult($result);
- if (!sizeof($forum_ids))
+ if (!count($forum_ids))
{
break;
}
@@ -2083,7 +1805,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
// 3: Get post count for each forum (optional)
if ($sync_extra)
{
- if (sizeof($forum_ids) == 1)
+ if (count($forum_ids) == 1)
{
$sql = 'SELECT SUM(t.topic_posts_approved) AS forum_posts_approved, SUM(t.topic_posts_unapproved) AS forum_posts_unapproved, SUM(t.topic_posts_softdeleted) AS forum_posts_softdeleted
FROM ' . TOPICS_TABLE . ' t
@@ -2103,7 +1825,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
while ($row = $db->sql_fetchrow($result))
{
- $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
+ $forum_id = (count($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
$forum_data[$forum_id]['posts_approved'] = (int) $row['forum_posts_approved'];
$forum_data[$forum_id]['posts_unapproved'] = (int) $row['forum_posts_unapproved'];
@@ -2113,7 +1835,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
// 4: Get last_post_id for each forum
- if (sizeof($forum_ids) == 1)
+ if (count($forum_ids) == 1)
{
$sql = 'SELECT MAX(t.topic_last_post_id) as last_post_id
FROM ' . TOPICS_TABLE . ' t
@@ -2133,7 +1855,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
while ($row = $db->sql_fetchrow($result))
{
- $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
+ $forum_id = (count($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
$forum_data[$forum_id]['last_post_id'] = (int) $row['last_post_id'];
@@ -2142,7 +1864,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$db->sql_freeresult($result);
// 5: Retrieve last_post infos
- if (sizeof($post_ids))
+ if (count($post_ids))
{
$sql = 'SELECT p.post_id, p.poster_id, p.post_subject, p.post_time, p.post_username, u.username, u.user_colour
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
@@ -2210,7 +1932,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
}
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$sql = 'UPDATE ' . FORUMS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
@@ -2333,20 +2055,20 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
// Now we delete empty topics and orphan posts
- if (sizeof($delete_posts))
+ if (count($delete_posts))
{
delete_posts('topic_id', array_keys($delete_posts), false);
unset($delete_posts);
}
- if (!sizeof($topic_data))
+ if (!count($topic_data))
{
// If we get there, topic ids were invalid or topics did not contain any posts
delete_topics($where_type, $where_ids, true);
return;
}
- if (sizeof($delete_topics))
+ if (count($delete_topics))
{
$delete_topic_ids = array();
foreach ($delete_topics as $topic_id => $void)
@@ -2365,7 +2087,6 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
AND u.user_id = p.poster_id';
$result = $db->sql_query($sql);
- $post_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$topic_id = intval($row['topic_id']);
@@ -2390,7 +2111,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$db->sql_freeresult($result);
// Make sure shadow topics do link to existing topics
- if (sizeof($moved_topics))
+ if (count($moved_topics))
{
$delete_topics = array();
@@ -2407,7 +2128,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
$db->sql_freeresult($result);
- if (sizeof($delete_topics))
+ if (count($delete_topics))
{
delete_topics('topic_id', $delete_topics, false);
}
@@ -2430,7 +2151,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$db->sql_freeresult($result);
$sync_shadow_topics = array();
- if (sizeof($post_ids))
+ if (count($post_ids))
{
$sql = 'SELECT p.post_id, p.topic_id, p.post_visibility, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
@@ -2438,7 +2159,6 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
AND u.user_id = p.poster_id';
$result = $db->sql_query($sql);
- $post_ids = array();
while ($row = $db->sql_fetchrow($result))
{
$topic_id = (int) $row['topic_id'];
@@ -2484,7 +2204,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$shadow_topic_data = array();
// Update the information we collected
- if (sizeof($sync_shadow_topics))
+ if (count($sync_shadow_topics))
{
foreach ($sync_shadow_topics as $sync_topic_id => $sql_ary)
{
@@ -2549,7 +2269,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
}
}
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
@@ -2566,7 +2286,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
// if some topics have been resync'ed then resync parent forums
// except when we're only syncing a range, we don't want to sync forums during
// batch processing.
- if ($resync_parents && sizeof($resync_forums) && $where_type != 'range')
+ if ($resync_parents && count($resync_forums) && $where_type != 'range')
{
sync('forum', 'forum_id', array_values($resync_forums), true, true);
}
@@ -2588,7 +2308,7 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync
$forum_id = array($forum_id);
}
- if (!sizeof($forum_id))
+ if (!count($forum_id))
{
return;
}
@@ -2679,6 +2399,16 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync
$topic_list = array_unique($topic_list);
}
+ /**
+ * Perform additional actions before topic deletion via pruning
+ *
+ * @event core.prune_delete_before
+ * @var int[] topic_list The IDs of the topics to be deleted
+ * @since 3.2.2-RC1
+ */
+ $vars = array('topic_list');
+ extract($phpbb_dispatcher->trigger_event('core.prune_delete_before', compact($vars)));
+
return delete_topics('topic_id', $topic_list, $auto_sync, false);
}
@@ -2687,7 +2417,7 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync
*/
function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_freq)
{
- global $db;
+ global $db, $user, $phpbb_log;
$sql = 'SELECT forum_name
FROM ' . FORUMS_TABLE . "
@@ -2711,7 +2441,7 @@ function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_fr
$db->sql_query($sql);
}
- add_log('admin', 'LOG_AUTO_PRUNE', $row['forum_name']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_AUTO_PRUNE', false, array($row['forum_name']));
}
return;
@@ -2735,7 +2465,6 @@ function phpbb_cache_moderators($db, $cache, $auth)
// Clear table
switch ($db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
$db->sql_query('DELETE FROM ' . MODERATOR_CACHE_TABLE);
break;
@@ -2746,13 +2475,13 @@ function phpbb_cache_moderators($db, $cache, $auth)
}
// We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting
- $hold_ary = $ug_id_ary = $sql_ary = array();
+ $sql_ary = array();
// Grab all users having moderative options...
$hold_ary = $auth->acl_user_raw_data(false, 'm_%', false);
// Add users?
- if (sizeof($hold_ary))
+ if (!empty($hold_ary))
{
// At least one moderative option warrants a display
$ug_id_ary = array_keys($hold_ary);
@@ -2797,7 +2526,7 @@ function phpbb_cache_moderators($db, $cache, $auth)
}
$db->sql_freeresult($result);
- if (sizeof($hold_ary))
+ if (count($hold_ary))
{
// Get usernames...
$sql = 'SELECT user_id, username
@@ -2837,7 +2566,7 @@ function phpbb_cache_moderators($db, $cache, $auth)
// Now to the groups...
$hold_ary = $auth->acl_group_raw_data(false, 'm_%', false);
- if (sizeof($hold_ary))
+ if (!empty($hold_ary))
{
$ug_id_ary = array_keys($hold_ary);
@@ -2941,7 +2670,7 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id
function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false)
{
// update foes for some user
- if (is_array($user_id) && sizeof($user_id))
+ if (is_array($user_id) && count($user_id))
{
$sql = 'DELETE FROM ' . ZEBRA_TABLE . '
WHERE ' . $db->sql_in_set('zebra_id', $user_id) . '
@@ -2951,7 +2680,7 @@ function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false)
}
// update foes for some group
- if (is_array($group_id) && sizeof($group_id))
+ if (is_array($group_id) && count($group_id))
{
// Grab group settings...
$sql_ary = array(
@@ -2985,7 +2714,7 @@ function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false)
}
$db->sql_freeresult($result);
- if (!sizeof($groups))
+ if (!count($groups))
{
return;
}
@@ -3015,7 +2744,7 @@ function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false)
}
$db->sql_freeresult($result);
- if (sizeof($users))
+ if (count($users))
{
$sql = 'DELETE FROM ' . ZEBRA_TABLE . '
WHERE ' . $db->sql_in_set('zebra_id', $users) . '
@@ -3038,7 +2767,7 @@ function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false)
}
}
- if (sizeof($perms))
+ if (count($perms))
{
$sql = 'DELETE FROM ' . ZEBRA_TABLE . '
WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . '
@@ -3193,7 +2922,6 @@ function get_database_size()
}
break;
- case 'sqlite':
case 'sqlite3':
global $dbhost;
@@ -3204,7 +2932,6 @@ function get_database_size()
break;
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$sql = 'SELECT @@VERSION AS mssql_version';
@@ -3278,25 +3005,6 @@ function get_database_size()
return $database_size;
}
-/**
-* Retrieve contents from remotely stored file
-*
-* @deprecated 3.1.2 Use file_downloader instead
-*/
-function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 6)
-{
- global $phpbb_container;
-
- // Get file downloader and assign $errstr and $errno
- $file_downloader = $phpbb_container->get('file_downloader');
-
- $file_data = $file_downloader->get($host, $directory, $filename, $port, $timeout);
- $errstr = $file_downloader->get_error_string();
- $errno = $file_downloader->get_error_number();
-
- return $file_data;
-}
-
/*
* Tidy Warnings
* Remove all warnings which have now expired from the database
@@ -3322,7 +3030,7 @@ function tidy_warnings()
}
$db->sql_freeresult($result);
- if (sizeof($warning_list))
+ if (count($warning_list))
{
$db->sql_transaction('begin');
@@ -3340,7 +3048,7 @@ function tidy_warnings()
$db->sql_transaction('commit');
}
- set_config('warnings_last_gc', time(), true);
+ $config->set('warnings_last_gc', time(), false);
}
/**
@@ -3348,7 +3056,7 @@ function tidy_warnings()
*/
function tidy_database()
{
- global $db;
+ global $config, $db;
// Here we check permission consistency
@@ -3364,6 +3072,8 @@ function tidy_database()
}
$db->sql_freeresult($result);
+ $db->sql_transaction('begin');
+
// Delete those rows from the acl tables not having listed the forums above
$sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true);
@@ -3373,7 +3083,9 @@ function tidy_database()
WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true);
$db->sql_query($sql);
- set_config('database_last_gc', time(), true);
+ $db->sql_transaction('commit');
+
+ $config->set('database_last_gc', time(), false);
}
/**
@@ -3381,47 +3093,18 @@ function tidy_database()
*/
function add_permission_language()
{
- global $config, $user, $phpEx, $phpbb_extension_manager;
+ global $user, $phpEx, $phpbb_extension_manager;
// add permission language files from extensions
$finder = $phpbb_extension_manager->get_finder();
- // We grab the language files from the default, English and user's language.
- // So we can fall back to the other files like we do when using add_lang()
- $default_lang_files = $english_lang_files = $user_lang_files = array();
-
- // Search for board default language if it's not the user language
- if ($config['default_lang'] != $user->lang_name)
- {
- $default_lang_files = $finder
- ->prefix('permissions_')
- ->suffix(".$phpEx")
- ->core_path('language/' . basename($config['default_lang']) . '/')
- ->extension_directory('/language/' . basename($config['default_lang']))
- ->find();
- }
-
- // Search for english, if its not the default or user language
- if ($config['default_lang'] != 'en' && $user->lang_name != 'en')
- {
- $english_lang_files = $finder
- ->prefix('permissions_')
- ->suffix(".$phpEx")
- ->core_path('language/en/')
- ->extension_directory('/language/en')
- ->find();
- }
-
- // Find files in the user's language
- $user_lang_files = $finder
+ $lang_files = $finder
->prefix('permissions_')
->suffix(".$phpEx")
- ->core_path('language/' . $user->lang_name . '/')
- ->extension_directory('/language/' . $user->lang_name)
+ ->core_path('language/')
+ ->extension_directory('/language')
->find();
- $lang_files = array_merge($english_lang_files, $default_lang_files, $user_lang_files);
-
foreach ($lang_files as $lang_file => $ext_name)
{
if ($ext_name === '/')
diff --git a/phpBB/includes/functions_compatibility.php b/phpBB/includes/functions_compatibility.php
index b59c7376e9..e95fa40a58 100644
--- a/phpBB/includes/functions_compatibility.php
+++ b/phpBB/includes/functions_compatibility.php
@@ -60,6 +60,7 @@ function phpbb_hash($password)
{
global $phpbb_container;
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
return $passwords_manager->hash($password);
}
@@ -78,6 +79,7 @@ function phpbb_check_hash($password, $hash)
{
global $phpbb_container;
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
return $passwords_manager->check($password, $hash);
}
@@ -90,7 +92,7 @@ function phpbb_check_hash($password, $hash)
* @param string $path Path to clean
* @return string Cleaned path
*
-* @deprecated
+* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function phpbb_clean_path($path)
{
@@ -98,6 +100,7 @@ function phpbb_clean_path($path)
if (!$phpbb_path_helper && $phpbb_container)
{
+ /* @var $phpbb_path_helper \phpbb\path_helper */
$phpbb_path_helper = $phpbb_container->get('path_helper');
}
else if (!$phpbb_path_helper)
@@ -115,7 +118,7 @@ function phpbb_clean_path($path)
new phpbb\symfony_request(
$request
),
- new phpbb\filesystem(),
+ new phpbb\filesystem\filesystem(),
$request,
$phpbb_root_path,
$phpEx
@@ -133,7 +136,7 @@ function phpbb_clean_path($path)
*
* @return string Returns the options for timezone selector only
*
-* @deprecated
+* @deprecated 3.1.0 (To be removed: 3.3.0)
*/
function tz_select($default = '', $truncate = false)
{
@@ -147,7 +150,7 @@ function tz_select($default = '', $truncate = false)
* via admin_permissions. Changes of usernames and group names
* must be carried through for the moderators table.
*
-* @deprecated 3.1
+* @deprecated 3.1.0 (To be removed: 3.3.0)
* @return null
*/
function cache_moderators()
@@ -159,7 +162,7 @@ function cache_moderators()
/**
* Removes moderators and administrators from foe lists.
*
-* @deprecated 3.1
+* @deprecated 3.1.0 (To be removed: 3.3.0)
* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore
* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore
* @return null
@@ -196,3 +199,315 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank
$rank_img = $rank_data['img'];
$rank_img_src = $rank_data['img_src'];
}
+
+/**
+ * Retrieve contents from remotely stored file
+ *
+ * @deprecated 3.1.2 Use file_downloader instead
+ */
+function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port = 80, $timeout = 6)
+{
+ global $phpbb_container;
+
+ // Get file downloader and assign $errstr and $errno
+ /* @var $file_downloader \phpbb\file_downloader */
+ $file_downloader = $phpbb_container->get('file_downloader');
+
+ $file_data = $file_downloader->get($host, $directory, $filename, $port, $timeout);
+ $errstr = $file_downloader->get_error_string();
+ $errno = $file_downloader->get_error_number();
+
+ return $file_data;
+}
+
+/**
+ * Add log entry
+ *
+ * @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+ * @param int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise
+ * @param int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise
+ * @param int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise
+ * @param string $log_operation Name of the operation
+ * @param array $additional_data More arguments can be added, depending on the log_type
+ *
+ * @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
+ *
+ * @deprecated 3.1.0 (To be removed: 3.3.0)
+ */
+function add_log()
+{
+ global $phpbb_log, $user;
+
+ $args = func_get_args();
+ $mode = array_shift($args);
+
+ // This looks kind of dirty, but add_log has some additional data before the log_operation
+ $additional_data = array();
+ switch ($mode)
+ {
+ case 'admin':
+ case 'critical':
+ break;
+ case 'mod':
+ $additional_data['forum_id'] = array_shift($args);
+ $additional_data['topic_id'] = array_shift($args);
+ break;
+ case 'user':
+ $additional_data['reportee_id'] = array_shift($args);
+ break;
+ }
+
+ $log_operation = array_shift($args);
+ $additional_data = array_merge($additional_data, $args);
+
+ $user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id'];
+ $user_ip = (empty($user->ip)) ? '' : $user->ip;
+
+ return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data);
+}
+
+/**
+ * Sets a configuration option's value.
+ *
+ * Please note that this function does not update the is_dynamic value for
+ * an already existing config option.
+ *
+ * @param string $config_name The configuration option's name
+ * @param string $config_value New configuration value
+ * @param bool $is_dynamic Whether this variable should be cached (false) or
+ * if it changes too frequently (true) to be
+ * efficiently cached.
+ *
+ * @return null
+ *
+ * @deprecated 3.1.0 (To be removed: 3.3.0)
+ */
+function set_config($config_name, $config_value, $is_dynamic = false, \phpbb\config\config $set_config = null)
+{
+ static $config = null;
+
+ if ($set_config !== null)
+ {
+ $config = $set_config;
+
+ if (empty($config_name))
+ {
+ return;
+ }
+ }
+
+ $config->set($config_name, $config_value, !$is_dynamic);
+}
+
+/**
+ * Increments an integer config value directly in the database.
+ *
+ * @param string $config_name The configuration option's name
+ * @param int $increment Amount to increment by
+ * @param bool $is_dynamic Whether this variable should be cached (false) or
+ * if it changes too frequently (true) to be
+ * efficiently cached.
+ *
+ * @return null
+ *
+ * @deprecated 3.1.0 (To be removed: 3.3.0)
+ */
+function set_config_count($config_name, $increment, $is_dynamic = false, \phpbb\config\config $set_config = null)
+{
+ static $config = null;
+ if ($set_config !== null)
+ {
+ $config = $set_config;
+ if (empty($config_name))
+ {
+ return;
+ }
+ }
+ $config->increment($config_name, $increment, !$is_dynamic);
+}
+
+/**
+ * Wrapper function of \phpbb\request\request::variable which exists for backwards compatability.
+ * See {@link \phpbb\request\request_interface::variable \phpbb\request\request_interface::variable} for
+ * documentation of this function's use.
+ *
+ * @deprecated 3.1.0 (To be removed: 3.3.0)
+ * @param mixed $var_name The form variable's name from which data shall be retrieved.
+ * If the value is an array this may be an array of indizes which will give
+ * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
+ * then specifying array("var", 1) as the name will return "a".
+ * If you pass an instance of {@link \phpbb\request\request_interface phpbb_request_interface}
+ * as this parameter it will overwrite the current request class instance. If you do
+ * not do so, it will create its own instance (but leave superglobals enabled).
+ * @param mixed $default A default value that is returned if the variable was not set.
+ * This function will always return a value of the same type as the default.
+ * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
+ * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
+ * @param bool $cookie This param is mapped to \phpbb\request\request_interface::COOKIE as the last param for
+ * \phpbb\request\request_interface::variable for backwards compatability reasons.
+ * @param \phpbb\request\request_interface|null|false If an instance of \phpbb\request\request_interface is given the instance is stored in
+ * a static variable and used for all further calls where this parameters is null. Until
+ * the function is called with an instance it automatically creates a new \phpbb\request\request
+ * instance on every call. By passing false this per-call instantiation can be restored
+ * after having passed in a \phpbb\request\request_interface instance.
+ *
+ * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
+ * the same as that of $default. If the variable is not set $default is returned.
+ */
+function request_var($var_name, $default, $multibyte = false, $cookie = false, $request = null)
+{
+ // This is all just an ugly hack to add "Dependency Injection" to a function
+ // the only real code is the function call which maps this function to a method.
+ static $static_request = null;
+ if ($request instanceof \phpbb\request\request_interface)
+ {
+ $static_request = $request;
+ if (empty($var_name))
+ {
+ return;
+ }
+ }
+ else if ($request === false)
+ {
+ $static_request = null;
+ if (empty($var_name))
+ {
+ return;
+ }
+ }
+ $tmp_request = $static_request;
+ // no request class set, create a temporary one ourselves to keep backwards compatibility
+ if ($tmp_request === null)
+ {
+ // false param: enable super globals, so the created request class does not
+ // make super globals inaccessible everywhere outside this function.
+ $tmp_request = new \phpbb\request\request(new \phpbb\request\type_cast_helper(), false);
+ }
+ return $tmp_request->variable($var_name, $default, $multibyte, ($cookie) ? \phpbb\request\request_interface::COOKIE : \phpbb\request\request_interface::REQUEST);
+}
+
+/**
+ * Get tables of a database
+ *
+ * @deprecated 3.1.0 (To be removed: 3.3.0)
+ */
+function get_tables($db)
+{
+ $db_tools_factory = new \phpbb\db\tools\factory();
+ $db_tools = $db_tools_factory->get($db);
+
+ return $db_tools->sql_list_tables();
+}
+
+/**
+ * Global function for chmodding directories and files for internal use
+ *
+ * This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
+ * The function determines owner and group from common.php file and sets the same to the provided file.
+ * The function uses bit fields to build the permissions.
+ * The function sets the appropiate execute bit on directories.
+ *
+ * Supported constants representing bit fields are:
+ *
+ * CHMOD_ALL - all permissions (7)
+ * CHMOD_READ - read permission (4)
+ * CHMOD_WRITE - write permission (2)
+ * CHMOD_EXECUTE - execute permission (1)
+ *
+ * NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions.
+ *
+ * @param string $filename The file/directory to be chmodded
+ * @param int $perms Permissions to set
+ *
+ * @return bool true on success, otherwise false
+ *
+ * @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::phpbb_chmod() instead
+ */
+function phpbb_chmod($filename, $perms = CHMOD_READ)
+{
+ global $phpbb_filesystem;
+
+ try
+ {
+ $phpbb_filesystem->phpbb_chmod($filename, $perms);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Test if a file/directory is writable
+ *
+ * This function calls the native is_writable() when not running under
+ * Windows and it is not disabled.
+ *
+ * @param string $file Path to perform write test on
+ * @return bool True when the path is writable, otherwise false.
+ *
+ * @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::is_writable() instead
+ */
+function phpbb_is_writable($file)
+{
+ global $phpbb_filesystem;
+
+ return $phpbb_filesystem->is_writable($file);
+}
+
+/**
+ * Checks if a path ($path) is absolute or relative
+ *
+ * @param string $path Path to check absoluteness of
+ * @return boolean
+ *
+ * @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::is_absolute_path() instead
+ */
+function phpbb_is_absolute($path)
+{
+ global $phpbb_filesystem;
+
+ return $phpbb_filesystem->is_absolute_path($path);
+}
+
+/**
+ * A wrapper for realpath
+ *
+ * @deprecated 3.2.0-dev use \phpbb\filesystem\filesystem::realpath() instead
+ */
+function phpbb_realpath($path)
+{
+ global $phpbb_filesystem;
+
+ return $phpbb_filesystem->realpath($path);
+}
+
+/**
+ * Determine which plural form we should use.
+ * For some languages this is not as simple as for English.
+ *
+ * @param $rule int ID of the plural rule we want to use, see https://area51.phpbb.com/docs/dev/32x/language/plurals.html
+ * @param $number int|float The number we want to get the plural case for. Float numbers are floored.
+ * @return int The plural-case we need to use for the number plural-rule combination
+ *
+ * @deprecated 3.2.0-dev (To be removed: 3.3.0)
+ */
+function phpbb_get_plural_form($rule, $number)
+{
+ global $phpbb_container;
+
+ /** @var \phpbb\language\language $language */
+ $language = $phpbb_container->get('language');
+ return $language->get_plural_form($number, $rule);
+}
+
+/**
+* @return bool Always true
+* @deprecated 3.2.0-dev
+*/
+function phpbb_pcre_utf8_support()
+{
+ return true;
+}
diff --git a/phpBB/includes/functions_compress.php b/phpBB/includes/functions_compress.php
index a7ee29dd91..e86da77b38 100644
--- a/phpBB/includes/functions_compress.php
+++ b/phpBB/includes/functions_compress.php
@@ -56,7 +56,6 @@ class compress
// Clean up path, add closing / if not present
$src_path = ($src_path && substr($src_path, -1) != '/') ? $src_path . '/' : $src_path;
- $filelist = array();
$filelist = filelist("$phpbb_root_path$src", '', '*');
krsort($filelist);
@@ -184,7 +183,7 @@ class compress
}
/**
-* Zip creation class from phpMyAdmin 2.3.0 (c) Tobias Ratschiller, Olivier Müller, Loïc Chapeaux,
+* Zip creation class from phpMyAdmin 2.3.0 (c) Tobias Ratschiller, Olivier Müller, Loïc Chapeaux,
* Marc Delisle, http://www.phpmyadmin.net/
*
* Zip extraction function by Alexandre Tedeschi, alexandrebr at gmail dot com
@@ -204,11 +203,19 @@ class compress_zip extends compress
var $datasec_len = 0;
/**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
* Constructor
*/
- function compress_zip($mode, $file)
+ function __construct($mode, $file)
{
+ global $phpbb_filesystem;
+
$this->fp = @fopen($file, $mode . 'b');
+ $this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem();
if (!$this->fp)
{
@@ -286,7 +293,15 @@ class compress_zip extends compress
{
trigger_error("Could not create directory $folder");
}
- phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
}
}
}
@@ -315,7 +330,15 @@ class compress_zip extends compress
{
trigger_error("Could not create directory $folder");
}
- phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
}
}
}
@@ -386,7 +409,7 @@ class compress_zip extends compress
function close()
{
// Write out central file directory and footer ... if it exists
- if (sizeof($this->ctrl_dir))
+ if (count($this->ctrl_dir))
{
fwrite($this->fp, $this->file());
}
@@ -488,8 +511,8 @@ class compress_zip extends compress
$ctrldir = implode('', $this->ctrl_dir);
return $ctrldir . $this->eof_cdh .
- pack('v', sizeof($this->ctrl_dir)) . // total # of entries "on this disk"
- pack('v', sizeof($this->ctrl_dir)) . // total # of entries overall
+ pack('v', count($this->ctrl_dir)) . // total # of entries "on this disk"
+ pack('v', count($this->ctrl_dir)) . // total # of entries overall
pack('V', strlen($ctrldir)) . // size of central dir
pack('V', $this->datasec_len) . // offset to start of central dir
"\x00\x00"; // .zip file comment length
@@ -539,10 +562,17 @@ class compress_tar extends compress
var $wrote = false;
/**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
* Constructor
*/
- function compress_tar($mode, $file, $type = '')
+ function __construct($mode, $file, $type = '')
{
+ global $phpbb_filesystem;
+
$type = (!$type) ? $file : $type;
$this->isgz = preg_match('#(\.tar\.gz|\.tgz)$#', $type);
$this->isbz = preg_match('#\.tar\.bz2$#', $type);
@@ -551,6 +581,8 @@ class compress_tar extends compress
$this->file = &$file;
$this->type = &$type;
$this->open();
+
+ $this->filesystem = ($phpbb_filesystem instanceof \phpbb\filesystem\filesystem_interface) ? $phpbb_filesystem : new \phpbb\filesystem\filesystem();
}
/**
@@ -601,7 +633,15 @@ class compress_tar extends compress
{
trigger_error("Could not create directory $folder");
}
- phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
}
}
}
@@ -628,7 +668,15 @@ class compress_tar extends compress
{
trigger_error("Could not create directory $folder");
}
- phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
}
}
@@ -637,7 +685,15 @@ class compress_tar extends compress
{
trigger_error("Couldn't create file $filename");
}
- phpbb_chmod($target_filename, CHMOD_READ);
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($target_filename, CHMOD_READ);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
// Grab the file contents
fwrite($fp, ($filesize) ? $fzread($this->fp, ($filesize + 511) &~ 511) : '', $filesize);
diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php
index f671f33ed0..2542be5e02 100644
--- a/phpBB/includes/functions_content.php
+++ b/phpBB/includes/functions_content.php
@@ -336,7 +336,7 @@ function get_context($text, $words, $length = 400)
$text = str_replace($entities, $characters, $text);
$word_indizes = array();
- if (sizeof($words))
+ if (count($words))
{
$match = '';
// find the starting indizes of all words
@@ -361,12 +361,12 @@ function get_context($text, $words, $length = 400)
}
unset($match);
- if (sizeof($word_indizes))
+ if (count($word_indizes))
{
$word_indizes = array_unique($word_indizes);
sort($word_indizes);
- $wordnum = sizeof($word_indizes);
+ $wordnum = count($word_indizes);
// number of characters on the right and left side of each word
$sequence_length = (int) ($length / (2 * $wordnum)) - 2;
$final_text = '';
@@ -434,7 +434,7 @@ function get_context($text, $words, $length = 400)
}
}
- if (!sizeof($words) || !sizeof($word_indizes))
+ if (!count($words) || !count($word_indizes))
{
return str_replace($characters, $entities, ((utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text));
}
@@ -460,41 +460,54 @@ function phpbb_clean_search_string($search_string)
/**
* Decode text whereby text is coming from the db and expected to be pre-parsed content
* We are placing this outside of the message parser because we are often in need of it...
+*
+* NOTE: special chars are kept encoded
+*
+* @param string &$message Original message, passed by reference
+* @param string $bbcode_uid BBCode UID
+* @return null
*/
function decode_message(&$message, $bbcode_uid = '')
{
- global $config, $phpbb_dispatcher;
-
- if ($bbcode_uid)
- {
- $match = array('<br />', "[/*:m:$bbcode_uid]", ":u:$bbcode_uid", ":o:$bbcode_uid", ":$bbcode_uid");
- $replace = array("\n", '', '', '', '');
- }
- else
- {
- $match = array('<br />');
- $replace = array("\n");
- }
+ global $phpbb_container, $phpbb_dispatcher;
/**
- * Use this event to modify the message before it is decoded
- *
- * @event core.decode_message_before
- * @var string message_text The message content
- * @var string bbcode_uid The message BBCode UID
- * @since 3.1.9-RC1
- */
+ * Use this event to modify the message before it is decoded
+ *
+ * @event core.decode_message_before
+ * @var string message_text The message content
+ * @var string bbcode_uid The message BBCode UID
+ * @since 3.1.9-RC1
+ */
$message_text = $message;
$vars = array('message_text', 'bbcode_uid');
extract($phpbb_dispatcher->trigger_event('core.decode_message_before', compact($vars)));
$message = $message_text;
- $message = str_replace($match, $replace, $message);
+ if (preg_match('#^<[rt][ >]#', $message))
+ {
+ $message = htmlspecialchars($phpbb_container->get('text_formatter.utils')->unparse($message), ENT_COMPAT);
+ }
+ else
+ {
+ if ($bbcode_uid)
+ {
+ $match = array('<br />', "[/*:m:$bbcode_uid]", ":u:$bbcode_uid", ":o:$bbcode_uid", ":$bbcode_uid");
+ $replace = array("\n", '', '', '', '');
+ }
+ else
+ {
+ $match = array('<br />');
+ $replace = array("\n");
+ }
+
+ $message = str_replace($match, $replace, $message);
- $match = get_preg_expression('bbcode_htm');
- $replace = array('\1', '\1', '\2', '\1', '', '');
+ $match = get_preg_expression('bbcode_htm');
+ $replace = array('\1', '\1', '\2', '\2', '\1', '', '');
- $message = preg_replace($match, $replace, $message);
+ $message = preg_replace($match, $replace, $message);
+ }
/**
* Use this event to modify the message after it is decoded
@@ -511,21 +524,30 @@ function decode_message(&$message, $bbcode_uid = '')
}
/**
-* Strips all bbcode from a text and returns the plain content
+* Strips all bbcode from a text in place
*/
function strip_bbcode(&$text, $uid = '')
{
- if (!$uid)
+ global $phpbb_container;
+
+ if (preg_match('#^<[rt][ >]#', $text))
{
- $uid = '[0-9a-z]{5,}';
+ $text = $phpbb_container->get('text_formatter.utils')->clean_formatting($text);
}
+ else
+ {
+ if (!$uid)
+ {
+ $uid = '[0-9a-z]{5,}';
+ }
- $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=(?:&quot;.*&quot;|[^\]]*))?(?::[a-z])?(\:$uid)\]#", ' ', $text);
+ $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=(?:&quot;.*&quot;|[^\]]*))?(?::[a-z])?(\:$uid)\]#", ' ', $text);
- $match = get_preg_expression('bbcode_htm');
- $replace = array('\1', '\1', '\2', '\1', '', '');
+ $match = get_preg_expression('bbcode_htm');
+ $replace = array('\1', '\1', '\2', '\1', '', '');
- $text = preg_replace($match, $replace, $text);
+ $text = preg_replace($match, $replace, $text);
+ }
}
/**
@@ -535,7 +557,8 @@ function strip_bbcode(&$text, $uid = '')
function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text = true)
{
static $bbcode;
- global $phpbb_dispatcher;
+ global $auth, $config, $user;
+ global $phpbb_dispatcher, $phpbb_container;
if ($text === '')
{
@@ -556,34 +579,63 @@ function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text
$vars = array('text', 'uid', 'bitfield', 'flags', 'censor_text');
extract($phpbb_dispatcher->trigger_event('core.modify_text_for_display_before', compact($vars)));
- if ($censor_text)
+ if (preg_match('#^<[rt][ >]#', $text))
{
- $text = censor_text($text);
- }
+ $renderer = $phpbb_container->get('text_formatter.renderer');
- // Parse bbcode if bbcode uid stored and bbcode enabled
- if ($uid && ($flags & OPTION_FLAG_BBCODE))
- {
- if (!class_exists('bbcode'))
+ // Temporarily switch off viewcensors if applicable
+ $old_censor = $renderer->get_viewcensors();
+
+ // Check here if the user is having viewing censors disabled (and also allowed to do so).
+ if (!$user->optionget('viewcensors') && $config['allow_nocensors'] && $auth->acl_get('u_chgcensors'))
{
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
+ $censor_text = false;
}
- if (empty($bbcode))
+ if ($old_censor !== $censor_text)
{
- $bbcode = new bbcode($bitfield);
+ $renderer->set_viewcensors($censor_text);
}
- else
+
+ $text = $renderer->render($text);
+
+ // Restore the previous value
+ if ($old_censor !== $censor_text)
{
- $bbcode->bbcode($bitfield);
+ $renderer->set_viewcensors($old_censor);
}
-
- $bbcode->bbcode_second_pass($text, $uid);
}
+ else
+ {
+ if ($censor_text)
+ {
+ $text = censor_text($text);
+ }
+
+ // Parse bbcode if bbcode uid stored and bbcode enabled
+ if ($uid && ($flags & OPTION_FLAG_BBCODE))
+ {
+ if (!class_exists('bbcode'))
+ {
+ global $phpbb_root_path, $phpEx;
+ include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
+ }
+
+ if (empty($bbcode))
+ {
+ $bbcode = new bbcode($bitfield);
+ }
+ else
+ {
+ $bbcode->bbcode_set_bitfield($bitfield);
+ }
- $text = bbcode_nl2br($text);
- $text = smiley_text($text, !($flags & OPTION_FLAG_SMILIES));
+ $bbcode->bbcode_second_pass($text, $uid);
+ }
+
+ $text = bbcode_nl2br($text);
+ $text = smiley_text($text, !($flags & OPTION_FLAG_SMILIES));
+ }
/**
* Use this event to modify the text after it is parsed
@@ -604,7 +656,7 @@ function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text
/**
* For parsing custom parsed text to be stored within the database.
* This function additionally returns the uid and bitfield that needs to be stored.
-* Expects $text to be the value directly from request_var() and in it's non-parsed form
+* Expects $text to be the value directly from $request->variable() and in it's non-parsed form
*
* @param string $text The text to be replaced with the parsed one
* @param string $uid The BBCode uid for this parse
@@ -613,10 +665,15 @@ function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text
* @param bool $allow_bbcode If BBCode is allowed (i.e. if BBCode is parsed)
* @param bool $allow_urls If urls is allowed
* @param bool $allow_smilies If smilies are allowed
+* @param bool $allow_img_bbcode
+* @param bool $allow_flash_bbcode
+* @param bool $allow_quote_bbcode
+* @param bool $allow_url_bbcode
+* @param string $mode Mode to parse text as, e.g. post or sig
*
* @return array An array of string with the errors that occurred while parsing
*/
-function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bbcode = false, $allow_urls = false, $allow_smilies = false)
+function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bbcode = false, $allow_urls = false, $allow_smilies = false, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $mode = 'post')
{
global $phpbb_root_path, $phpEx, $phpbb_dispatcher;
@@ -631,7 +688,13 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb
* @var bool allow_bbcode Whether or not to parse BBCode
* @var bool allow_urls Whether or not to parse URLs
* @var bool allow_smilies Whether or not to parse Smilies
+ * @var bool allow_img_bbcode Whether or not to parse the [img] BBCode
+ * @var bool allow_flash_bbcode Whether or not to parse the [flash] BBCode
+ * @var bool allow_quote_bbcode Whether or not to parse the [quote] BBCode
+ * @var bool allow_url_bbcode Whether or not to parse the [url] BBCode
+ * @var string mode Mode to parse text as, e.g. post or sig
* @since 3.1.0-a1
+ * @changed 3.2.0-a1 Added mode
*/
$vars = array(
'text',
@@ -641,24 +704,24 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb
'allow_bbcode',
'allow_urls',
'allow_smilies',
+ 'allow_img_bbcode',
+ 'allow_flash_bbcode',
+ 'allow_quote_bbcode',
+ 'allow_url_bbcode',
+ 'mode',
);
extract($phpbb_dispatcher->trigger_event('core.modify_text_for_storage_before', compact($vars)));
$uid = $bitfield = '';
$flags = (($allow_bbcode) ? OPTION_FLAG_BBCODE : 0) + (($allow_smilies) ? OPTION_FLAG_SMILIES : 0) + (($allow_urls) ? OPTION_FLAG_LINKS : 0);
- if ($text === '')
- {
- return;
- }
-
if (!class_exists('parse_message'))
{
include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
}
$message_parser = new parse_message($text);
- $message_parser->parse($allow_bbcode, $allow_urls, $allow_smilies);
+ $message_parser->parse($allow_bbcode, $allow_urls, $allow_smilies, $allow_img_bbcode, $allow_flash_bbcode, $allow_quote_bbcode, $allow_url_bbcode, true, $mode);
$text = $message_parser->message;
$uid = $message_parser->bbcode_uid;
@@ -695,7 +758,7 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb
*/
function generate_text_for_edit($text, $uid, $flags)
{
- global $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $phpbb_dispatcher;
/**
* Use this event to modify the text before it is decoded for editing
@@ -958,7 +1021,7 @@ function censor_text($text)
}
}
- if (sizeof($censors))
+ if (count($censors))
{
return preg_replace($censors['match'], $censors['replace'], $text);
}
@@ -1011,12 +1074,12 @@ function smiley_text($text, $force_option = false)
* @param mixed $forum_id The forum id the attachments are displayed in (false if in private message)
* @param string &$message The post/private message
* @param array &$attachments The attachments to parse for (inline) display. The attachments array will hold templated data after parsing.
-* @param array &$update_count The attachment counts to be updated - will be filled
+* @param array &$update_count_ary The attachment counts to be updated - will be filled
* @param bool $preview If set to true the attachments are parsed for preview. Within preview mode the comments are fetched from the given $attachments array and not fetched from the database.
*/
-function parse_attachments($forum_id, &$message, &$attachments, &$update_count, $preview = false)
+function parse_attachments($forum_id, &$message, &$attachments, &$update_count_ary, $preview = false)
{
- if (!sizeof($attachments))
+ if (!count($attachments))
{
return;
}
@@ -1051,7 +1114,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
}
// Grab attachments (security precaution)
- if (sizeof($attach_ids))
+ if (count($attach_ids))
{
global $db;
@@ -1088,7 +1151,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
foreach ($attachments as $attachment)
{
- if (!sizeof($attachment))
+ if (!count($attachment))
{
continue;
}
@@ -1101,7 +1164,6 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
// Some basics...
$attachment['extension'] = strtolower(trim($attachment['extension']));
$filename = $phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($attachment['physical_filename']);
- $thumbnail_filename = $phpbb_root_path . $config['upload_path'] . '/thumb_' . utf8_basename($attachment['physical_filename']);
$upload_icon = '';
@@ -1143,7 +1205,6 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
if (!$denied)
{
- $l_downloaded_viewed = $download_link = '';
$display_cat = $extensions[$attachment['extension']]['display_cat'];
if ($display_cat == ATTACHMENT_CATEGORY_IMAGE)
@@ -1204,7 +1265,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
'U_INLINE_LINK' => $inline_link,
);
- $update_count[] = $attachment['attach_id'];
+ $update_count_ary[] = $attachment['attach_id'];
break;
// Images, but display Thumbnail
@@ -1217,39 +1278,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
'THUMB_IMAGE' => $thumbnail_link,
);
- $update_count[] = $attachment['attach_id'];
- break;
-
- // Windows Media Streams
- case ATTACHMENT_CATEGORY_WM:
-
- // Giving the filename directly because within the wm object all variables are in local context making it impossible
- // to validate against a valid session (all params can differ)
- // $download_link = $filename;
-
- $block_array += array(
- 'U_FORUM' => generate_board_url(),
- 'ATTACH_ID' => $attachment['attach_id'],
- 'S_WM_FILE' => true,
- );
-
- // Viewed/Heared File ... update the download count
- $update_count[] = $attachment['attach_id'];
- break;
-
- // Real Media Streams
- case ATTACHMENT_CATEGORY_RM:
- case ATTACHMENT_CATEGORY_QUICKTIME:
-
- $block_array += array(
- 'S_RM_FILE' => ($display_cat == ATTACHMENT_CATEGORY_RM) ? true : false,
- 'S_QUICKTIME_FILE' => ($display_cat == ATTACHMENT_CATEGORY_QUICKTIME) ? true : false,
- 'U_FORUM' => generate_board_url(),
- 'ATTACH_ID' => $attachment['attach_id'],
- );
-
- // Viewed/Heared File ... update the download count
- $update_count[] = $attachment['attach_id'];
+ $update_count_ary[] = $attachment['attach_id'];
break;
// Macromedia Flash Files
@@ -1264,7 +1293,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
);
// Viewed/Heared File ... update the download count
- $update_count[] = $attachment['attach_id'];
+ $update_count_ary[] = $attachment['attach_id'];
break;
default:
@@ -1287,6 +1316,7 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
);
}
+ $update_count = $update_count_ary;
/**
* Use this event to modify the attachment template data.
*
@@ -1314,6 +1344,8 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count,
'update_count',
);
extract($phpbb_dispatcher->trigger_event('core.parse_attachments_modify_template_data', compact($vars)));
+ $update_count_ary = $update_count;
+ unset($update_count);
$template->assign_block_vars('_file', $block_array);
@@ -1399,8 +1431,6 @@ function extension_allowed($forum_id, $extension, &$extensions)
*/
function truncate_string($string, $max_length = 60, $max_store_length = 255, $allow_reply = false, $append = '')
{
- $chars = array();
-
$strip_reply = false;
$stripped = false;
if ($allow_reply && strpos($string, 'Re: ') === 0)
@@ -1413,7 +1443,7 @@ function truncate_string($string, $max_length = 60, $max_store_length = 255, $al
$chars = array_map('utf8_htmlspecialchars', $_chars);
// Now check the length ;)
- if (sizeof($chars) > $max_length)
+ if (count($chars) > $max_length)
{
// Cut off the last elements from the array
$string = implode('', array_slice($chars, 0, $max_length - utf8_strlen($append)));
@@ -1452,6 +1482,8 @@ function truncate_string($string, $max_length = 60, $max_store_length = 255, $al
* Get username details for placing into templates.
* This function caches all modes on first call, except for no_profile and anonymous user - determined by $user_id.
*
+* @html Username spans and links
+*
* @param string $mode Can be profile (for getting an url to the profile), username (for obtaining the username), colour (for obtaining the user colour), full (for obtaining a html string representing a coloured link to the users profile) or no_profile (the same as full but forcing no profile link)
* @param int $user_id The users id
* @param string $username The users name
@@ -1471,6 +1503,7 @@ function get_username_string($mode, $user_id, $username, $username_colour = '',
{
global $phpbb_root_path, $phpEx;
+ /** @html Username spans and links for usage in the template */
$_profile_cache['base_url'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&amp;u={USER_ID}');
$_profile_cache['tpl_noprofile'] = '<span class="username">{USERNAME}</span>';
$_profile_cache['tpl_noprofile_colour'] = '<span style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</span>';
@@ -1621,7 +1654,7 @@ function phpbb_generate_string_list($items, $user)
return '';
}
- $count = sizeof($items);
+ $count = count($items);
$last_item = array_pop($items);
$lang_key = 'STRING_LIST_MULTI';
@@ -1642,7 +1675,7 @@ class bitfield
{
var $data;
- function bitfield($bitfield = '')
+ function __construct($bitfield = '')
{
$this->data = base64_decode($bitfield);
}
@@ -1728,3 +1761,48 @@ class bitfield
$this->data = $this->data | $bitfield->get_blob();
}
}
+
+/**
+ * Formats the quote according to the given BBCode status setting
+ *
+ * @param phpbb\language\language $language Language class
+ * @param parse_message $message_parser Message parser class
+ * @param phpbb\textformatter\utils_interface $text_formatter_utils Text formatter utilities
+ * @param bool $bbcode_status The status of the BBCode setting
+ * @param array $quote_attributes The attributes of the quoted post
+ * @param string $message_link Link of the original quoted post
+ */
+function phpbb_format_quote($language, $message_parser, $text_formatter_utils, $bbcode_status, $quote_attributes, $message_link = '')
+{
+ if ($bbcode_status)
+ {
+ $quote_text = $text_formatter_utils->generate_quote(
+ censor_text($message_parser->message),
+ $quote_attributes
+ );
+
+ $message_parser->message = $quote_text . "\n\n";
+ }
+ else
+ {
+ $offset = 0;
+ $quote_string = "&gt; ";
+ $message = censor_text(trim($message_parser->message));
+ // see if we are nesting. It's easily tricked but should work for one level of nesting
+ if (strpos($message, "&gt;") !== false)
+ {
+ $offset = 10;
+ }
+ $message = utf8_wordwrap($message, 75 + $offset, "\n");
+
+ $message = $quote_string . $message;
+ $message = str_replace("\n", "\n" . $quote_string, $message);
+
+ $message_parser->message = $quote_attributes['author'] . " " . $language->lang('WROTE') . ":\n" . $message . "\n";
+ }
+
+ if ($message_link)
+ {
+ $message_parser->message = $message_link . $message_parser->message;
+ }
+}
diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php
index da4820134d..2cfbe9541d 100644
--- a/phpBB/includes/functions_convert.php
+++ b/phpBB/includes/functions_convert.php
@@ -192,7 +192,7 @@ function get_group_id($group_name)
$db->sql_freeresult($result);
}
- if (!sizeof($group_mapping))
+ if (!count($group_mapping))
{
add_default_groups();
return get_group_id($group_name);
@@ -249,7 +249,7 @@ function validate_website($url)
{
return '';
}
- else if (!preg_match('#^[a-z0-9]+://#i', $url) && strlen($url) > 0)
+ else if (!preg_match('#^http[s]?://#i', $url) && strlen($url) > 0)
{
return 'http://' . $url;
}
@@ -307,7 +307,7 @@ function decode_ip($int_ip)
$hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
// Any mod changing the way ips are stored? Then we are not able to convert and enter the ip "as is" to not "destroy" anything...
- if (sizeof($hexipbang) < 4)
+ if (count($hexipbang) < 4)
{
return $int_ip;
}
@@ -423,7 +423,7 @@ function remote_avatar_dims()
function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false)
{
- global $config, $convert, $phpbb_root_path, $user;
+ global $config, $convert, $user;
$relative_path = empty($convert->convertor['source_path_absolute']);
@@ -479,7 +479,7 @@ function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false
$dir->close();
}
- for ($i = 0, $end = sizeof($dirlist); $i < $end; ++$i)
+ for ($i = 0, $end = count($dirlist); $i < $end; ++$i)
{
$dir = $dirlist[$i];
@@ -492,7 +492,7 @@ function import_avatar_gallery($gallery_name = '', $subdirs_as_galleries = false
function import_attachment_files($category_name = '')
{
- global $config, $convert, $phpbb_root_path, $db, $user;
+ global $config, $convert, $db, $user;
$sql = 'SELECT config_value AS upload_path
FROM ' . CONFIG_TABLE . "
@@ -590,7 +590,7 @@ function import_attachment($source, $use_target = false)
return '';
}
- global $convert, $phpbb_root_path, $config, $user;
+ global $convert, $config, $user;
// check for trailing slash
if (rtrim($convert->convertor['upload_path'], '/') === '')
@@ -632,7 +632,7 @@ function import_rank($source, $use_target = false)
return '';
}
- global $convert, $phpbb_root_path, $config, $user;
+ global $convert, $user;
if (!isset($convert->convertor['ranks_path']))
{
@@ -650,7 +650,7 @@ function import_smiley($source, $use_target = false)
return '';
}
- global $convert, $phpbb_root_path, $config, $user;
+ global $convert, $user;
// check for trailing slash
if (rtrim($convert->convertor['smilies_path'], '/') === '')
@@ -671,7 +671,7 @@ function import_avatar($source, $use_target = false, $user_id = false)
return;
}
- global $convert, $phpbb_root_path, $config, $user;
+ global $convert, $config, $user;
// check for trailing slash
if (rtrim($convert->convertor['avatar_path'], '/') === '')
@@ -684,7 +684,7 @@ function import_avatar($source, $use_target = false, $user_id = false)
$use_target = $config['avatar_salt'] . '_' . $user_id . '.' . substr(strrchr($source, '.'), 1);
}
- $result = _import_check('avatar_path', $source, $use_target);
+ _import_check('avatar_path', $source, $use_target);
return ((!empty($user_id)) ? $user_id : $use_target) . '.' . substr(strrchr($source, '.'), 1);
}
@@ -750,7 +750,7 @@ function get_smiley_dim($source, $axis)
return $smiley_cache[$source][$axis];
}
- global $convert, $phpbb_root_path, $config, $user;
+ global $convert, $user;
$orig_source = $source;
@@ -858,14 +858,12 @@ function get_upload_avatar_dim($source, $axis)
return $cachedims[$axis];
}
- $orig_source = $source;
-
if (substr($source, 0, 7) == 'upload:')
{
$source = substr($source, 7);
}
- global $convert, $phpbb_root_path, $config, $user;
+ global $convert, $user;
if (!isset($convert->convertor['avatar_path']))
{
@@ -907,7 +905,7 @@ function get_gallery_avatar_dim($source, $axis)
return $avatar_cache[$source][$axis];
}
- global $convert, $phpbb_root_path, $config, $user;
+ global $convert, $user;
$orig_source = $source;
@@ -1122,7 +1120,7 @@ function words_unique(&$words)
*/
function add_user_group($group_id, $user_id, $group_leader = false)
{
- global $convert, $phpbb_root_path, $config, $user, $db;
+ global $db;
$sql = 'INSERT INTO ' . USER_GROUP_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'group_id' => $group_id,
@@ -1142,7 +1140,7 @@ function add_user_group($group_id, $user_id, $group_leader = false)
*/
function user_group_auth($group, $select_query, $use_src_db)
{
- global $convert, $phpbb_root_path, $config, $user, $db, $src_db, $same_db;
+ global $convert, $user, $db, $src_db, $same_db;
if (!in_array($group, array('guests', 'registered', 'registered_coppa', 'global_moderators', 'administrators', 'bots')))
{
@@ -1198,7 +1196,7 @@ function get_config()
return $convert_config;
}
- global $src_db, $same_db, $phpbb_root_path, $config;
+ global $src_db, $same_db;
global $convert;
if ($convert->config_schema['table_format'] != 'file')
@@ -1263,7 +1261,7 @@ function get_config()
}
}
- if (!sizeof($convert_config))
+ if (!count($convert_config))
{
$convert->p_master->error($user->lang['CONV_ERROR_CONFIG_EMPTY'], __LINE__, __FILE__);
}
@@ -1277,7 +1275,7 @@ function get_config()
*/
function restore_config($schema)
{
- global $db, $config;
+ global $config;
$convert_config = get_config();
@@ -1312,7 +1310,7 @@ function restore_config($schema)
$config_value = truncate_string(utf8_htmlspecialchars($config_value), 255, 255, false);
}
- set_config($config_name, $config_value);
+ $config->set($config_name, $config_value);
}
}
}
@@ -1322,7 +1320,7 @@ function restore_config($schema)
*/
function update_folder_pm_count()
{
- global $db, $convert, $user;
+ global $db;
$sql = 'SELECT user_id, folder_id, COUNT(msg_id) as num_messages
FROM ' . PRIVMSGS_TO_TABLE . '
@@ -1381,7 +1379,7 @@ function extract_variables_from_file($_filename)
function get_path($src_path, $src_url, $test_file)
{
- global $config, $phpbb_root_path, $phpEx;
+ global $phpbb_root_path, $phpEx;
$board_config = get_config();
@@ -1408,9 +1406,9 @@ function get_path($src_path, $src_url, $test_file)
$url_parts = explode('/', $m[2]);
if (substr($src_url, -1) != '/')
{
- if (preg_match('/.*\.([a-z0-9]{3,4})$/i', $url_parts[sizeof($url_parts) - 1]))
+ if (preg_match('/.*\.([a-z0-9]{3,4})$/i', $url_parts[count($url_parts) - 1]))
{
- $url_parts[sizeof($url_parts) - 1] = '';
+ $url_parts[count($url_parts) - 1] = '';
}
else
{
@@ -1427,9 +1425,9 @@ function get_path($src_path, $src_url, $test_file)
$path_array = array();
$phpbb_parts = explode('/', $script_path);
- for ($i = 0, $end = sizeof($url_parts); $i < $end; ++$i)
+ for ($i = 0, $end = count($url_parts); $i < $end; ++$i)
{
- if ($i < sizeof($phpbb_parts[$i]) && $url_parts[$i] == $phpbb_parts[$i])
+ if ($i < count($phpbb_parts[$i]) && $url_parts[$i] == $phpbb_parts[$i])
{
$path_array[] = $url_parts[$i];
unset($url_parts[$i]);
@@ -1437,7 +1435,7 @@ function get_path($src_path, $src_url, $test_file)
else
{
$path = '';
- for ($j = $i, $end2 = sizeof($phpbb_parts); $j < $end2; ++$j)
+ for ($j = $i, $end2 = count($phpbb_parts); $j < $end2; ++$j)
{
$path .= '../';
}
@@ -1460,7 +1458,7 @@ function get_path($src_path, $src_url, $test_file)
function compare_table($tables, $tablename, &$prefixes)
{
- for ($i = 0, $table_size = sizeof($tables); $i < $table_size; ++$i)
+ for ($i = 0, $table_size = count($tables); $i < $table_size; ++$i)
{
if (preg_match('/(.*)' . $tables[$i] . '$/', $tablename, $m))
{
@@ -1492,7 +1490,7 @@ function compare_table($tables, $tablename, &$prefixes)
*/
function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO)
{
- global $db, $convert, $user, $config;
+ global $db;
static $acl_option_ids, $group_ids;
if (($ug_type == 'group' || $ug_type == 'group_role') && is_string($ug_id))
@@ -1654,8 +1652,6 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO)
$sql = 'VALUES ' . implode(', ', preg_replace('#^(.*?)$#', '(\1)', $sql_subary));
break;
- case 'mssql':
- case 'sqlite':
case 'sqlite3':
case 'mssqlnative':
$sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary));
@@ -1758,7 +1754,7 @@ function add_default_groups()
);
}
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(GROUPS_TABLE, $sql_ary);
}
@@ -1790,7 +1786,7 @@ function add_groups_to_teampage()
}
$db->sql_freeresult($result);
- if (sizeof($teampage_ary))
+ if (count($teampage_ary))
{
$db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_ary);
}
@@ -1968,9 +1964,9 @@ function update_dynamic_config()
if ($row)
{
- set_config('newest_user_id', $row['user_id'], true);
- set_config('newest_username', $row['username'], true);
- set_config('newest_user_colour', $row['user_colour'], true);
+ $config->set('newest_user_id', $row['user_id'], false);
+ $config->set('newest_username', $row['username'], false);
+ $config->set('newest_user_colour', $row['user_colour'], false);
}
// Also do not reset record online user/date. There will be old data or the fresh data from the schema.
@@ -1984,7 +1980,7 @@ function update_dynamic_config()
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('num_posts', (int) $row['stat'], true);
+ $config->set('num_posts', (int) $row['stat'], false);
$sql = 'SELECT COUNT(topic_id) AS stat
FROM ' . TOPICS_TABLE . '
@@ -1993,7 +1989,7 @@ function update_dynamic_config()
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('num_topics', (int) $row['stat'], true);
+ $config->set('num_topics', (int) $row['stat'], false);
$sql = 'SELECT COUNT(user_id) AS stat
FROM ' . USERS_TABLE . '
@@ -2002,20 +1998,20 @@ function update_dynamic_config()
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('num_users', (int) $row['stat'], true);
+ $config->set('num_users', (int) $row['stat'], false);
$sql = 'SELECT COUNT(attach_id) as stat
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 0';
$result = $db->sql_query($sql);
- set_config('num_files', (int) $db->sql_fetchfield('stat'), true);
+ $config->set('num_files', (int) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
$sql = 'SELECT SUM(filesize) as stat
FROM ' . ATTACHMENTS_TABLE . '
WHERE is_orphan = 0';
$result = $db->sql_query($sql);
- set_config('upload_dir_size', (float) $db->sql_fetchfield('stat'), true);
+ $config->set('upload_dir_size', (float) $db->sql_fetchfield('stat'), false);
$db->sql_freeresult($result);
/**
@@ -2039,11 +2035,10 @@ function update_dynamic_config()
*/
function update_topics_posted()
{
- global $db, $config;
+ global $db;
switch ($db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
$db->sql_query('DELETE FROM ' . TOPICS_POSTED_TABLE);
break;
@@ -2106,7 +2101,7 @@ function update_topics_posted()
}
unset($posted);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary);
}
@@ -2141,7 +2136,7 @@ function fix_empty_primary_groups()
}
$db->sql_freeresult($result);
- if (sizeof($user_ids))
+ if (count($user_ids))
{
$db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('administrators') . '
WHERE group_id = 0 AND ' . $db->sql_in_set('user_id', $user_ids));
@@ -2157,7 +2152,7 @@ function fix_empty_primary_groups()
}
$db->sql_freeresult($result);
- if (sizeof($user_ids))
+ if (count($user_ids))
{
$db->sql_query('UPDATE ' . USERS_TABLE . ' SET group_id = ' . get_group_id('global_moderators') . '
WHERE group_id = 0 AND ' . $db->sql_in_set('user_id', $user_ids));
@@ -2180,7 +2175,7 @@ function fix_empty_primary_groups()
*/
function remove_invalid_users()
{
- global $convert, $db, $phpEx, $phpbb_root_path;
+ global $db, $phpEx, $phpbb_root_path;
// username_clean is UNIQUE
$sql = 'SELECT user_id
@@ -2269,7 +2264,7 @@ function convert_bbcode($message, $convert_size = true, $extended_bbcodes = fals
"\n\n"
);
- for ($i = 0, $end = sizeof($str_from); $i < $end; ++$i)
+ for ($i = 0, $end = count($str_from); $i < $end; ++$i)
{
$origx[] = '#\\' . str_replace(']', '\\]', $str_from[$i]) . '#is';
$replx[] = $str_to[$i];
@@ -2278,7 +2273,7 @@ function convert_bbcode($message, $convert_size = true, $extended_bbcodes = fals
if (preg_match_all('#\[email=([^\]]+)\](.*?)\[/email\]#i', $message, $m))
{
- for ($i = 0, $end = sizeof($m[1]); $i < $end; ++$i)
+ for ($i = 0, $end = count($m[1]); $i < $end; ++$i)
{
if ($m[1][$i] == $m[2][$i])
{
@@ -2297,7 +2292,7 @@ function convert_bbcode($message, $convert_size = true, $extended_bbcodes = fals
$message = preg_replace('#\[size=([0-9]+)\](.*?)\[/size\]#i', '[size=\1]\2[/size]', $message);
$message = preg_replace('#\[size=[0-9]{2,}\](.*?)\[/size\]#i', '[size=29]\1[/size]', $message);
- for ($i = sizeof($size); $i;)
+ for ($i = count($size); $i;)
{
$i--;
$message = str_replace('[size=' . $i . ']', '[size=' . $size[$i] . ']', $message);
@@ -2316,7 +2311,10 @@ function convert_bbcode($message, $convert_size = true, $extended_bbcodes = fals
function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
{
- global $convert, $phpbb_root_path, $config, $user, $db;
+ global $convert, $phpbb_root_path, $user, $phpbb_filesystem;
+
+ /** @var \phpbb\filesystem\filesystem_interface $filesystem */
+ $filesystem = $phpbb_filesystem;
if (substr($trg, -1) == '/')
{
@@ -2337,9 +2335,9 @@ function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $sour
$path = $phpbb_root_path;
$parts = explode('/', $trg);
- unset($parts[sizeof($parts) - 1]);
+ unset($parts[count($parts) - 1]);
- for ($i = 0, $end = sizeof($parts); $i < $end; ++$i)
+ for ($i = 0, $end = count($parts); $i < $end; ++$i)
{
$path .= $parts[$i] . '/';
@@ -2349,7 +2347,7 @@ function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $sour
}
}
- if (!phpbb_is_writable($path))
+ if (!$filesystem->is_writable($path))
{
@chmod($path, 0777);
}
@@ -2370,7 +2368,10 @@ function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $sour
function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_failure = true, $source_relative_path = true)
{
- global $convert, $phpbb_root_path, $config, $user, $db;
+ global $convert, $phpbb_root_path, $config, $user, $phpbb_filesystem;
+
+ /** @var \phpbb\filesystem\filesystem_interface $filesystem */
+ $filesystem = $phpbb_filesystem;
$dirlist = $filelist = $bad_dirs = array();
$src = path($src, $source_relative_path);
@@ -2384,7 +2385,7 @@ function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_
@chmod($trg_path, 0777);
}
- if (!phpbb_is_writable($trg_path))
+ if (!$filesystem->is_writable($trg_path))
{
$bad_dirs[] = path($config['script_path']) . $trg;
}
@@ -2436,7 +2437,7 @@ function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_
if ($copy_subdirs)
{
- for ($i = 0, $end = sizeof($dirlist); $i < $end; ++$i)
+ for ($i = 0, $end = count($dirlist); $i < $end; ++$i)
{
$dir = $dirlist[$i];
@@ -2451,27 +2452,27 @@ function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_
@chmod($trg_path . $dir, 0777);
}
- if (!phpbb_is_writable($trg_path . $dir))
+ if (!$filesystem->is_writable($trg_path . $dir))
{
$bad_dirs[] = $trg . $dir;
$bad_dirs[] = $trg_path . $dir;
}
- if (!sizeof($bad_dirs))
+ if (!count($bad_dirs))
{
copy_dir($src . $dir, $trg . $dir, true, $overwrite, $die_on_failure, $source_relative_path);
}
}
}
- if (sizeof($bad_dirs))
+ if (count($bad_dirs))
{
- $str = (sizeof($bad_dirs) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
+ $str = (count($bad_dirs) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
sort($bad_dirs);
$convert->p_master->error(sprintf($str, implode('<br />', $bad_dirs)), __LINE__, __FILE__);
}
- for ($i = 0, $end = sizeof($filelist); $i < $end; ++$i)
+ for ($i = 0, $end = count($filelist); $i < $end; ++$i)
{
copy_file($src . $filelist[$i], $trg . $filelist[$i], $overwrite, $die_on_failure, $source_relative_path);
}
@@ -2479,7 +2480,7 @@ function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_
function relative_base($path, $is_relative = true, $line = false, $file = false)
{
- global $convert, $phpbb_root_path, $config, $user, $db;
+ global $convert, $user;
if (!$is_relative)
{
diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php
index 3b2d66c2d3..e4adce14fc 100644
--- a/phpBB/includes/functions_display.php
+++ b/phpBB/includes/functions_display.php
@@ -30,10 +30,9 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$forum_rows = $subforums = $forum_ids = $forum_ids_moderator = $forum_moderators = $active_forum_ary = array();
$parent_id = $visible_forums = 0;
- $sql_from = '';
// Mark forums read?
- $mark_read = request_var('mark', '');
+ $mark_read = $request->variable('mark', '');
if ($mark_read == 'all')
{
@@ -61,9 +60,9 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$redirect = build_url(array('mark', 'hash', 'mark_time'));
meta_refresh(3, $redirect);
- if (check_link_hash(request_var('hash', ''), 'global'))
+ if (check_link_hash($request->variable('hash', ''), 'global'))
{
- markread('all', false, false, request_var('mark_time', 0));
+ markread('all', false, false, $request->variable('mark_time', 0));
if ($request->is_ajax())
{
@@ -71,7 +70,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$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()) : '',
+ '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(), false) : '',
'MESSAGE_TITLE' => $user->lang['INFORMATION'],
'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED']
);
@@ -153,6 +152,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$forum_tracking_info = $valid_categories = array();
$branch_root_id = $root_data['forum_id'];
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
while ($row = $db->sql_fetchrow($result))
@@ -282,6 +282,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$subforums[$parent_id][$forum_id]['name'] = $row['forum_name'];
$subforums[$parent_id][$forum_id]['orig_forum_last_post_time'] = $row['forum_last_post_time'];
$subforums[$parent_id][$forum_id]['children'] = array();
+ $subforums[$parent_id][$forum_id]['type'] = $row['forum_type'];
if (isset($subforums[$parent_id][$row['parent_id']]) && !$row['display_on_index'])
{
@@ -341,10 +342,10 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
if ($mark_read == 'forums')
{
$redirect = build_url(array('mark', 'hash', 'mark_time'));
- $token = request_var('hash', '');
+ $token = $request->variable('hash', '');
if (check_link_hash($token, 'global'))
{
- markread('topics', $forum_ids, false, request_var('mark_time', 0));
+ markread('topics', $forum_ids, false, $request->variable('mark_time', 0));
$message = sprintf($user->lang['RETURN_FORUM'], '<a href="' . $redirect . '">', '</a>');
meta_refresh(3, $redirect);
@@ -354,7 +355,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$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()) : '',
+ '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(), false) : '',
'MESSAGE_TITLE' => $user->lang['INFORMATION'],
'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED']
);
@@ -437,15 +438,14 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
*
* @event core.display_forums_modify_category_template_vars
* @var array cat_row Template data of the 'category'
- * @var bool catless The flag indicating whether the 'category' has a parent category
* @var bool last_catless The flag indicating whether the last forum had a parent category
* @var array root_data Array with the root forum data
* @var array row The data of the 'category'
* @since 3.1.0-RC4
+ * @changed 3.1.7-RC1 Removed undefined catless variable
*/
$vars = array(
'cat_row',
- 'catless',
'last_catless',
'root_data',
'row',
@@ -491,6 +491,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
'link' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $subforum_id),
'name' => $subforum_row['name'],
'unread' => $subforum_unread,
+ 'type' => $subforum_row['type'],
);
}
else
@@ -505,7 +506,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
}
}
- $l_subforums = (sizeof($subforums[$forum_id]) == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS'];
+ $l_subforums = (count($subforums[$forum_id]) == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS'];
$folder_image = ($forum_unread) ? 'forum_unread_subforum' : 'forum_read_subforum';
}
else
@@ -536,9 +537,10 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
// Create last post link information, if appropriate
if ($row['forum_last_post_id'])
{
- if ($row['forum_password_last_post'] === '' && $auth->acl_get('f_read', $row['forum_id_last_post']))
+ if ($row['forum_password_last_post'] === '' && $auth->acl_gets('f_read', 'f_list_topics', $row['forum_id_last_post']))
{
- $last_post_subject = censor_text($row['forum_last_post_subject']);
+ $last_post_subject = utf8_decode_ncr(censor_text($row['forum_last_post_subject']));
+
$last_post_subject_truncated = truncate_string($last_post_subject, 30, 255, false, $user->lang['ELLIPSIS']);
}
else
@@ -546,18 +548,19 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$last_post_subject = $last_post_subject_truncated = '';
}
$last_post_time = $user->format_date($row['forum_last_post_time']);
+ $last_post_time_rfc3339 = gmdate(DATE_RFC3339, $row['forum_last_post_time']);
$last_post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id_last_post'] . '&amp;p=' . $row['forum_last_post_id']) . '#p' . $row['forum_last_post_id'];
}
else
{
- $last_post_subject = $last_post_time = $last_post_url = $last_post_subject_truncated = '';
+ $last_post_subject = $last_post_time = $last_post_time_rfc3339 = $last_post_url = $last_post_subject_truncated = '';
}
// Output moderator listing ... if applicable
$l_moderator = $moderators_list = '';
if ($display_moderators && !empty($forum_moderators[$forum_id]))
{
- $l_moderator = (sizeof($forum_moderators[$forum_id]) == 1) ? $user->lang['MODERATOR'] : $user->lang['MODERATORS'];
+ $l_moderator = (count($forum_moderators[$forum_id]) == 1) ? $user->lang['MODERATOR'] : $user->lang['MODERATORS'];
$moderators_list = implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]);
}
@@ -572,6 +575,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
'U_SUBFORUM' => $subforum['link'],
'SUBFORUM_NAME' => $subforum['name'],
'S_UNREAD' => $subforum['unread'],
+ 'IS_LINK' => $subforum['type'] == FORUM_LINK,
);
}
$s_subforums_list = (string) implode($user->lang['COMMA_SEPARATOR'], $s_subforums_list);
@@ -603,7 +607,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
'S_AUTH_READ' => $auth->acl_get('f_read', $row['forum_id']),
'S_LOCKED_FORUM' => ($row['forum_status'] == ITEM_LOCKED) ? true : false,
'S_LIST_SUBFORUMS' => ($row['display_subforum_list']) ? true : false,
- 'S_SUBFORUMS' => (sizeof($subforums_list)) ? true : false,
+ 'S_SUBFORUMS' => (count($subforums_list)) ? true : false,
'S_DISPLAY_SUBJECT' => ($last_post_subject !== '' && $config['display_last_subject']) ? true : false,
'S_FEED_ENABLED' => ($config['feed_forum'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $row['forum_options']) && $row['forum_type'] == FORUM_POST) ? true : false,
@@ -620,6 +624,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
'LAST_POST_SUBJECT' => $last_post_subject,
'LAST_POST_SUBJECT_TRUNCATED' => $last_post_subject_truncated,
'LAST_POST_TIME' => $last_post_time,
+ 'LAST_POST_TIME_RFC3339'=> $last_post_time_rfc3339,
'LAST_POSTER' => get_username_string('username', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']),
'LAST_POSTER_COLOUR' => get_username_string('colour', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']),
'LAST_POSTER_FULL' => get_username_string('full', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']),
@@ -727,18 +732,18 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
*/
function generate_forum_rules(&$forum_data)
{
- if (!$forum_data['forum_rules'] && !$forum_data['forum_rules_link'])
+ if ($forum_data['forum_rules'])
{
- return;
+ $forum_data['forum_rules'] = generate_text_for_display($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options']);
}
- global $template, $phpbb_root_path, $phpEx;
-
- if ($forum_data['forum_rules'])
+ if (!$forum_data['forum_rules'] && !$forum_data['forum_rules_link'])
{
- $forum_data['forum_rules'] = generate_text_for_display($forum_data['forum_rules'], $forum_data['forum_rules_uid'], $forum_data['forum_rules_bitfield'], $forum_data['forum_rules_options']);
+ return;
}
+ global $template;
+
$template->assign_vars(array(
'S_FORUM_RULES' => true,
'U_FORUM_RULES' => $forum_data['forum_rules_link'],
@@ -750,20 +755,20 @@ function generate_forum_rules(&$forum_data)
* Create forum navigation links for given forum, create parent
* list if currently null, assign basic forum info to template
*/
-function generate_forum_nav(&$forum_data)
+function generate_forum_nav(&$forum_data_ary)
{
- global $db, $user, $template, $auth, $config;
+ global $template, $auth, $config;
global $phpEx, $phpbb_root_path, $phpbb_dispatcher;
- if (!$auth->acl_get('f_list', $forum_data['forum_id']))
+ if (!$auth->acl_get('f_list', $forum_data_ary['forum_id']))
{
return;
}
- $navlinks = $navlinks_parents = $forum_template_data = array();
+ $navlinks_parents = $forum_template_data = array();
// Get forum parents
- $forum_parents = get_forum_parents($forum_data);
+ $forum_parents = get_forum_parents($forum_data_ary);
$microdata_attr = 'data-forum-id';
@@ -793,23 +798,24 @@ function generate_forum_nav(&$forum_data)
}
$navlinks = array(
- 'S_IS_CAT' => ($forum_data['forum_type'] == FORUM_CAT) ? true : false,
- 'S_IS_LINK' => ($forum_data['forum_type'] == FORUM_LINK) ? true : false,
- 'S_IS_POST' => ($forum_data['forum_type'] == FORUM_POST) ? true : false,
- 'FORUM_NAME' => $forum_data['forum_name'],
- 'FORUM_ID' => $forum_data['forum_id'],
- 'MICRODATA' => $microdata_attr . '="' . $forum_data['forum_id'] . '"',
- 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_data['forum_id']),
+ 'S_IS_CAT' => ($forum_data_ary['forum_type'] == FORUM_CAT) ? true : false,
+ 'S_IS_LINK' => ($forum_data_ary['forum_type'] == FORUM_LINK) ? true : false,
+ 'S_IS_POST' => ($forum_data_ary['forum_type'] == FORUM_POST) ? true : false,
+ 'FORUM_NAME' => $forum_data_ary['forum_name'],
+ 'FORUM_ID' => $forum_data_ary['forum_id'],
+ 'MICRODATA' => $microdata_attr . '="' . $forum_data_ary['forum_id'] . '"',
+ 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_data_ary['forum_id']),
);
$forum_template_data = array(
- 'FORUM_ID' => $forum_data['forum_id'],
- 'FORUM_NAME' => $forum_data['forum_name'],
- 'FORUM_DESC' => generate_text_for_display($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options']),
+ 'FORUM_ID' => $forum_data_ary['forum_id'],
+ 'FORUM_NAME' => $forum_data_ary['forum_name'],
+ 'FORUM_DESC' => generate_text_for_display($forum_data_ary['forum_desc'], $forum_data_ary['forum_desc_uid'], $forum_data_ary['forum_desc_bitfield'], $forum_data_ary['forum_desc_options']),
- 'S_ENABLE_FEEDS_FORUM' => ($config['feed_forum'] && $forum_data['forum_type'] == FORUM_POST && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $forum_data['forum_options'])) ? true : false,
+ 'S_ENABLE_FEEDS_FORUM' => ($config['feed_forum'] && $forum_data_ary['forum_type'] == FORUM_POST && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $forum_data_ary['forum_options'])) ? true : false,
);
+ $forum_data = $forum_data_ary;
/**
* Event to modify the navlinks text
*
@@ -829,6 +835,8 @@ function generate_forum_nav(&$forum_data)
'navlinks',
);
extract($phpbb_dispatcher->trigger_event('core.generate_forum_nav', compact($vars)));
+ $forum_data_ary = $forum_data;
+ unset($forum_data);
$template->assign_block_vars_array('navlinks', $navlinks_parents);
$template->assign_block_vars('navlinks', $navlinks);
@@ -884,7 +892,8 @@ function get_forum_parents(&$forum_data)
*/
function get_moderators(&$forum_moderators, $forum_id = false)
{
- global $config, $template, $db, $phpbb_root_path, $phpEx, $user, $auth;
+ global $db, $phpbb_root_path, $phpEx, $user, $auth;
+ global $phpbb_container;
$forum_id_ary = array();
@@ -920,6 +929,9 @@ function get_moderators(&$forum_moderators, $forum_id = false)
'WHERE' => 'm.display_on_index = 1',
);
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
// We query every forum here because for caching we should not have any parameter.
$sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql, 3600);
@@ -939,7 +951,7 @@ function get_moderators(&$forum_moderators, $forum_id = false)
}
else
{
- $group_name = (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']);
+ $group_name = $group_helper->get_name($row['group_name']);
if ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile'))
{
@@ -996,8 +1008,6 @@ function topic_status(&$topic_row, $replies, $unread_topic, &$folder_img, &$fold
{
global $user, $config;
- $folder = $folder_new = '';
-
if ($topic_row['topic_status'] == ITEM_MOVED)
{
$topic_type = $user->lang['VIEW_TOPIC_MOVED'];
@@ -1072,7 +1082,7 @@ function display_custom_bbcodes()
global $db, $template, $user, $phpbb_dispatcher;
// Start counting from 22 for the bbcode ids (every bbcode takes two ids - opening/closing)
- $num_predefined_bbcodes = 22;
+ $num_predefined_bbcodes = NUM_PREDEFINED_BBCODES;
$sql_ary = array(
'SELECT' => 'b.bbcode_id, b.bbcode_tag, b.bbcode_helpline',
@@ -1110,7 +1120,6 @@ function display_custom_bbcodes()
'BBCODE_TAG' => $row['bbcode_tag'],
'BBCODE_TAG_CLEAN' => str_replace('=', '-', $row['bbcode_tag']),
'BBCODE_HELPLINE' => $row['bbcode_helpline'],
- 'A_BBCODE_HELPLINE' => str_replace(array('&amp;', '&quot;', "'", '&lt;', '&gt;'), array('&', '"', "\'", '<', '>'), $row['bbcode_helpline']),
);
/**
@@ -1143,46 +1152,28 @@ function display_custom_bbcodes()
/**
* Display reasons
+*
+* @deprecated 3.2.0-dev
*/
function display_reasons($reason_id = 0)
{
- global $db, $user, $template;
-
- $sql = 'SELECT *
- FROM ' . REPORTS_REASONS_TABLE . '
- ORDER BY reason_order ASC';
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- // If the reason is defined within the language file, we will use the localized version, else just use the database entry...
- if (isset($user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])]) && isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])]))
- {
- $row['reason_description'] = $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])];
- $row['reason_title'] = $user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])];
- }
+ global $phpbb_container;
- $template->assign_block_vars('reason', array(
- 'ID' => $row['reason_id'],
- 'TITLE' => $row['reason_title'],
- 'DESCRIPTION' => $row['reason_description'],
- 'S_SELECTED' => ($row['reason_id'] == $reason_id) ? true : false)
- );
- }
- $db->sql_freeresult($result);
+ $phpbb_container->get('phpbb.report.report_reason_list_provider')->display_reasons($reason_id);
}
/**
* Display user activity (action forum/topic)
*/
-function display_user_activity(&$userdata)
+function display_user_activity(&$userdata_ary)
{
- global $auth, $template, $db, $user;
+ global $auth, $template, $db, $user, $config;
global $phpbb_root_path, $phpEx;
global $phpbb_container, $phpbb_dispatcher;
- // Do not display user activity for users having more than 5000 posts...
- if ($userdata['user_posts'] > 5000)
+ // Do not display user activity for users having too many posts...
+ $limit = $config['load_user_activity_limit'];
+ if ($userdata_ary['user_posts'] > $limit && $limit != 0)
{
return;
}
@@ -1203,12 +1194,13 @@ function display_user_activity(&$userdata)
$active_f_row = $active_t_row = array();
if (!empty($forum_ary))
{
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
// Obtain active forum
$sql = 'SELECT forum_id, COUNT(post_id) AS num_posts
FROM ' . POSTS_TABLE . '
- WHERE poster_id = ' . $userdata['user_id'] . '
+ WHERE poster_id = ' . $userdata_ary['user_id'] . '
AND post_postcount = 1
AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . '
GROUP BY forum_id
@@ -1230,7 +1222,7 @@ function display_user_activity(&$userdata)
// Obtain active topic
$sql = 'SELECT topic_id, COUNT(post_id) AS num_posts
FROM ' . POSTS_TABLE . '
- WHERE poster_id = ' . $userdata['user_id'] . '
+ WHERE poster_id = ' . $userdata_ary['user_id'] . '
AND post_postcount = 1
AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . '
GROUP BY topic_id
@@ -1250,6 +1242,8 @@ function display_user_activity(&$userdata)
}
}
+ $userdata = $userdata_ary;
+ $show_user_activity = true;
/**
* Alter list of forums and topics to display as active
*
@@ -1257,13 +1251,17 @@ function display_user_activity(&$userdata)
* @var array userdata User's data
* @var array active_f_row List of active forums
* @var array active_t_row List of active posts
+ * @var bool show_user_activity Show user forum and topic activity
* @since 3.1.0-RC3
+ * @changed 3.2.5-RC1 Added show_user_activity into event
*/
- $vars = array('userdata', 'active_f_row', 'active_t_row');
+ $vars = array('userdata', 'active_f_row', 'active_t_row', 'show_user_activity');
extract($phpbb_dispatcher->trigger_event('core.display_user_activity_modify_actives', compact($vars)));
+ $userdata_ary = $userdata;
+ unset($userdata);
- $userdata['active_t_row'] = $active_t_row;
- $userdata['active_f_row'] = $active_f_row;
+ $userdata_ary['active_t_row'] = $active_t_row;
+ $userdata_ary['active_f_row'] = $active_f_row;
$active_f_name = $active_f_id = $active_f_count = $active_f_pct = '';
if (!empty($active_f_row['num_posts']))
@@ -1271,7 +1269,7 @@ function display_user_activity(&$userdata)
$active_f_name = $active_f_row['forum_name'];
$active_f_id = $active_f_row['forum_id'];
$active_f_count = $active_f_row['num_posts'];
- $active_f_pct = ($userdata['user_posts']) ? ($active_f_count / $userdata['user_posts']) * 100 : 0;
+ $active_f_pct = ($userdata_ary['user_posts']) ? ($active_f_count / $userdata_ary['user_posts']) * 100 : 0;
}
$active_t_name = $active_t_id = $active_t_count = $active_t_pct = '';
@@ -1280,10 +1278,10 @@ function display_user_activity(&$userdata)
$active_t_name = $active_t_row['topic_title'];
$active_t_id = $active_t_row['topic_id'];
$active_t_count = $active_t_row['num_posts'];
- $active_t_pct = ($userdata['user_posts']) ? ($active_t_count / $userdata['user_posts']) * 100 : 0;
+ $active_t_pct = ($userdata_ary['user_posts']) ? ($active_t_count / $userdata_ary['user_posts']) * 100 : 0;
}
- $l_active_pct = ($userdata['user_id'] != ANONYMOUS && $userdata['user_id'] == $user->data['user_id']) ? $user->lang['POST_PCT_ACTIVE_OWN'] : $user->lang['POST_PCT_ACTIVE'];
+ $l_active_pct = ($userdata_ary['user_id'] != ANONYMOUS && $userdata_ary['user_id'] == $user->data['user_id']) ? $user->lang['POST_PCT_ACTIVE_OWN'] : $user->lang['POST_PCT_ACTIVE'];
$template->assign_vars(array(
'ACTIVE_FORUM' => $active_f_name,
@@ -1294,7 +1292,7 @@ function display_user_activity(&$userdata)
'ACTIVE_TOPIC_PCT' => sprintf($l_active_pct, $active_t_pct),
'U_ACTIVE_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $active_f_id),
'U_ACTIVE_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $active_t_id),
- 'S_SHOW_ACTIVITY' => true)
+ 'S_SHOW_ACTIVITY' => $show_user_activity)
);
}
@@ -1303,7 +1301,7 @@ function display_user_activity(&$userdata)
*/
function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id, $notify_status = 'unset', $start = 0, $item_title = '')
{
- global $template, $db, $user, $phpEx, $start, $phpbb_root_path;
+ global $db, $user, $phpEx, $start, $phpbb_root_path;
global $request;
$table_sql = ($mode == 'forum') ? FORUMS_WATCH_TABLE : TOPICS_WATCH_TABLE;
@@ -1334,8 +1332,8 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id,
{
if (isset($_GET['unwatch']))
{
- $uid = request_var('uid', 0);
- $token = request_var('hash', '');
+ $uid = $request->variable('uid', 0);
+ $token = $request->variable('hash', '');
if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true))
{
@@ -1408,8 +1406,8 @@ function watch_topic_forum($mode, &$s_watching, $user_id, $forum_id, $topic_id,
{
if (isset($_GET['watch']))
{
- $uid = request_var('uid', 0);
- $token = request_var('hash', '');
+ $uid = $request->variable('uid', 0);
+ $token = $request->variable('hash', '');
if ($token && check_link_hash($token, "{$mode}_$match_id") || confirm_box(true))
{
@@ -1653,10 +1651,10 @@ function phpbb_show_profile($data, $user_notes_enabled = false, $warn_user_enabl
($data['user_type'] != USER_INACTIVE || $data['user_inactive_reason'] != INACTIVE_MANUAL) &&
// They must be able to read PMs
- sizeof($auth->acl_get_list($user_id, 'u_readpm')) &&
+ count($auth->acl_get_list($user_id, 'u_readpm')) &&
// They must not be permanently banned
- !sizeof(phpbb_get_banned_user_ids($user_id, false)) &&
+ !count(phpbb_get_banned_user_ids($user_id, false)) &&
// They must allow users to contact via PM
(($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $data['user_allow_pm'])
diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php
index 053e362682..1f409be58c 100644
--- a/phpBB/includes/functions_download.php
+++ b/phpBB/includes/functions_download.php
@@ -124,7 +124,7 @@ function wrap_img_in_html($src, $title)
*/
function send_file_to_browser($attachment, $upload_dir, $category)
{
- global $user, $db, $config, $phpbb_dispatcher, $phpbb_root_path;
+ global $user, $db, $phpbb_dispatcher, $phpbb_root_path, $request;
$filename = $phpbb_root_path . $upload_dir . '/' . $attachment['physical_filename'];
@@ -196,7 +196,7 @@ function send_file_to_browser($attachment, $upload_dir, $category)
}
// Now the tricky part... let's dance
- header('Cache-Control: public');
+ header('Cache-Control: private');
// Send out the Headers. Do not set Content-Disposition to inline please, it is a security measure for users using the Internet Explorer.
header('Content-Type: ' . $attachment['mimetype']);
@@ -206,7 +206,7 @@ function send_file_to_browser($attachment, $upload_dir, $category)
header('X-Content-Type-Options: nosniff');
}
- if ($category == ATTACHMENT_CATEGORY_FLASH && request_var('view', 0) === 1)
+ if ($category == ATTACHMENT_CATEGORY_FLASH && $request->variable('view', 0) === 1)
{
// We use content-disposition: inline for flash files and view=1 to let it correctly play with flash player 10 - any other disposition will fail to play inline
header('Content-Disposition: inline');
@@ -274,11 +274,21 @@ function send_file_to_browser($attachment, $upload_dir, $category)
send_status_line(206, 'Partial Content');
header('Content-Range: bytes ' . $range['byte_pos_start'] . '-' . $range['byte_pos_end'] . '/' . $range['bytes_total']);
header('Content-Length: ' . $range['bytes_requested']);
- }
- while (!feof($fp))
+ // First read chunks
+ while (!feof($fp) && ftell($fp) < $range['byte_pos_end'] - 8192)
+ {
+ echo fread($fp, 8192);
+ }
+ // Then, read the remainder
+ echo fread($fp, $range['bytes_requested'] % 8192);
+ }
+ else
{
- echo fread($fp, 8192);
+ while (!feof($fp))
+ {
+ echo fread($fp, 8192);
+ }
}
fclose($fp);
}
@@ -441,7 +451,7 @@ function set_modified_headers($stamp, $browser)
{
send_status_line(304, 'Not Modified');
// seems that we need those too ... browsers
- header('Cache-Control: public');
+ header('Cache-Control: private');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
return true;
}
@@ -549,73 +559,75 @@ function phpbb_find_range_request()
*/
function phpbb_parse_range_request($request_array, $filesize)
{
+ $first_byte_pos = -1;
+ $last_byte_pos = -1;
+
// Go through all ranges
foreach ($request_array as $range_string)
{
$range = explode('-', trim($range_string));
// "-" is invalid, "0-0" however is valid and means the very first byte.
- if (sizeof($range) != 2 || $range[0] === '' && $range[1] === '')
+ if (count($range) != 2 || $range[0] === '' && $range[1] === '')
{
continue;
}
+ // Substitute defaults
if ($range[0] === '')
{
- // Return last $range[1] bytes.
-
- if (!$range[1])
- {
- continue;
- }
+ $range[0] = 0;
+ }
- if ($range[1] >= $filesize)
- {
- return false;
- }
+ if ($range[1] === '')
+ {
+ $range[1] = $filesize - 1;
+ }
- $first_byte_pos = $filesize - (int) $range[1];
- $last_byte_pos = $filesize - 1;
+ if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0])
+ {
+ // We only support contiguous ranges, no multipart stuff :(
+ return false;
}
- else
+
+ if ($range[1] && $range[1] < $range[0])
{
- // Return bytes from $range[0] to $range[1]
+ // The requested range contains 0 bytes.
+ continue;
+ }
+ // Return bytes from $range[0] to $range[1]
+ if ($first_byte_pos < 0)
+ {
$first_byte_pos = (int) $range[0];
- $last_byte_pos = (int) $range[1];
-
- if ($last_byte_pos && $last_byte_pos < $first_byte_pos)
- {
- // The requested range contains 0 bytes.
- continue;
- }
+ }
- if ($first_byte_pos >= $filesize)
- {
- // Requested range not satisfiable
- return false;
- }
+ $last_byte_pos = (int) $range[1];
- // Adjust last-byte-pos if it is absent or greater than the content.
- if ($range[1] === '' || $last_byte_pos >= $filesize)
- {
- $last_byte_pos = $filesize - 1;
- }
+ if ($first_byte_pos >= $filesize)
+ {
+ // Requested range not satisfiable
+ return false;
}
- // We currently do not support range requests that end before the end of the file
- if ($last_byte_pos != $filesize - 1)
+ // Adjust last-byte-pos if it is absent or greater than the content.
+ if ($range[1] === '' || $last_byte_pos >= $filesize)
{
- continue;
+ $last_byte_pos = $filesize - 1;
}
+ }
- return array(
- 'byte_pos_start' => $first_byte_pos,
- 'byte_pos_end' => $last_byte_pos,
- 'bytes_requested' => $last_byte_pos - $first_byte_pos + 1,
- 'bytes_total' => $filesize,
- );
+ if ($first_byte_pos < 0 || $last_byte_pos < 0)
+ {
+ return false;
}
+
+ return array(
+ 'byte_pos_start' => $first_byte_pos,
+ 'byte_pos_end' => $last_byte_pos,
+ 'bytes_requested' => $last_byte_pos - $first_byte_pos + 1,
+ 'bytes_total' => $filesize,
+ );
}
/**
@@ -650,6 +662,8 @@ function phpbb_increment_downloads($db, $ids)
*/
function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
{
+ global $phpbb_container;
+
$sql_array = array(
'SELECT' => 't.topic_visibility, t.forum_id, f.forum_name, f.forum_password, f.parent_id',
'FROM' => array(
@@ -665,7 +679,9 @@ function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- if ($row && $row['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $row['forum_id']))
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
+ if ($row && !$phpbb_content_visibility->is_visible('topic', $row['forum_id'], $row))
{
send_status_line(404, 'Not Found');
trigger_error('ERROR_NO_ATTACHMENT');
diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php
deleted file mode 100644
index 28cc603bdb..0000000000
--- a/phpBB/includes/functions_install.php
+++ /dev/null
@@ -1,545 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Returns an array of available DBMS with some data, if a DBMS is specified it will only
-* return data for that DBMS and will load its extension if necessary.
-*/
-function get_available_dbms($dbms = false, $return_unavailable = false, $only_20x_options = false)
-{
- global $lang;
- $available_dbms = array(
- // Note: php 5.5 alpha 2 deprecated mysql.
- // Keep mysqli before mysql in this list.
- 'mysqli' => array(
- 'LABEL' => 'MySQL with MySQLi Extension',
- 'SCHEMA' => 'mysql_41',
- 'MODULE' => 'mysqli',
- 'DELIM' => ';',
- 'DRIVER' => 'phpbb\db\driver\mysqli',
- 'AVAILABLE' => true,
- '2.0.x' => true,
- ),
- 'mysql' => array(
- 'LABEL' => 'MySQL',
- 'SCHEMA' => 'mysql',
- 'MODULE' => 'mysql',
- 'DELIM' => ';',
- 'DRIVER' => 'phpbb\db\driver\mysql',
- 'AVAILABLE' => true,
- '2.0.x' => true,
- ),
- 'mssql' => array(
- 'LABEL' => 'MS SQL Server 2000+',
- 'SCHEMA' => 'mssql',
- 'MODULE' => 'mssql',
- 'DELIM' => 'GO',
- 'DRIVER' => 'phpbb\db\driver\mssql',
- 'AVAILABLE' => true,
- '2.0.x' => true,
- ),
- 'mssql_odbc'=> array(
- 'LABEL' => 'MS SQL Server [ ODBC ]',
- 'SCHEMA' => 'mssql',
- 'MODULE' => 'odbc',
- 'DELIM' => 'GO',
- 'DRIVER' => 'phpbb\db\driver\mssql_odbc',
- 'AVAILABLE' => true,
- '2.0.x' => true,
- ),
- 'mssqlnative' => array(
- 'LABEL' => 'MS SQL Server 2005+ [ Native ]',
- 'SCHEMA' => 'mssql',
- 'MODULE' => 'sqlsrv',
- 'DELIM' => 'GO',
- 'DRIVER' => 'phpbb\db\driver\mssqlnative',
- 'AVAILABLE' => true,
- '2.0.x' => false,
- ),
- 'oracle' => array(
- 'LABEL' => 'Oracle',
- 'SCHEMA' => 'oracle',
- 'MODULE' => 'oci8',
- 'DELIM' => '/',
- 'DRIVER' => 'phpbb\db\driver\oracle',
- 'AVAILABLE' => true,
- '2.0.x' => false,
- ),
- 'postgres' => array(
- 'LABEL' => 'PostgreSQL 8.3+',
- 'SCHEMA' => 'postgres',
- 'MODULE' => 'pgsql',
- 'DELIM' => ';',
- 'DRIVER' => 'phpbb\db\driver\postgres',
- 'AVAILABLE' => true,
- '2.0.x' => true,
- ),
- 'sqlite' => array(
- 'LABEL' => 'SQLite',
- 'SCHEMA' => 'sqlite',
- 'MODULE' => 'sqlite',
- 'DELIM' => ';',
- 'DRIVER' => 'phpbb\db\driver\sqlite',
- 'AVAILABLE' => true,
- '2.0.x' => false,
- ),
- 'sqlite3' => array(
- 'LABEL' => 'SQLite3',
- 'SCHEMA' => 'sqlite',
- 'MODULE' => 'sqlite3',
- 'DELIM' => ';',
- 'DRIVER' => 'phpbb\db\driver\sqlite3',
- 'AVAILABLE' => true,
- '2.0.x' => false,
- ),
- );
-
- if ($dbms)
- {
- if (isset($available_dbms[$dbms]))
- {
- $available_dbms = array($dbms => $available_dbms[$dbms]);
- }
- else
- {
- return array();
- }
- }
-
- // now perform some checks whether they are really available
- foreach ($available_dbms as $db_name => $db_ary)
- {
- if ($only_20x_options && !$db_ary['2.0.x'])
- {
- if ($return_unavailable)
- {
- $available_dbms[$db_name]['AVAILABLE'] = false;
- }
- else
- {
- unset($available_dbms[$db_name]);
- }
- continue;
- }
-
- $dll = $db_ary['MODULE'];
-
- if (!@extension_loaded($dll))
- {
- if ($return_unavailable)
- {
- $available_dbms[$db_name]['AVAILABLE'] = false;
- }
- else
- {
- unset($available_dbms[$db_name]);
- }
- continue;
- }
- $any_db_support = true;
- }
-
- if ($return_unavailable)
- {
- $available_dbms['ANY_DB_SUPPORT'] = $any_db_support;
- }
- return $available_dbms;
-}
-
-/**
-* Generate the drop down of available database options
-*/
-function dbms_select($default = '', $only_20x_options = false)
-{
- global $lang;
-
- $available_dbms = get_available_dbms(false, false, $only_20x_options);
- $dbms_options = '';
- foreach ($available_dbms as $dbms_name => $details)
- {
- $selected = ($dbms_name == $default) ? ' selected="selected"' : '';
- $dbms_options .= '<option value="' . $dbms_name . '"' . $selected .'>' . $lang['DLL_' . strtoupper($dbms_name)] . '</option>';
- }
- return $dbms_options;
-}
-
-/**
-* Get tables of a database
-*
-* @deprecated
-*/
-function get_tables(&$db)
-{
- $db_tools = new \phpbb\db\tools($db);
-
- return $db_tools->sql_list_tables();
-}
-
-/**
-* Used to test whether we are able to connect to the database the user has specified
-* and identify any problems (eg there are already tables with the names we want to use
-* @param array $dbms should be of the format of an element of the array returned by {@link get_available_dbms get_available_dbms()}
-* necessary extensions should be loaded already
-*/
-function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, $dbhost, $dbuser, $dbpasswd, $dbname, $dbport, $prefix_may_exist = false, $load_dbal = true, $unicode_check = true)
-{
- global $phpbb_root_path, $phpEx, $config, $lang;
-
- $dbms = $dbms_details['DRIVER'];
-
- // Instantiate it and set return on error true
- $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'] != 'phpbb\db\driver\sqlite' && $dbms_details['DRIVER'] != 'phpbb\db\driver\sqlite3' && $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'] == 'phpbb\db\driver\sqlite' || $dbms_details['DRIVER'] == 'phpbb\db\driver\sqlite3') && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0)
- {
- $error[] = $lang['INST_ERR_DB_FORUM_PATH'];
- return false;
- }
-
- // Check the prefix length to ensure that index names are not too long and does not contain invalid characters
- switch ($dbms_details['DRIVER'])
- {
- case 'phpbb\db\driver\mysql':
- case 'phpbb\db\driver\mysqli':
- if (strspn($table_prefix, '-./\\') !== 0)
- {
- $error[] = $lang['INST_ERR_PREFIX_INVALID'];
- return false;
- }
-
- // no break;
-
- case 'phpbb\db\driver\postgres':
- $prefix_length = 36;
- break;
-
- case 'phpbb\db\driver\mssql':
- case 'phpbb\db\driver\mssql_odbc':
- case 'phpbb\db\driver\mssqlnative':
- $prefix_length = 90;
- break;
-
- case 'phpbb\db\driver\sqlite':
- case 'phpbb\db\driver\sqlite3':
- $prefix_length = 200;
- break;
-
- case 'phpbb\db\driver\oracle':
- $prefix_length = 6;
- break;
- }
-
- if (strlen($table_prefix) > $prefix_length)
- {
- $error[] = sprintf($lang['INST_ERR_PREFIX_TOO_LONG'], $prefix_length);
- return false;
- }
-
- // Try and connect ...
- if (is_array($db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true)))
- {
- $db_error = $db->sql_error();
- $error[] = $lang['INST_ERR_DB_CONNECT'] . '<br />' . (($db_error['message']) ? utf8_convert_message($db_error['message']) : $lang['INST_ERR_DB_NO_ERROR']);
- }
- else
- {
- // Likely matches for an existing phpBB installation
- if (!$prefix_may_exist)
- {
- $temp_prefix = strtolower($table_prefix);
- $table_ary = array($temp_prefix . 'attachments', $temp_prefix . 'config', $temp_prefix . 'sessions', $temp_prefix . 'topics', $temp_prefix . 'users');
-
- $tables = get_tables($db);
- $tables = array_map('strtolower', $tables);
- $table_intersect = array_intersect($tables, $table_ary);
-
- if (sizeof($table_intersect))
- {
- $error[] = $lang['INST_ERR_PREFIX'];
- }
- }
-
- // Make sure that the user has selected a sensible DBAL for the DBMS actually installed
- switch ($dbms_details['DRIVER'])
- {
- case 'phpbb\db\driver\mysqli':
- if (version_compare(mysqli_get_server_info($db->get_db_connect_id()), '4.1.3', '<'))
- {
- $error[] = $lang['INST_ERR_DB_NO_MYSQLI'];
- }
- break;
-
- case 'phpbb\db\driver\sqlite':
- if (version_compare(sqlite_libversion(), '2.8.2', '<'))
- {
- $error[] = $lang['INST_ERR_DB_NO_SQLITE'];
- }
- break;
-
- case 'phpbb\db\driver\sqlite3':
- $version = \SQLite3::version();
- if (version_compare($version['versionString'], '3.6.15', '<'))
- {
- $error[] = $lang['INST_ERR_DB_NO_SQLITE3'];
- }
- break;
-
- case 'phpbb\db\driver\oracle':
- if ($unicode_check)
- {
- $sql = "SELECT *
- FROM NLS_DATABASE_PARAMETERS
- WHERE PARAMETER = 'NLS_RDBMS_VERSION'
- OR PARAMETER = 'NLS_CHARACTERSET'";
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $stats[$row['parameter']] = $row['value'];
- }
- $db->sql_freeresult($result);
-
- if (version_compare($stats['NLS_RDBMS_VERSION'], '9.2', '<') && $stats['NLS_CHARACTERSET'] !== 'UTF8')
- {
- $error[] = $lang['INST_ERR_DB_NO_ORACLE'];
- }
- }
- break;
-
- case 'phpbb\db\driver\postgres':
- if ($unicode_check)
- {
- $sql = "SHOW server_encoding;";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ($row['server_encoding'] !== 'UNICODE' && $row['server_encoding'] !== 'UTF8')
- {
- $error[] = $lang['INST_ERR_DB_NO_POSTGRES'];
- }
- }
- break;
- }
-
- }
-
- if ($error_connect && (!isset($error) || !sizeof($error)))
- {
- return true;
- }
- return false;
-}
-
-/**
-* Removes "/* style" as well as "# style" comments from $input.
-*
-* @param string $input Input string
-*
-* @return string Input string with comments removed
-*/
-function phpbb_remove_comments($input)
-{
- // Remove /* */ comments (http://ostermiller.org/findcomment.html)
- $input = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $input);
-
- // Remove # style comments
- $input = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $input));
-
- return $input;
-}
-
-/**
-* split_sql_file will split an uploaded sql file into single sql statements.
-* Note: expects trim() to have already been run on $sql.
-*/
-function split_sql_file($sql, $delimiter)
-{
- $sql = str_replace("\r" , '', $sql);
- $data = preg_split('/' . preg_quote($delimiter, '/') . '$/m', $sql);
-
- $data = array_map('trim', $data);
-
- // The empty case
- $end_data = end($data);
-
- if (empty($end_data))
- {
- unset($data[key($data)]);
- }
-
- return $data;
-}
-
-/**
-* For replacing {L_*} strings with preg_replace_callback
-*/
-function adjust_language_keys_callback($matches)
-{
- if (!empty($matches[1]))
- {
- global $lang, $db;
-
- return (!empty($lang[$matches[1]])) ? $db->sql_escape($lang[$matches[1]]) : $db->sql_escape($matches[1]);
- }
-}
-
-/**
-* Creates the output to be stored in a phpBB config.php file
-*
-* @param array $data Array containing the database connection information
-* @param string $dbms The name of the DBAL class to use
-* @param bool $debug If the debug constants should be enabled by default or not
-* @param bool $debug_container If the container should be compiled on
-* every page load or not
-* @param bool $debug_test If the DEBUG_TEST constant should be added
-* NOTE: Only for use within the testing framework
-*
-* @return string The output to write to the file
-*/
-function phpbb_create_config_file_data($data, $dbms, $debug = false, $debug_container = false, $debug_test = false)
-{
- $config_data = "<?php\n";
- $config_data .= "// phpBB 3.1.x auto-generated configuration file\n// Do not change anything in this file!\n";
-
- $config_data_array = array(
- 'dbms' => $dbms,
- 'dbhost' => $data['dbhost'],
- 'dbport' => $data['dbport'],
- 'dbname' => $data['dbname'],
- 'dbuser' => $data['dbuser'],
- 'dbpasswd' => htmlspecialchars_decode($data['dbpasswd']),
- 'table_prefix' => $data['table_prefix'],
-
- 'phpbb_adm_relative_path' => 'adm/',
-
- 'acm_type' => 'phpbb\cache\driver\file',
- );
-
- foreach ($config_data_array as $key => $value)
- {
- $config_data .= "\${$key} = '" . str_replace("'", "\\'", str_replace('\\', '\\\\', $value)) . "';\n";
- }
-
- $config_data .= "\n@define('PHPBB_INSTALLED', true);\n";
- $config_data .= "// @define('PHPBB_DISPLAY_LOAD_TIME', true);\n";
-
- if ($debug)
- {
- $config_data .= "@define('DEBUG', true);\n";
- }
- else
- {
- $config_data .= "// @define('DEBUG', true);\n";
- }
-
- if ($debug_container)
- {
- $config_data .= "@define('DEBUG_CONTAINER', true);\n";
- }
- else
- {
- $config_data .= "// @define('DEBUG_CONTAINER', true);\n";
- }
-
- if ($debug_test)
- {
- $config_data .= "@define('DEBUG_TEST', true);\n";
- }
-
- return $config_data;
-}
-
-/**
-* Check whether a file should be ignored on update
-*
-* We ignore new files in some circumstances:
-* 1. The file is a language file, but the language is not installed
-* 2. The file is a style file, but the style is not installed
-* 3. The file is a style language file, but the language is not installed
-*
-* @param string $phpbb_root_path phpBB root path
-* @param string $file File including path from phpbb root
-* @return bool Should we ignore the new file or add it to the board?
-*/
-function phpbb_ignore_new_file_on_update($phpbb_root_path, $file)
-{
- $ignore_new_file = false;
-
- // We ignore new files in some circumstances:
- // 1. The file is a language file, but the language is not installed
- if (!$ignore_new_file && strpos($file, 'language/') === 0)
- {
- list($language_dir, $language_iso) = explode('/', $file);
- $ignore_new_file = !file_exists($phpbb_root_path . $language_dir . '/' . $language_iso);
- }
-
- // 2. The file is a style file, but the style is not installed
- if (!$ignore_new_file && strpos($file, 'styles/') === 0)
- {
- list($styles_dir, $style_name) = explode('/', $file);
- $ignore_new_file = !file_exists($phpbb_root_path . $styles_dir . '/' . $style_name);
- }
-
- // 3. The file is a style language file, but the language is not installed
- if (!$ignore_new_file && strpos($file, 'styles/') === 0)
- {
- $dirs = explode('/', $file);
- if (sizeof($dirs) >= 5)
- {
- list($styles_dir, $style_name, $template_component, $language_iso) = explode('/', $file);
- if ($template_component == 'theme' && $language_iso !== 'images')
- {
- $ignore_new_file = !file_exists($phpbb_root_path . 'language/' . $language_iso);
- }
- }
- }
-
- return $ignore_new_file;
-}
-
-/**
-* Check whether phpBB is installed.
-*
-* @param string $phpbb_root_path Path to the phpBB board root.
-* @param string $php_ext PHP file extension.
-*
-* @return bool Returns true if phpBB is installed.
-*/
-function phpbb_check_installation_exists($phpbb_root_path, $php_ext)
-{
- // Try opening config file
- if (file_exists($phpbb_root_path . 'config.' . $php_ext))
- {
- include($phpbb_root_path . 'config.' . $php_ext);
- }
-
- return defined('PHPBB_INSTALLED');
-}
diff --git a/phpBB/includes/functions_jabber.php b/phpBB/includes/functions_jabber.php
index c9ec6fea61..cf0865e608 100644
--- a/phpBB/includes/functions_jabber.php
+++ b/phpBB/includes/functions_jabber.php
@@ -103,8 +103,7 @@ class jabber
*/
static public function can_use_ssl()
{
- // Will not work with PHP >= 5.2.1 or < 5.2.3RC2 until timeout problem with ssl hasn't been fixed (http://bugs.php.net/41236)
- return ((version_compare(PHP_VERSION, '5.2.1', '<') || version_compare(PHP_VERSION, '5.2.3RC2', '>=')) && @extension_loaded('openssl')) ? true : false;
+ return @extension_loaded('openssl');
}
/**
@@ -208,7 +207,7 @@ class jabber
*/
function login()
{
- if (!sizeof($this->features))
+ if (!count($this->features))
{
$this->add_to_log('Error: No feature information from server available.');
return false;
@@ -294,7 +293,7 @@ class jabber
*/
function get_log()
{
- if ($this->enable_logging && sizeof($this->log_array))
+ if ($this->enable_logging && count($this->log_array))
{
return implode("<br /><br />", $this->log_array);
}
@@ -401,14 +400,14 @@ class jabber
*/
function response($xml)
{
- if (!is_array($xml) || !sizeof($xml))
+ if (!is_array($xml) || !count($xml))
{
return false;
}
// did we get multiple elements? do one after another
// array('message' => ..., 'presence' => ...)
- if (sizeof($xml) > 1)
+ if (count($xml) > 1)
{
foreach ($xml as $key => $value)
{
@@ -420,7 +419,7 @@ class jabber
{
// or even multiple elements of the same type?
// array('message' => array(0 => ..., 1 => ...))
- if (sizeof(reset($xml)) > 1)
+ if (count(reset($xml)) > 1)
{
foreach (reset($xml) as $value)
{
@@ -859,14 +858,14 @@ class jabber
array_push($children, $vals[$i]['value']);
}
- while (++$i < sizeof($vals))
+ while (++$i < count($vals))
{
switch ($vals[$i]['type'])
{
case 'open':
$tagname = (isset($vals[$i]['tag'])) ? $vals[$i]['tag'] : '';
- $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0;
+ $size = (isset($children[$tagname])) ? count($children[$tagname]) : 0;
if (isset($vals[$i]['attributes']))
{
@@ -884,7 +883,7 @@ class jabber
case 'complete':
$tagname = $vals[$i]['tag'];
- $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0;
+ $size = (isset($children[$tagname])) ? count($children[$tagname]) : 0;
$children[$tagname][$size]['#'] = (isset($vals[$i]['value'])) ? $vals[$i]['value'] : array();
if (isset($vals[$i]['attributes']))
diff --git a/phpBB/includes/functions_mcp.php b/phpBB/includes/functions_mcp.php
index 1e08864bdc..75e24618de 100644
--- a/phpBB/includes/functions_mcp.php
+++ b/phpBB/includes/functions_mcp.php
@@ -22,12 +22,12 @@ if (!defined('IN_PHPBB'))
/**
* Functions used to generate additional URL paramters
*/
-function phpbb_module__url($mode, &$module_row)
+function phpbb_module__url($mode, $module_row)
{
return phpbb_extra_url();
}
-function phpbb_module_notes_url($mode, &$module_row)
+function phpbb_module_notes_url($mode, $module_row)
{
if ($mode == 'front')
{
@@ -38,7 +38,7 @@ function phpbb_module_notes_url($mode, &$module_row)
return ($user_id) ? "&amp;u=$user_id" : '';
}
-function phpbb_module_warn_url($mode, &$module_row)
+function phpbb_module_warn_url($mode, $module_row)
{
if ($mode == 'front' || $mode == 'list')
{
@@ -64,27 +64,27 @@ function phpbb_module_warn_url($mode, &$module_row)
}
}
-function phpbb_module_main_url($mode, &$module_row)
+function phpbb_module_main_url($mode, $module_row)
{
return phpbb_extra_url();
}
-function phpbb_module_logs_url($mode, &$module_row)
+function phpbb_module_logs_url($mode, $module_row)
{
return phpbb_extra_url();
}
-function phpbb_module_ban_url($mode, &$module_row)
+function phpbb_module_ban_url($mode, $module_row)
{
return phpbb_extra_url();
}
-function phpbb_module_queue_url($mode, &$module_row)
+function phpbb_module_queue_url($mode, $module_row)
{
return phpbb_extra_url();
}
-function phpbb_module_reports_url($mode, &$module_row)
+function phpbb_module_reports_url($mode, $module_row)
{
return phpbb_extra_url();
}
@@ -113,7 +113,7 @@ function phpbb_get_topic_data($topic_ids, $acl_list = false, $read_tracking = fa
$topics = array();
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
return array();
}
@@ -130,7 +130,7 @@ function phpbb_get_topic_data($topic_ids, $acl_list = false, $read_tracking = fa
$cache_topic_ids = array();
}
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$sql_array = array(
'SELECT' => 't.*, f.*',
@@ -197,11 +197,11 @@ function phpbb_get_topic_data($topic_ids, $acl_list = false, $read_tracking = fa
*/
function phpbb_get_post_data($post_ids, $acl_list = false, $read_tracking = false)
{
- global $db, $auth, $config, $user;
+ global $db, $auth, $config, $user, $phpbb_container;
$rowset = array();
- if (!sizeof($post_ids))
+ if (!count($post_ids))
{
return array();
}
@@ -246,6 +246,8 @@ function phpbb_get_post_data($post_ids, $acl_list = false, $read_tracking = fals
$result = $db->sql_query($sql);
unset($sql_array);
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
while ($row = $db->sql_fetchrow($result))
{
if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id']))
@@ -253,7 +255,7 @@ function phpbb_get_post_data($post_ids, $acl_list = false, $read_tracking = fals
continue;
}
- if ($row['post_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $row['forum_id']))
+ if (!$phpbb_content_visibility->is_visible('post', $row['forum_id'], $row))
{
// Moderators without the permission to approve post should at least not see them. ;)
continue;
@@ -280,7 +282,7 @@ function phpbb_get_forum_data($forum_id, $acl_list = 'f_list', $read_tracking =
$forum_id = array($forum_id);
}
- if (!sizeof($forum_id))
+ if (!count($forum_id))
{
return array();
}
@@ -301,6 +303,7 @@ function phpbb_get_forum_data($forum_id, $acl_list = 'f_list', $read_tracking =
WHERE " . $db->sql_in_set('f.forum_id', $forum_id);
$result = $db->sql_query($sql);
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
while ($row = $db->sql_fetchrow($result))
@@ -328,7 +331,7 @@ function phpbb_get_pm_data($pm_ids)
$rowset = array();
- if (!sizeof($pm_ids))
+ if (!count($pm_ids))
{
return array();
}
@@ -366,12 +369,12 @@ function phpbb_get_pm_data($pm_ids)
* $mode reports and reports_closed: the $where parameters uses aliases p for posts table and r for report table
* $mode unapproved_posts: the $where parameters uses aliases p for posts table and t for topic table
*/
-function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by_sql, &$sort_order_sql, &$total, $forum_id = 0, $topic_id = 0, $where_sql = 'WHERE')
+function phpbb_mcp_sorting($mode, &$sort_days_val, &$sort_key_val, &$sort_dir_val, &$sort_by_sql_ary, &$sort_order_sql, &$total_val, $forum_id = 0, $topic_id = 0, $where_sql = 'WHERE')
{
- global $db, $user, $auth, $template, $phpbb_dispatcher;
+ global $db, $user, $auth, $template, $request, $phpbb_dispatcher;
- $sort_days = request_var('st', 0);
- $min_time = ($sort_days) ? time() - ($sort_days * 86400) : 0;
+ $sort_days_val = $request->variable('st', 0);
+ $min_time = ($sort_days_val) ? time() - ($sort_days_val * 86400) : 0;
switch ($mode)
{
@@ -511,8 +514,8 @@ function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by
break;
}
- $sort_key = request_var('sk', $default_key);
- $sort_dir = request_var('sd', $default_dir);
+ $sort_key_val = $request->variable('sk', $default_key);
+ $sort_dir_val = $request->variable('sd', $default_dir);
$sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']);
switch ($type)
@@ -521,41 +524,46 @@ function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by
$limit_days = array(0 => $user->lang['ALL_TOPICS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'tt' => $user->lang['TOPIC_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']);
- $sort_by_sql = array('a' => 't.topic_first_poster_name', 't' => array('t.topic_last_post_time', 't.topic_last_post_id'), 'tt' => 't.topic_time', 'r' => (($auth->acl_get('m_approve', $forum_id)) ? 't.topic_posts_approved + t.topic_posts_unapproved + t.topic_posts_softdeleted' : 't.topic_posts_approved'), 's' => 't.topic_title', 'v' => 't.topic_views');
+ $sort_by_sql_ary = array('a' => 't.topic_first_poster_name', 't' => array('t.topic_last_post_time', 't.topic_last_post_id'), 'tt' => 't.topic_time', 'r' => (($auth->acl_get('m_approve', $forum_id)) ? 't.topic_posts_approved + t.topic_posts_unapproved + t.topic_posts_softdeleted' : 't.topic_posts_approved'), 's' => 't.topic_title', 'v' => 't.topic_views');
$limit_time_sql = ($min_time) ? "AND t.topic_last_post_time >= $min_time" : '';
break;
case 'posts':
$limit_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']);
- $sort_by_sql = array('a' => 'u.username_clean', 't' => array('p.post_time', 'p.post_id'), 's' => 'p.post_subject');
+ $sort_by_sql_ary = array('a' => 'u.username_clean', 't' => array('p.post_time', 'p.post_id'), 's' => 'p.post_subject');
$limit_time_sql = ($min_time) ? "AND p.post_time >= $min_time" : '';
break;
case 'reports':
$limit_days = array(0 => $user->lang['ALL_REPORTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 'r' => $user->lang['REPORTER'], 'p' => $user->lang['POST_TIME'], 't' => $user->lang['REPORT_TIME'], 's' => $user->lang['SUBJECT']);
- $sort_by_sql = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => array('p.post_time', 'p.post_id'), 't' => 'r.report_time', 's' => 'p.post_subject');
+ $sort_by_sql_ary = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => array('p.post_time', 'p.post_id'), 't' => 'r.report_time', 's' => 'p.post_subject');
break;
case 'pm_reports':
$limit_days = array(0 => $user->lang['ALL_REPORTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['AUTHOR'], 'r' => $user->lang['REPORTER'], 'p' => $user->lang['POST_TIME'], 't' => $user->lang['REPORT_TIME'], 's' => $user->lang['SUBJECT']);
- $sort_by_sql = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => 'p.message_time', 't' => 'r.report_time', 's' => 'p.message_subject');
+ $sort_by_sql_ary = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => 'p.message_time', 't' => 'r.report_time', 's' => 'p.message_subject');
break;
case 'logs':
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('u' => $user->lang['SORT_USERNAME'], 't' => $user->lang['SORT_DATE'], 'i' => $user->lang['SORT_IP'], 'o' => $user->lang['SORT_ACTION']);
- $sort_by_sql = array('u' => 'u.username_clean', 't' => 'l.log_time', 'i' => 'l.log_ip', 'o' => 'l.log_operation');
+ $sort_by_sql_ary = array('u' => 'u.username_clean', 't' => 'l.log_time', 'i' => 'l.log_ip', 'o' => 'l.log_operation');
$limit_time_sql = ($min_time) ? "AND l.log_time >= $min_time" : '';
break;
}
// Default total to -1 to allow editing by the event
- $total = -1;
+ $total_val = -1;
+ $sort_by_sql = $sort_by_sql_ary;
+ $sort_days = $sort_days_val;
+ $sort_dir = $sort_dir_val;
+ $sort_key = $sort_key_val;
+ $total = $total_val;
/**
* This event allows you to control the SQL query used to get the total number
* of reports the user can access.
@@ -602,25 +610,35 @@ function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by
'where_sql',
);
extract($phpbb_dispatcher->trigger_event('core.mcp_sorting_query_before', compact($vars)));
-
- if (!isset($sort_by_sql[$sort_key]))
+ $sort_by_sql_ary = $sort_by_sql;
+ $sort_days_val = $sort_days;
+ $sort_key_val = $sort_key;
+ $sort_dir_val = $sort_dir;
+ $total_val = $total;
+ unset($sort_by_sql);
+ unset($sort_days);
+ unset($sort_key);
+ unset($sort_dir);
+ unset($total);
+
+ if (!isset($sort_by_sql_ary[$sort_key_val]))
{
- $sort_key = $default_key;
+ $sort_key_val = $default_key;
}
- $direction = ($sort_dir == 'd') ? 'DESC' : 'ASC';
+ $direction = ($sort_dir_val == 'd') ? 'DESC' : 'ASC';
- if (is_array($sort_by_sql[$sort_key]))
+ if (is_array($sort_by_sql_ary[$sort_key_val]))
{
- $sort_order_sql = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction;
+ $sort_order_sql = implode(' ' . $direction . ', ', $sort_by_sql_ary[$sort_key_val]) . ' ' . $direction;
}
else
{
- $sort_order_sql = $sort_by_sql[$sort_key] . ' ' . $direction;
+ $sort_order_sql = $sort_by_sql_ary[$sort_key_val] . ' ' . $direction;
}
$s_limit_days = $s_sort_key = $s_sort_dir = $sort_url = '';
- gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $sort_url);
+ gen_sort_selects($limit_days, $sort_by_text, $sort_days_val, $sort_key_val, $sort_dir_val, $s_limit_days, $s_sort_key, $s_sort_dir, $sort_url);
$template->assign_vars(array(
'S_SELECT_SORT_DIR' => $s_sort_dir,
@@ -628,15 +646,15 @@ function phpbb_mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by
'S_SELECT_SORT_DAYS' => $s_limit_days)
);
- if (($sort_days && $mode != 'viewlogs') || in_array($mode, array('reports', 'unapproved_topics', 'unapproved_posts', 'deleted_topics', 'deleted_posts')) || $where_sql != 'WHERE')
+ if (($sort_days_val && $mode != 'viewlogs') || in_array($mode, array('reports', 'unapproved_topics', 'unapproved_posts', 'deleted_topics', 'deleted_posts')) || $where_sql != 'WHERE')
{
$result = $db->sql_query($sql);
- $total = (int) $db->sql_fetchfield('total');
+ $total_val = (int) $db->sql_fetchfield('total');
$db->sql_freeresult($result);
}
- else if ($total < -1)
+ else if ($total_val < -1)
{
- $total = -1;
+ $total_val = -1;
}
}
@@ -714,7 +732,7 @@ function phpbb_check_ids(&$ids, $table, $sql_id, $acl_list = false, $single_foru
}
$db->sql_freeresult($result);
- if (!sizeof($ids))
+ if (!count($ids))
{
return false;
}
diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php
index 98975b9d8f..ec297b536a 100644
--- a/phpBB/includes/functions_messenger.php
+++ b/phpBB/includes/functions_messenger.php
@@ -24,8 +24,9 @@ if (!defined('IN_PHPBB'))
*/
class messenger
{
- var $msg, $extra_headers, $replyto, $from, $subject;
+ var $msg, $replyto, $from, $subject;
var $addresses = array();
+ var $extra_headers = array();
var $mail_priority = MAIL_NORMAL_PRIORITY;
var $use_queue = true;
@@ -33,21 +34,15 @@ class messenger
/** @var \phpbb\template\template */
protected $template;
- var $eol = "\n";
-
/**
* Constructor
*/
- function messenger($use_queue = true)
+ function __construct($use_queue = true)
{
global $config;
$this->use_queue = (!$config['email_package_size']) ? false : $use_queue;
$this->subject = '';
-
- // Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
- $this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
- $this->eol = (!$this->eol) ? "\n" : $this->eol;
}
/**
@@ -90,7 +85,7 @@ class messenger
return;
}
- $pos = isset($this->addresses['to']) ? sizeof($this->addresses['to']) : 0;
+ $pos = isset($this->addresses['to']) ? count($this->addresses['to']) : 0;
$this->addresses['to'][$pos]['email'] = trim($address);
@@ -115,7 +110,7 @@ class messenger
return;
}
- $pos = isset($this->addresses['cc']) ? sizeof($this->addresses['cc']) : 0;
+ $pos = isset($this->addresses['cc']) ? count($this->addresses['cc']) : 0;
$this->addresses['cc'][$pos]['email'] = trim($address);
$this->addresses['cc'][$pos]['name'] = trim($realname);
}
@@ -130,7 +125,7 @@ class messenger
return;
}
- $pos = isset($this->addresses['bcc']) ? sizeof($this->addresses['bcc']) : 0;
+ $pos = isset($this->addresses['bcc']) ? count($this->addresses['bcc']) : 0;
$this->addresses['bcc'][$pos]['email'] = trim($address);
$this->addresses['bcc'][$pos]['name'] = trim($realname);
}
@@ -146,7 +141,7 @@ class messenger
return;
}
- $pos = isset($this->addresses['im']) ? sizeof($this->addresses['im']) : 0;
+ $pos = isset($this->addresses['im']) ? count($this->addresses['im']) : 0;
$this->addresses['im'][$pos]['uid'] = trim($address);
$this->addresses['im'][$pos]['name'] = trim($realname);
}
@@ -186,10 +181,9 @@ class messenger
/**
* Adds X-AntiAbuse headers
*
- * @param array $config Configuration array
- * @param user $user A user object
- *
- * @return null
+ * @param \phpbb\config\config $config Config object
+ * @param \phpbb\user $user User object
+ * @return void
*/
function anti_abuse_headers($config, $user)
{
@@ -212,7 +206,7 @@ class messenger
*/
function template($template_file, $template_lang = '', $template_path = '', $template_dir_prefix = '')
{
- global $config, $phpbb_root_path, $phpEx, $user, $phpbb_extension_manager;
+ global $config, $phpbb_root_path, $user;
$template_dir_prefix = (!$template_dir_prefix || $template_dir_prefix[0] === '/') ? $template_dir_prefix : '/' . $template_dir_prefix;
@@ -331,9 +325,26 @@ class messenger
));
$subject = $this->subject;
- $message = $this->msg;
+ $template = $this->template;
+ /**
+ * Event to modify the template before parsing
+ *
+ * @event core.modify_notification_template
+ * @var int method User notification method NOTIFY_EMAIL|NOTIFY_IM|NOTIFY_BOTH
+ * @var bool break Flag indicating if the function only formats the subject
+ * and the message without sending it
+ * @var string subject The message subject
+ * @var \phpbb\template\template template The (readonly) template object
+ * @since 3.2.4-RC1
+ */
+ $vars = array('method', 'break', 'subject', 'template');
+ extract($phpbb_dispatcher->trigger_event('core.modify_notification_template', compact($vars)));
+
+ // Parse message through template
+ $message = trim($this->template->assign_display('body'));
+
/**
- * Event to modify notification message text before parsing
+ * Event to modify notification message text after parsing
*
* @event core.modify_notification_message
* @var int method User notification method NOTIFY_EMAIL|NOTIFY_IM|NOTIFY_BOTH
@@ -343,19 +354,12 @@ class messenger
* @var string message The message text
* @since 3.1.11-RC1
*/
- $vars = array(
- 'method',
- 'break',
- 'subject',
- 'message',
- );
+ $vars = array('method', 'break', 'subject', 'message');
extract($phpbb_dispatcher->trigger_event('core.modify_notification_message', compact($vars)));
+
$this->subject = $subject;
$this->msg = $message;
- unset($subject, $message);
-
- // Parse message through template
- $this->msg = trim($this->template->assign_display('body'));
+ unset($subject, $message, $template);
// Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding
$this->msg = str_replace("\r\n", "\n", $this->msg);
@@ -374,6 +378,12 @@ class messenger
$this->subject = (($this->subject != '') ? $this->subject : $user->lang['NO_EMAIL_SUBJECT']);
}
+ if (preg_match('#^(List-Unsubscribe:(.*?))$#m', $this->msg, $match))
+ {
+ $this->extra_headers[] = $match[1];
+ $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#');
+ }
+
if ($drop_header)
{
$this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg));
@@ -409,7 +419,7 @@ class messenger
*/
function error($type, $msg)
{
- global $user, $phpEx, $phpbb_root_path, $config, $request;
+ global $user, $config, $request, $phpbb_log;
// Session doesn't exist, create it
if (!isset($user->session_id) || $user->session_id === '')
@@ -419,11 +429,10 @@ class messenger
$calling_page = htmlspecialchars_decode($request->server('PHP_SELF'));
- $message = '';
switch ($type)
{
case 'EMAIL':
- $message = '<strong>EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/' . $config['email_function_name'] . '()') . '</strong>';
+ $message = '<strong>EMAIL/' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP/mail()') . '</strong>';
break;
default:
@@ -432,7 +441,7 @@ class messenger
}
$message .= '<br /><em>' . htmlspecialchars($calling_page) . '</em><br /><br />' . $msg . '<br />';
- add_log('critical', 'LOG_ERROR_' . $type, $message);
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_' . $type, false, array($message));
}
/**
@@ -510,7 +519,7 @@ class messenger
$vars = array('headers');
extract($phpbb_dispatcher->trigger_event('core.modify_email_headers', compact($vars)));
- if (sizeof($this->extra_headers))
+ if (count($this->extra_headers))
{
$headers = array_merge($headers, $this->extra_headers);
}
@@ -523,7 +532,7 @@ class messenger
*/
function msg_email()
{
- global $config, $user;
+ global $config, $phpbb_dispatcher;
if (empty($config['email_enable']))
{
@@ -551,6 +560,33 @@ class messenger
$contact_name = htmlspecialchars_decode($config['board_contact_name']);
$board_contact = (($contact_name !== '') ? '"' . mail_encode($contact_name) . '" ' : '') . '<' . $config['board_contact'] . '>';
+ $break = false;
+ $addresses = $this->addresses;
+ $subject = $this->subject;
+ $msg = $this->msg;
+ /**
+ * Event to send message via external transport
+ *
+ * @event core.notification_message_email
+ * @var bool break Flag indicating if the function return after hook
+ * @var array addresses The message recipients
+ * @var string subject The message subject
+ * @var string msg The message text
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'break',
+ 'addresses',
+ 'subject',
+ 'msg',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.notification_message_email', compact($vars)));
+
+ if ($break)
+ {
+ return true;
+ }
+
if (empty($this->replyto))
{
$this->replyto = $board_contact;
@@ -561,7 +597,7 @@ class messenger
$this->from = $board_contact;
}
- $encode_eol = ($config['smtp_delivery']) ? "\r\n" : $this->eol;
+ $encode_eol = ($config['smtp_delivery']) ? "\r\n" : PHP_EOL;
// Build to, cc and bcc strings
$to = $cc = $bcc = '';
@@ -593,7 +629,7 @@ class messenger
}
else
{
- $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, $this->eol, $err_msg);
+ $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, PHP_EOL, $err_msg);
}
if (!$result)
@@ -621,7 +657,7 @@ class messenger
*/
function msg_jabber()
{
- global $config, $db, $user, $phpbb_root_path, $phpEx;
+ global $config, $user, $phpbb_root_path, $phpEx;
if (empty($config['jab_enable']) || empty($config['jab_host']) || empty($config['jab_username']) || empty($config['jab_password']))
{
@@ -693,14 +729,37 @@ class messenger
*/
protected function setup_template()
{
- global $config, $phpbb_path_helper, $user, $phpbb_extension_manager;
+ global $phpbb_container, $phpbb_dispatcher;
if ($this->template instanceof \phpbb\template\template)
{
return;
}
- $this->template = new \phpbb\template\twig\twig($phpbb_path_helper, $config, $user, new \phpbb\template\context(), $phpbb_extension_manager);
+ $template_environment = new \phpbb\template\twig\environment(
+ $phpbb_container->get('config'),
+ $phpbb_container->get('filesystem'),
+ $phpbb_container->get('path_helper'),
+ $phpbb_container->getParameter('core.template.cache_path'),
+ $phpbb_container->get('ext.manager'),
+ new \phpbb\template\twig\loader(
+ $phpbb_container->get('filesystem')
+ ),
+ $phpbb_dispatcher,
+ array()
+ );
+ $template_environment->setLexer($phpbb_container->get('template.twig.lexer'));
+
+ $this->template = new \phpbb\template\twig\twig(
+ $phpbb_container->get('path_helper'),
+ $phpbb_container->get('config'),
+ new \phpbb\template\context(),
+ $template_environment,
+ $phpbb_container->getParameter('core.template.cache_path'),
+ $phpbb_container->get('user'),
+ $phpbb_container->get('template.twig.extensions.collection'),
+ $phpbb_container->get('ext.manager')
+ );
}
/**
@@ -726,18 +785,20 @@ class queue
var $eol = "\n";
/**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
* constructor
*/
- function queue()
+ function __construct()
{
- global $phpEx, $phpbb_root_path;
+ global $phpEx, $phpbb_root_path, $phpbb_filesystem, $phpbb_container;
$this->data = array();
- $this->cache_file = "{$phpbb_root_path}cache/queue.$phpEx";
-
- // Determine EOL character (\n for UNIX, \r\n for Windows and \r for Mac)
- $this->eol = (!defined('PHP_EOL')) ? (($eol = strtolower(substr(PHP_OS, 0, 3))) == 'win') ? "\r\n" : (($eol == 'mac') ? "\r" : "\n") : PHP_EOL;
- $this->eol = (!$this->eol) ? "\n" : $this->eol;
+ $this->cache_file = $phpbb_container->getParameter('core.cache_dir') . "queue.$phpEx";
+ $this->filesystem = $phpbb_filesystem;
}
/**
@@ -764,7 +825,7 @@ class queue
*/
function process()
{
- global $db, $config, $phpEx, $phpbb_root_path, $user;
+ global $config, $phpEx, $phpbb_root_path, $user, $phpbb_dispatcher;
$lock = new \phpbb\lock\flock($this->cache_file);
$lock->acquire();
@@ -775,14 +836,14 @@ class queue
{
if (!$have_cache_file)
{
- set_config('last_queue_run', time(), true);
+ $config->set('last_queue_run', time(), false);
}
$lock->release();
return;
}
- set_config('last_queue_run', time(), true);
+ $config->set('last_queue_run', time(), false);
include($this->cache_file);
@@ -796,7 +857,7 @@ class queue
}
$package_size = $data_ary['package_size'];
- $num_items = (!$package_size || sizeof($data_ary['data']) < $package_size) ? sizeof($data_ary['data']) : $package_size;
+ $num_items = (!$package_size || count($data_ary['data']) < $package_size) ? count($data_ary['data']) : $package_size;
/*
* This code is commented out because it causes problems on some web hosts.
@@ -805,9 +866,9 @@ class queue
* web host and the package size setting is wrong.
// If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs...
- if (sizeof($data_ary['data']) > $package_size * 2.5)
+ if (count($data_ary['data']) > $package_size * 2.5)
{
- $num_items = sizeof($data_ary['data']);
+ $num_items = count($data_ary['data']);
}
*/
@@ -861,23 +922,45 @@ class queue
switch ($object)
{
case 'email':
- $err_msg = '';
- $to = (!$to) ? 'undisclosed-recipients:;' : $to;
-
- if ($config['smtp_delivery'])
- {
- $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers);
- }
- else
+ $break = false;
+ /**
+ * Event to send message via external transport
+ *
+ * @event core.notification_message_process
+ * @var bool break Flag indicating if the function return after hook
+ * @var array addresses The message recipients
+ * @var string subject The message subject
+ * @var string msg The message text
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'break',
+ 'addresses',
+ 'subject',
+ 'msg',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.notification_message_process', compact($vars)));
+
+ if (!$break)
{
- $result = phpbb_mail($to, $subject, $msg, $headers, $this->eol, $err_msg);
- }
+ $err_msg = '';
+ $to = (!$to) ? 'undisclosed-recipients:;' : $to;
- if (!$result)
- {
- $messenger = new messenger();
- $messenger->error('EMAIL', $err_msg);
- continue 2;
+ if ($config['smtp_delivery'])
+ {
+ $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers);
+ }
+ else
+ {
+ $result = phpbb_mail($to, $subject, $msg, $headers, PHP_EOL, $err_msg);
+ }
+
+ if (!$result)
+ {
+ $messenger = new messenger();
+ $messenger->error('EMAIL', $err_msg);
+ continue 2;
+ }
}
break;
@@ -896,7 +979,7 @@ class queue
}
// No more data for this object? Unset it
- if (!sizeof($this->queue_data[$object]['data']))
+ if (!count($this->queue_data[$object]['data']))
{
unset($this->queue_data[$object]);
}
@@ -912,7 +995,7 @@ class queue
}
}
- if (!sizeof($this->queue_data))
+ if (!count($this->queue_data))
{
@unlink($this->cache_file);
}
@@ -928,7 +1011,14 @@ class queue
@opcache_invalidate($this->cache_file);
}
- phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
+ try
+ {
+ $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
}
}
@@ -940,7 +1030,7 @@ class queue
*/
function save()
{
- if (!sizeof($this->data))
+ if (!count($this->data))
{
return;
}
@@ -954,7 +1044,7 @@ class queue
foreach ($this->queue_data as $object => $data_ary)
{
- if (isset($this->data[$object]) && sizeof($this->data[$object]))
+ if (isset($this->data[$object]) && count($this->data[$object]))
{
$this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']);
}
@@ -975,7 +1065,14 @@ class queue
@opcache_invalidate($this->cache_file);
}
- phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
+ try
+ {
+ $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
$this->data = array();
}
@@ -1035,7 +1132,7 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false)
$mail_rcpt = $mail_to = $mail_cc = array();
// Build correct addresses for RCPT TO command and the client side display (TO, CC)
- if (isset($addresses['to']) && sizeof($addresses['to']))
+ if (isset($addresses['to']) && count($addresses['to']))
{
foreach ($addresses['to'] as $which_ary)
{
@@ -1044,7 +1141,7 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false)
}
}
- if (isset($addresses['bcc']) && sizeof($addresses['bcc']))
+ if (isset($addresses['bcc']) && count($addresses['bcc']))
{
foreach ($addresses['bcc'] as $which_ary)
{
@@ -1052,7 +1149,7 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $headers = false)
}
}
- if (isset($addresses['cc']) && sizeof($addresses['cc']))
+ if (isset($addresses['cc']) && count($addresses['cc']))
{
foreach ($addresses['cc'] as $which_ary)
{
@@ -1231,7 +1328,7 @@ class smtp_class
var $backtrace = false;
var $backtrace_log = array();
- function smtp_class()
+ function __construct()
{
// Always create a backtrace for admins to identify SMTP problems
$this->backtrace = true;
@@ -1314,8 +1411,6 @@ class smtp_class
{
global $user;
- $err_msg = '';
-
// Here we try to determine the *real* hostname (reverse DNS entry preferrably)
$local_host = $user->host;
@@ -1350,7 +1445,7 @@ class smtp_class
$this->server_send("QUIT");
fclose($this->socket);
- $result = $this->pop_before_smtp($hostname, $username, $password);
+ $this->pop_before_smtp($hostname, $username, $password);
$username = $password = $default_auth_method = '';
// We need to close the previous session, else the server is not
@@ -1486,6 +1581,14 @@ class smtp_class
*/
protected function starttls()
{
+ global $config;
+
+ // allow SMTPS (what was used by phpBB 3.0) if hostname is prefixed with tls:// or ssl://
+ if (strpos($config['smtp_host'], 'tls://') === 0 || strpos($config['smtp_host'], 'ssl://') === 0)
+ {
+ return true;
+ }
+
if (!function_exists('stream_socket_enable_crypto'))
{
return false;
@@ -1508,7 +1611,9 @@ class smtp_class
if (socket_set_blocking($this->socket, 1))
{
- $result = stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
+ // https://secure.php.net/manual/en/function.stream-socket-enable-crypto.php#119122
+ $crypto = (phpbb_version_compare(PHP_VERSION, '5.6.7', '<')) ? STREAM_CRYPTO_METHOD_TLS_CLIENT : STREAM_CRYPTO_METHOD_SSLv23_CLIENT;
+ $result = stream_socket_enable_crypto($this->socket, true, $crypto);
socket_set_blocking($this->socket, (int) $stream_meta['blocked']);
}
@@ -1772,11 +1877,11 @@ function mail_encode($str, $eol = "\r\n")
$array = utf8_str_split($str);
$str = '';
- while (sizeof($array))
+ while (count($array))
{
$text = '';
- while (sizeof($array) && intval((strlen($text . $array[0]) + 2) / 3) << 2 <= $split_length)
+ while (count($array) && intval((strlen($text . $array[0]) + 2) / 3) << 2 <= $split_length)
{
$text .= array_shift($array);
}
@@ -1788,14 +1893,21 @@ function mail_encode($str, $eol = "\r\n")
}
/**
-* Wrapper for sending out emails with the PHP's mail function
-*/
+ * Wrapper for sending out emails with the PHP's mail function
+ */
function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg)
{
global $config, $phpbb_root_path, $phpEx;
- // We use the EOL character for the OS here because the PHP mail function does not correctly transform line endings. On Windows SMTP is used (SMTP is \r\n), on UNIX a command is used...
- // Reference: http://bugs.php.net/bug.php?id=15841
+ // Convert Numeric Character References to UTF-8 chars (ie. Emojis)
+ $subject = utf8_decode_ncr($subject);
+ $msg = utf8_decode_ncr($msg);
+
+ /**
+ * We use the EOL character for the OS here because the PHP mail function does not correctly transform line endings.
+ * On Windows SMTP is used (SMTP is \r\n), on UNIX a command is used...
+ * Reference: http://bugs.php.net/bug.php?id=15841
+ */
$headers = implode($eol, $headers);
if (!class_exists('\phpbb\error_collector'))
@@ -1806,10 +1918,15 @@ function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg)
$collector = new \phpbb\error_collector;
$collector->install();
- // On some PHP Versions mail() *may* fail if there are newlines within the subject.
- // Newlines are used as a delimiter for lines in mail_encode() according to RFC 2045 section 6.8.
- // Because PHP can't decide what is wanted we revert back to the non-RFC-compliant way of separating by one space (Use '' as parameter to mail_encode() results in SPACE used)
- $result = $config['email_function_name']($to, mail_encode($subject, ''), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers);
+ /**
+ * On some PHP Versions mail() *may* fail if there are newlines within the subject.
+ * Newlines are used as a delimiter for lines in mail_encode() according to RFC 2045 section 6.8.
+ * Because PHP can't decide what is wanted we revert back to the non-RFC-compliant way of separating by one space
+ * (Use '' as parameter to mail_encode() results in SPACE used)
+ */
+ $additional_parameters = $config['email_force_sender'] ? '-f' . $config['board_email'] : '';
+
+ $result = mail($to, mail_encode($subject, ''), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers, $additional_parameters);
$collector->uninstall();
$err_msg = $collector->format_errors();
diff --git a/phpBB/includes/functions_module.php b/phpBB/includes/functions_module.php
index 90d59cfd1e..88dafc4300 100644
--- a/phpBB/includes/functions_module.php
+++ b/phpBB/includes/functions_module.php
@@ -40,7 +40,7 @@ class p_master
* Constuctor
* Set module include path
*/
- function p_master($include_path = false)
+ function __construct($include_path = false)
{
global $phpbb_root_path;
@@ -82,8 +82,8 @@ class p_master
*/
function list_modules($p_class)
{
- global $auth, $db, $user, $cache;
- global $config, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $db, $user, $cache;
+ global $phpbb_dispatcher;
// Sanitise for future path use, it's escaped as appropriate for queries
$this->p_class = str_replace(array('.', '/', '\\'), '', basename($p_class));
@@ -243,7 +243,7 @@ class p_master
}
}
- $depth = sizeof($this->module_cache['parents'][$row['module_id']]);
+ $depth = count($this->module_cache['parents'][$row['module_id']]);
// We need to prefix the functions to not create a naming conflict
@@ -279,7 +279,7 @@ class p_master
'parent' => (int) $row['parent_id'],
'cat' => ($row['right_id'] > $row['left_id'] + 1) ? true : false,
- 'is_duplicate' => ($row['module_basename'] && sizeof($names[$row['module_basename'] . '_' . $row['module_mode']]) > 1) ? true : false,
+ 'is_duplicate' => ($row['module_basename'] && count($names[$row['module_basename'] . '_' . $row['module_mode']]) > 1) ? true : false,
'name' => (string) $row['module_basename'],
'mode' => (string) $row['module_mode'],
@@ -431,7 +431,7 @@ class p_master
extract($phpbb_dispatcher->trigger_event('core.module_auth', compact($vars)));
$tokens = $match[0];
- for ($i = 0, $size = sizeof($tokens); $i < $size; $i++)
+ for ($i = 0, $size = count($tokens); $i < $size; $i++)
{
$token = &$tokens[$i];
@@ -480,13 +480,15 @@ class p_master
*/
function set_active($id = false, $mode = false)
{
+ global $request;
+
$icat = false;
$this->active_module = false;
- if (request_var('icat', ''))
+ if ($request->variable('icat', ''))
{
$icat = $id;
- $id = request_var('icat', '');
+ $id = $request->variable('icat', '');
}
// Restore the backslashes in class names
@@ -553,10 +555,10 @@ class p_master
*/
function load_active($mode = false, $module_url = false, $execute_module = true)
{
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template, $request;
$module_path = $this->include_path . $this->p_class;
- $icat = request_var('icat', '');
+ $icat = $request->variable('icat', '');
if ($this->active_module === false)
{
@@ -727,8 +729,6 @@ class p_master
*/
function get_parents($parent_id, $left_id, $right_id, &$all_parents)
{
- global $db;
-
$parents = array();
if ($parent_id > 0)
@@ -820,7 +820,7 @@ class p_master
// Make sure the module_url has a question mark set, effectively determining the delimiter to use
$delim = (strpos($module_url, '?') === false) ? '?' : '&amp;';
- $current_padding = $current_depth = 0;
+ $current_depth = 0;
$linear_offset = 'l_block1';
$tabular_offset = 't_block2';
diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php
index 9712b6e922..1956f65666 100644
--- a/phpBB/includes/functions_posting.php
+++ b/phpBB/includes/functions_posting.php
@@ -24,12 +24,13 @@ if (!defined('IN_PHPBB'))
*/
function generate_smilies($mode, $forum_id)
{
- global $db, $user, $config, $template, $phpbb_dispatcher;
+ global $db, $user, $config, $template, $phpbb_dispatcher, $request;
global $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_path_helper;
- $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&amp;f=' . $forum_id);
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
- $start = request_var('start', 0);
+ $base_url = append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&amp;f=' . $forum_id);
+ $start = $request->variable('start', 0);
if ($mode == 'window')
{
@@ -51,9 +52,29 @@ function generate_smilies($mode, $forum_id)
page_header($user->lang['SMILIES']);
- $sql = 'SELECT COUNT(smiley_id) AS item_count
- FROM ' . SMILIES_TABLE . '
- GROUP BY smiley_url';
+ $sql_ary = [
+ 'SELECT' => 'COUNT(s.smiley_id) AS item_count',
+ 'FROM' => [
+ SMILIES_TABLE => 's',
+ ],
+ 'GROUP_BY' => 's.smiley_url',
+ ];
+
+ /**
+ * Modify SQL query that fetches the total number of smilies in window mode
+ *
+ * @event core.generate_smilies_count_sql_before
+ * @var int forum_id Forum where smilies are generated
+ * @var array sql_ary Array with the SQL query
+ * @since 3.2.9-RC1
+ */
+ $vars = [
+ 'forum_id',
+ 'sql_ary',
+ ];
+ extract($phpbb_dispatcher->trigger_event('core.generate_smilies_count_sql_before', compact($vars)));
+
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
$result = $db->sql_query($sql, 3600);
$smiley_count = 0;
@@ -113,7 +134,23 @@ function generate_smilies($mode, $forum_id)
}
$db->sql_freeresult($result);
- if (sizeof($smilies))
+ /**
+ * Modify smilies before they are assigned to the template
+ *
+ * @event core.generate_smilies_modify_rowset
+ * @var string mode Smiley mode, either window or inline
+ * @var int forum_id Forum where smilies are generated
+ * @var array smilies Smiley rows fetched from the database
+ * @since 3.2.9-RC1
+ */
+ $vars = [
+ 'mode',
+ 'forum_id',
+ 'smilies',
+ ];
+ extract($phpbb_dispatcher->trigger_event('core.generate_smilies_modify_rowset', compact($vars)));
+
+ if (count($smilies))
{
$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_path_helper->get_web_root_path();
@@ -199,13 +236,15 @@ function update_post_information($type, $ids, $return_update_sql = false)
$topic_condition = '';
}
- if (sizeof($ids) == 1)
+ if (count($ids) == 1)
{
- $sql = 'SELECT MAX(p.post_id) as last_post_id
+ $sql = 'SELECT p.post_id as last_post_id
FROM ' . POSTS_TABLE . " p $topic_join
WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
$topic_condition
- AND p.post_visibility = " . ITEM_APPROVED;
+ AND p.post_visibility = " . ITEM_APPROVED . "
+ ORDER BY p.post_id DESC";
+ $result = $db->sql_query_limit($sql, 1);
}
else
{
@@ -215,13 +254,13 @@ function update_post_information($type, $ids, $return_update_sql = false)
$topic_condition
AND p.post_visibility = " . ITEM_APPROVED . "
GROUP BY p.{$type}_id";
+ $result = $db->sql_query($sql);
}
- $result = $db->sql_query($sql);
$last_post_ids = array();
while ($row = $db->sql_fetchrow($result))
{
- if (sizeof($ids) == 1)
+ if (count($ids) == 1)
{
$row[$type . '_id'] = $ids[0];
}
@@ -255,7 +294,7 @@ function update_post_information($type, $ids, $return_update_sql = false)
}
}
- if (sizeof($last_post_ids))
+ if (count($last_post_ids))
{
$sql = 'SELECT p.' . $type . '_id, p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
@@ -276,7 +315,7 @@ function update_post_information($type, $ids, $return_update_sql = false)
}
unset($empty_forums, $ids, $last_post_ids);
- if ($return_update_sql || !sizeof($update_sql))
+ if ($return_update_sql || !count($update_sql))
{
return $update_sql;
}
@@ -309,7 +348,7 @@ function posting_gen_topic_icons($mode, $icon_id)
$template->assign_var('S_NO_ICON_CHECKED', ' checked="checked"');
}
- if (sizeof($icons))
+ if (count($icons))
{
$root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path;
@@ -319,10 +358,10 @@ function posting_gen_topic_icons($mode, $icon_id)
{
$template->assign_block_vars('topic_icon', array(
'ICON_ID' => $id,
- 'ICON_NAME' => $data['img'],
'ICON_IMG' => $root_path . $config['icons_path'] . '/' . $data['img'],
'ICON_WIDTH' => $data['width'],
'ICON_HEIGHT' => $data['height'],
+ 'ICON_ALT' => $data['alt'],
'S_CHECKED' => ($id == $icon_id) ? true : false,
'S_ICON_CHECKED' => ($id == $icon_id) ? ' checked="checked"' : '')
@@ -341,23 +380,20 @@ function posting_gen_topic_icons($mode, $icon_id)
*/
function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
{
- global $auth, $user, $template, $topic_type;
+ global $auth, $user, $template;
$toggle = false;
$topic_types = array(
- 'sticky' => array('const' => POST_STICKY, 'lang' => 'POST_STICKY'),
- 'announce' => array('const' => POST_ANNOUNCE, 'lang' => 'POST_ANNOUNCEMENT'),
- 'global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL')
+ 'sticky' => array('const' => POST_STICKY, 'lang' => 'POST_STICKY'),
+ 'announce' => array('const' => POST_ANNOUNCE, 'lang' => 'POST_ANNOUNCEMENT'),
+ 'announce_global' => array('const' => POST_GLOBAL, 'lang' => 'POST_GLOBAL')
);
$topic_type_array = array();
foreach ($topic_types as $auth_key => $topic_value)
{
- // We do not have a special post global announcement permission
- $auth_key = ($auth_key == 'global') ? 'announce' : $auth_key;
-
if ($auth->acl_get('f_' . $auth_key, $forum_id))
{
$toggle = true;
@@ -387,8 +423,8 @@ function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
$template->assign_vars(array(
'S_TOPIC_TYPE_STICKY' => ($auth->acl_get('f_sticky', $forum_id)),
- 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_get('f_announce', $forum_id)))
- );
+ 'S_TOPIC_TYPE_ANNOUNCE' => ($auth->acl_gets('f_announce', 'f_announce_global', $forum_id)),
+ ));
}
return $toggle;
@@ -402,183 +438,27 @@ function posting_gen_topic_types($forum_id, $cur_topic_type = POST_NORMAL)
* Upload Attachment - filedata is generated here
* Uses upload class
*
+* @deprecated 3.2.0-a1 (To be removed: 3.4.0)
+*
* @param string $form_name The form name of the file upload input
* @param int $forum_id The id of the forum
* @param bool $local Whether the file is local or not
* @param string $local_storage The path to the local file
* @param bool $is_message Whether it is a PM or not
-* @param \filespec $local_filedata A filespec object created for the local file
-* @param \phpbb\mimetype\guesser $mimetype_guesser The mimetype guesser object if used
-* @param \phpbb\plupload\plupload $plupload The plupload object if one is being used
+* @param array $local_filedata A filespec object created for the local file
*
-* @return object filespec
+* @return array File data array
*/
-function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
+function upload_attachment($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = false)
{
- global $auth, $user, $config, $db, $cache;
- global $phpbb_root_path, $phpEx, $phpbb_dispatcher;
-
- $filedata = array(
- 'error' => array()
- );
-
- include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
- $upload = new fileupload();
-
- if ($config['check_attachment_content'] && isset($config['mime_triggers']))
- {
- $upload->set_disallowed_content(explode('|', $config['mime_triggers']));
- }
- else if (!$config['check_attachment_content'])
- {
- $upload->set_disallowed_content(array());
- }
-
- $filedata['post_attach'] = $local || $upload->is_valid($form_name);
-
- if (!$filedata['post_attach'])
- {
- $filedata['error'][] = $user->lang['NO_UPLOAD_FORM_FOUND'];
- return $filedata;
- }
-
- $extensions = $cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
- $upload->set_allowed_extensions(array_keys($extensions['_allowed_']));
-
- $file = ($local) ? $upload->local_upload($local_storage, $local_filedata, $mimetype_guesser) : $upload->form_upload($form_name, $mimetype_guesser, $plupload);
-
- if ($file->init_error)
- {
- $filedata['post_attach'] = false;
- return $filedata;
- }
-
- // Whether the uploaded file is in the image category
- $is_image = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
-
- if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id))
- {
- // Check Image Size, if it is an image
- if ($is_image)
- {
- $file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']);
- }
-
- // Admins and mods are allowed to exceed the allowed filesize
- if (!empty($extensions[$file->get('extension')]['max_filesize']))
- {
- $allowed_filesize = $extensions[$file->get('extension')]['max_filesize'];
- }
- else
- {
- $allowed_filesize = ($is_message) ? $config['max_filesize_pm'] : $config['max_filesize'];
- }
-
- $file->upload->set_max_filesize($allowed_filesize);
- }
-
- $file->clean_filename('unique', $user->data['user_id'] . '_');
-
- // Are we uploading an image *and* this image being within the image category?
- // Only then perform additional image checks.
- $file->move_file($config['upload_path'], false, !$is_image);
-
- // Do we have to create a thumbnail?
- $filedata['thumbnail'] = ($is_image && $config['img_create_thumbnail']) ? 1 : 0;
-
- if (sizeof($file->error))
- {
- $file->remove();
- $filedata['error'] = array_merge($filedata['error'], $file->error);
- $filedata['post_attach'] = false;
-
- return $filedata;
- }
-
- // Make sure the image category only holds valid images...
- if ($is_image && !$file->is_image())
- {
- $file->remove();
-
- if ($plupload && $plupload->is_active())
- {
- $plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE');
- }
-
- // If this error occurs a user tried to exploit an IE Bug by renaming extensions
- // Since the image category is displaying content inline we need to catch this.
- trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']);
- }
-
- $filedata['filesize'] = $file->get('filesize');
- $filedata['mimetype'] = $file->get('mimetype');
- $filedata['extension'] = $file->get('extension');
- $filedata['physical_filename'] = $file->get('realname');
- $filedata['real_filename'] = $file->get('uploadname');
- $filedata['filetime'] = time();
-
- /**
- * Event to modify uploaded file before submit to the post
- *
- * @event core.modify_uploaded_file
- * @var array filedata Array containing uploaded file data
- * @var bool is_image Flag indicating if the file is an image
- * @since 3.1.0-RC3
- */
- $vars = array(
- 'filedata',
- 'is_image',
- );
- extract($phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars)));
-
- // Check our complete quota
- if ($config['attachment_quota'])
- {
- if ($config['upload_dir_size'] + $file->get('filesize') > $config['attachment_quota'])
- {
- $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
- $filedata['post_attach'] = false;
-
- $file->remove();
-
- return $filedata;
- }
- }
-
- // Check free disk space
- if ($free_space = @disk_free_space($phpbb_root_path . $config['upload_path']))
- {
- if ($free_space <= $file->get('filesize'))
- {
- if ($auth->acl_get('a_'))
- {
- $filedata['error'][] = $user->lang['ATTACH_DISK_FULL'];
- }
- else
- {
- $filedata['error'][] = $user->lang['ATTACH_QUOTA_REACHED'];
- }
- $filedata['post_attach'] = false;
-
- $file->remove();
-
- return $filedata;
- }
- }
-
- // Create Thumbnail
- if ($filedata['thumbnail'])
- {
- $source = $file->get('destination_file');
- $destination = $file->get('destination_path') . '/thumb_' . $file->get('realname');
+ global $phpbb_container;
- if (!create_thumbnail($source, $destination, $file->get('mimetype')))
- {
- $filedata['thumbnail'] = 0;
- }
- }
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $file = $attachment_manager->upload($form_name, $forum_id, $local, $local_storage, $is_message, $local_filedata);
+ unset($attachment_manager);
- return $filedata;
+ return $file;
}
/**
@@ -677,7 +557,7 @@ function get_supported_image_types($type = false)
*/
function create_thumbnail($source, $destination, $mimetype)
{
- global $config;
+ global $config, $phpbb_filesystem, $phpbb_dispatcher;
$min_filesize = (int) $config['img_min_thumb_filesize'];
$img_filesize = (file_exists($source)) ? @filesize($source) : false;
@@ -709,25 +589,31 @@ function create_thumbnail($source, $destination, $mimetype)
return false;
}
- $used_imagick = false;
-
- // Only use ImageMagick if defined and the passthru function not disabled
- if ($config['img_imagick'] && function_exists('passthru'))
- {
- if (substr($config['img_imagick'], -1) !== '/')
- {
- $config['img_imagick'] .= '/';
- }
-
- @passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -quality 85 -geometry ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" "' . str_replace('\\', '/', $destination) . '"');
+ $thumbnail_created = false;
- if (file_exists($destination))
- {
- $used_imagick = true;
- }
- }
+ /**
+ * Create thumbnail event to replace GD thumbnail creation with for example ImageMagick
+ *
+ * @event core.thumbnail_create_before
+ * @var string source Image source path
+ * @var string destination Thumbnail destination path
+ * @var string mimetype Image mime type
+ * @var float new_width Calculated thumbnail width
+ * @var float new_height Calculated thumbnail height
+ * @var bool thumbnail_created Set to true to skip default GD thumbnail creation
+ * @since 3.2.4
+ */
+ $vars = array(
+ 'source',
+ 'destination',
+ 'mimetype',
+ 'new_width',
+ 'new_height',
+ 'thumbnail_created',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.thumbnail_create_before', compact($vars)));
- if (!$used_imagick)
+ if (!$thumbnail_created)
{
$type = get_supported_image_types($type);
@@ -829,7 +715,14 @@ function create_thumbnail($source, $destination, $mimetype)
return false;
}
- phpbb_chmod($destination, CHMOD_READ | CHMOD_WRITE);
+ try
+ {
+ $phpbb_filesystem->phpbb_chmod($destination, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
return true;
}
@@ -841,7 +734,7 @@ function posting_gen_inline_attachments(&$attachment_data)
{
global $template;
- if (sizeof($attachment_data))
+ if (count($attachment_data))
{
$s_inline_attachment_options = '';
@@ -863,21 +756,23 @@ function posting_gen_inline_attachments(&$attachment_data)
*/
function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_attach_box = true)
{
- global $template, $config, $phpbb_root_path, $phpEx, $user;
+ global $template, $config, $phpbb_root_path, $phpEx, $user, $phpbb_dispatcher;
// Some default template variables
$template->assign_vars(array(
'S_SHOW_ATTACH_BOX' => $show_attach_box,
- 'S_HAS_ATTACHMENTS' => sizeof($attachment_data),
+ 'S_HAS_ATTACHMENTS' => count($attachment_data),
'FILESIZE' => $config['max_filesize'],
'FILE_COMMENT' => (isset($filename_data['filecomment'])) ? $filename_data['filecomment'] : '',
));
- if (sizeof($attachment_data))
+ if (count($attachment_data))
{
// We display the posted attachments within the desired order.
($config['display_order']) ? krsort($attachment_data) : ksort($attachment_data);
+ $attachrow_template_vars = [];
+
foreach ($attachment_data as $count => $attach_row)
{
$hidden = '';
@@ -890,7 +785,7 @@ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_a
$download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&amp;id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false);
- $template->assign_block_vars('attach_row', array(
+ $attachrow_template_vars[(int) $attach_row['attach_id']] = array(
'FILENAME' => utf8_basename($attach_row['real_filename']),
'A_FILENAME' => addslashes(utf8_basename($attach_row['real_filename'])),
'FILE_COMMENT' => $attach_row['attach_comment'],
@@ -900,12 +795,25 @@ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_a
'FILESIZE' => get_formatted_filesize($attach_row['filesize']),
'U_VIEW_ATTACHMENT' => $download_link,
- 'S_HIDDEN' => $hidden)
+ 'S_HIDDEN' => $hidden,
);
}
+
+ /**
+ * Modify inline attachments template vars
+ *
+ * @event core.modify_inline_attachments_template_vars
+ * @var array attachment_data Array containing attachments data
+ * @var array attachrow_template_vars Array containing attachments template vars
+ * @since 3.2.2-RC1
+ */
+ $vars = array('attachment_data', 'attachrow_template_vars');
+ extract($phpbb_dispatcher->trigger_event('core.modify_inline_attachments_template_vars', compact($vars)));
+
+ $template->assign_block_vars_array('attach_row', $attachrow_template_vars);
}
- return sizeof($attachment_data);
+ return count($attachment_data);
}
//
@@ -953,13 +861,13 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $ms
}
$db->sql_freeresult($result);
- if (!sizeof($draft_rows))
+ if (!count($draft_rows))
{
return;
}
$topic_rows = array();
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$sql = 'SELECT topic_id, forum_id, topic_title, topic_poster
FROM ' . TOPICS_TABLE . '
@@ -993,7 +901,7 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $ms
foreach ($draft_rows as $draft)
{
$link_topic = $link_forum = $link_pm = false;
- $insert_url = $view_url = $title = '';
+ $view_url = $title = '';
if (isset($topic_rows[$draft['topic_id']])
&& (
@@ -1046,9 +954,10 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $ms
*/
function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true)
{
- global $user, $auth, $db, $template, $cache;
+ global $user, $auth, $db, $template;
global $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
$sql_sort = ($mode == 'post_review') ? 'ASC' : 'DESC';
@@ -1071,7 +980,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
$db->sql_freeresult($result);
- if (!sizeof($post_list))
+ if (!count($post_list))
{
return false;
}
@@ -1105,6 +1014,30 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
AND u.user_id = p.poster_id',
);
+ /**
+ * Event to modify the SQL query for topic reviews
+ *
+ * @event core.topic_review_modify_sql_ary
+ * @var int topic_id The topic ID that is being reviewed
+ * @var int forum_id The topic's forum ID
+ * @var string mode The topic review mode
+ * @var int cur_post_id Post offset ID
+ * @var bool show_quote_button Flag indicating if the quote button should be displayed
+ * @var array post_list Array with the post IDs
+ * @var array sql_ary Array with the SQL query
+ * @since 3.2.8-RC1
+ */
+ $vars = array(
+ 'topic_id',
+ 'forum_id',
+ 'mode',
+ 'cur_post_id',
+ 'show_quote_button',
+ 'post_list',
+ 'sql_ary',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_sql_ary', compact($vars)));
+
$sql = $db->sql_build_query('SELECT', $sql_ary);
$result = $db->sql_query($sql);
@@ -1122,11 +1055,9 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
$db->sql_freeresult($result);
// Grab extensions
- $extensions = $attachments = array();
+ $attachments = array();
if ($has_attachments && $auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
{
- $extensions = $cache->obtain_attach_extensions($forum_id);
-
// Get attachments...
$sql = 'SELECT *
FROM ' . ATTACHMENTS_TABLE . '
@@ -1168,7 +1099,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
);
extract($phpbb_dispatcher->trigger_event('core.topic_review_modify_post_list', compact($vars)));
- for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
+ for ($i = 0, $end = count($post_list); $i < $end; ++$i)
{
// A non-existing rowset only happens if there was no user present for the entered poster_id
// This could be a broken posts table.
@@ -1251,6 +1182,8 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
'MESSAGE' => $message,
'DECODED_MESSAGE' => $decoded_message,
'POST_ID' => $row['post_id'],
+ 'POST_TIME' => $row['post_time'],
+ 'USER_ID' => $row['user_id'],
'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'],
'U_MCP_DETAILS' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&amp;mode=post_details&amp;f=' . $forum_id . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
'POSTER_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes(get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '',
@@ -1315,7 +1248,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
*/
function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '')
{
- global $db, $user, $auth, $phpbb_container, $phpbb_dispatcher;
+ global $db, $user, $phpbb_container, $phpbb_dispatcher;
global $config, $phpEx, $phpbb_root_path;
// Specify our post mode
@@ -1362,6 +1295,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $
$db->sql_freeresult($result);
}
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
// (Soft) delete the post
@@ -1392,7 +1326,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $
foreach ($shadow_forum_ids as $updated_forum => $topic_count)
{
- // counting is fun! we only have to do sizeof($forum_ids) number of queries,
+ // counting is fun! we only have to do count($forum_ids) number of queries,
// even if the topic is moved back to where its shadow lives (we count how many times it is in a forum)
$sql = 'UPDATE ' . FORUMS_TABLE . '
SET forum_topics_approved = forum_topics_approved - ' . $topic_count . '
@@ -1403,7 +1337,6 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $
if ($is_soft)
{
- $topic_row = array();
$phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason);
}
else
@@ -1411,9 +1344,10 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $
delete_topics('topic_id', array($topic_id), false);
$phpbb_content_visibility->remove_topic_from_statistic($data, $sql_data);
+ $config->increment('num_posts', -1, false);
$update_sql = update_post_information('forum', $forum_id, true);
- if (sizeof($update_sql))
+ if (count($update_sql))
{
$sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
$sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
@@ -1462,7 +1396,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $
{
// Update last post information when hard deleting. Soft delete already did that by itself.
$update_sql = update_post_information('forum', $forum_id, true);
- if (sizeof($update_sql))
+ if (count($update_sql))
{
$sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]);
}
@@ -1601,10 +1535,12 @@ function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $
* Submit Post
* @todo Split up and create lightweight, simple API for this.
*/
-function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true, $update_search_index = true)
+function submit_post($mode, $subject, $username, $topic_type, &$poll_ary, &$data_ary, $update_message = true, $update_search_index = true)
{
- global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
+ global $db, $auth, $user, $config, $phpEx, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $phpbb_log, $request;
+ $poll = $poll_ary;
+ $data = $data_ary;
/**
* Modify the data for post submitting
*
@@ -1630,6 +1566,10 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'update_search_index',
);
extract($phpbb_dispatcher->trigger_event('core.modify_submit_post_data', compact($vars)));
+ $poll_ary = $poll;
+ $data_ary = $data;
+ unset($poll);
+ unset($data);
// We do not handle erasing posts here
if ($mode == 'delete')
@@ -1637,9 +1577,9 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
return false;
}
- if (!empty($data['post_time']))
+ if (!empty($data_ary['post_time']))
{
- $current_time = $data['post_time'];
+ $current_time = $data_ary['post_time'];
}
else
{
@@ -1658,31 +1598,31 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
else if ($mode == 'edit')
{
- $post_mode = ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1) ? 'edit_topic' : (($data['topic_first_post_id'] == $data['post_id']) ? 'edit_first_post' : (($data['topic_last_post_id'] == $data['post_id']) ? 'edit_last_post' : 'edit'));
+ $post_mode = ($data_ary['topic_posts_approved'] + $data_ary['topic_posts_unapproved'] + $data_ary['topic_posts_softdeleted'] == 1) ? 'edit_topic' : (($data_ary['topic_first_post_id'] == $data_ary['post_id']) ? 'edit_first_post' : (($data_ary['topic_last_post_id'] == $data_ary['post_id']) ? 'edit_last_post' : 'edit'));
}
// First of all make sure the subject and topic title are having the correct length.
// To achieve this without cutting off between special chars we convert to an array and then count the elements.
$subject = truncate_string($subject, 120);
- $data['topic_title'] = truncate_string($data['topic_title'], 120);
+ $data_ary['topic_title'] = truncate_string($data_ary['topic_title'], 120);
// Collect some basic information about which tables and which rows to update/insert
$sql_data = $topic_row = array();
- $poster_id = ($mode == 'edit') ? $data['poster_id'] : (int) $user->data['user_id'];
+ $poster_id = ($mode == 'edit') ? $data_ary['poster_id'] : (int) $user->data['user_id'];
// Retrieve some additional information if not present
- if ($mode == 'edit' && (!isset($data['post_visibility']) || !isset($data['topic_visibility']) || $data['post_visibility'] === false || $data['topic_visibility'] === false))
+ if ($mode == 'edit' && (!isset($data_ary['post_visibility']) || !isset($data_ary['topic_visibility']) || $data_ary['post_visibility'] === false || $data_ary['topic_visibility'] === false))
{
$sql = 'SELECT p.post_visibility, t.topic_type, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_visibility
FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
WHERE t.topic_id = p.topic_id
- AND p.post_id = ' . $data['post_id'];
+ AND p.post_id = ' . $data_ary['post_id'];
$result = $db->sql_query($sql);
$topic_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- $data['topic_visibility'] = $topic_row['topic_visibility'];
- $data['post_visibility'] = $topic_row['post_visibility'];
+ $data_ary['topic_visibility'] = $topic_row['topic_visibility'];
+ $data_ary['post_visibility'] = $topic_row['post_visibility'];
}
// This variable indicates if the user is able to post or put into the queue
@@ -1690,7 +1630,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
// Check the permissions for post approval.
// Moderators must go through post approval like ordinary users.
- if (!$auth->acl_get('f_noapprove', $data['forum_id']))
+ if (!$auth->acl_get('f_noapprove', $data_ary['forum_id']))
{
// Post not approved, but in queue
$post_visibility = ITEM_UNAPPROVED;
@@ -1704,19 +1644,19 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
break;
}
}
- else if (isset($data['post_visibility']) && $data['post_visibility'] !== false)
+ else if (isset($data_ary['post_visibility']) && $data_ary['post_visibility'] !== false)
{
- $post_visibility = $data['post_visibility'];
+ $post_visibility = $data_ary['post_visibility'];
}
// MODs/Extensions are able to force any visibility on posts
- if (isset($data['force_approved_state']))
+ if (isset($data_ary['force_approved_state']))
{
- $post_visibility = (in_array((int) $data['force_approved_state'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data['force_approved_state'] : $post_visibility;
+ $post_visibility = (in_array((int) $data_ary['force_approved_state'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data_ary['force_approved_state'] : $post_visibility;
}
- if (isset($data['force_visibility']))
+ if (isset($data_ary['force_visibility']))
{
- $post_visibility = (in_array((int) $data['force_visibility'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data['force_visibility'] : $post_visibility;
+ $post_visibility = (in_array((int) $data_ary['force_visibility'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED, ITEM_REAPPROVE))) ? (int) $data_ary['force_visibility'] : $post_visibility;
}
// Start the transaction here
@@ -1728,25 +1668,25 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
case 'post':
case 'reply':
$sql_data[POSTS_TABLE]['sql'] = array(
- 'forum_id' => $data['forum_id'],
+ 'forum_id' => $data_ary['forum_id'],
'poster_id' => (int) $user->data['user_id'],
- 'icon_id' => $data['icon_id'],
+ 'icon_id' => $data_ary['icon_id'],
'poster_ip' => $user->ip,
'post_time' => $current_time,
'post_visibility' => $post_visibility,
- 'enable_bbcode' => $data['enable_bbcode'],
- 'enable_smilies' => $data['enable_smilies'],
- 'enable_magic_url' => $data['enable_urls'],
- 'enable_sig' => $data['enable_sig'],
+ 'enable_bbcode' => $data_ary['enable_bbcode'],
+ 'enable_smilies' => $data_ary['enable_smilies'],
+ 'enable_magic_url' => $data_ary['enable_urls'],
+ 'enable_sig' => $data_ary['enable_sig'],
'post_username' => (!$user->data['is_registered']) ? $username : '',
'post_subject' => $subject,
- 'post_text' => $data['message'],
- 'post_checksum' => $data['message_md5'],
- 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
- 'bbcode_bitfield' => $data['bbcode_bitfield'],
- 'bbcode_uid' => $data['bbcode_uid'],
- 'post_postcount' => ($auth->acl_get('f_postcount', $data['forum_id'])) ? 1 : 0,
- 'post_edit_locked' => $data['post_edit_locked']
+ 'post_text' => $data_ary['message'],
+ 'post_checksum' => $data_ary['message_md5'],
+ 'post_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : 0,
+ 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
+ 'bbcode_uid' => $data_ary['bbcode_uid'],
+ 'post_postcount' => ($auth->acl_get('f_postcount', $data_ary['forum_id'])) ? 1 : 0,
+ 'post_edit_locked' => $data_ary['post_edit_locked']
);
break;
@@ -1763,19 +1703,19 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
// If normal edit display edit info
// Display edit info if edit reason given or user is editing his post, which is not the last within the topic.
- if ($data['post_edit_reason'] || (!$auth->acl_get('m_edit', $data['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post')))
+ if ($data_ary['post_edit_reason'] || (!$auth->acl_get('m_edit', $data_ary['forum_id']) && ($post_mode == 'edit' || $post_mode == 'edit_first_post')))
{
- $data['post_edit_reason'] = truncate_string($data['post_edit_reason'], 255, 255, false);
+ $data_ary['post_edit_reason'] = truncate_string($data_ary['post_edit_reason'], 255, 255, false);
$sql_data[POSTS_TABLE]['sql'] = array(
'post_edit_time' => $current_time,
- 'post_edit_reason' => $data['post_edit_reason'],
- 'post_edit_user' => (int) $data['post_edit_user'],
+ 'post_edit_reason' => $data_ary['post_edit_reason'],
+ 'post_edit_user' => (int) $data_ary['post_edit_user'],
);
$sql_data[POSTS_TABLE]['stat'][] = 'post_edit_count = post_edit_count + 1';
}
- else if (!$data['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data['forum_id']))
+ else if (!$data_ary['post_edit_reason'] && $mode == 'edit' && $auth->acl_get('m_edit', $data_ary['forum_id']))
{
$sql_data[POSTS_TABLE]['sql'] = array(
'post_edit_reason' => '',
@@ -1786,8 +1726,15 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
// Could be simplified by only adding to the log if the edit is not tracked - but this may confuse admins/mods
if ($user->data['user_id'] != $poster_id)
{
- $log_subject = ($subject) ? $subject : $data['topic_title'];
- add_log('mod', $data['forum_id'], $data['topic_id'], 'LOG_POST_EDITED', $log_subject, (!empty($username)) ? $username : $user->lang['GUEST'], $data['post_edit_reason']);
+ $log_subject = ($subject) ? $subject : $data_ary['topic_title'];
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_POST_EDITED', false, array(
+ 'forum_id' => $data_ary['forum_id'],
+ 'topic_id' => $data_ary['topic_id'],
+ 'post_id' => $data_ary['post_id'],
+ $log_subject,
+ (!empty($username)) ? $username : $user->lang['GUEST'],
+ $data_ary['post_edit_reason']
+ ));
}
if (!isset($sql_data[POSTS_TABLE]['sql']))
@@ -1796,32 +1743,31 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
$sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
- 'forum_id' => $data['forum_id'],
- 'poster_id' => $data['poster_id'],
- 'icon_id' => $data['icon_id'],
+ 'forum_id' => $data_ary['forum_id'],
+ 'poster_id' => $data_ary['poster_id'],
+ 'icon_id' => $data_ary['icon_id'],
// We will change the visibility later
//'post_visibility' => $post_visibility,
- 'enable_bbcode' => $data['enable_bbcode'],
- 'enable_smilies' => $data['enable_smilies'],
- 'enable_magic_url' => $data['enable_urls'],
- 'enable_sig' => $data['enable_sig'],
- 'post_username' => ($username && $data['poster_id'] == ANONYMOUS) ? $username : '',
+ 'enable_bbcode' => $data_ary['enable_bbcode'],
+ 'enable_smilies' => $data_ary['enable_smilies'],
+ 'enable_magic_url' => $data_ary['enable_urls'],
+ 'enable_sig' => $data_ary['enable_sig'],
+ 'post_username' => ($username && $data_ary['poster_id'] == ANONYMOUS) ? $username : '',
'post_subject' => $subject,
- 'post_checksum' => $data['message_md5'],
- 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
- 'bbcode_bitfield' => $data['bbcode_bitfield'],
- 'bbcode_uid' => $data['bbcode_uid'],
- 'post_edit_locked' => $data['post_edit_locked'])
+ 'post_checksum' => $data_ary['message_md5'],
+ 'post_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : 0,
+ 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
+ 'bbcode_uid' => $data_ary['bbcode_uid'],
+ 'post_edit_locked' => $data_ary['post_edit_locked'])
);
if ($update_message)
{
- $sql_data[POSTS_TABLE]['sql']['post_text'] = $data['message'];
+ $sql_data[POSTS_TABLE]['sql']['post_text'] = $data_ary['message'];
}
break;
}
- $topic_row = array();
// And the topic ladies and gentlemen
switch ($post_mode)
@@ -1831,8 +1777,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'topic_poster' => (int) $user->data['user_id'],
'topic_time' => $current_time,
'topic_last_view_time' => $current_time,
- 'forum_id' => $data['forum_id'],
- 'icon_id' => $data['icon_id'],
+ 'forum_id' => $data_ary['forum_id'],
+ 'icon_id' => $data_ary['icon_id'],
'topic_posts_approved' => ($post_visibility == ITEM_APPROVED) ? 1 : 0,
'topic_posts_softdeleted' => ($post_visibility == ITEM_DELETED) ? 1 : 0,
'topic_posts_unapproved' => ($post_visibility == ITEM_UNAPPROVED) ? 1 : 0,
@@ -1842,15 +1788,15 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
'topic_first_poster_colour' => $user->data['user_colour'],
'topic_type' => $topic_type,
- 'topic_time_limit' => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data['topic_time_limit'] * 86400) : 0,
- 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : 0,
- 'topic_status' => (isset($data['topic_status'])) ? $data['topic_status'] : ITEM_UNLOCKED,
+ 'topic_time_limit' => $topic_type != POST_NORMAL ? ($data_ary['topic_time_limit'] * 86400) : 0,
+ 'topic_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : 0,
+ 'topic_status' => (isset($data_ary['topic_status'])) ? $data_ary['topic_status'] : ITEM_UNLOCKED,
);
- if (isset($poll['poll_options']) && !empty($poll['poll_options']))
+ if (isset($poll_ary['poll_options']) && !empty($poll_ary['poll_options']))
{
- $poll_start = ($poll['poll_start']) ? $poll['poll_start'] : $current_time;
- $poll_length = $poll['poll_length'] * 86400;
+ $poll_start = ($poll_ary['poll_start']) ? $poll_ary['poll_start'] : $current_time;
+ $poll_length = $poll_ary['poll_length'] * 86400;
if ($poll_length < 0)
{
$poll_start = $poll_start + $poll_length;
@@ -1862,15 +1808,15 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
$sql_data[TOPICS_TABLE]['sql'] = array_merge($sql_data[TOPICS_TABLE]['sql'], array(
- 'poll_title' => $poll['poll_title'],
+ 'poll_title' => $poll_ary['poll_title'],
'poll_start' => $poll_start,
- 'poll_max_options' => $poll['poll_max_options'],
+ 'poll_max_options' => $poll_ary['poll_max_options'],
'poll_length' => $poll_length,
- 'poll_vote_change' => $poll['poll_vote_change'])
+ 'poll_vote_change' => $poll_ary['poll_vote_change'])
);
}
- $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
+ $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
if ($post_visibility == ITEM_APPROVED)
{
@@ -1896,9 +1842,9 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
(($post_visibility == ITEM_APPROVED) ? ', topic_posts_approved = topic_posts_approved + 1' : '') .
(($post_visibility == ITEM_UNAPPROVED) ? ', topic_posts_unapproved = topic_posts_unapproved + 1' : '') .
(($post_visibility == ITEM_DELETED) ? ', topic_posts_softdeleted = topic_posts_softdeleted + 1' : '') .
- ((!empty($data['attachment_data']) || (isset($data['topic_attachment']) && $data['topic_attachment'])) ? ', topic_attachment = 1' : '');
+ ((!empty($data_ary['attachment_data']) || (isset($data_ary['topic_attachment']) && $data_ary['topic_attachment'])) ? ', topic_attachment = 1' : '');
- $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
+ $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data_ary['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
if ($post_visibility == ITEM_APPROVED)
{
@@ -1916,10 +1862,10 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
case 'edit_topic':
case 'edit_first_post':
- if (isset($poll['poll_options']))
+ if (isset($poll_ary['poll_options']))
{
- $poll_start = ($poll['poll_start'] || empty($poll['poll_options'])) ? $poll['poll_start'] : $current_time;
- $poll_length = $poll['poll_length'] * 86400;
+ $poll_start = ($poll_ary['poll_start'] || empty($poll_ary['poll_options'])) ? $poll_ary['poll_start'] : $current_time;
+ $poll_length = $poll_ary['poll_length'] * 86400;
if ($poll_length < 0)
{
$poll_start = $poll_start + $poll_length;
@@ -1932,25 +1878,27 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
$sql_data[TOPICS_TABLE]['sql'] = array(
- 'forum_id' => $data['forum_id'],
- 'icon_id' => $data['icon_id'],
+ 'forum_id' => $data_ary['forum_id'],
+ 'icon_id' => $data_ary['icon_id'],
'topic_title' => $subject,
'topic_first_poster_name' => $username,
'topic_type' => $topic_type,
- 'topic_time_limit' => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data['topic_time_limit'] * 86400) : 0,
- 'poll_title' => (isset($poll['poll_options'])) ? $poll['poll_title'] : '',
- 'poll_start' => (isset($poll['poll_options'])) ? $poll_start : 0,
- 'poll_max_options' => (isset($poll['poll_options'])) ? $poll['poll_max_options'] : 1,
- 'poll_length' => (isset($poll['poll_options'])) ? $poll_length : 0,
- 'poll_vote_change' => (isset($poll['poll_vote_change'])) ? $poll['poll_vote_change'] : 0,
+ 'topic_time_limit' => $topic_type != POST_NORMAL ? ($data_ary['topic_time_limit'] * 86400) : 0,
+ 'poll_title' => (isset($poll_ary['poll_options'])) ? $poll_ary['poll_title'] : '',
+ 'poll_start' => (isset($poll_ary['poll_options'])) ? $poll_start : 0,
+ 'poll_max_options' => (isset($poll_ary['poll_options'])) ? $poll_ary['poll_max_options'] : 1,
+ 'poll_length' => (isset($poll_ary['poll_options'])) ? $poll_length : 0,
+ 'poll_vote_change' => (isset($poll_ary['poll_vote_change'])) ? $poll_ary['poll_vote_change'] : 0,
'topic_last_view_time' => $current_time,
- 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : (isset($data['topic_attachment']) ? $data['topic_attachment'] : 0),
+ 'topic_attachment' => (!empty($data_ary['attachment_data'])) ? 1 : (isset($data_ary['topic_attachment']) ? $data_ary['topic_attachment'] : 0),
);
break;
}
+ $poll = $poll_ary;
+ $data = $data_ary;
/**
* Modify sql query data for post submitting
*
@@ -1974,6 +1922,10 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'username',
);
extract($phpbb_dispatcher->trigger_event('core.submit_post_modify_sql_data', compact($vars)));
+ $poll_ary = $poll;
+ $data_ary = $data;
+ unset($poll);
+ unset($data);
// Submit new topic
if ($post_mode == 'post')
@@ -1982,10 +1934,10 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$db->sql_build_array('INSERT', $sql_data[TOPICS_TABLE]['sql']);
$db->sql_query($sql);
- $data['topic_id'] = $db->sql_nextid();
+ $data_ary['topic_id'] = $db->sql_nextid();
$sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
- 'topic_id' => $data['topic_id'])
+ 'topic_id' => $data_ary['topic_id'])
);
unset($sql_data[TOPICS_TABLE]['sql']);
}
@@ -1996,18 +1948,18 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
if ($post_mode == 'reply')
{
$sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
- 'topic_id' => $data['topic_id'],
+ 'topic_id' => $data_ary['topic_id'],
));
}
$sql = 'INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data[POSTS_TABLE]['sql']);
$db->sql_query($sql);
- $data['post_id'] = $db->sql_nextid();
+ $data_ary['post_id'] = $db->sql_nextid();
if ($post_mode == 'post' || $post_visibility == ITEM_APPROVED)
{
$sql_data[TOPICS_TABLE]['sql'] = array(
- 'topic_last_post_id' => $data['post_id'],
+ 'topic_last_post_id' => $data_ary['post_id'],
'topic_last_post_time' => $current_time,
'topic_last_poster_id' => $sql_data[POSTS_TABLE]['sql']['poster_id'],
'topic_last_poster_name' => ($user->data['user_id'] == ANONYMOUS) ? $sql_data[POSTS_TABLE]['sql']['post_username'] : $user->data['username'],
@@ -2018,7 +1970,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
if ($post_mode == 'post')
{
- $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data['post_id'];
+ $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data_ary['post_id'];
}
// Update total post count and forum information
@@ -2026,11 +1978,11 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
{
if ($post_mode == 'post')
{
- set_config_count('num_topics', 1, true);
+ $config->increment('num_topics', 1, false);
}
- set_config_count('num_posts', 1, true);
+ $config->increment('num_posts', 1, false);
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data['post_id'];
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data_ary['post_id'];
$sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
$sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time;
$sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id'];
@@ -2046,7 +1998,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . '
- WHERE topic_id = ' . $data['topic_id'];
+ WHERE topic_id = ' . $data_ary['topic_id'];
$db->sql_query($sql);
unset($sql_data[TOPICS_TABLE]['sql']);
@@ -2057,14 +2009,14 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
{
$sql = 'UPDATE ' . POSTS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . '
- WHERE post_id = ' . $data['post_id'];
+ WHERE post_id = ' . $data_ary['post_id'];
$db->sql_query($sql);
unset($sql_data[POSTS_TABLE]['sql']);
}
// Update Poll Tables
- if (isset($poll['poll_options']))
+ if (isset($poll_ary['poll_options']))
{
$cur_poll_options = array();
@@ -2072,7 +2024,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
{
$sql = 'SELECT *
FROM ' . POLL_OPTIONS_TABLE . '
- WHERE topic_id = ' . $data['topic_id'] . '
+ WHERE topic_id = ' . $data_ary['topic_id'] . '
ORDER BY poll_option_id';
$result = $db->sql_query($sql);
@@ -2086,25 +2038,25 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$sql_insert_ary = array();
- for ($i = 0, $size = sizeof($poll['poll_options']); $i < $size; $i++)
+ for ($i = 0, $size = count($poll_ary['poll_options']); $i < $size; $i++)
{
- if (strlen(trim($poll['poll_options'][$i])))
+ if (strlen(trim($poll_ary['poll_options'][$i])))
{
if (empty($cur_poll_options[$i]))
{
// If we add options we need to put them to the end to be able to preserve votes...
$sql_insert_ary[] = array(
- 'poll_option_id' => (int) sizeof($cur_poll_options) + 1 + sizeof($sql_insert_ary),
- 'topic_id' => (int) $data['topic_id'],
- 'poll_option_text' => (string) $poll['poll_options'][$i]
+ 'poll_option_id' => (int) count($cur_poll_options) + 1 + count($sql_insert_ary),
+ 'topic_id' => (int) $data_ary['topic_id'],
+ 'poll_option_text' => (string) $poll_ary['poll_options'][$i]
);
}
- else if ($poll['poll_options'][$i] != $cur_poll_options[$i])
+ else if ($poll_ary['poll_options'][$i] != $cur_poll_options[$i])
{
$sql = 'UPDATE ' . POLL_OPTIONS_TABLE . "
- SET poll_option_text = '" . $db->sql_escape($poll['poll_options'][$i]) . "'
+ SET poll_option_text = '" . $db->sql_escape($poll_ary['poll_options'][$i]) . "'
WHERE poll_option_id = " . $cur_poll_options[$i]['poll_option_id'] . '
- AND topic_id = ' . $data['topic_id'];
+ AND topic_id = ' . $data_ary['topic_id'];
$db->sql_query($sql);
}
}
@@ -2112,34 +2064,34 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary);
- if (sizeof($poll['poll_options']) < sizeof($cur_poll_options))
+ if (count($poll_ary['poll_options']) < count($cur_poll_options))
{
$sql = 'DELETE FROM ' . POLL_OPTIONS_TABLE . '
- WHERE poll_option_id > ' . sizeof($poll['poll_options']) . '
- AND topic_id = ' . $data['topic_id'];
+ WHERE poll_option_id > ' . count($poll_ary['poll_options']) . '
+ AND topic_id = ' . $data_ary['topic_id'];
$db->sql_query($sql);
}
// If edited, we would need to reset votes (since options can be re-ordered above, you can't be sure if the change is for changing the text or adding an option
- if ($mode == 'edit' && sizeof($poll['poll_options']) != sizeof($cur_poll_options))
+ if ($mode == 'edit' && count($poll_ary['poll_options']) != count($cur_poll_options))
{
- $db->sql_query('DELETE FROM ' . POLL_VOTES_TABLE . ' WHERE topic_id = ' . $data['topic_id']);
- $db->sql_query('UPDATE ' . POLL_OPTIONS_TABLE . ' SET poll_option_total = 0 WHERE topic_id = ' . $data['topic_id']);
+ $db->sql_query('DELETE FROM ' . POLL_VOTES_TABLE . ' WHERE topic_id = ' . $data_ary['topic_id']);
+ $db->sql_query('UPDATE ' . POLL_OPTIONS_TABLE . ' SET poll_option_total = 0 WHERE topic_id = ' . $data_ary['topic_id']);
}
}
// Submit Attachments
- if (!empty($data['attachment_data']) && $data['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit')))
+ if (!empty($data_ary['attachment_data']) && $data_ary['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit')))
{
$space_taken = $files_added = 0;
$orphan_rows = array();
- foreach ($data['attachment_data'] as $pos => $attach_row)
+ foreach ($data_ary['attachment_data'] as $pos => $attach_row)
{
$orphan_rows[(int) $attach_row['attach_id']] = array();
}
- if (sizeof($orphan_rows))
+ if (count($orphan_rows))
{
$sql = 'SELECT attach_id, filesize, physical_filename
FROM ' . ATTACHMENTS_TABLE . '
@@ -2156,13 +2108,18 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$db->sql_freeresult($result);
}
- foreach ($data['attachment_data'] as $pos => $attach_row)
+ foreach ($data_ary['attachment_data'] as $pos => $attach_row)
{
if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
{
continue;
}
+ if (preg_match('/[\x{10000}-\x{10FFFF}]/u', $attach_row['attach_comment']))
+ {
+ trigger_error('ATTACH_COMMENT_NO_EMOJIS');
+ }
+
if (!$attach_row['is_orphan'])
{
// update entry in db if attachment already stored in db and filespace
@@ -2184,8 +2141,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$files_added++;
$attach_sql = array(
- 'post_msg_id' => $data['post_id'],
- 'topic_id' => $data['topic_id'],
+ 'post_msg_id' => $data_ary['post_id'],
+ 'topic_id' => $data_ary['topic_id'],
'is_orphan' => 0,
'poster_id' => $poster_id,
'attach_comment' => $attach_row['attach_comment'],
@@ -2201,37 +2158,38 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
if ($space_taken && $files_added)
{
- set_config_count('upload_dir_size', $space_taken, true);
- set_config_count('num_files', $files_added, true);
+ $config->increment('upload_dir_size', $space_taken, false);
+ $config->increment('num_files', $files_added, false);
}
}
$first_post_has_topic_info = ($post_mode == 'edit_first_post' &&
- (($post_visibility == ITEM_DELETED && $data['topic_posts_softdeleted'] == 1) ||
- ($post_visibility == ITEM_UNAPPROVED && $data['topic_posts_unapproved'] == 1) ||
- ($post_visibility == ITEM_REAPPROVE && $data['topic_posts_unapproved'] == 1) ||
- ($post_visibility == ITEM_APPROVED && $data['topic_posts_approved'] == 1)));
+ (($post_visibility == ITEM_DELETED && $data_ary['topic_posts_softdeleted'] == 1) ||
+ ($post_visibility == ITEM_UNAPPROVED && $data_ary['topic_posts_unapproved'] == 1) ||
+ ($post_visibility == ITEM_REAPPROVE && $data_ary['topic_posts_unapproved'] == 1) ||
+ ($post_visibility == ITEM_APPROVED && $data_ary['topic_posts_approved'] == 1)));
// Fix the post's and topic's visibility and first/last post information, when the post is edited
- if (($post_mode != 'post' && $post_mode != 'reply') && $data['post_visibility'] != $post_visibility)
+ if (($post_mode != 'post' && $post_mode != 'reply') && $data_ary['post_visibility'] != $post_visibility)
{
// If the post was not approved, it could also be the starter,
// so we sync the starter after approving/restoring, to ensure that the stats are correct
// Same applies for the last post
- $is_starter = ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic' || $data['post_visibility'] != ITEM_APPROVED);
- $is_latest = ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $data['post_visibility'] != ITEM_APPROVED);
+ $is_starter = ($post_mode == 'edit_first_post' || $post_mode == 'edit_topic' || $data_ary['post_visibility'] != ITEM_APPROVED);
+ $is_latest = ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $data_ary['post_visibility'] != ITEM_APPROVED);
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
- $phpbb_content_visibility->set_post_visibility($post_visibility, $data['post_id'], $data['topic_id'], $data['forum_id'], $user->data['user_id'], time(), '', $is_starter, $is_latest);
+ $phpbb_content_visibility->set_post_visibility($post_visibility, $data_ary['post_id'], $data_ary['topic_id'], $data_ary['forum_id'], $user->data['user_id'], time(), '', $is_starter, $is_latest);
}
else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $first_post_has_topic_info)
{
- if ($post_visibility == ITEM_APPROVED || $data['topic_visibility'] == $post_visibility)
+ if ($post_visibility == ITEM_APPROVED || $data_ary['topic_visibility'] == $post_visibility)
{
// only the subject can be changed from edit
$sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
// Maybe not only the subject, but also changing anonymous usernames. ;)
- if ($data['poster_id'] == ANONYMOUS)
+ if ($data_ary['poster_id'] == ANONYMOUS)
{
$sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'";
}
@@ -2242,13 +2200,13 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
// it just means that we might have to
$sql = 'SELECT forum_last_post_id, forum_last_post_subject
FROM ' . FORUMS_TABLE . '
- WHERE forum_id = ' . (int) $data['forum_id'];
+ WHERE forum_id = ' . (int) $data_ary['forum_id'];
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
// this post is the latest post in the forum, better update
- if ($row['forum_last_post_id'] == $data['post_id'] && ($row['forum_last_post_subject'] !== $subject || $data['poster_id'] == ANONYMOUS))
+ if ($row['forum_last_post_id'] == $data_ary['post_id'] && ($row['forum_last_post_subject'] !== $subject || $data_ary['poster_id'] == ANONYMOUS))
{
// the post's subject changed
if ($row['forum_last_post_subject'] !== $subject)
@@ -2257,7 +2215,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
// Update the user name if poster is anonymous... just in case a moderator changed it
- if ($data['poster_id'] == ANONYMOUS)
+ if ($data_ary['poster_id'] == ANONYMOUS)
{
$sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'";
}
@@ -2268,9 +2226,9 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
// Update forum stats
$where_sql = array(
- POSTS_TABLE => 'post_id = ' . $data['post_id'],
- TOPICS_TABLE => 'topic_id = ' . $data['topic_id'],
- FORUMS_TABLE => 'forum_id = ' . $data['forum_id'],
+ POSTS_TABLE => 'post_id = ' . $data_ary['post_id'],
+ TOPICS_TABLE => 'topic_id = ' . $data_ary['topic_id'],
+ FORUMS_TABLE => 'forum_id = ' . $data_ary['forum_id'],
USERS_TABLE => 'user_id = ' . $poster_id
);
@@ -2287,7 +2245,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
if ($topic_type == POST_GLOBAL)
{
$sql = 'DELETE FROM ' . TOPICS_TABLE . '
- WHERE topic_moved_id = ' . $data['topic_id'];
+ WHERE topic_moved_id = ' . $data_ary['topic_id'];
$db->sql_query($sql);
}
@@ -2295,7 +2253,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$db->sql_transaction('commit');
// Delete draft if post was loaded...
- $draft_id = request_var('draft_loaded', 0);
+ $draft_id = $request->variable('draft_loaded', 0);
if ($draft_id)
{
$sql = 'DELETE FROM ' . DRAFTS_TABLE . "
@@ -2305,7 +2263,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
// Index message contents
- if ($update_search_index && $data['enable_indexing'])
+ if ($update_search_index && $data_ary['enable_indexing'])
{
// Select the search method and do some additional checks to ensure it can actually be utilised
$search_type = $config['search_type'];
@@ -2323,23 +2281,23 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
trigger_error($error);
}
- $search->index($mode, $data['post_id'], $data['message'], $subject, $poster_id, $data['forum_id']);
+ $search->index($mode, $data_ary['post_id'], $data_ary['message'], $subject, $poster_id, $data_ary['forum_id']);
}
// Topic Notification, do not change if moderator is changing other users posts...
if ($user->data['user_id'] == $poster_id)
{
- if (!$data['notify_set'] && $data['notify'])
+ if (!$data_ary['notify_set'] && $data_ary['notify'])
{
$sql = 'INSERT INTO ' . TOPICS_WATCH_TABLE . ' (user_id, topic_id)
- VALUES (' . $user->data['user_id'] . ', ' . $data['topic_id'] . ')';
+ VALUES (' . $user->data['user_id'] . ', ' . $data_ary['topic_id'] . ')';
$db->sql_query($sql);
}
- else if (($config['email_enable'] || $config['jab_enable']) && $data['notify_set'] && !$data['notify'])
+ else if (($config['email_enable'] || $config['jab_enable']) && $data_ary['notify_set'] && !$data_ary['notify'])
{
$sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . '
WHERE user_id = ' . $user->data['user_id'] . '
- AND topic_id = ' . $data['topic_id'];
+ AND topic_id = ' . $data_ary['topic_id'];
$db->sql_query($sql);
}
}
@@ -2347,12 +2305,12 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
if ($mode == 'post' || $mode == 'reply' || $mode == 'quote')
{
// Mark this topic as posted to
- markread('post', $data['forum_id'], $data['topic_id']);
+ markread('post', $data_ary['forum_id'], $data_ary['topic_id']);
}
// Mark this topic as read
// We do not use post_time here, this is intended (post_time can have a date in the past if editing a message)
- markread('topic', $data['forum_id'], $data['topic_id'], time());
+ markread('topic', $data_ary['forum_id'], $data_ary['topic_id'], time());
//
if ($config['load_db_lastread'] && $user->data['is_registered'])
@@ -2360,7 +2318,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$sql = 'SELECT mark_time
FROM ' . FORUMS_TRACK_TABLE . '
WHERE user_id = ' . $user->data['user_id'] . '
- AND forum_id = ' . $data['forum_id'];
+ AND forum_id = ' . $data_ary['forum_id'];
$result = $db->sql_query($sql);
$f_mark_time = (int) $db->sql_fetchfield('mark_time');
$db->sql_freeresult($result);
@@ -2375,12 +2333,12 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
// Update forum info
$sql = 'SELECT forum_last_post_time
FROM ' . FORUMS_TABLE . '
- WHERE forum_id = ' . $data['forum_id'];
+ WHERE forum_id = ' . $data_ary['forum_id'];
$result = $db->sql_query($sql);
$forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time');
$db->sql_freeresult($result);
- update_forum_tracking_info($data['forum_id'], $forum_last_post_time, $f_mark_time, false);
+ update_forum_tracking_info($data_ary['forum_id'], $forum_last_post_time, $f_mark_time, false);
}
// If a username was supplied or the poster is a guest, we will use the supplied username.
@@ -2389,15 +2347,29 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username'];
// Send Notifications
- $notification_data = array_merge($data, array(
- 'topic_title' => (isset($data['topic_title'])) ? $data['topic_title'] : $subject,
+ $notification_data = array_merge($data_ary, array(
+ 'topic_title' => (isset($data_ary['topic_title'])) ? $data_ary['topic_title'] : $subject,
'post_username' => $username,
'poster_id' => $poster_id,
- 'post_text' => $data['message'],
+ 'post_text' => $data_ary['message'],
'post_time' => $current_time,
'post_subject' => $subject,
));
+ /**
+ * This event allows you to modify the notification data upon submission
+ *
+ * @event core.modify_submit_notification_data
+ * @var array notification_data The notification data to be inserted in to the database
+ * @var array data_ary The data array with a lot of the post submission data
+ * @var string mode The posting mode
+ * @var int poster_id The poster id
+ * @since 3.2.4-RC1
+ */
+ $vars = array('notification_data', 'data_ary', 'mode', 'poster_id');
+ extract($phpbb_dispatcher->trigger_event('core.modify_submit_notification_data', compact($vars)));
+
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
if ($post_visibility == ITEM_APPROVED)
@@ -2424,8 +2396,14 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
case 'edit_first_post':
case 'edit':
case 'edit_last_post':
+ if ($user->data['user_id'] == $poster_id)
+ {
+ $phpbb_notifications->update_notifications(array(
+ 'notification.type.quote',
+ ), $notification_data);
+ }
+
$phpbb_notifications->update_notifications(array(
- 'notification.type.quote',
'notification.type.bookmark',
'notification.type.topic',
'notification.type.post',
@@ -2502,25 +2480,27 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$params = $add_anchor = '';
if ($post_visibility == ITEM_APPROVED ||
- ($auth->acl_get('m_softdelete', $data['forum_id']) && $post_visibility == ITEM_DELETED) ||
- ($auth->acl_get('m_approve', $data['forum_id']) && in_array($post_visibility, array(ITEM_UNAPPROVED, ITEM_REAPPROVE))))
+ ($auth->acl_get('m_softdelete', $data_ary['forum_id']) && $post_visibility == ITEM_DELETED) ||
+ ($auth->acl_get('m_approve', $data_ary['forum_id']) && in_array($post_visibility, array(ITEM_UNAPPROVED, ITEM_REAPPROVE))))
{
- $params .= '&amp;t=' . $data['topic_id'];
+ $params .= '&amp;t=' . $data_ary['topic_id'];
if ($mode != 'post')
{
- $params .= '&amp;p=' . $data['post_id'];
- $add_anchor = '#p' . $data['post_id'];
+ $params .= '&amp;p=' . $data_ary['post_id'];
+ $add_anchor = '#p' . $data_ary['post_id'];
}
}
else if ($mode != 'post' && $post_mode != 'edit_first_post' && $post_mode != 'edit_topic')
{
- $params .= '&amp;t=' . $data['topic_id'];
+ $params .= '&amp;t=' . $data_ary['topic_id'];
}
$url = (!$params) ? "{$phpbb_root_path}viewforum.$phpEx" : "{$phpbb_root_path}viewtopic.$phpEx";
- $url = append_sid($url, 'f=' . $data['forum_id'] . $params) . $add_anchor;
+ $url = append_sid($url, 'f=' . $data_ary['forum_id'] . $params) . $add_anchor;
+ $poll = $poll_ary;
+ $data = $data_ary;
/**
* This event is used for performing actions directly after a post or topic
* has been submitted. When a new topic is posted, the topic ID is
@@ -2558,6 +2538,10 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'url',
);
extract($phpbb_dispatcher->trigger_event('core.submit_post_end', compact($vars)));
+ $data_ary = $data;
+ $poll_ary = $poll;
+ unset($data);
+ unset($poll);
return $url;
}
@@ -2578,7 +2562,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
*/
function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false)
{
- global $config, $db, $user, $phpEx, $phpbb_root_path;
+ global $config, $db, $user, $phpEx, $phpbb_root_path, $phpbb_log;
if ($bump_time === false)
{
@@ -2657,7 +2641,11 @@ function phpbb_bump_topic($forum_id, $topic_id, $post_data, $bump_time = false)
update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time, false);
}
- add_log('mod', $forum_id, $topic_id, 'LOG_BUMP_TOPIC', $post_data['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_BUMP_TOPIC', false, array(
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ $post_data['topic_title']
+ ));
$url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p={$post_data['topic_last_post_id']}") . "#p{$post_data['topic_last_post_id']}";
@@ -2704,7 +2692,7 @@ function phpbb_upload_popup($forum_style = 0)
function phpbb_handle_post_delete($forum_id, $topic_id, $post_id, &$post_data, $is_soft = false, $delete_reason = '')
{
global $user, $auth, $config, $request;
- global $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $phpbb_root_path, $phpEx, $phpbb_log, $phpbb_dispatcher;
$force_delete_allowed = $force_softdelete_allowed = false;
$perm_check = ($is_soft) ? 'softdelete' : 'delete';
@@ -2768,14 +2756,27 @@ function phpbb_handle_post_delete($forum_id, $topic_id, $post_id, &$post_data, $
if ($next_post_id === false)
{
- add_log('mod', $forum_id, $topic_id, (($is_soft) ? 'LOG_SOFTDELETE_TOPIC' : 'LOG_DELETE_TOPIC'), $post_data['topic_title'], $post_username, $delete_reason);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, (($is_soft) ? 'LOG_SOFTDELETE_TOPIC' : 'LOG_DELETE_TOPIC'), false, array(
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ $post_data['topic_title'],
+ $post_username,
+ $delete_reason
+ ));
$meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id");
$message = $user->lang['POST_DELETED'];
}
else
{
- add_log('mod', $forum_id, $topic_id, (($is_soft) ? 'LOG_SOFTDELETE_POST' : 'LOG_DELETE_POST'), $post_data['post_subject'], $post_username, $delete_reason);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, (($is_soft) ? 'LOG_SOFTDELETE_POST' : 'LOG_DELETE_POST'), false, array(
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ 'post_id' => $post_id,
+ $post_data['post_subject'],
+ $post_username,
+ $delete_reason
+ ));
$meta_info = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p=$next_post_id") . "#p$next_post_id";
$message = $user->lang['POST_DELETED'];
diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php
index 4aad1746d5..f07512d623 100644
--- a/phpBB/includes/functions_privmsgs.php
+++ b/phpBB/includes/functions_privmsgs.php
@@ -226,7 +226,7 @@ function get_folder($user_id, $folder_id = false)
*/
function clean_sentbox($num_sentbox_messages)
{
- global $db, $user, $config;
+ global $db, $user;
// Check Message Limit
if ($user->data['message_limit'] && $num_sentbox_messages > $user->data['message_limit'])
@@ -255,8 +255,6 @@ function clean_sentbox($num_sentbox_messages)
*/
function check_rule(&$rules, &$rule_row, &$message_row, $user_id)
{
- global $user, $config;
-
if (!isset($rules[$rule_row['rule_check']][$rule_row['rule_connection']]))
{
return false;
@@ -335,7 +333,7 @@ function check_rule(&$rules, &$rule_row, &$message_row, $user_id)
break;
case ACTION_DELETE_MESSAGE:
- global $db, $auth;
+ global $db;
// Check for admins/mods - users are not allowed to remove those messages...
// We do the check here to make sure the data we use is consistent
@@ -468,7 +466,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
$user_rules = $db->sql_fetchrowset($result);
$db->sql_freeresult($result);
- if (sizeof($user_rules))
+ if (count($user_rules))
{
$sql = 'SELECT zebra_id, friend, foe
FROM ' . ZEBRA_TABLE . "
@@ -492,7 +490,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
'bcc' => explode(':', $row['bcc_address']),
'friend' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['friend'] : 0,
'foe' => (isset($zebra[$row['author_id']])) ? $zebra[$row['author_id']]['foe'] : 0,
- 'user_in_group' => array($user->data['group_id']),
+ 'user_in_group' => $user->data['group_id'],
'author_in_group' => array())
);
@@ -501,7 +499,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
$db->sql_freeresult($result);
// Retrieve user memberships
- if (sizeof($user_ids))
+ if (count($user_ids))
{
$sql = 'SELECT *
FROM ' . USER_GROUP_TABLE . '
@@ -546,7 +544,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
}
// We place actions into arrays, to save queries.
- $sql = $unread_ids = $delete_ids = $important_ids = array();
+ $unread_ids = $delete_ids = $important_ids = array();
foreach ($action_ary as $msg_id => $msg_ary)
{
@@ -602,14 +600,14 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
// only gone through if new messages arrive.
// Delete messages
- if (sizeof($delete_ids))
+ if (count($delete_ids))
{
- $num_removed += sizeof($delete_ids);
+ $num_removed += count($delete_ids);
delete_pm($user_id, $delete_ids, PRIVMSGS_NO_BOX);
}
// Set messages to Unread
- if (sizeof($unread_ids))
+ if (count($unread_ids))
{
$sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
SET pm_unread = 0
@@ -620,7 +618,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
}
// mark messages as important
- if (sizeof($important_ids))
+ if (count($important_ids))
{
$sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
SET pm_marked = 1 - pm_marked
@@ -633,7 +631,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
// Move into folder
$folder = array();
- if (sizeof($move_into_folder))
+ if (count($move_into_folder))
{
// Determine Full Folder Action - we need the move to folder id later eventually
$full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
@@ -678,12 +676,12 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
// Check Message Limit - we calculate with the complete array, most of the time it is one message
// But we are making sure that the other way around works too (more messages in queue than allowed to be stored)
- if ($user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + sizeof($msg_ary)) > $user->data['message_limit'])
+ if ($user->data['message_limit'] && $folder[$folder_id] && ($folder[$folder_id] + count($msg_ary)) > $user->data['message_limit'])
{
$full_folder_action = ($user->data['user_full_folder'] == FULL_FOLDER_NONE) ? ($config['full_folder_action'] - (FULL_FOLDER_NONE*(-1))) : $user->data['user_full_folder'];
// If destination folder itself is full...
- if ($full_folder_action >= 0 && ($folder[$full_folder_action] + sizeof($msg_ary)) > $user->data['message_limit'])
+ if ($full_folder_action >= 0 && ($folder[$full_folder_action] + count($msg_ary)) > $user->data['message_limit'])
{
$full_folder_action = $config['full_folder_action'] - (FULL_FOLDER_NONE*(-1));
}
@@ -701,7 +699,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
WHERE user_id = $user_id
AND folder_id = $dest_folder
ORDER BY msg_id ASC";
- $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + sizeof($msg_ary)) - $user->data['message_limit']));
+ $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + count($msg_ary)) - $user->data['message_limit']));
$delete_ids = array();
while ($row = $db->sql_fetchrow($result))
@@ -710,7 +708,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
}
$db->sql_freeresult($result);
- $num_removed += sizeof($delete_ids);
+ $num_removed += count($delete_ids);
delete_pm($user_id, $delete_ids, $dest_folder);
}
}
@@ -746,7 +744,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false)
}
}
- if (sizeof($action_ary))
+ if (count($action_ary))
{
// Move from OUTBOX to SENTBOX
// We are not checking any full folder status here... SENTBOX is a special treatment (old messages get deleted)
@@ -787,7 +785,7 @@ function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_fol
$move_msg_ids = array($move_msg_ids);
}
- if (sizeof($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
+ if (count($move_msg_ids) && !in_array($dest_folder, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX, PRIVMSGS_SENTBOX)) &&
!in_array($cur_folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)) && $cur_folder_id != $dest_folder)
{
// We have to check the destination folder ;)
@@ -803,10 +801,11 @@ function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_fol
if (!$row)
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
- if ($message_limit && $row['pm_count'] + sizeof($move_msg_ids) > $message_limit)
+ if ($message_limit && $row['pm_count'] + count($move_msg_ids) > $message_limit)
{
$message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $row['folder_name']) . '<br /><br />';
$message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $row['folder_id']) . '">', '</a>', $row['folder_name']);
@@ -823,7 +822,7 @@ function move_pm($user_id, $message_limit, $move_msg_ids, $dest_folder, $cur_fol
$num_messages = (int) $db->sql_fetchfield('num_messages');
$db->sql_freeresult($result);
- if ($message_limit && $num_messages + sizeof($move_msg_ids) > $message_limit)
+ if ($message_limit && $num_messages + count($move_msg_ids) > $message_limit)
{
$message = sprintf($user->lang['NOT_ENOUGH_SPACE_FOLDER'], $user->lang['PM_INBOX']) . '<br /><br />';
$message .= sprintf($user->lang['CLICK_RETURN_FOLDER'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=inbox') . '">', '</a>', $user->lang['PM_INBOX']);
@@ -881,9 +880,10 @@ function update_unread_status($unread, $msg_id, $user_id, $folder_id)
global $db, $user, $phpbb_container;
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
- $phpbb_notifications->mark_notifications_read('notification.type.pm', $msg_id, $user_id);
+ $phpbb_notifications->mark_notifications('notification.type.pm', $msg_id, $user_id);
$sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
SET pm_unread = 0
@@ -944,13 +944,12 @@ function mark_folder_read($user_id, $folder_id)
*/
function handle_mark_actions($user_id, $mark_action)
{
- global $db, $user, $phpbb_root_path, $phpEx;
+ global $db, $user, $phpbb_root_path, $phpEx, $request;
- $msg_ids = request_var('marked_msg_id', array(0));
- $cur_folder_id = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
- $confirm = (isset($_POST['confirm'])) ? true : false;
+ $msg_ids = $request->variable('marked_msg_id', array(0));
+ $cur_folder_id = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX);
- if (!sizeof($msg_ids))
+ if (!count($msg_ids))
{
return false;
}
@@ -974,6 +973,7 @@ function handle_mark_actions($user_id, $mark_action)
if (!$auth->acl_get('u_pm_delete'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_DELETE_MESSAGE');
}
@@ -981,7 +981,7 @@ function handle_mark_actions($user_id, $mark_action)
{
delete_pm($user_id, $msg_ids, $cur_folder_id);
- $success_msg = (sizeof($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
+ $success_msg = (count($msg_ids) == 1) ? 'MESSAGE_DELETED' : 'MESSAGES_DELETED';
$redirect = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;folder=' . $cur_folder_id);
meta_refresh(3, $redirect);
@@ -1013,7 +1013,7 @@ function handle_mark_actions($user_id, $mark_action)
*/
function delete_pm($user_id, $msg_ids, $folder_id)
{
- global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
+ global $db, $user, $phpbb_container, $phpbb_dispatcher;
$user_id = (int) $user_id;
$folder_id = (int) $folder_id;
@@ -1032,7 +1032,7 @@ function delete_pm($user_id, $msg_ids, $folder_id)
$msg_ids = array($msg_ids);
}
- if (!sizeof($msg_ids))
+ if (!count($msg_ids))
{
return false;
}
@@ -1069,7 +1069,7 @@ function delete_pm($user_id, $msg_ids, $folder_id)
$db->sql_freeresult($result);
unset($msg_ids);
- if (!sizeof($delete_rows))
+ if (!count($delete_rows))
{
return false;
}
@@ -1137,6 +1137,7 @@ function delete_pm($user_id, $msg_ids, $folder_id)
$user->data['user_unread_privmsg'] -= $num_unread;
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->delete_notifications('notification.type.pm', array_keys($delete_rows));
@@ -1155,15 +1156,13 @@ function delete_pm($user_id, $msg_ids, $folder_id)
$delete_ids = array_keys($delete_rows);
- if (sizeof($delete_ids))
+ if (count($delete_ids))
{
// Check if there are any attachments we need to remove
- if (!function_exists('delete_attachments'))
- {
- include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
- }
-
- delete_attachments('message', $delete_ids, false);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $attachment_manager->delete('message', $delete_ids, false);
+ unset($attachment_manager);
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
@@ -1184,8 +1183,6 @@ function delete_pm($user_id, $msg_ids, $folder_id)
*/
function phpbb_delete_user_pms($user_id)
{
- global $db, $user, $phpbb_root_path, $phpEx;
-
$user_id = (int) $user_id;
if (!$user_id)
@@ -1205,7 +1202,7 @@ function phpbb_delete_user_pms($user_id)
*/
function phpbb_delete_users_pms($user_ids)
{
- global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
+ global $db, $phpbb_container;
$user_id_sql = $db->sql_in_set('user_id', $user_ids);
$author_id_sql = $db->sql_in_set('author_id', $user_ids);
@@ -1250,6 +1247,7 @@ function phpbb_delete_users_pms($user_ids)
$db->sql_transaction('begin');
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
if (!empty($undelivered_msg))
@@ -1291,7 +1289,7 @@ function phpbb_delete_users_pms($user_ids)
$num_pms = (int) $row['num_undelivered_privmsgs'];
$undelivered_user[$num_pms][] = (int) $row['user_id'];
- if (sizeof($undelivered_user[$num_pms]) > 50)
+ if (count($undelivered_user[$num_pms]) > 50)
{
// If there are too many users affected the query might get
// too long, so we update the value for the first bunch here.
@@ -1367,12 +1365,10 @@ function phpbb_delete_users_pms($user_ids)
if (!empty($delete_ids))
{
// Check if there are any attachments we need to remove
- if (!function_exists('delete_attachments'))
- {
- include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
- }
-
- delete_attachments('message', $delete_ids, false);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $attachment_manager->delete('message', $delete_ids, false);
+ unset($attachment_manager);
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
@@ -1404,8 +1400,6 @@ function phpbb_delete_users_pms($user_ids)
*/
function rebuild_header($check_ary)
{
- global $db;
-
$address = array();
foreach ($check_ary as $check_type => $address_field)
@@ -1422,7 +1416,7 @@ function rebuild_header($check_ary)
$_types = array('u', 'g');
foreach ($_types as $type)
{
- if (sizeof(${$type}))
+ if (count(${$type}))
{
foreach (${$type} as $id)
{
@@ -1440,7 +1434,10 @@ function rebuild_header($check_ary)
*/
function write_pm_addresses($check_ary, $author_id, $plaintext = false)
{
- global $db, $user, $template, $phpbb_root_path, $phpEx;
+ global $db, $user, $template, $phpbb_root_path, $phpEx, $phpbb_container;
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
$addresses = array();
@@ -1464,7 +1461,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false)
}
$address = array();
- if (sizeof($u))
+ if (count($u))
{
$sql = 'SELECT user_id, username, user_colour
FROM ' . USERS_TABLE . '
@@ -1488,7 +1485,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false)
$db->sql_freeresult($result);
}
- if (sizeof($g))
+ if (count($g))
{
if ($plaintext)
{
@@ -1501,7 +1498,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false)
{
if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
{
- $address[] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $address[] = $group_helper->get_name($row['group_name']);
}
}
$db->sql_freeresult($result);
@@ -1521,7 +1518,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false)
{
if ($check_type == 'to' || $author_id == $user->data['user_id'] || $row['user_id'] == $user->data['user_id'])
{
- $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $row['group_name'] = $group_helper->get_name($row['group_name']);
$address['group'][$row['group_id']] = array('name' => $row['group_name'], 'colour' => $row['group_colour']);
}
}
@@ -1535,7 +1532,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false)
}
}
- if (sizeof($address) && !$plaintext)
+ if (count($address) && !$plaintext)
{
$template->assign_var('S_' . strtoupper($check_type) . '_RECIPIENT', true);
@@ -1582,7 +1579,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false)
*/
function get_folder_status($folder_id, $folder)
{
- global $db, $user, $config;
+ global $user;
if (isset($folder[$folder_id]))
{
@@ -1613,9 +1610,9 @@ function get_folder_status($folder_id, $folder)
/**
* Submit PM
*/
-function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
+function submit_pm($mode, $subject, &$data_ary, $put_in_outbox = true)
{
- global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher;
+ global $db, $auth, $config, $user, $phpbb_root_path, $phpbb_container, $phpbb_dispatcher, $request;
// We do not handle erasing pms here
if ($mode == 'delete')
@@ -1625,6 +1622,7 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$current_time = time();
+ $data = $data_ary;
/**
* Get all parts of the PM that are to be submited to the DB.
*
@@ -1636,6 +1634,8 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
*/
$vars = array('mode', 'subject', 'data');
extract($phpbb_dispatcher->trigger_event('core.submit_pm_before', compact($vars)));
+ $data_ary = $data;
+ unset($data);
// Collect some basic information about which tables and which rows to update/insert
$sql_data = array();
@@ -1651,9 +1651,9 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$_types = array('u', 'g');
foreach ($_types as $ug_type)
{
- if (isset($data['address_list'][$ug_type]) && sizeof($data['address_list'][$ug_type]))
+ if (isset($data_ary['address_list'][$ug_type]) && count($data_ary['address_list'][$ug_type]))
{
- foreach ($data['address_list'][$ug_type] as $id => $field)
+ foreach ($data_ary['address_list'][$ug_type] as $id => $field)
{
$id = (int) $id;
@@ -1673,7 +1673,7 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
}
}
- if (isset($data['address_list']['g']) && sizeof($data['address_list']['g']))
+ if (isset($data_ary['address_list']['g']) && count($data_ary['address_list']['g']))
{
// We need to check the PM status of group members (do they want to receive PM's?)
// Only check if not a moderator or admin, since they are allowed to override this user setting
@@ -1681,7 +1681,7 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$sql = 'SELECT u.user_type, ug.group_id, ug.user_id
FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . ' ug
- WHERE ' . $db->sql_in_set('ug.group_id', array_keys($data['address_list']['g'])) . '
+ WHERE ' . $db->sql_in_set('ug.group_id', array_keys($data_ary['address_list']['g'])) . '
AND ug.user_pending = 0
AND u.user_id = ug.user_id
AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')' .
@@ -1690,13 +1690,13 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
while ($row = $db->sql_fetchrow($result))
{
- $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
+ $field = ($data_ary['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc';
$recipients[$row['user_id']] = $field;
}
$db->sql_freeresult($result);
}
- if (!sizeof($recipients))
+ if (!count($recipients))
{
trigger_error('NO_RECIPIENT');
}
@@ -1713,13 +1713,13 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
{
case 'reply':
case 'quote':
- $root_level = ($data['reply_from_root_level']) ? $data['reply_from_root_level'] : $data['reply_from_msg_id'];
+ $root_level = ($data_ary['reply_from_root_level']) ? $data_ary['reply_from_root_level'] : $data_ary['reply_from_msg_id'];
// Set message_replied switch for this user
$sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . '
SET pm_replied = 1
- WHERE user_id = ' . $data['from_user_id'] . '
- AND msg_id = ' . $data['reply_from_msg_id'];
+ WHERE user_id = ' . $data_ary['from_user_id'] . '
+ AND msg_id = ' . $data_ary['reply_from_msg_id'];
// no break
@@ -1728,19 +1728,19 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
case 'quotepost':
$sql_data = array(
'root_level' => $root_level,
- 'author_id' => $data['from_user_id'],
- 'icon_id' => $data['icon_id'],
- 'author_ip' => $data['from_user_ip'],
+ 'author_id' => $data_ary['from_user_id'],
+ 'icon_id' => $data_ary['icon_id'],
+ 'author_ip' => $data_ary['from_user_ip'],
'message_time' => $current_time,
- 'enable_bbcode' => $data['enable_bbcode'],
- 'enable_smilies' => $data['enable_smilies'],
- 'enable_magic_url' => $data['enable_urls'],
- 'enable_sig' => $data['enable_sig'],
+ 'enable_bbcode' => $data_ary['enable_bbcode'],
+ 'enable_smilies' => $data_ary['enable_smilies'],
+ 'enable_magic_url' => $data_ary['enable_urls'],
+ 'enable_sig' => $data_ary['enable_sig'],
'message_subject' => $subject,
- 'message_text' => $data['message'],
- 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
- 'bbcode_bitfield' => $data['bbcode_bitfield'],
- 'bbcode_uid' => $data['bbcode_uid'],
+ 'message_text' => $data_ary['message'],
+ 'message_attachment'=> (!empty($data_ary['attachment_data'])) ? 1 : 0,
+ 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
+ 'bbcode_uid' => $data_ary['bbcode_uid'],
'to_address' => implode(':', $to),
'bcc_address' => implode(':', $bcc),
'message_reported' => 0,
@@ -1749,35 +1749,33 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
case 'edit':
$sql_data = array(
- 'icon_id' => $data['icon_id'],
+ 'icon_id' => $data_ary['icon_id'],
'message_edit_time' => $current_time,
- 'enable_bbcode' => $data['enable_bbcode'],
- 'enable_smilies' => $data['enable_smilies'],
- 'enable_magic_url' => $data['enable_urls'],
- 'enable_sig' => $data['enable_sig'],
+ 'enable_bbcode' => $data_ary['enable_bbcode'],
+ 'enable_smilies' => $data_ary['enable_smilies'],
+ 'enable_magic_url' => $data_ary['enable_urls'],
+ 'enable_sig' => $data_ary['enable_sig'],
'message_subject' => $subject,
- 'message_text' => $data['message'],
- 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0,
- 'bbcode_bitfield' => $data['bbcode_bitfield'],
- 'bbcode_uid' => $data['bbcode_uid']
+ 'message_text' => $data_ary['message'],
+ 'message_attachment'=> (!empty($data_ary['attachment_data'])) ? 1 : 0,
+ 'bbcode_bitfield' => $data_ary['bbcode_bitfield'],
+ 'bbcode_uid' => $data_ary['bbcode_uid']
);
break;
}
- if (sizeof($sql_data))
+ if (count($sql_data))
{
- $query = '';
-
if ($mode == 'post' || $mode == 'reply' || $mode == 'quote' || $mode == 'quotepost' || $mode == 'forward')
{
$db->sql_query('INSERT INTO ' . PRIVMSGS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data));
- $data['msg_id'] = $db->sql_nextid();
+ $data_ary['msg_id'] = $db->sql_nextid();
}
else if ($mode == 'edit')
{
$sql = 'UPDATE ' . PRIVMSGS_TABLE . '
SET message_edit_count = message_edit_count + 1, ' . $db->sql_build_array('UPDATE', $sql_data) . '
- WHERE msg_id = ' . $data['msg_id'];
+ WHERE msg_id = ' . $data_ary['msg_id'];
$db->sql_query($sql);
}
}
@@ -1794,9 +1792,9 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
foreach ($recipients as $user_id => $type)
{
$sql_ary[] = array(
- 'msg_id' => (int) $data['msg_id'],
+ 'msg_id' => (int) $data_ary['msg_id'],
'user_id' => (int) $user_id,
- 'author_id' => (int) $data['from_user_id'],
+ 'author_id' => (int) $data_ary['from_user_id'],
'folder_id' => PRIVMSGS_NO_BOX,
'pm_new' => 1,
'pm_unread' => 1,
@@ -1815,9 +1813,9 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
if ($put_in_outbox)
{
$db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', array(
- 'msg_id' => (int) $data['msg_id'],
- 'user_id' => (int) $data['from_user_id'],
- 'author_id' => (int) $data['from_user_id'],
+ 'msg_id' => (int) $data_ary['msg_id'],
+ 'user_id' => (int) $data_ary['from_user_id'],
+ 'author_id' => (int) $data_ary['from_user_id'],
'folder_id' => PRIVMSGS_OUTBOX,
'pm_new' => 0,
'pm_unread' => 0,
@@ -1831,22 +1829,22 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
{
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_lastpost_time = $current_time
- WHERE user_id = " . $data['from_user_id'];
+ WHERE user_id = " . $data_ary['from_user_id'];
$db->sql_query($sql);
}
// Submit Attachments
- if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
+ if (!empty($data_ary['attachment_data']) && $data_ary['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward')))
{
$space_taken = $files_added = 0;
$orphan_rows = array();
- foreach ($data['attachment_data'] as $pos => $attach_row)
+ foreach ($data_ary['attachment_data'] as $pos => $attach_row)
{
$orphan_rows[(int) $attach_row['attach_id']] = array();
}
- if (sizeof($orphan_rows))
+ if (count($orphan_rows))
{
$sql = 'SELECT attach_id, filesize, physical_filename
FROM ' . ATTACHMENTS_TABLE . '
@@ -1864,7 +1862,7 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$db->sql_freeresult($result);
}
- foreach ($data['attachment_data'] as $pos => $attach_row)
+ foreach ($data_ary['attachment_data'] as $pos => $attach_row)
{
if ($attach_row['is_orphan'] && !isset($orphan_rows[$attach_row['attach_id']]))
{
@@ -1892,10 +1890,10 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$files_added++;
$attach_sql = array(
- 'post_msg_id' => $data['msg_id'],
+ 'post_msg_id' => $data_ary['msg_id'],
'topic_id' => 0,
'is_orphan' => 0,
- 'poster_id' => $data['from_user_id'],
+ 'poster_id' => $data_ary['from_user_id'],
'attach_comment' => $attach_row['attach_comment'],
);
@@ -1909,29 +1907,30 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
if ($space_taken && $files_added)
{
- set_config_count('upload_dir_size', $space_taken, true);
- set_config_count('num_files', $files_added, true);
+ $config->increment('upload_dir_size', $space_taken, false);
+ $config->increment('num_files', $files_added, false);
}
}
// Delete draft if post was loaded...
- $draft_id = request_var('draft_loaded', 0);
+ $draft_id = $request->variable('draft_loaded', 0);
if ($draft_id)
{
$sql = 'DELETE FROM ' . DRAFTS_TABLE . "
WHERE draft_id = $draft_id
- AND user_id = " . $data['from_user_id'];
+ AND user_id = " . $data_ary['from_user_id'];
$db->sql_query($sql);
}
$db->sql_transaction('commit');
// Send Notifications
- $pm_data = array_merge($data, array(
+ $pm_data = array_merge($data_ary, array(
'message_subject' => $subject,
'recipients' => $recipients,
));
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
if ($mode == 'edit')
@@ -1943,6 +1942,7 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$phpbb_notifications->add_notifications('notification.type.pm', $pm_data);
}
+ $data = $data_ary;
/**
* Get PM message ID after submission to DB
*
@@ -1955,8 +1955,10 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
*/
$vars = array('mode', 'subject', 'data', 'pm_data');
extract($phpbb_dispatcher->trigger_event('core.submit_pm_after', compact($vars)));
+ $data_ary = $data;
+ unset($data);
- return $data['msg_id'];
+ return $data_ary['msg_id'];
}
/**
@@ -1964,7 +1966,7 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
*/
function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode = false)
{
- global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth;
+ global $db, $user, $template, $phpbb_root_path, $phpEx, $auth, $phpbb_dispatcher;
// Select all receipts and the author from the pm we currently view, to only display their pm-history
$sql = 'SELECT author_id, user_id
@@ -1983,9 +1985,7 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode
$recipients = array_unique($recipients);
// Get History Messages (could be newer)
- $sql = 'SELECT t.*, p.*, u.*
- FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u
- WHERE t.msg_id = p.msg_id
+ $sql_where = 't.msg_id = p.msg_id
AND p.author_id = u.user_id
AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ')
AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . "
@@ -1996,13 +1996,37 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode
if (!$message_row['root_level'])
{
- $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
+ $sql_where .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))";
}
else
{
- $sql .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
+ $sql_where .= " AND (p.root_level = " . $message_row['root_level'] . ' OR p.msg_id = ' . $message_row['root_level'] . ')';
}
- $sql .= ' ORDER BY p.message_time DESC';
+
+ $sql_ary = array(
+ 'SELECT' => 't.*, p.*, u.*',
+ 'FROM' => array(
+ PRIVMSGS_TABLE => 'p',
+ PRIVMSGS_TO_TABLE => 't',
+ USERS_TABLE => 'u'
+ ),
+ 'LEFT_JOIN' => array(),
+ 'WHERE' => $sql_where,
+ 'ORDER_BY' => 'p.message_time DESC',
+ );
+
+ /**
+ * Event to modify the SQL query before the message history in private message is queried
+ *
+ * @event core.message_history_modify_sql_ary
+ * @var array sql_ary The SQL array to get the data of the message history in private message
+ * @since 3.2.8-RC1
+ */
+ $vars = array('sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.message_history_modify_sql_ary', compact($vars)));
+
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ unset($sql_ary);
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
@@ -2036,7 +2060,7 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode
while ($row = $db->sql_fetchrow($result));
$db->sql_freeresult($result);
- if (sizeof($rowset) == 1 && !$in_post_mode)
+ if (count($rowset) == 1 && !$in_post_mode)
{
return false;
}
@@ -2049,7 +2073,7 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode
// Re-order rowset to be able to get the next/prev message rows...
$rowset = array_values($rowset);
- for ($i = 0, $size = sizeof($rowset); $i < $size; $i++)
+ for ($i = 0, $size = count($rowset); $i < $size; $i++)
{
$row = &$rowset[$i];
$id = (int) $row['msg_id'];
@@ -2085,7 +2109,7 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode
$previous_history_pm = $prev_id;
}
- $template->assign_block_vars('history_row', array(
+ $template_vars = array(
'MESSAGE_AUTHOR_QUOTE' => (($decoded_message) ? addslashes(get_username_string('username', $author_id, $row['username'], $row['user_colour'], $row['username'])) : ''),
'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $row['username'], $row['user_colour'], $row['username']),
'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $row['username'], $row['user_colour'], $row['username']),
@@ -2103,10 +2127,29 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode
'S_IN_POST_MODE' => $in_post_mode,
'MSG_ID' => $row['msg_id'],
+ 'MESSAGE_TIME' => $row['message_time'],
+ 'USER_ID' => $row['user_id'],
'U_VIEW_MESSAGE' => "$url&amp;f=$folder_id&amp;p=" . $row['msg_id'],
'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&amp;mode=compose&amp;action=quote&amp;f=" . $folder_id . "&amp;p=" . $row['msg_id'] : '',
- 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&amp;mode=compose&amp;action=reply&amp;f=$folder_id&amp;p=" . $row['msg_id'] : '')
+ 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&amp;mode=compose&amp;action=reply&amp;f=$folder_id&amp;p=" . $row['msg_id'] : ''
+ );
+
+ /**
+ * Modify the template vars for displaying the message history in private message
+ *
+ * @event core.message_history_modify_template_vars
+ * @var array template_vars Array containing the query
+ * @var array row Array containing the action user row
+ * @since 3.2.8-RC1
+ */
+ $vars = array(
+ 'template_vars',
+ 'row',
);
+ extract($phpbb_dispatcher->trigger_event('core.message_history_modify_template_vars', compact($vars)));
+
+ $template->assign_block_vars('history_row', $template_vars);
+
unset($rowset[$i]);
$prev_id = $id;
}
@@ -2130,17 +2173,41 @@ function set_user_message_limit()
{
global $user, $db, $config;
- // Get maximum about from user memberships - if it is 0, there is no limit set and we use the maximum value within the config.
- $sql = 'SELECT MAX(g.group_message_limit) as max_message_limit
+ // Get maximum about from user memberships
+ $message_limit = phpbb_get_max_setting_from_group($db, $user->data['user_id'], 'message_limit');
+
+ // If it is 0, there is no limit set and we use the maximum value within the config.
+ $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
+}
+
+/**
+ * Get the maximum PM setting for the groups of the user
+ *
+ * @param \phpbb\db\driver\driver_interface $db
+ * @param int $user_id
+ * @param string $setting Only 'max_recipients' and 'message_limit' are supported
+ * @return int The maximum setting for all groups of the user, unless one group has '0'
+ * @throws \InvalidArgumentException If selected group setting is not supported
+ */
+function phpbb_get_max_setting_from_group(\phpbb\db\driver\driver_interface $db, $user_id, $setting)
+{
+ if ($setting !== 'max_recipients' && $setting !== 'message_limit')
+ {
+ throw new InvalidArgumentException('Setting "' . $setting . '" is not supported');
+ }
+
+ // Get maximum number of allowed recipients
+ $sql = 'SELECT MAX(g.group_' . $setting . ') as max_setting
FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
- WHERE ug.user_id = ' . $user->data['user_id'] . '
+ WHERE ug.user_id = ' . (int) $user_id . '
AND ug.user_pending = 0
AND ug.group_id = g.group_id';
$result = $db->sql_query($sql);
- $message_limit = (int) $db->sql_fetchfield('max_message_limit');
+ $row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
+ $max_setting = (int) $row['max_setting'];
- $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit;
+ return $max_setting;
}
/**
@@ -2154,7 +2221,10 @@ function set_user_message_limit()
*/
function get_recipient_strings($pm_by_id)
{
- global $db, $phpbb_root_path, $phpEx, $user;
+ global $db, $phpbb_root_path, $phpEx, $user, $phpbb_container;
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
$address_list = $recipient_list = $address = array();
@@ -2166,7 +2236,7 @@ function get_recipient_strings($pm_by_id)
foreach ($_types as $ug_type)
{
- if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type]))
+ if (isset($address[$message_id][$ug_type]) && count($address[$message_id][$ug_type]))
{
foreach ($address[$message_id][$ug_type] as $ug_id => $in_to)
{
@@ -2200,7 +2270,7 @@ function get_recipient_strings($pm_by_id)
{
if ($ug_type == 'g')
{
- $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name'];
+ $row['name'] = $group_helper->get_name($row['name']);
}
$recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
diff --git a/phpBB/includes/functions_transfer.php b/phpBB/includes/functions_transfer.php
index 42fdee364c..7427b89917 100644
--- a/phpBB/includes/functions_transfer.php
+++ b/phpBB/includes/functions_transfer.php
@@ -38,7 +38,7 @@ class transfer
/**
* Constructor - init some basic values
*/
- function transfer()
+ function __construct()
{
global $phpbb_root_path;
@@ -112,7 +112,7 @@ class transfer
$dir = explode('/', $dir);
$dirs = '';
- for ($i = 0, $total = sizeof($dir); $i < $total; $i++)
+ for ($i = 0, $total = count($dir); $i < $total; $i++)
{
$result = true;
@@ -264,7 +264,7 @@ class ftp extends transfer
/**
* Standard parameters for FTP session
*/
- function ftp($host, $username, $password, $root_path, $port = 21, $timeout = 10)
+ function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10)
{
$this->host = $host;
$this->port = $port;
@@ -406,9 +406,6 @@ class ftp extends transfer
*/
function _put($from_file, $to_file)
{
- // get the file extension
- $file_extension = strtolower(substr(strrchr($to_file, '.'), 1));
-
// We only use the BINARY file mode to cicumvent rewrite actions from ftp server (mostly linefeeds being replaced)
$mode = FTP_BINARY;
@@ -515,7 +512,7 @@ class ftp_fsock extends transfer
/**
* Standard parameters for FTP session
*/
- function ftp_fsock($host, $username, $password, $root_path, $port = 21, $timeout = 10)
+ function __construct($host, $username, $password, $root_path, $port = 21, $timeout = 10)
{
$this->host = $host;
$this->port = $port;
@@ -532,7 +529,7 @@ class ftp_fsock extends transfer
}
// Init some needed values
- $this->transfer();
+ parent::__construct();
return;
}
diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php
deleted file mode 100644
index 1aac0e803c..0000000000
--- a/phpBB/includes/functions_upload.php
+++ /dev/null
@@ -1,1118 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Responsible for holding all file relevant information, as well as doing file-specific operations.
-* The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on.
-*/
-class filespec
-{
- var $filename = '';
- var $realname = '';
- var $uploadname = '';
- var $mimetype = '';
- var $extension = '';
- var $filesize = 0;
- var $width = 0;
- var $height = 0;
- var $image_info = array();
-
- var $destination_file = '';
- var $destination_path = '';
-
- var $file_moved = false;
- var $init_error = false;
- var $local = false;
-
- var $error = array();
-
- var $upload = '';
-
- /**
- * The plupload object
- * @var \phpbb\plupload\plupload
- */
- protected $plupload;
-
- /**
- * phpBB Mimetype guesser
- * @var \phpbb\mimetype\guesser
- */
- protected $mimetype_guesser;
-
- /**
- * File Class
- * @access private
- */
- function filespec($upload_ary, $upload_namespace, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
- {
- if (!isset($upload_ary))
- {
- $this->init_error = true;
- return;
- }
-
- $this->filename = $upload_ary['tmp_name'];
- $this->filesize = $upload_ary['size'];
- $name = (STRIP) ? stripslashes($upload_ary['name']) : $upload_ary['name'];
- $name = trim(utf8_basename($name));
- $this->realname = $this->uploadname = $name;
- $this->mimetype = $upload_ary['type'];
-
- // Opera adds the name to the mime type
- $this->mimetype = (strpos($this->mimetype, '; name') !== false) ? str_replace(strstr($this->mimetype, '; name'), '', $this->mimetype) : $this->mimetype;
-
- if (!$this->mimetype)
- {
- $this->mimetype = 'application/octet-stream';
- }
-
- $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;
-
- $this->width = $this->height = 0;
- $this->file_moved = false;
-
- $this->local = (isset($upload_ary['local_mode'])) ? true : false;
- $this->upload = $upload_namespace;
- $this->plupload = $plupload;
- $this->mimetype_guesser = $mimetype_guesser;
- }
-
- /**
- * Cleans destination filename
- *
- * @param real|unique|unique_ext $mode real creates a realname, filtering some characters, lowering every character. Unique creates an unique filename
- * @param string $prefix Prefix applied to filename
- * @param string $user_id The user_id is only needed for when cleaning a user's avatar
- * @access public
- */
- function clean_filename($mode = 'unique', $prefix = '', $user_id = '')
- {
- if ($this->init_error)
- {
- return;
- }
-
- switch ($mode)
- {
- case 'real':
- // Remove every extension from filename (to not let the mime bug being exposed)
- if (strpos($this->realname, '.') !== false)
- {
- $this->realname = substr($this->realname, 0, strpos($this->realname, '.'));
- }
-
- // Replace any chars which may cause us problems with _
- $bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|');
-
- $this->realname = rawurlencode(str_replace($bad_chars, '_', strtolower($this->realname)));
- $this->realname = preg_replace("/%(\w{2})/", '_', $this->realname);
-
- $this->realname = $prefix . $this->realname . '.' . $this->extension;
- break;
-
- case 'unique':
- $this->realname = $prefix . md5(unique_id());
- break;
-
- case 'avatar':
- $this->extension = strtolower($this->extension);
- $this->realname = $prefix . $user_id . '.' . $this->extension;
-
- break;
-
- case 'unique_ext':
- default:
- $this->realname = $prefix . md5(unique_id()) . '.' . $this->extension;
- break;
- }
- }
-
- /**
- * Get property from file object
- */
- function get($property)
- {
- if ($this->init_error || !isset($this->$property))
- {
- return false;
- }
-
- return $this->$property;
- }
-
- /**
- * Check if file is an image (mimetype)
- *
- * @return true if it is an image, false if not
- */
- function is_image()
- {
- return (strpos($this->mimetype, 'image/') === 0);
- }
-
- /**
- * Check if the file got correctly uploaded
- *
- * @return true if it is a valid upload, false if not
- */
- function is_uploaded()
- {
- $is_plupload = $this->plupload && $this->plupload->is_active();
-
- if (!$this->local && !$is_plupload && !is_uploaded_file($this->filename))
- {
- return false;
- }
-
- if (($this->local || $is_plupload) && !file_exists($this->filename))
- {
- return false;
- }
-
- return true;
- }
-
- /**
- * Remove file
- */
- function remove()
- {
- if ($this->file_moved)
- {
- @unlink($this->destination_file);
- }
- }
-
- /**
- * Get file extension
- *
- * @param string Filename that needs to be checked
- * @return string Extension of the supplied filename
- */
- static public function get_extension($filename)
- {
- $filename = utf8_basename($filename);
-
- if (strpos($filename, '.') === false)
- {
- return '';
- }
-
- $filename = explode('.', $filename);
- return array_pop($filename);
- }
-
- /**
- * Get mimetype
- *
- * @param string $filename Filename that needs to be checked
- * @return string Mimetype of supplied filename
- */
- function get_mimetype($filename)
- {
- if ($this->mimetype_guesser !== null)
- {
- $mimetype = $this->mimetype_guesser->guess($filename, $this->uploadname);
-
- if ($mimetype !== 'application/octet-stream')
- {
- $this->mimetype = $mimetype;
- }
- }
-
- return $this->mimetype;
- }
-
- /**
- * Get filesize
- */
- function get_filesize($filename)
- {
- return @filesize($filename);
- }
-
-
- /**
- * Check the first 256 bytes for forbidden content
- */
- function check_content($disallowed_content)
- {
- if (empty($disallowed_content))
- {
- return true;
- }
-
- $fp = @fopen($this->filename, 'rb');
-
- if ($fp !== false)
- {
- $ie_mime_relevant = fread($fp, 256);
- fclose($fp);
- foreach ($disallowed_content as $forbidden)
- {
- if (stripos($ie_mime_relevant, '<' . $forbidden) !== false)
- {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Move file to destination folder
- * The phpbb_root_path variable will be applied to the destination path
- *
- * @param string $destination Destination path, for example $config['avatar_path']
- * @param bool $overwrite If set to true, an already existing file will be overwritten
- * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped
- * @param string $chmod Permission mask for chmodding the file after a successful move. The mode entered here reflects the mode defined by {@link phpbb_chmod()}
- *
- * @access public
- */
- function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false)
- {
- global $user, $phpbb_root_path;
-
- if (sizeof($this->error))
- {
- return false;
- }
-
- $chmod = ($chmod === false) ? CHMOD_READ | CHMOD_WRITE : $chmod;
-
- // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it...
- $this->destination_path = $phpbb_root_path . $destination;
-
- // Check if the destination path exist...
- if (!file_exists($this->destination_path))
- {
- @unlink($this->filename);
- return false;
- }
-
- $upload_mode = (@ini_get('open_basedir') || @ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'on') ? 'move' : 'copy';
- $upload_mode = ($this->local) ? 'local' : $upload_mode;
- $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname);
-
- // Check if the file already exist, else there is something wrong...
- if (file_exists($this->destination_file) && !$overwrite)
- {
- @unlink($this->filename);
- $this->error[] = $user->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
- $this->file_moved = false;
- return false;
- }
- else
- {
- if (file_exists($this->destination_file))
- {
- @unlink($this->destination_file);
- }
-
- switch ($upload_mode)
- {
- case 'copy':
-
- if (!@copy($this->filename, $this->destination_file))
- {
- if (!@move_uploaded_file($this->filename, $this->destination_file))
- {
- $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
- }
- }
-
- break;
-
- case 'move':
-
- if (!@move_uploaded_file($this->filename, $this->destination_file))
- {
- if (!@copy($this->filename, $this->destination_file))
- {
- $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
- }
- }
-
- break;
-
- case 'local':
-
- if (!@copy($this->filename, $this->destination_file))
- {
- $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file);
- }
-
- break;
- }
-
- // Remove temporary filename
- @unlink($this->filename);
-
- if (sizeof($this->error))
- {
- return false;
- }
-
- phpbb_chmod($this->destination_file, $chmod);
- }
-
- // Try to get real filesize from destination folder
- $this->filesize = (@filesize($this->destination_file)) ? @filesize($this->destination_file) : $this->filesize;
-
- // Get mimetype of supplied file
- $this->mimetype = $this->get_mimetype($this->destination_file);
-
- if ($this->is_image() && !$skip_image_check)
- {
- $this->width = $this->height = 0;
-
- if (($this->image_info = @getimagesize($this->destination_file)) !== false)
- {
- $this->width = $this->image_info[0];
- $this->height = $this->image_info[1];
-
- if (!empty($this->image_info['mime']))
- {
- $this->mimetype = $this->image_info['mime'];
- }
-
- // Check image type
- $types = fileupload::image_types();
-
- if (!isset($types[$this->image_info[2]]) || !in_array($this->extension, $types[$this->image_info[2]]))
- {
- if (!isset($types[$this->image_info[2]]))
- {
- $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_INVALID'], $this->image_info[2], $this->mimetype);
- }
- else
- {
- $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$this->image_info[2]][0], $this->extension);
- }
- }
-
- // Make sure the dimensions match a valid image
- if (empty($this->width) || empty($this->height))
- {
- $this->error[] = $user->lang['ATTACHED_IMAGE_NOT_IMAGE'];
- }
- }
- else
- {
- $this->error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- }
- }
-
- $this->file_moved = true;
- $this->additional_checks();
- unset($this->upload);
-
- return true;
- }
-
- /**
- * Performing additional checks
- */
- function additional_checks()
- {
- global $user;
-
- if (!$this->file_moved)
- {
- return false;
- }
-
- // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
- if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0))
- {
- $max_filesize = get_formatted_filesize($this->upload->max_filesize, false);
-
- $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
-
- return false;
- }
-
- if (!$this->upload->valid_dimensions($this))
- {
- $this->error[] = $user->lang($this->upload->error_prefix . 'WRONG_SIZE',
- $user->lang('PIXELS', (int) $this->upload->min_width),
- $user->lang('PIXELS', (int) $this->upload->min_height),
- $user->lang('PIXELS', (int) $this->upload->max_width),
- $user->lang('PIXELS', (int) $this->upload->max_height),
- $user->lang('PIXELS', (int) $this->width),
- $user->lang('PIXELS', (int) $this->height));
-
- return false;
- }
-
- return true;
- }
-}
-
-/**
-* Class for assigning error messages before a real filespec class can be assigned
-*/
-class fileerror extends filespec
-{
- function fileerror($error_msg)
- {
- $this->error[] = $error_msg;
- }
-}
-
-/**
-* File upload class
-* Init class (all parameters optional and able to be set/overwritten separately) - scope is global and valid for all uploads
-*/
-class fileupload
-{
- var $allowed_extensions = array();
- var $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title');
- var $max_filesize = 0;
- var $min_width = 0;
- var $min_height = 0;
- var $max_width = 0;
- var $max_height = 0;
- var $error_prefix = '';
-
- /** @var int Timeout for remote upload */
- var $upload_timeout = 6;
-
- /**
- * Init file upload class.
- *
- * @param string $error_prefix Used error messages will get prefixed by this string
- * @param array $allowed_extensions Array of allowed extensions, for example array('jpg', 'jpeg', 'gif', 'png')
- * @param int $max_filesize Maximum filesize
- * @param int $min_width Minimum image width (only checked for images)
- * @param int $min_height Minimum image height (only checked for images)
- * @param int $max_width Maximum image width (only checked for images)
- * @param int $max_height Maximum image height (only checked for images)
- * @param bool|array $disallowed_content If enabled, the first 256 bytes of the file must not
- * contain any of its values. Defaults to false.
- *
- */
- function fileupload($error_prefix = '', $allowed_extensions = false, $max_filesize = false, $min_width = false, $min_height = false, $max_width = false, $max_height = false, $disallowed_content = false)
- {
- $this->set_allowed_extensions($allowed_extensions);
- $this->set_max_filesize($max_filesize);
- $this->set_allowed_dimensions($min_width, $min_height, $max_width, $max_height);
- $this->set_error_prefix($error_prefix);
- $this->set_disallowed_content($disallowed_content);
- }
-
- /**
- * Reset vars
- */
- function reset_vars()
- {
- $this->max_filesize = 0;
- $this->min_width = $this->min_height = $this->max_width = $this->max_height = 0;
- $this->error_prefix = '';
- $this->allowed_extensions = array();
- $this->disallowed_content = array();
- }
-
- /**
- * Set allowed extensions
- */
- function set_allowed_extensions($allowed_extensions)
- {
- if ($allowed_extensions !== false && is_array($allowed_extensions))
- {
- $this->allowed_extensions = $allowed_extensions;
- }
- }
-
- /**
- * Set allowed dimensions
- */
- function set_allowed_dimensions($min_width, $min_height, $max_width, $max_height)
- {
- $this->min_width = (int) $min_width;
- $this->min_height = (int) $min_height;
- $this->max_width = (int) $max_width;
- $this->max_height = (int) $max_height;
- }
-
- /**
- * Set maximum allowed filesize
- */
- function set_max_filesize($max_filesize)
- {
- if ($max_filesize !== false && (int) $max_filesize)
- {
- $this->max_filesize = (int) $max_filesize;
- }
- }
-
- /**
- * Set disallowed strings
- */
- function set_disallowed_content($disallowed_content)
- {
- if ($disallowed_content !== false && is_array($disallowed_content))
- {
- $this->disallowed_content = array_diff($disallowed_content, array(''));
- }
- }
-
- /**
- * Set error prefix
- */
- function set_error_prefix($error_prefix)
- {
- $this->error_prefix = $error_prefix;
- }
-
- /**
- * Form upload method
- * Upload file from users harddisk
- *
- * @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified)
- * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser
- * @param \phpbb\plupload\plupload $plupload The plupload object
- *
- * @return object $file Object "filespec" is returned, all further operations can be done with this object
- * @access public
- */
- function form_upload($form_name, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
- {
- global $user, $request;
-
- $upload = $request->file($form_name);
- unset($upload['local_mode']);
-
- if ($plupload)
- {
- $result = $plupload->handle_upload($form_name);
- if (is_array($result))
- {
- $upload = array_merge($upload, $result);
- }
- }
-
- $file = new filespec($upload, $this, $mimetype_guesser, $plupload);
-
- if ($file->init_error)
- {
- $file->error[] = '';
- return $file;
- }
-
- // Error array filled?
- if (isset($upload['error']))
- {
- $error = $this->assign_internal_error($upload['error']);
-
- if ($error !== false)
- {
- $file->error[] = $error;
- return $file;
- }
- }
-
- // Check if empty file got uploaded (not catched by is_uploaded_file)
- if (isset($upload['size']) && $upload['size'] == 0)
- {
- $file->error[] = $user->lang[$this->error_prefix . 'EMPTY_FILEUPLOAD'];
- return $file;
- }
-
- // PHP Upload filesize exceeded
- if ($file->get('filename') == 'none')
- {
- $max_filesize = @ini_get('upload_max_filesize');
- $unit = 'MB';
-
- if (!empty($max_filesize))
- {
- $unit = strtolower(substr($max_filesize, -1, 1));
- $max_filesize = (int) $max_filesize;
-
- $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
- }
-
- $file->error[] = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
- return $file;
- }
-
- // Not correctly uploaded
- if (!$file->is_uploaded())
- {
- $file->error[] = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
- return $file;
- }
-
- $this->common_checks($file);
-
- return $file;
- }
-
- /**
- * Move file from another location to phpBB
- */
- function local_upload($source_file, $filedata = false, \phpbb\mimetype\guesser $mimetype_guesser = null)
- {
- global $user, $request;
-
- $upload = array();
-
- $upload['local_mode'] = true;
- $upload['tmp_name'] = $source_file;
-
- if ($filedata === false)
- {
- $upload['name'] = utf8_basename($source_file);
- $upload['size'] = 0;
- }
- else
- {
- $upload['name'] = $filedata['realname'];
- $upload['size'] = $filedata['size'];
- $upload['type'] = $filedata['type'];
- }
-
- $file = new filespec($upload, $this, $mimetype_guesser);
-
- if ($file->init_error)
- {
- $file->error[] = '';
- return $file;
- }
-
- if (isset($upload['error']))
- {
- $error = $this->assign_internal_error($upload['error']);
-
- if ($error !== false)
- {
- $file->error[] = $error;
- return $file;
- }
- }
-
- // PHP Upload filesize exceeded
- if ($file->get('filename') == 'none')
- {
- $max_filesize = @ini_get('upload_max_filesize');
- $unit = 'MB';
-
- if (!empty($max_filesize))
- {
- $unit = strtolower(substr($max_filesize, -1, 1));
- $max_filesize = (int) $max_filesize;
-
- $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
- }
-
- $file->error[] = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
- return $file;
- }
-
- // Not correctly uploaded
- if (!$file->is_uploaded())
- {
- $file->error[] = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
- return $file;
- }
-
- $this->common_checks($file);
- $request->overwrite('local', $upload, \phpbb\request\request_interface::FILES);
-
- return $file;
- }
-
- /**
- * Remote upload method
- * Uploads file from given url
- *
- * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif
- * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser
- * @return object $file Object "filespec" is returned, all further operations can be done with this object
- * @access public
- */
- function remote_upload($upload_url, \phpbb\mimetype\guesser $mimetype_guesser = null)
- {
- global $user, $phpbb_root_path;
-
- $upload_ary = array();
- $upload_ary['local_mode'] = true;
-
- if (!preg_match('#^(https?://).*?\.(' . implode('|', $this->allowed_extensions) . ')$#i', $upload_url, $match))
- {
- $file = new fileerror($user->lang[$this->error_prefix . 'URL_INVALID']);
- return $file;
- }
-
- if (empty($match[2]))
- {
- $file = new fileerror($user->lang[$this->error_prefix . 'URL_INVALID']);
- return $file;
- }
-
- $url = parse_url($upload_url);
-
- $default_port = 80;
- $hostname = $url['host'];
-
- if ($url['scheme'] == 'https')
- {
- $default_port = 443;
- $hostname = 'tls://' . $url['host'];
- }
-
- $host = $url['host'];
- $path = $url['path'];
- $port = (!empty($url['port'])) ? (int) $url['port'] : $default_port;
-
- $upload_ary['type'] = 'application/octet-stream';
-
- $url['path'] = explode('.', $url['path']);
- $ext = array_pop($url['path']);
-
- $url['path'] = implode('', $url['path']);
- $upload_ary['name'] = utf8_basename($url['path']) . (($ext) ? '.' . $ext : '');
- $filename = $url['path'];
- $filesize = 0;
-
- $remote_max_filesize = $this->max_filesize;
- if (!$remote_max_filesize)
- {
- $max_filesize = @ini_get('upload_max_filesize');
-
- if (!empty($max_filesize))
- {
- $unit = strtolower(substr($max_filesize, -1, 1));
- $remote_max_filesize = (int) $max_filesize;
-
- switch ($unit)
- {
- case 'g':
- $remote_max_filesize *= 1024;
- // no break
- case 'm':
- $remote_max_filesize *= 1024;
- // no break
- case 'k':
- $remote_max_filesize *= 1024;
- // no break
- }
- }
- }
-
- $errno = 0;
- $errstr = '';
-
- if (!($fsock = @fsockopen($hostname, $port, $errno, $errstr)))
- {
- $file = new fileerror($user->lang[$this->error_prefix . 'NOT_UPLOADED']);
- return $file;
- }
-
- // Make sure $path not beginning with /
- if (strpos($path, '/') === 0)
- {
- $path = substr($path, 1);
- }
-
- fputs($fsock, 'GET /' . $path . " HTTP/1.1\r\n");
- fputs($fsock, "HOST: " . $host . "\r\n");
- fputs($fsock, "Connection: close\r\n\r\n");
-
- // Set a proper timeout for the socket
- socket_set_timeout($fsock, $this->upload_timeout);
-
- $get_info = false;
- $data = '';
- $length = false;
- $timer_stop = time() + $this->upload_timeout;
-
- while ((!$length || $filesize < $length) && !@feof($fsock))
- {
- if ($get_info)
- {
- if ($length)
- {
- // Don't attempt to read past end of file if server indicated length
- $block = @fread($fsock, min($length - $filesize, 1024));
- }
- else
- {
- $block = @fread($fsock, 1024);
- }
-
- $filesize += strlen($block);
-
- if ($remote_max_filesize && $filesize > $remote_max_filesize)
- {
- $max_filesize = get_formatted_filesize($remote_max_filesize, false);
-
- $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']));
- return $file;
- }
-
- $data .= $block;
- }
- else
- {
- $line = @fgets($fsock, 1024);
-
- if ($line == "\r\n")
- {
- $get_info = true;
- }
- else
- {
- if (stripos($line, 'content-type: ') !== false)
- {
- $upload_ary['type'] = rtrim(str_replace('content-type: ', '', strtolower($line)));
- }
- else if ($this->max_filesize && stripos($line, 'content-length: ') !== false)
- {
- $length = (int) str_replace('content-length: ', '', strtolower($line));
-
- if ($remote_max_filesize && $length && $length > $remote_max_filesize)
- {
- $max_filesize = get_formatted_filesize($remote_max_filesize, false);
-
- $file = new fileerror(sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']));
- return $file;
- }
- }
- else if (stripos($line, '404 not found') !== false)
- {
- $file = new fileerror($user->lang[$this->error_prefix . 'URL_NOT_FOUND']);
- return $file;
- }
- }
- }
-
- $stream_meta_data = stream_get_meta_data($fsock);
-
- // Cancel upload if we exceed timeout
- if (!empty($stream_meta_data['timed_out']) || time() >= $timer_stop)
- {
- $file = new fileerror($user->lang[$this->error_prefix . 'REMOTE_UPLOAD_TIMEOUT']);
- return $file;
- }
- }
- @fclose($fsock);
-
- if (empty($data))
- {
- $file = new fileerror($user->lang[$this->error_prefix . 'EMPTY_REMOTE_DATA']);
- return $file;
- }
-
- $tmp_path = (!@ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'off') ? sys_get_temp_dir() : $phpbb_root_path . 'cache';
- $filename = tempnam($tmp_path, unique_id() . '-');
-
- if (!($fp = @fopen($filename, 'wb')))
- {
- $file = new fileerror($user->lang[$this->error_prefix . 'NOT_UPLOADED']);
- return $file;
- }
-
- $upload_ary['size'] = fwrite($fp, $data);
- fclose($fp);
- unset($data);
-
- $upload_ary['tmp_name'] = $filename;
-
- $file = new filespec($upload_ary, $this, $mimetype_guesser);
- $this->common_checks($file);
-
- return $file;
- }
-
- /**
- * Assign internal error
- * @access private
- */
- function assign_internal_error($errorcode)
- {
- global $user;
-
- switch ($errorcode)
- {
- case 1:
- $max_filesize = @ini_get('upload_max_filesize');
- $unit = 'MB';
-
- if (!empty($max_filesize))
- {
- $unit = strtolower(substr($max_filesize, -1, 1));
- $max_filesize = (int) $max_filesize;
-
- $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
- }
-
- $error = (empty($max_filesize)) ? $user->lang[$this->error_prefix . 'PHP_SIZE_NA'] : sprintf($user->lang[$this->error_prefix . 'PHP_SIZE_OVERRUN'], $max_filesize, $user->lang[$unit]);
- break;
-
- case 2:
- $max_filesize = get_formatted_filesize($this->max_filesize, false);
-
- $error = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
- break;
-
- case 3:
- $error = $user->lang[$this->error_prefix . 'PARTIAL_UPLOAD'];
- break;
-
- case 4:
- $error = $user->lang[$this->error_prefix . 'NOT_UPLOADED'];
- break;
-
- case 6:
- $error = 'Temporary folder could not be found. Please check your PHP installation.';
- break;
-
- default:
- $error = false;
- break;
- }
-
- return $error;
- }
-
- /**
- * Perform common checks
- */
- function common_checks(&$file)
- {
- global $user;
-
- // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
- if ($this->max_filesize && ($file->get('filesize') > $this->max_filesize || $file->get('filesize') == 0))
- {
- $max_filesize = get_formatted_filesize($this->max_filesize, false);
-
- $file->error[] = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']);
- }
-
- // check Filename
- if (preg_match("#[\\/:*?\"<>|]#i", $file->get('realname')))
- {
- $file->error[] = sprintf($user->lang[$this->error_prefix . 'INVALID_FILENAME'], $file->get('realname'));
- }
-
- // Invalid Extension
- if (!$this->valid_extension($file))
- {
- $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_EXTENSION'], $file->get('extension'));
- }
-
- // MIME Sniffing
- if (!$this->valid_content($file))
- {
- $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_CONTENT']);
- }
- }
-
- /**
- * Check for allowed extension
- */
- function valid_extension(&$file)
- {
- return (in_array($file->get('extension'), $this->allowed_extensions)) ? true : false;
- }
-
- /**
- * Check for allowed dimension
- */
- function valid_dimensions(&$file)
- {
- if (!$this->max_width && !$this->max_height && !$this->min_width && !$this->min_height)
- {
- return true;
- }
-
- if (($file->get('width') > $this->max_width && $this->max_width) ||
- ($file->get('height') > $this->max_height && $this->max_height) ||
- ($file->get('width') < $this->min_width && $this->min_width) ||
- ($file->get('height') < $this->min_height && $this->min_height))
- {
- return false;
- }
-
- return true;
- }
-
- /**
- * Check if form upload is valid
- */
- function is_valid($form_name)
- {
- global $request;
- $upload = $request->file($form_name);
-
- return (!empty($upload) && $upload['name'] !== 'none');
- }
-
-
- /**
- * Check for bad content (IE mime-sniffing)
- */
- function valid_content(&$file)
- {
- return ($file->check_content($this->disallowed_content));
- }
-
- /**
- * Get image type/extension mapping
- *
- * @return array Array containing the image types and their extensions
- */
- static public function image_types()
- {
- $result = 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_IFF => array('iff'),
- IMAGETYPE_WBMP => array('wbmp'),
- IMAGETYPE_XBM => array('xbm'),
- );
-
- if (defined('IMAGETYPE_SWC'))
- {
- $result[IMAGETYPE_SWC] = array('swc');
- }
-
- return $result;
- }
-}
diff --git a/phpBB/includes/functions_url_matcher.php b/phpBB/includes/functions_url_matcher.php
deleted file mode 100644
index b965046aad..0000000000
--- a/phpBB/includes/functions_url_matcher.php
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
-use Symfony\Component\Routing\Matcher\UrlMatcher;
-use Symfony\Component\Routing\RequestContext;
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Create a new UrlMatcher class and dump it into the cache file
-*
-* @param \phpbb\extension\manager $manager Extension manager
-* @param RequestContext $context Symfony RequestContext object
-* @param string $root_path Root path
-* @param string $php_ext PHP file extension
-* @return null
-*/
-function phpbb_get_url_matcher(\phpbb\extension\manager $manager, RequestContext $context, $root_path, $php_ext)
-{
- if (defined('DEBUG'))
- {
- return phpbb_create_url_matcher($manager, $context, $root_path);
- }
-
- if (!phpbb_url_matcher_dumped($root_path, $php_ext))
- {
- phpbb_create_dumped_url_matcher($manager, $root_path, $php_ext);
- }
-
- return phpbb_load_url_matcher($context, $root_path, $php_ext);
-}
-
-/**
-* Create a new UrlMatcher class and dump it into the cache file
-*
-* @param \phpbb\extension\manager $manager Extension manager
-* @param string $root_path Root path
-* @param string $php_ext PHP file extension
-* @return null
-*/
-function phpbb_create_dumped_url_matcher(\phpbb\extension\manager $manager, $root_path, $php_ext)
-{
- $provider = new \phpbb\controller\provider();
- $provider->find_routing_files($manager->get_finder());
- $routes = $provider->find($root_path)->get_routes();
- $dumper = new PhpMatcherDumper($routes);
- $cached_url_matcher_dump = $dumper->dump(array(
- 'class' => 'phpbb_url_matcher',
- ));
-
- file_put_contents($root_path . 'cache/url_matcher.' . $php_ext, $cached_url_matcher_dump);
-}
-
-/**
-* Create a non-cached UrlMatcher
-*
-* @param \phpbb\extension\manager $manager Extension manager
-* @param RequestContext $context Symfony RequestContext object
-* @return UrlMatcher
-*/
-function phpbb_create_url_matcher(\phpbb\extension\manager $manager, RequestContext $context, $root_path)
-{
- $provider = new \phpbb\controller\provider();
- $provider->find_routing_files($manager->get_finder());
- $routes = $provider->find($root_path)->get_routes();
- return new UrlMatcher($routes, $context);
-}
-
-/**
-* Load the cached phpbb_url_matcher class
-*
-* @param RequestContext $context Symfony RequestContext object
-* @param string $root_path Root path
-* @param string $php_ext PHP file extension
-* @return phpbb_url_matcher
-*/
-function phpbb_load_url_matcher(RequestContext $context, $root_path, $php_ext)
-{
- require($root_path . 'cache/url_matcher.' . $php_ext);
- return new phpbb_url_matcher($context);
-}
-
-/**
-* Determine whether we have our dumped URL matcher
-*
-* The class is automatically dumped to the cache directory
-*
-* @param string $root_path Root path
-* @param string $php_ext PHP file extension
-* @return bool True if it exists, false if not
-*/
-function phpbb_url_matcher_dumped($root_path, $php_ext)
-{
- return file_exists($root_path . 'cache/url_matcher.' . $php_ext);
-}
diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php
index 4aecbff6ba..e0b6a9d0c6 100644
--- a/phpBB/includes/functions_user.php
+++ b/phpBB/includes/functions_user.php
@@ -26,8 +26,10 @@ if (!defined('IN_PHPBB'))
* @param array &$user_id_ary The user ids to check or empty if usernames used
* @param array &$username_ary The usernames to check or empty if user ids used
* @param mixed $user_type Array of user types to check, false if not restricting by user type
+* @param boolean $update_references If false, the supplied array is unset and appears unchanged from where it was called
+* @return boolean|string Returns false on success, error string on failure
*/
-function user_get_id_name(&$user_id_ary, &$username_ary, $user_type = false)
+function user_get_id_name(&$user_id_ary, &$username_ary, $user_type = false, $update_references = false)
{
global $db;
@@ -50,7 +52,13 @@ function user_get_id_name(&$user_id_ary, &$username_ary, $user_type = false)
}
$sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', ${$which_ary}) : array_map('utf8_clean_string', ${$which_ary});
- unset(${$which_ary});
+
+ // By unsetting the array here, the values passed in at the point user_get_id_name() was called will be retained.
+ // Otherwise, if we don't unset (as the array was passed by reference) the original array will be updated below.
+ if ($update_references === false)
+ {
+ unset(${$which_ary});
+ }
$user_id_ary = $username_ary = array();
@@ -89,7 +97,7 @@ function user_get_id_name(&$user_id_ary, &$username_ary, $user_type = false)
*/
function update_last_username()
{
- global $db;
+ global $config, $db;
// Get latest username
$sql = 'SELECT user_id, username, user_colour
@@ -102,9 +110,9 @@ function update_last_username()
if ($row)
{
- set_config('newest_user_id', $row['user_id'], true);
- set_config('newest_username', $row['username'], true);
- set_config('newest_user_colour', $row['user_colour'], true);
+ $config->set('newest_user_id', $row['user_id'], false);
+ $config->set('newest_username', $row['username'], false);
+ $config->set('newest_user_colour', $row['user_colour'], false);
}
}
@@ -148,7 +156,7 @@ function user_update_name($old_name, $new_name)
if ($config['newest_username'] == $old_name)
{
- set_config('newest_username', $new_name, true);
+ $config->set('newest_username', $new_name, false);
}
/**
@@ -170,13 +178,13 @@ function user_update_name($old_name, $new_name)
* Adds an user
*
* @param mixed $user_row An array containing the following keys (and the appropriate values): username, group_id (the group to place the user in), user_email and the user_type(usually 0). Additional entries not overridden by defaults will be forwarded.
-* @param string $cp_data custom profile fields, see custom_profile::build_insert_sql_array
+* @param array $cp_data custom profile fields, see custom_profile::build_insert_sql_array
* @param array $notifications_data The notifications settings for the new user
* @return the new user's ID.
*/
function user_add($user_row, $cp_data = false, $notifications_data = null)
{
- global $db, $user, $auth, $config, $phpbb_root_path, $phpEx;
+ global $db, $config;
global $phpbb_dispatcher, $phpbb_container;
if (empty($user_row['username']) || !isset($user_row['group_id']) || !isset($user_row['user_email']) || !isset($user_row['user_type']))
@@ -260,7 +268,7 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
$remaining_vars = array_diff(array_keys($user_row), array_keys($sql_ary));
// Now fill our sql array with the remaining vars
- if (sizeof($remaining_vars))
+ if (count($remaining_vars))
{
foreach ($remaining_vars as $key)
{
@@ -272,8 +280,8 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
* Use this event to modify the values to be inserted when a user is added
*
* @event core.user_add_modify_data
- * @var array user_row Array of user details submited to user_add
- * @var array cp_data Array of Custom profile fields submited to user_add
+ * @var array user_row Array of user details submitted to user_add
+ * @var array cp_data Array of Custom profile fields submitted to user_add
* @var array sql_ary Array of data to be inserted when a user is added
* @var array notifications_data Array of notification data to be inserted when a user is added
* @since 3.1.0-a1
@@ -289,10 +297,11 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
$user_id = $db->sql_nextid();
// Insert Custom Profile Fields
- if ($cp_data !== false && sizeof($cp_data))
+ if ($cp_data !== false && count($cp_data))
{
$cp_data['user_id'] = (int) $user_id;
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' .
$db->sql_build_array('INSERT', $cp->build_insert_sql_array($cp_data));
@@ -325,7 +334,7 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
{
global $phpbb_log;
- // Because these actions only fill the log unneccessarily we skip the add_log() entry.
+ // Because these actions only fill the log unnecessarily, we disable it
$phpbb_log->disable('admin');
// Add user to "newly registered users" group and set to default group if admin specified so.
@@ -346,9 +355,9 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
// set the newest user and adjust the user count if the user is a normal user and no activation mail is sent
if ($user_row['user_type'] == USER_NORMAL || $user_row['user_type'] == USER_FOUNDER)
{
- set_config('newest_user_id', $user_id, true);
- set_config('newest_username', $user_row['username'], true);
- set_config_count('num_users', 1, true);
+ $config->set('newest_user_id', $user_id, false);
+ $config->set('newest_username', $user_row['username'], false);
+ $config->increment('num_users', 1, false);
$sql = 'SELECT group_colour
FROM ' . GROUPS_TABLE . '
@@ -357,7 +366,7 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- set_config('newest_user_colour', $row['group_colour'], true);
+ $config->set('newest_user_colour', $row['group_colour'], false);
}
// Use default notifications settings if notifications_data is not set
@@ -375,9 +384,23 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
);
}
+ /**
+ * Modify the notifications data to be inserted in the database when a user is added
+ *
+ * @event core.user_add_modify_notifications_data
+ * @var array user_row Array of user details submitted to user_add
+ * @var array cp_data Array of Custom profile fields submitted to user_add
+ * @var array sql_ary Array of data to be inserted when a user is added
+ * @var array notifications_data Array of notification data to be inserted when a user is added
+ * @since 3.2.2-RC1
+ */
+ $vars = array('user_row', 'cp_data', 'sql_ary', 'notifications_data');
+ extract($phpbb_dispatcher->trigger_event('core.user_add_modify_notifications_data', compact($vars)));
+
// Subscribe user to notifications if necessary
if (!empty($notifications_data))
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
foreach ($notifications_data as $subscription)
{
@@ -386,12 +409,12 @@ function user_add($user_row, $cp_data = false, $notifications_data = null)
}
/**
- * Event that returns user id, user detals and user CPF of newly registared user
+ * Event that returns user id, user details and user CPF of newly registered user
*
* @event core.user_add_after
- * @var int user_id User id of newly registared user
- * @var array user_row Array of user details submited to user_add
- * @var array cp_data Array of Custom profile fields submited to user_add
+ * @var int user_id User id of newly registered user
+ * @var array user_row Array of user details submitted to user_add
+ * @var array cp_data Array of Custom profile fields submitted to user_add
* @since 3.1.0-b5
*/
$vars = array('user_id', 'user_row', 'cp_data');
@@ -446,9 +469,11 @@ function user_delete($mode, $user_ids, $retain_username = true)
* @var array user_ids IDs of the deleted user
* @var mixed retain_username True if username should be retained
* or false if not
+ * @var array user_rows Array containing data of the deleted users
* @since 3.1.0-a1
+ * @changed 3.2.4-RC1 Added user_rows
*/
- $vars = array('mode', 'user_ids', 'retain_username');
+ $vars = array('mode', 'user_ids', 'retain_username', 'user_rows');
extract($phpbb_dispatcher->trigger_event('core.delete_user_before', compact($vars)));
// Before we begin, we will remove the reports the user issued.
@@ -466,7 +491,7 @@ function user_delete($mode, $user_ids, $retain_username = true)
}
$db->sql_freeresult($result);
- if (sizeof($report_posts))
+ if (count($report_posts))
{
$report_posts = array_unique($report_posts);
$report_topics = array_unique($report_topics);
@@ -486,7 +511,7 @@ function user_delete($mode, $user_ids, $retain_username = true)
}
$db->sql_freeresult($result);
- if (sizeof($keep_report_topics))
+ if (count($keep_report_topics))
{
$report_topics = array_diff($report_topics, $keep_report_topics);
}
@@ -498,7 +523,7 @@ function user_delete($mode, $user_ids, $retain_username = true)
WHERE ' . $db->sql_in_set('post_id', $report_posts);
$db->sql_query($sql);
- if (sizeof($report_topics))
+ if (count($report_topics))
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET topic_reported = 0
@@ -618,7 +643,7 @@ function user_delete($mode, $user_ids, $retain_username = true)
if ($num_users_delta != 0)
{
- set_config_count('num_users', $num_users_delta, true);
+ $config->increment('num_users', $num_users_delta, false);
}
// Now do the invariant tasks
@@ -649,8 +674,30 @@ function user_delete($mode, $user_ids, $retain_username = true)
delete_posts('poster_id', $user_ids);
}
- $table_ary = array(USERS_TABLE, USER_GROUP_TABLE, TOPICS_WATCH_TABLE, FORUMS_WATCH_TABLE, ACL_USERS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, FORUMS_TRACK_TABLE, PROFILE_FIELDS_DATA_TABLE, MODERATOR_CACHE_TABLE, DRAFTS_TABLE, BOOKMARKS_TABLE, SESSIONS_KEYS_TABLE, PRIVMSGS_FOLDER_TABLE, PRIVMSGS_RULES_TABLE);
-
+ $table_ary = [
+ USERS_TABLE,
+ USER_GROUP_TABLE,
+ TOPICS_WATCH_TABLE,
+ FORUMS_WATCH_TABLE,
+ ACL_USERS_TABLE,
+ TOPICS_TRACK_TABLE,
+ TOPICS_POSTED_TABLE,
+ FORUMS_TRACK_TABLE,
+ PROFILE_FIELDS_DATA_TABLE,
+ MODERATOR_CACHE_TABLE,
+ DRAFTS_TABLE,
+ BOOKMARKS_TABLE,
+ SESSIONS_KEYS_TABLE,
+ PRIVMSGS_FOLDER_TABLE,
+ PRIVMSGS_RULES_TABLE,
+ $phpbb_container->getParameter('tables.auth_provider_oauth_token_storage'),
+ $phpbb_container->getParameter('tables.auth_provider_oauth_states'),
+ $phpbb_container->getParameter('tables.auth_provider_oauth_account_assoc'),
+ $phpbb_container->getParameter('tables.user_notifications')
+ ];
+
+ // Ignore errors on deleting from non-existent tables, e.g. when migrating
+ $db->sql_return_on_error(true);
// Delete the miscellaneous (non-post) data for the user
foreach ($table_ary as $table)
{
@@ -658,6 +705,7 @@ function user_delete($mode, $user_ids, $retain_username = true)
WHERE " . $user_id_sql;
$db->sql_query($sql);
}
+ $db->sql_return_on_error();
$cache->destroy('sql', MODERATOR_CACHE_TABLE);
@@ -732,9 +780,11 @@ function user_delete($mode, $user_ids, $retain_username = true)
* @var array user_ids IDs of the deleted user
* @var mixed retain_username True if username should be retained
* or false if not
+ * @var array user_rows Array containing data of the deleted users
* @since 3.1.0-a1
+ * @changed 3.2.2-RC1 Added user_rows
*/
- $vars = array('mode', 'user_ids', 'retain_username');
+ $vars = array('mode', 'user_ids', 'retain_username', 'user_rows');
extract($phpbb_dispatcher->trigger_event('core.delete_user_after', compact($vars)));
// Reset newest user info if appropriate
@@ -763,7 +813,7 @@ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL)
$user_id_ary = array($user_id_ary);
}
- if (!sizeof($user_id_ary))
+ if (!count($user_id_ary))
{
return;
}
@@ -821,7 +871,7 @@ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL)
$vars = array('mode', 'reason', 'activated', 'deactivated', 'user_id_ary', 'sql_statements');
extract($phpbb_dispatcher->trigger_event('core.user_active_flip_before', compact($vars)));
- if (sizeof($sql_statements))
+ if (count($sql_statements))
{
foreach ($sql_statements as $user_id => $sql_ary)
{
@@ -851,12 +901,12 @@ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL)
if ($deactivated)
{
- set_config_count('num_users', $deactivated * (-1), true);
+ $config->increment('num_users', $deactivated * (-1), false);
}
if ($activated)
{
- set_config_count('num_users', $activated, true);
+ $config->increment('num_users', $activated, false);
}
// Update latest username
@@ -876,7 +926,7 @@ function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL)
*/
function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reason, $ban_give_reason = '')
{
- global $db, $user, $auth, $cache;
+ global $db, $user, $cache, $phpbb_log;
// Delete stale bans
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
@@ -899,7 +949,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
else
{
$ban_other = explode('-', $ban_len_other);
- if (sizeof($ban_other) == 3 && ((int) $ban_other[0] < 9999) &&
+ if (count($ban_other) == 3 && ((int) $ban_other[0] < 9999) &&
(strlen($ban_other[0]) == 4) && (strlen($ban_other[1]) == 2) && (strlen($ban_other[2]) == 2))
{
$ban_end = max($current_time, $user->create_datetime()
@@ -967,7 +1017,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
}
// Make sure we have been given someone to ban
- if (!sizeof($sql_usernames))
+ if (!count($sql_usernames))
{
trigger_error('NO_USER_SPECIFIED', E_USER_WARNING);
}
@@ -978,7 +1028,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
// Do not allow banning yourself, the guest account, or founders.
$non_bannable = array($user->data['user_id'], ANONYMOUS);
- if (sizeof($founder))
+ if (count($founder))
{
$sql .= ' AND ' . $db->sql_in_set('user_id', array_merge(array_keys($founder), $non_bannable), true);
}
@@ -1025,7 +1075,6 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
if ($ip_2_counter == 0 && $ip_2_end == 254)
{
$ip_2_counter = 256;
- $ip_2_fragment = 256;
$banlist_ary[] = "$ip_1_counter.*";
}
@@ -1038,7 +1087,6 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
if ($ip_3_counter == 0 && $ip_3_end == 254)
{
$ip_3_counter = 256;
- $ip_3_fragment = 256;
$banlist_ary[] = "$ip_1_counter.$ip_2_counter.*";
}
@@ -1051,7 +1099,6 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
if ($ip_4_counter == 0 && $ip_4_end == 254)
{
$ip_4_counter = 256;
- $ip_4_fragment = 256;
$banlist_ary[] = "$ip_1_counter.$ip_2_counter.$ip_3_counter.*";
}
@@ -1121,14 +1168,14 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
continue;
}
- if (!sizeof($founder) || !in_array($ban_item, $founder))
+ if (!count($founder) || !in_array($ban_item, $founder))
{
$banlist_ary[] = $ban_item;
}
}
}
- if (sizeof($ban_list) == 0)
+ if (count($ban_list) == 0)
{
trigger_error('NO_EMAILS_DEFINED', E_USER_WARNING);
}
@@ -1175,7 +1222,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
$banlist_ary_tmp = array_intersect($banlist_ary, $banlist_ary_tmp);
- if (sizeof($banlist_ary_tmp))
+ if (count($banlist_ary_tmp))
{
// One or more entities are already banned/excluded, delete the existing bans, so they can be re-inserted with the given new length
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
@@ -1189,7 +1236,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
$db->sql_freeresult($result);
// We have some entities to ban
- if (sizeof($banlist_ary))
+ if (count($banlist_ary))
{
$sql_ary = array();
@@ -1267,13 +1314,22 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
$log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_';
// Add to admin log, moderator log and user notes
- add_log('admin', $log_entry . strtoupper($mode), $ban_reason, $ban_list_log);
- add_log('mod', 0, 0, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log_entry . strtoupper($mode), false, array($ban_reason, $ban_list_log));
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, $log_entry . strtoupper($mode), false, array(
+ 'forum_id' => 0,
+ 'topic_id' => 0,
+ $ban_reason,
+ $ban_list_log
+ ));
if ($mode == 'user')
{
foreach ($banlist_ary as $user_id)
{
- add_log('user', $user_id, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, $log_entry . strtoupper($mode), false, array(
+ 'reportee_id' => $user_id,
+ $ban_reason,
+ $ban_list_log
+ ));
}
}
@@ -1293,7 +1349,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas
*/
function user_unban($mode, $ban)
{
- global $db, $user, $auth, $cache, $phpbb_dispatcher;
+ global $db, $user, $cache, $phpbb_log, $phpbb_dispatcher;
// Delete stale bans
$sql = 'DELETE FROM ' . BANLIST_TABLE . '
@@ -1308,7 +1364,7 @@ function user_unban($mode, $ban)
$unban_sql = array_map('intval', $ban);
- if (sizeof($unban_sql))
+ if (count($unban_sql))
{
// Grab details of bans for logging information later
switch ($mode)
@@ -1351,13 +1407,20 @@ function user_unban($mode, $ban)
$db->sql_query($sql);
// Add to moderator log, admin log and user notes
- add_log('admin', 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list);
- add_log('mod', 0, 0, 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array($l_unban_list));
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array(
+ 'forum_id' => 0,
+ 'topic_id' => 0,
+ $l_unban_list
+ ));
if ($mode == 'user')
{
foreach ($user_ids_ary as $user_id)
{
- add_log('user', $user_id, 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_UNBAN_' . strtoupper($mode), false, array(
+ 'reportee_id' => $user_id,
+ $l_unban_list
+ ));
}
}
@@ -1397,21 +1460,14 @@ function user_ipwhois($ip)
return '';
}
- if (preg_match(get_preg_expression('ipv4'), $ip))
- {
- // IPv4 address
- $whois_host = 'whois.arin.net.';
- }
- else if (preg_match(get_preg_expression('ipv6'), $ip))
- {
- // IPv6 address
- $whois_host = 'whois.sixxs.net.';
- }
- else
+ if (!preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip))
{
return '';
}
+ // IPv4 & IPv6 addresses
+ $whois_host = 'whois.arin.net.';
+
$ipwhois = '';
if (($fsk = @fsockopen($whois_host, 43)))
@@ -1565,7 +1621,7 @@ function validate_num($num, $optional = false, $min = 0, $max = 1E99)
function validate_date($date_string, $optional = false)
{
$date = explode('-', $date_string);
- if ((empty($date) || sizeof($date) != 3) && $optional)
+ if ((empty($date) || count($date) != 3) && $optional)
{
return false;
}
@@ -1587,7 +1643,7 @@ function validate_date($date_string, $optional = false)
}
}
- if (sizeof($date) != 3 || !checkdate($date[1], $date[0], $date[2]))
+ if (count($date) != 3 || !checkdate($date[1], $date[0], $date[2]))
{
return 'INVALID';
}
@@ -1662,17 +1718,21 @@ function phpbb_validate_timezone($timezone)
return (in_array($timezone, phpbb_get_timezone_identifiers($timezone))) ? false : 'TIMEZONE_INVALID';
}
-/**
-* Check to see if the username has been taken, or if it is disallowed.
-* Also checks if it includes the " character, which we don't allow in usernames.
-* Used for registering, changing names, and posting anonymously with a username
-*
-* @param string $username The username to check
-* @param string $allowed_username An allowed username, default being $user->data['username']
-*
-* @return mixed Either false if validation succeeded or a string which will be used as the error message (with the variable name appended)
-*/
-function validate_username($username, $allowed_username = false)
+/***
+ * Validate Username
+ *
+ * Check to see if the username has been taken, or if it is disallowed.
+ * Also checks if it includes the " character or the 4-bytes Unicode ones
+ * (aka emojis) which we don't allow in usernames.
+ * Used for registering, changing names, and posting anonymously with a username
+ *
+ * @param string $username The username to check
+ * @param string $allowed_username An allowed username, default being $user->data['username']
+ *
+ * @return mixed Either false if validation succeeded or a string which will be
+ * used as the error message (with the variable name appended)
+ */
+function validate_username($username, $allowed_username = false, $allow_all_names = false)
{
global $config, $db, $user, $cache;
@@ -1684,95 +1744,51 @@ function validate_username($username, $allowed_username = false)
return false;
}
- // ... fast checks first.
- if (strpos($username, '&quot;') !== false || strpos($username, '"') !== false || empty($clean_username))
+ // The very first check is for
+ // out-of-bounds characters that are currently
+ // not supported by utf8_bin in MySQL
+ if (preg_match('/[\x{10000}-\x{10FFFF}]/u', $username))
{
- return 'INVALID_CHARS';
+ return 'INVALID_EMOJIS';
}
- $mbstring = $pcre = false;
-
- // generic UTF-8 character types supported?
- if (phpbb_pcre_utf8_support())
- {
- $pcre = true;
- }
- else if (function_exists('mb_ereg_match'))
+ // ... fast checks first.
+ if (strpos($username, '&quot;') !== false || strpos($username, '"') !== false || empty($clean_username))
{
- mb_regex_encoding('UTF-8');
- $mbstring = true;
+ return 'INVALID_CHARS';
}
switch ($config['allow_name_chars'])
{
case 'USERNAME_CHARS_ANY':
- $pcre = true;
$regex = '.+';
break;
case 'USERNAME_ALPHA_ONLY':
- $pcre = true;
$regex = '[A-Za-z0-9]+';
break;
case 'USERNAME_ALPHA_SPACERS':
- $pcre = true;
$regex = '[A-Za-z0-9-[\]_+ ]+';
break;
case 'USERNAME_LETTER_NUM':
- if ($pcre)
- {
- $regex = '[\p{Lu}\p{Ll}\p{N}]+';
- }
- else if ($mbstring)
- {
- $regex = '[[:upper:][:lower:][:digit:]]+';
- }
- else
- {
- $pcre = true;
- $regex = '[a-zA-Z0-9]+';
- }
+ $regex = '[\p{Lu}\p{Ll}\p{N}]+';
break;
case 'USERNAME_LETTER_NUM_SPACERS':
- if ($pcre)
- {
- $regex = '[-\]_+ [\p{Lu}\p{Ll}\p{N}]+';
- }
- else if ($mbstring)
- {
- $regex = '[-\]_+ \[[:upper:][:lower:][:digit:]]+';
- }
- else
- {
- $pcre = true;
- $regex = '[-\]_+ [a-zA-Z0-9]+';
- }
+ $regex = '[-\]_+ [\p{Lu}\p{Ll}\p{N}]+';
break;
case 'USERNAME_ASCII':
default:
- $pcre = true;
$regex = '[\x01-\x7F]+';
break;
}
- if ($pcre)
- {
- if (!preg_match('#^' . $regex . '$#u', $username))
- {
- return 'INVALID_CHARS';
- }
- }
- else if ($mbstring)
+ if (!preg_match('#^' . $regex . '$#u', $username))
{
- mb_ereg_search_init($username, '^' . $regex . '$');
- if (!mb_ereg_search())
- {
- return 'INVALID_CHARS';
- }
+ return 'INVALID_CHARS';
}
$sql = 'SELECT username
@@ -1799,13 +1815,16 @@ function validate_username($username, $allowed_username = false)
return 'USERNAME_TAKEN';
}
- $bad_usernames = $cache->obtain_disallowed_usernames();
-
- foreach ($bad_usernames as $bad_username)
+ if (!$allow_all_names)
{
- if (preg_match('#^' . $bad_username . '$#', $clean_username))
+ $bad_usernames = $cache->obtain_disallowed_usernames();
+
+ foreach ($bad_usernames as $bad_username)
{
- return 'USERNAME_DISALLOWED';
+ if (preg_match('#^' . $bad_username . '$#', $clean_username))
+ {
+ return 'USERNAME_DISALLOWED';
+ }
}
}
@@ -1827,35 +1846,10 @@ function validate_password($password)
return false;
}
- $pcre = $mbstring = false;
-
- // generic UTF-8 character types supported?
- if (phpbb_pcre_utf8_support())
- {
- $upp = '\p{Lu}';
- $low = '\p{Ll}';
- $num = '\p{N}';
- $sym = '[^\p{Lu}\p{Ll}\p{N}]';
- $pcre = true;
- }
- else if (function_exists('mb_ereg_match'))
- {
- mb_regex_encoding('UTF-8');
- $upp = '[[:upper:]]';
- $low = '[[:lower:]]';
- $num = '[[:digit:]]';
- $sym = '[^[:upper:][:lower:][:digit:]]';
- $mbstring = true;
- }
- else
- {
- $upp = '[A-Z]';
- $low = '[a-z]';
- $num = '[0-9]';
- $sym = '[^A-Za-z0-9]';
- $pcre = true;
- }
-
+ $upp = '\p{Lu}';
+ $low = '\p{Ll}';
+ $num = '\p{N}';
+ $sym = '[^\p{Lu}\p{Ll}\p{N}]';
$chars = array();
switch ($config['pass_complex'])
@@ -1878,24 +1872,11 @@ function validate_password($password)
$chars[] = $upp;
}
- if ($pcre)
+ foreach ($chars as $char)
{
- foreach ($chars as $char)
+ if (!preg_match('#' . $char . '#u', $password))
{
- if (!preg_match('#' . $char . '#u', $password))
- {
- return 'INVALID_CHARS';
- }
- }
- }
- else if ($mbstring)
- {
- foreach ($chars as $char)
- {
- if (mb_ereg($char, $password) === false)
- {
- return 'INVALID_CHARS';
- }
+ return 'INVALID_CHARS';
}
}
@@ -1964,9 +1945,10 @@ function validate_user_email($email, $allowed_email = false)
return $validate_email;
}
- if (($ban_reason = $user->check_ban(false, false, $email, true)) !== false)
+ $ban = $user->check_ban(false, false, $email, true);
+ if (!empty($ban))
{
- return ($ban_reason === true) ? 'EMAIL_BANNED' : $ban_reason;
+ return !empty($ban['ban_give_reason']) ? $ban['ban_give_reason'] : 'EMAIL_BANNED';
}
if (!$config['allow_emailreuse'])
@@ -2017,7 +1999,7 @@ function validate_jabber($jid)
$arr = explode('.', $realm);
- if (sizeof($arr) == 0)
+ if (count($arr) == 0)
{
return 'WRONG_DATA';
}
@@ -2239,7 +2221,7 @@ function phpbb_style_is_active($style_id)
*/
function avatar_delete($mode, $row, $clean_db = false)
{
- global $phpbb_root_path, $config, $db, $user;
+ global $phpbb_root_path, $config;
// Check if the users avatar is actually *not* a group avatar
if ($mode == 'user')
@@ -2311,7 +2293,10 @@ function phpbb_avatar_explanation_string()
*/
function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false)
{
- global $phpbb_root_path, $config, $db, $user, $file_upload, $phpbb_container;
+ global $db, $user, $phpbb_container, $phpbb_log;
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
$error = array();
@@ -2338,13 +2323,17 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$group_teampage = !empty($group_attributes['group_teampage']);
unset($group_attributes['group_teampage']);
- if (!sizeof($error))
+ if (!count($error))
{
$current_legend = \phpbb\groupposition\legend::GROUP_DISABLED;
$current_teampage = \phpbb\groupposition\teampage::GROUP_DISABLED;
+ /* @var $legend \phpbb\groupposition\legend */
$legend = $phpbb_container->get('groupposition.legend');
+
+ /* @var $teampage \phpbb\groupposition\teampage */
$teampage = $phpbb_container->get('groupposition.teampage');
+
if ($group_id)
{
try
@@ -2407,7 +2396,7 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
generate_text_for_storage($sql_ary['group_desc'], $sql_ary['group_desc_uid'], $sql_ary['group_desc_bitfield'], $sql_ary['group_desc_options'], $allow_desc_bbcode, $allow_desc_urls, $allow_desc_smilies);
}
- if (sizeof($group_attributes))
+ if (count($group_attributes))
{
// Merge them with $sql_ary to properly update the group
$sql_ary = array_merge($sql_ary, $group_attributes);
@@ -2416,8 +2405,6 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
// Setting the log message before we set the group id (if group gets added)
$log = ($group_id) ? 'LOG_GROUP_UPDATED' : 'LOG_GROUP_CREATED';
- $query = '';
-
if ($group_id)
{
$sql = 'SELECT user_id
@@ -2535,7 +2522,7 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
// Set user attributes
$sql_ary = array();
- if (sizeof($group_attributes))
+ if (count($group_attributes))
{
// Go through the user attributes array, check if a group attribute matches it and then set it. ;)
foreach ($user_attribute_ary as $attribute)
@@ -2555,18 +2542,18 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
}
}
- if (sizeof($sql_ary) && sizeof($user_ary))
+ if (count($sql_ary) && count($user_ary))
{
group_set_user_default($group_id, $user_ary, $sql_ary);
}
- $name = ($type == GROUP_SPECIAL) ? $user->lang['G_' . $name] : $name;
- add_log('admin', $log, $name);
+ $name = $group_helper->get_name($name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log, false, array($name));
group_update_listings($group_id);
}
- return (sizeof($error)) ? $error : false;
+ return (count($error)) ? $error : false;
}
@@ -2599,7 +2586,7 @@ function group_correct_avatar($group_id, $old_entry)
*/
function avatar_remove_db($avatar_name)
{
- global $config, $db;
+ global $db;
$sql = 'UPDATE ' . USERS_TABLE . "
SET user_avatar = '',
@@ -2614,7 +2601,7 @@ function avatar_remove_db($avatar_name)
*/
function group_delete($group_id, $group_name = false)
{
- global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container;
+ global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container, $phpbb_log;
if (!$group_name)
{
@@ -2658,6 +2645,7 @@ function group_delete($group_id, $group_name = false)
// Delete group from legend and teampage
try
{
+ /* @var $legend \phpbb\groupposition\legend */
$legend = $phpbb_container->get('groupposition.legend');
$legend->delete_group($group_id);
unset($legend);
@@ -2671,6 +2659,7 @@ function group_delete($group_id, $group_name = false)
try
{
+ /* @var $teampage \phpbb\groupposition\teampage */
$teampage = $phpbb_container->get('groupposition.teampage');
$teampage->delete_group($group_id);
unset($teampage);
@@ -2711,7 +2700,7 @@ function group_delete($group_id, $group_name = false)
phpbb_cache_moderators($db, $cache, $auth);
- add_log('admin', 'LOG_GROUP_DELETE', $group_name);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_GROUP_DELETE', false, array($group_name));
// Return false - no error
return false;
@@ -2724,16 +2713,23 @@ function group_delete($group_id, $group_name = false)
*/
function group_user_add($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $default = false, $leader = 0, $pending = 0, $group_attributes = false)
{
- global $db, $auth, $phpbb_container, $phpbb_dispatcher;
+ global $db, $auth, $user, $phpbb_container, $phpbb_log, $phpbb_dispatcher;
// We need both username and user_id info
$result = user_get_id_name($user_id_ary, $username_ary);
- if (!sizeof($user_id_ary) || $result !== false)
+ if (empty($user_id_ary) || $result !== false)
{
return 'NO_USER';
}
+ // Because the item that gets passed into the previous function is unset, the reference is lost and our original
+ // array is retained - so we know there's a problem if there's a different number of ids to usernames now.
+ if (count($user_id_ary) != count($username_ary))
+ {
+ return 'GROUP_USERS_INVALID';
+ }
+
// Remove users who are already members of this group
$sql = 'SELECT user_id, group_leader
FROM ' . USER_GROUP_TABLE . '
@@ -2757,7 +2753,7 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false,
$add_id_ary = array_diff($user_id_ary, $add_id_ary);
// If we have no users
- if (!sizeof($add_id_ary) && !sizeof($update_id_ary))
+ if (!count($add_id_ary) && !count($update_id_ary))
{
return 'GROUP_USERS_EXIST';
}
@@ -2765,7 +2761,7 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false,
$db->sql_transaction('begin');
// Insert the new users
- if (sizeof($add_id_ary))
+ if (count($add_id_ary))
{
$sql_ary = array();
@@ -2782,7 +2778,7 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false,
$db->sql_multi_insert(USER_GROUP_TABLE, $sql_ary);
}
- if (sizeof($update_id_ary))
+ if (count($update_id_ary))
{
$sql = 'UPDATE ' . USER_GROUP_TABLE . '
SET group_leader = 1
@@ -2828,12 +2824,13 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false,
$log = ($leader) ? 'LOG_MODS_ADDED' : (($pending) ? 'LOG_USERS_PENDING' : 'LOG_USERS_ADDED');
- add_log('admin', $log, $group_name, implode(', ', $username_ary));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log, false, array($group_name, implode(', ', $username_ary)));
group_update_listings($group_id);
if ($pending)
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
foreach ($add_id_ary as $user_id)
@@ -2859,7 +2856,7 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false,
*/
function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $log_action = true)
{
- global $db, $auth, $config, $phpbb_dispatcher, $phpbb_container;
+ global $db, $auth, $config, $user, $phpbb_dispatcher, $phpbb_container, $phpbb_log;
if ($config['coppa_enable'])
{
@@ -2873,7 +2870,7 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false,
// We need both username and user_id info
$result = user_get_id_name($user_id_ary, $username_ary);
- if (!sizeof($user_id_ary) || $result !== false)
+ if (empty($user_id_ary) || $result !== false)
{
return 'NO_USER';
}
@@ -2949,7 +2946,7 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false,
foreach ($special_group_data as $gid => $default_data_ary)
{
- if (isset($sql_where_ary[$gid]) && sizeof($sql_where_ary[$gid]))
+ if (isset($sql_where_ary[$gid]) && count($sql_where_ary[$gid]))
{
remove_default_rank($group_id, $sql_where_ary[$gid]);
remove_default_avatar($group_id, $sql_where_ary[$gid]);
@@ -3003,12 +3000,13 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false,
if ($group_name)
{
- add_log('admin', $log, $group_name, implode(', ', $username_ary));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log, false, array($group_name, implode(', ', $username_ary)));
}
}
group_update_listings($group_id);
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->delete_notifications('notification.type.group_request', $user_id_ary, $group_id);
@@ -3102,12 +3100,12 @@ function remove_default_rank($group_id, $user_ids)
*/
function group_user_attributes($action, $group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $group_attributes = false)
{
- global $db, $auth, $phpbb_root_path, $phpEx, $config, $phpbb_container, $phpbb_dispatcher;
+ global $db, $auth, $user, $phpbb_container, $phpbb_log, $phpbb_dispatcher;
// We need both username and user_id info
$result = user_get_id_name($user_id_ary, $username_ary);
- if (!sizeof($user_id_ary) || $result !== false)
+ if (empty($user_id_ary) || $result !== false)
{
return 'NO_USERS';
}
@@ -3162,7 +3160,7 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
}
$db->sql_freeresult($result);
- if (!sizeof($user_id_ary))
+ if (!count($user_id_ary))
{
return false;
}
@@ -3173,6 +3171,7 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
AND " . $db->sql_in_set('user_id', $user_id_ary);
$db->sql_query($sql);
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->add_notifications('notification.type.group_request_approved', array(
@@ -3202,7 +3201,7 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
$db->sql_freeresult($result);
$result = user_get_id_name($user_id_ary, $username_ary);
- if (!sizeof($user_id_ary) || $result !== false)
+ if (!count($user_id_ary) || $result !== false)
{
return 'NO_USERS';
}
@@ -3258,7 +3257,7 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
// Clear permissions cache of relevant users
$auth->acl_clear_prefetch($user_id_ary);
- add_log('admin', $log, $group_name, implode(', ', $username_ary));
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, $log, false, array($group_name, implode(', ', $username_ary)));
group_update_listings($group_id);
@@ -3270,7 +3269,7 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
*/
function group_validate_groupname($group_id, $group_name)
{
- global $config, $db;
+ global $db;
$group_name = utf8_clean_string($group_name);
@@ -3318,7 +3317,7 @@ function group_validate_groupname($group_id, $group_name)
*/
function group_set_user_default($group_id, $user_id_ary, $group_attributes = false, $update_listing = false)
{
- global $phpbb_container, $db, $phpbb_dispatcher;
+ global $config, $phpbb_container, $db, $phpbb_dispatcher;
if (empty($user_id_ary))
{
@@ -3388,8 +3387,8 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal
if (isset($sql_ary[$avatar_option]))
{
$avatar_sql_ary[$avatar_option] = $sql_ary[$avatar_option];
- }
}
+ }
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $avatar_sql_ary) . "
@@ -3430,11 +3429,9 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal
WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary);
$db->sql_query($sql);
- global $config;
-
if (in_array($config['newest_user_id'], $user_id_ary))
{
- set_config('newest_user_colour', $sql_ary['user_colour'], true);
+ $config->set('newest_user_colour', $sql_ary['user_colour'], false);
}
}
@@ -3469,7 +3466,7 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal
*/
function get_group_name($group_id)
{
- global $db, $user;
+ global $db, $phpbb_container;
$sql = 'SELECT group_name, group_type
FROM ' . GROUPS_TABLE . '
@@ -3478,12 +3475,15 @@ function get_group_name($group_id)
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- if (!$row || ($row['group_type'] == GROUP_SPECIAL && empty($user->lang)))
+ if (!$row)
{
return '';
}
- return ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
+ return $group_helper->get_name($row['group_name']);
}
/**
@@ -3564,7 +3564,7 @@ function group_update_listings($group_id)
$hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_'));
- if (!sizeof($hold_ary))
+ if (empty($hold_ary))
{
return;
}
@@ -3651,11 +3651,6 @@ function remove_newly_registered($user_id, $user_data = false)
}
}
- if (empty($user_data['user_new']))
- {
- return false;
- }
-
$sql = 'SELECT group_id
FROM ' . GROUPS_TABLE . "
WHERE group_name = 'NEWLY_REGISTERED'
diff --git a/phpBB/includes/hooks/index.php b/phpBB/includes/hooks/index.php
index 805e0eea1a..821242cbf4 100644
--- a/phpBB/includes/hooks/index.php
+++ b/phpBB/includes/hooks/index.php
@@ -44,7 +44,7 @@ class phpbb_hook
*
* @param array $valid_hooks array containing the hookable functions/methods
*/
- function phpbb_hook($valid_hooks)
+ function __construct($valid_hooks)
{
foreach ($valid_hooks as $_null => $method)
{
diff --git a/phpBB/includes/mcp/info/mcp_ban.php b/phpBB/includes/mcp/info/mcp_ban.php
index 4aedbc8558..b4fd32792a 100644
--- a/phpBB/includes/mcp/info/mcp_ban.php
+++ b/phpBB/includes/mcp/info/mcp_ban.php
@@ -18,7 +18,6 @@ class mcp_ban_info
return array(
'filename' => 'mcp_ban',
'title' => 'MCP_BAN',
- 'version' => '1.0.0',
'modes' => array(
'user' => array('title' => 'MCP_BAN_USERNAMES', 'auth' => 'acl_m_ban', 'cat' => array('MCP_BAN')),
'ip' => array('title' => 'MCP_BAN_IPS', 'auth' => 'acl_m_ban', 'cat' => array('MCP_BAN')),
diff --git a/phpBB/includes/mcp/info/mcp_logs.php b/phpBB/includes/mcp/info/mcp_logs.php
index c6482c1255..7a0205fce9 100644
--- a/phpBB/includes/mcp/info/mcp_logs.php
+++ b/phpBB/includes/mcp/info/mcp_logs.php
@@ -18,7 +18,6 @@ class mcp_logs_info
return array(
'filename' => 'mcp_logs',
'title' => 'MCP_LOGS',
- 'version' => '1.0.0',
'modes' => array(
'front' => array('title' => 'MCP_LOGS_FRONT', 'auth' => 'acl_m_ || aclf_m_', 'cat' => array('MCP_LOGS')),
'forum_logs' => array('title' => 'MCP_LOGS_FORUM_VIEW', 'auth' => 'acl_m_,$id', 'cat' => array('MCP_LOGS')),
diff --git a/phpBB/includes/mcp/info/mcp_main.php b/phpBB/includes/mcp/info/mcp_main.php
index 81ccdbd1cd..c0f0363255 100644
--- a/phpBB/includes/mcp/info/mcp_main.php
+++ b/phpBB/includes/mcp/info/mcp_main.php
@@ -18,7 +18,6 @@ class mcp_main_info
return array(
'filename' => 'mcp_main',
'title' => 'MCP_MAIN',
- 'version' => '1.0.0',
'modes' => array(
'front' => array('title' => 'MCP_MAIN_FRONT', 'auth' => '', 'cat' => array('MCP_MAIN')),
'forum_view' => array('title' => 'MCP_MAIN_FORUM_VIEW', 'auth' => 'acl_m_,$id', 'cat' => array('MCP_MAIN')),
diff --git a/phpBB/includes/mcp/info/mcp_notes.php b/phpBB/includes/mcp/info/mcp_notes.php
index 4b8c255fe2..de4a41dd80 100644
--- a/phpBB/includes/mcp/info/mcp_notes.php
+++ b/phpBB/includes/mcp/info/mcp_notes.php
@@ -18,7 +18,6 @@ class mcp_notes_info
return array(
'filename' => 'mcp_notes',
'title' => 'MCP_NOTES',
- 'version' => '1.0.0',
'modes' => array(
'front' => array('title' => 'MCP_NOTES_FRONT', 'auth' => '', 'cat' => array('MCP_NOTES')),
'user_notes' => array('title' => 'MCP_NOTES_USER', 'auth' => '', 'cat' => array('MCP_NOTES')),
diff --git a/phpBB/includes/mcp/info/mcp_pm_reports.php b/phpBB/includes/mcp/info/mcp_pm_reports.php
index c80f3b86a3..2a57c0c49a 100644
--- a/phpBB/includes/mcp/info/mcp_pm_reports.php
+++ b/phpBB/includes/mcp/info/mcp_pm_reports.php
@@ -18,7 +18,6 @@ class mcp_pm_reports_info
return array(
'filename' => 'mcp_pm_reports',
'title' => 'MCP_PM_REPORTS',
- 'version' => '1.0.0',
'modes' => array(
'pm_reports' => array('title' => 'MCP_PM_REPORTS_OPEN', 'auth' => 'acl_m_pm_report', 'cat' => array('MCP_REPORTS')),
'pm_reports_closed' => array('title' => 'MCP_PM_REPORTS_CLOSED', 'auth' => 'acl_m_pm_report', 'cat' => array('MCP_REPORTS')),
diff --git a/phpBB/includes/mcp/info/mcp_queue.php b/phpBB/includes/mcp/info/mcp_queue.php
index 556c3902b0..d5605aa50e 100644
--- a/phpBB/includes/mcp/info/mcp_queue.php
+++ b/phpBB/includes/mcp/info/mcp_queue.php
@@ -18,7 +18,6 @@ class mcp_queue_info
return array(
'filename' => 'mcp_queue',
'title' => 'MCP_QUEUE',
- 'version' => '1.0.0',
'modes' => array(
'unapproved_topics' => array('title' => 'MCP_QUEUE_UNAPPROVED_TOPICS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
'unapproved_posts' => array('title' => 'MCP_QUEUE_UNAPPROVED_POSTS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
diff --git a/phpBB/includes/mcp/info/mcp_reports.php b/phpBB/includes/mcp/info/mcp_reports.php
index 31fee19d79..76e62efe9c 100644
--- a/phpBB/includes/mcp/info/mcp_reports.php
+++ b/phpBB/includes/mcp/info/mcp_reports.php
@@ -18,7 +18,6 @@ class mcp_reports_info
return array(
'filename' => 'mcp_reports',
'title' => 'MCP_REPORTS',
- 'version' => '1.0.0',
'modes' => array(
'reports' => array('title' => 'MCP_REPORTS_OPEN', 'auth' => 'aclf_m_report', 'cat' => array('MCP_REPORTS')),
'reports_closed' => array('title' => 'MCP_REPORTS_CLOSED', 'auth' => 'aclf_m_report', 'cat' => array('MCP_REPORTS')),
diff --git a/phpBB/includes/mcp/info/mcp_warn.php b/phpBB/includes/mcp/info/mcp_warn.php
index d85499f280..b4f83e77c6 100644
--- a/phpBB/includes/mcp/info/mcp_warn.php
+++ b/phpBB/includes/mcp/info/mcp_warn.php
@@ -18,7 +18,6 @@ class mcp_warn_info
return array(
'filename' => 'mcp_warn',
'title' => 'MCP_WARN',
- 'version' => '1.0.0',
'modes' => array(
'front' => array('title' => 'MCP_WARN_FRONT', 'auth' => 'aclf_m_warn', 'cat' => array('MCP_WARN')),
'list' => array('title' => 'MCP_WARN_LIST', 'auth' => 'aclf_m_warn', 'cat' => array('MCP_WARN')),
diff --git a/phpBB/includes/mcp/mcp_ban.php b/phpBB/includes/mcp/mcp_ban.php
index 2f3405f915..6f748f5433 100644
--- a/phpBB/includes/mcp/mcp_ban.php
+++ b/phpBB/includes/mcp/mcp_ban.php
@@ -34,7 +34,10 @@ class mcp_ban
}
// Include the admin banning interface...
- include($phpbb_root_path . 'includes/acp/acp_ban.' . $phpEx);
+ if (!class_exists('acp_ban'))
+ {
+ include($phpbb_root_path . 'includes/acp/acp_ban.' . $phpEx);
+ }
$bansubmit = $request->is_set_post('bansubmit');
$unbansubmit = $request->is_set_post('unbansubmit');
@@ -266,9 +269,9 @@ class mcp_ban
}
else if ($post_id)
{
- $post_info = phpbb_get_post_data($post_id, 'm_ban');
+ $post_info = phpbb_get_post_data(array($post_id), 'm_ban');
- if (sizeof($post_info) && !empty($post_info[$post_id]))
+ if (count($post_info) && !empty($post_info[$post_id]))
{
switch ($mode)
{
diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php
index 3deb58b96a..19f71e092a 100644
--- a/phpBB/includes/mcp/mcp_forum.php
+++ b/phpBB/includes/mcp/mcp_forum.php
@@ -36,11 +36,11 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
$merge_select = ($action == 'merge_select' || $action == 'merge_topic' || $action == 'merge_topics') ? true : false;
$forum_id = $forum_info['forum_id'];
- $start = request_var('start', 0);
- $topic_id_list = request_var('topic_id_list', array(0));
- $post_id_list = request_var('post_id_list', array(0));
- $source_topic_ids = array(request_var('t', 0));
- $to_topic_id = request_var('to_topic_id', 0);
+ $start = $request->variable('start', 0);
+ $topic_id_list = $request->variable('topic_id_list', array(0));
+ $post_id_list = $request->variable('post_id_list', array(0));
+ $source_topic_ids = array($request->variable('t', 0));
+ $to_topic_id = $request->variable('to_topic_id', 0);
$url_extra = '';
$url_extra .= ($forum_id) ? "&amp;f=$forum_id" : '';
@@ -54,7 +54,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
switch ($action)
{
case 'resync':
- $topic_ids = request_var('topic_id_list', array(0));
+ $topic_ids = $request->variable('topic_id_list', array(0));
mcp_resync_topics($topic_ids);
break;
@@ -92,17 +92,18 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
);
extract($phpbb_dispatcher->trigger_event('core.mcp_forum_view_before', compact($vars)));
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
$selected_ids = '';
- if (sizeof($post_id_list) && $action != 'merge_topics')
+ if (count($post_id_list) && $action != 'merge_topics')
{
foreach ($post_id_list as $num => $post_id)
{
$selected_ids .= '&amp;post_id_list[' . $num . ']=' . $post_id;
}
}
- else if (sizeof($topic_id_list) && $action == 'merge_topics')
+ else if (count($topic_id_list) && $action == 'merge_topics')
{
foreach ($topic_id_list as $num => $topic_id)
{
@@ -145,9 +146,10 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
'S_CAN_SYNC' => $auth->acl_get('m_', $forum_id),
'S_CAN_APPROVE' => $auth->acl_get('m_approve', $forum_id),
'S_MERGE_SELECT' => ($merge_select) ? true : false,
- 'S_CAN_MAKE_NORMAL' => $auth->acl_gets('f_sticky', 'f_announce', $forum_id),
+ 'S_CAN_MAKE_NORMAL' => $auth->acl_gets('f_sticky', 'f_announce', 'f_announce_global', $forum_id),
'S_CAN_MAKE_STICKY' => $auth->acl_get('f_sticky', $forum_id),
'S_CAN_MAKE_ANNOUNCE' => $auth->acl_get('f_announce', $forum_id),
+ 'S_CAN_MAKE_ANNOUNCE_GLOBAL' => $auth->acl_get('f_announce_global', $forum_id),
'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
'U_VIEW_FORUM_LOGS' => ($auth->acl_gets('a_', 'm_', $forum_id) && $module->loaded('logs')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&amp;mode=forum_logs&amp;f=' . $forum_id) : '',
@@ -172,6 +174,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
$read_tracking_join = $read_tracking_select = '';
}
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
$sql = 'SELECT t.topic_id
@@ -200,9 +203,9 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
$topic_list = $topic_tracking_info = array();
- while ($row = $db->sql_fetchrow($result))
+ while ($row_ary = $db->sql_fetchrow($result))
{
- $topic_list[] = $row['topic_id'];
+ $topic_list[] = $row_ary['topic_id'];
}
$db->sql_freeresult($result);
@@ -211,20 +214,20 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
WHERE " . $db->sql_in_set('t.topic_id', $topic_list, false, true);
$result = $db->sql_query($sql);
- while ($row = $db->sql_fetchrow($result))
+ while ($row_ary = $db->sql_fetchrow($result))
{
- $topic_rows[$row['topic_id']] = $row;
+ $topic_rows[$row_ary['topic_id']] = $row_ary;
}
$db->sql_freeresult($result);
// If there is more than one page, but we have no topic list, then the start parameter is... erm... out of sync
- if (!sizeof($topic_list) && $forum_topics && $start > 0)
+ if (!count($topic_list) && $forum_topics && $start > 0)
{
redirect($url . "&amp;i=$id&amp;action=$action&amp;mode=$mode");
}
// Get topic tracking info
- if (sizeof($topic_list))
+ if (count($topic_list))
{
if ($config['load_db_lastread'])
{
@@ -238,109 +241,110 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
foreach ($topic_list as $topic_id)
{
- $topic_title = '';
+ $row_ary = &$topic_rows[$topic_id];
- $row = &$topic_rows[$topic_id];
+ $replies = $phpbb_content_visibility->get_count('topic_posts', $row_ary, $forum_id) - 1;
- $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1;
-
- if ($row['topic_status'] == ITEM_MOVED)
+ if ($row_ary['topic_status'] == ITEM_MOVED)
{
$unread_topic = false;
}
else
{
- $unread_topic = (isset($topic_tracking_info[$topic_id]) && $row['topic_last_post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
+ $unread_topic = (isset($topic_tracking_info[$topic_id]) && $row_ary['topic_last_post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
}
// Get folder img, topic status/type related information
$folder_img = $folder_alt = $topic_type = '';
- topic_status($row, $replies, $unread_topic, $folder_img, $folder_alt, $topic_type);
+ topic_status($row_ary, $replies, $unread_topic, $folder_img, $folder_alt, $topic_type);
- $topic_title = censor_text($row['topic_title']);
+ $topic_title = censor_text($row_ary['topic_title']);
- $topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false;
- $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false;
- $topic_deleted = $row['topic_visibility'] == ITEM_DELETED;
- $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? $url . '&amp;i=queue&amp;mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . '&amp;t=' . $row['topic_id'] : '';
+ $topic_unapproved = (($row_ary['topic_visibility'] == ITEM_UNAPPROVED || $row_ary['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $row_ary['forum_id'])) ? true : false;
+ $posts_unapproved = ($row_ary['topic_visibility'] == ITEM_APPROVED && $row_ary['topic_posts_unapproved'] && $auth->acl_get('m_approve', $row_ary['forum_id'])) ? true : false;
+ $topic_deleted = $row_ary['topic_visibility'] == ITEM_DELETED;
+ $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? $url . '&amp;i=queue&amp;mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . '&amp;t=' . $row_ary['topic_id'] : '';
$u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? $url . '&amp;i=queue&amp;mode=deleted_topics&amp;t=' . $topic_id : $u_mcp_queue;
$topic_row = array(
- 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '',
+ 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row_ary['forum_id']) && $row_ary['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '',
'TOPIC_IMG_STYLE' => $folder_img,
'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt),
- 'TOPIC_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '',
- 'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '',
- 'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '',
+ 'TOPIC_ICON_IMG' => (!empty($icons[$row_ary['icon_id']])) ? $icons[$row_ary['icon_id']]['img'] : '',
+ 'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row_ary['icon_id']])) ? $icons[$row_ary['icon_id']]['width'] : '',
+ 'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row_ary['icon_id']])) ? $icons[$row_ary['icon_id']]['height'] : '',
'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '',
'DELETED_IMG' => ($topic_deleted) ? $user->img('icon_topic_deleted', 'TOPIC_DELETED') : '',
- 'TOPIC_AUTHOR' => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
- 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
- 'TOPIC_AUTHOR_FULL' => get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
- 'U_TOPIC_AUTHOR' => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
+ 'TOPIC_AUTHOR' => get_username_string('username', $row_ary['topic_poster'], $row_ary['topic_first_poster_name'], $row_ary['topic_first_poster_colour']),
+ 'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row_ary['topic_poster'], $row_ary['topic_first_poster_name'], $row_ary['topic_first_poster_colour']),
+ 'TOPIC_AUTHOR_FULL' => get_username_string('full', $row_ary['topic_poster'], $row_ary['topic_first_poster_name'], $row_ary['topic_first_poster_colour']),
+ 'U_TOPIC_AUTHOR' => get_username_string('profile', $row_ary['topic_poster'], $row_ary['topic_first_poster_name'], $row_ary['topic_first_poster_colour']),
- 'LAST_POST_AUTHOR' => get_username_string('username', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
- 'LAST_POST_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
- 'LAST_POST_AUTHOR_FULL' => get_username_string('full', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
- 'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
+ 'LAST_POST_AUTHOR' => get_username_string('username', $row_ary['topic_last_poster_id'], $row_ary['topic_last_poster_name'], $row_ary['topic_last_poster_colour']),
+ 'LAST_POST_AUTHOR_COLOUR' => get_username_string('colour', $row_ary['topic_last_poster_id'], $row_ary['topic_last_poster_name'], $row_ary['topic_last_poster_colour']),
+ 'LAST_POST_AUTHOR_FULL' => get_username_string('full', $row_ary['topic_last_poster_id'], $row_ary['topic_last_poster_name'], $row_ary['topic_last_poster_colour']),
+ 'U_LAST_POST_AUTHOR' => get_username_string('profile', $row_ary['topic_last_poster_id'], $row_ary['topic_last_poster_name'], $row_ary['topic_last_poster_colour']),
'TOPIC_TYPE' => $topic_type,
'TOPIC_TITLE' => $topic_title,
- 'REPLIES' => $phpbb_content_visibility->get_count('topic_posts', $row, $row['forum_id']) - 1,
- 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']),
- 'FIRST_POST_TIME' => $user->format_date($row['topic_time']),
- 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'],
- 'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']),
+ 'REPLIES' => $phpbb_content_visibility->get_count('topic_posts', $row_ary, $row_ary['forum_id']) - 1,
+ 'LAST_POST_TIME' => $user->format_date($row_ary['topic_last_post_time']),
+ 'FIRST_POST_TIME' => $user->format_date($row_ary['topic_time']),
+ 'LAST_POST_SUBJECT' => $row_ary['topic_last_post_subject'],
+ 'LAST_VIEW_TIME' => $user->format_date($row_ary['topic_last_view_time']),
- 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && empty($row['topic_moved_id']) && $auth->acl_get('m_report', $row['forum_id'])) ? true : false,
+ 'S_TOPIC_REPORTED' => (!empty($row_ary['topic_reported']) && empty($row_ary['topic_moved_id']) && $auth->acl_get('m_report', $row_ary['forum_id'])) ? true : false,
'S_TOPIC_UNAPPROVED' => $topic_unapproved,
'S_POSTS_UNAPPROVED' => $posts_unapproved,
'S_TOPIC_DELETED' => $topic_deleted,
'S_UNREAD_TOPIC' => $unread_topic,
);
- if ($row['topic_status'] == ITEM_MOVED)
+ if ($row_ary['topic_status'] == ITEM_MOVED)
{
$topic_row = array_merge($topic_row, array(
- 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row['topic_moved_id']}"),
- 'U_DELETE_TOPIC' => ($auth->acl_get('m_delete', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&amp;f=$forum_id&amp;topic_id_list[]={$row['topic_id']}&amp;mode=forum_view&amp;action=delete_topic") : '',
+ 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t={$row_ary['topic_moved_id']}"),
+ 'U_DELETE_TOPIC' => ($auth->acl_get('m_delete', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&amp;f=$forum_id&amp;topic_id_list[]={$row_ary['topic_id']}&amp;mode=forum_view&amp;action=delete_topic") : '',
'S_MOVED_TOPIC' => true,
- 'TOPIC_ID' => $row['topic_moved_id'],
+ 'TOPIC_ID' => $row_ary['topic_moved_id'],
));
}
else
{
if ($action == 'merge_topic' || $action == 'merge_topics')
{
- $u_select_topic = $url . "&amp;i=$id&amp;mode=forum_view&amp;action=$action&amp;to_topic_id=" . $row['topic_id'] . $selected_ids;
+ $u_select_topic = $url . "&amp;i=$id&amp;mode=forum_view&amp;action=$action&amp;to_topic_id=" . $row_ary['topic_id'] . $selected_ids;
}
else
{
- $u_select_topic = $url . "&amp;i=$id&amp;mode=topic_view&amp;action=merge&amp;to_topic_id=" . $row['topic_id'] . $selected_ids;
+ $u_select_topic = $url . "&amp;i=$id&amp;mode=topic_view&amp;action=merge&amp;to_topic_id=" . $row_ary['topic_id'] . $selected_ids;
}
$topic_row = array_merge($topic_row, array(
- 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&amp;f=$forum_id&amp;t={$row['topic_id']}&amp;mode=topic_view"),
+ 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&amp;f=$forum_id&amp;t={$row_ary['topic_id']}&amp;mode=topic_view"),
- 'S_SELECT_TOPIC' => ($merge_select && !in_array($row['topic_id'], $source_topic_ids)) ? true : false,
+ 'S_SELECT_TOPIC' => ($merge_select && !in_array($row_ary['topic_id'], $source_topic_ids)) ? true : false,
'U_SELECT_TOPIC' => $u_select_topic,
'U_MCP_QUEUE' => $u_mcp_queue,
- 'U_MCP_REPORT' => ($auth->acl_get('m_report', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&amp;mode=topic_view&amp;t=' . $row['topic_id'] . '&amp;action=reports') : '',
- 'TOPIC_ID' => $row['topic_id'],
- 'S_TOPIC_CHECKED' => ($topic_id_list && in_array($row['topic_id'], $topic_id_list)) ? true : false,
+ 'U_MCP_REPORT' => ($auth->acl_get('m_report', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&amp;mode=topic_view&amp;t=' . $row_ary['topic_id'] . '&amp;action=reports') : '',
+ 'TOPIC_ID' => $row_ary['topic_id'],
+ 'S_TOPIC_CHECKED' => ($topic_id_list && in_array($row_ary['topic_id'], $topic_id_list)) ? true : false,
));
}
+ $row = $row_ary;
/**
* Modify the topic data before it is assigned to the template in MCP
*
* @event core.mcp_view_forum_modify_topicrow
- * @var array row Array with topic data
+ * @var array row Array with topic data
* @var array topic_row Template array with topic data
* @since 3.1.0-a1
*/
$vars = array('row', 'topic_row');
extract($phpbb_dispatcher->trigger_event('core.mcp_view_forum_modify_topicrow', compact($vars)));
+ $row_ary = $row;
+ unset($row);
$template->assign_block_vars('topicrow', $topic_row);
}
@@ -352,9 +356,9 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
*/
function mcp_resync_topics($topic_ids)
{
- global $auth, $db, $template, $phpEx, $user, $phpbb_root_path;
+ global $db, $user, $phpbb_log, $request;
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
@@ -377,13 +381,17 @@ function mcp_resync_topics($topic_ids)
// Log this action
while ($row = $db->sql_fetchrow($result))
{
- add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_TOPIC_RESYNC', $row['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_TOPIC_RESYNC', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $row['topic_id'],
+ $row['topic_title']
+ ));
}
$db->sql_freeresult($result);
- $msg = (sizeof($topic_ids) == 1) ? $user->lang['TOPIC_RESYNC_SUCCESS'] : $user->lang['TOPICS_RESYNC_SUCCESS'];
+ $msg = (count($topic_ids) == 1) ? $user->lang['TOPIC_RESYNC_SUCCESS'] : $user->lang['TOPICS_RESYNC_SUCCESS'];
- $redirect = request_var('redirect', $user->data['session_page']);
+ $redirect = $request->variable('redirect', $user->data['session_page']);
meta_refresh(3, $redirect);
trigger_error($msg . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>'));
@@ -396,9 +404,9 @@ function mcp_resync_topics($topic_ids)
*/
function merge_topics($forum_id, $topic_ids, $to_topic_id)
{
- global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $phpbb_dispatcher;
+ global $db, $template, $user, $phpEx, $phpbb_root_path, $phpbb_log, $request, $phpbb_dispatcher;
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
$template->assign_var('MESSAGE', $user->lang['NO_TOPIC_SELECTED']);
return;
@@ -413,7 +421,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id)
$all_topic_data = phpbb_get_topic_data($sync_topics, 'm_merge');
- if (!sizeof($all_topic_data) || empty($all_topic_data[$to_topic_id]))
+ if (!count($all_topic_data) || empty($all_topic_data[$to_topic_id]))
{
$template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']);
return;
@@ -429,10 +437,10 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id)
$to_topic_data = $all_topic_data[$to_topic_id];
- $post_id_list = request_var('post_id_list', array(0));
- $start = request_var('start', 0);
+ $post_id_list = $request->variable('post_id_list', array(0));
+ $start = $request->variable('start', 0);
- if (!sizeof($post_id_list) && sizeof($topic_ids))
+ if (!count($post_id_list) && count($topic_ids))
{
$sql = 'SELECT post_id
FROM ' . POSTS_TABLE . '
@@ -447,7 +455,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id)
$db->sql_freeresult($result);
}
- if (!sizeof($post_id_list))
+ if (!count($post_id_list))
{
$template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']);
return;
@@ -458,7 +466,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id)
return;
}
- $redirect = request_var('redirect', "{$phpbb_root_path}mcp.$phpEx?f=$forum_id&amp;i=main&amp;mode=forum_view");
+ $redirect = $request->variable('redirect', "{$phpbb_root_path}mcp.$phpEx?f=$forum_id&amp;i=main&amp;mode=forum_view");
$s_hidden_fields = build_hidden_fields(array(
'i' => 'main',
@@ -471,14 +479,19 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id)
'redirect' => $redirect,
'topic_id_list' => $topic_ids)
);
- $success_msg = $return_link = '';
+ $return_link = '';
if (confirm_box(true))
{
$to_forum_id = $to_topic_data['forum_id'];
move_posts($post_id_list, $to_topic_id, false);
- add_log('mod', $to_forum_id, $to_topic_id, 'LOG_MERGE', $to_topic_data['topic_title']);
+
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MERGE', false, array(
+ 'forum_id' => $to_forum_id,
+ 'topic_id' => $to_topic_id,
+ $to_topic_data['topic_title']
+ ));
// Update topic views count
$sql = 'UPDATE ' . TOPICS_TABLE . '
@@ -508,7 +521,7 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id)
// Link to the new topic
$return_link .= (($return_link) ? '<br /><br />' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&amp;t=' . $to_topic_id) . '">', '</a>');
- $redirect = request_var('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&amp;t=$to_topic_id");
+ $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&amp;t=$to_topic_id");
$redirect = reapply_sid($redirect);
/**
diff --git a/phpBB/includes/mcp/mcp_front.php b/phpBB/includes/mcp/mcp_front.php
index 5d8aa18c16..918a98734b 100644
--- a/phpBB/includes/mcp/mcp_front.php
+++ b/phpBB/includes/mcp/mcp_front.php
@@ -24,9 +24,9 @@ if (!defined('IN_PHPBB'))
*/
function mcp_front_view($id, $mode, $action)
{
- global $phpEx, $phpbb_root_path, $config;
+ global $phpEx, $phpbb_root_path;
global $template, $db, $user, $auth, $module;
- global $phpbb_dispatcher;
+ global $phpbb_dispatcher, $request;
// Latest 5 unapproved
if ($module->loaded('queue'))
@@ -35,7 +35,7 @@ function mcp_front_view($id, $mode, $action)
$post_list = array();
$forum_names = array();
- $forum_id = request_var('f', 0);
+ $forum_id = $request->variable('f', 0);
$template->assign_var('S_SHOW_UNAPPROVED', (!empty($forum_list)) ? true : false);
@@ -290,7 +290,10 @@ function mcp_front_view($id, $mode, $action)
if ($total)
{
- include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);
+ if (!function_exists('get_recipient_strings'))
+ {
+ include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);
+ }
$sql_ary = array(
'SELECT' => 'r.report_id, r.report_time, p.msg_id, p.message_subject, p.message_time, p.to_address, p.bcc_address, p.message_attachment, u.username, u.username_clean, u.user_colour, u.user_id, u2.username as author_name, u2.username_clean as author_name_clean, u2.user_colour as author_colour, u2.user_id as author_id',
diff --git a/phpBB/includes/mcp/mcp_logs.php b/phpBB/includes/mcp/mcp_logs.php
index 9c76f0df90..79f9d35ebe 100644
--- a/phpBB/includes/mcp/mcp_logs.php
+++ b/phpBB/includes/mcp/mcp_logs.php
@@ -28,19 +28,19 @@ class mcp_logs
var $u_action;
var $p_master;
- function mcp_logs(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $auth, $db, $user, $template;
- global $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_log;
+ global $auth, $db, $user, $template, $request;
+ global $config, $phpbb_container, $phpbb_log;
$user->add_lang('acp/common');
- $action = request_var('action', array('' => ''));
+ $action = $request->variable('action', array('' => ''));
if (is_array($action))
{
@@ -48,23 +48,24 @@ class mcp_logs
}
else
{
- $action = request_var('action', '');
+ $action = $request->variable('action', '');
}
// Set up general vars
- $start = request_var('start', 0);
+ $start = $request->variable('start', 0);
$deletemark = ($action == 'del_marked') ? true : false;
$deleteall = ($action == 'del_all') ? true : false;
- $marked = request_var('mark', array(0));
+ $marked = $request->variable('mark', array(0));
// Sort keys
- $sort_days = request_var('st', 0);
- $sort_key = request_var('sk', 't');
- $sort_dir = request_var('sd', 'd');
+ $sort_days = $request->variable('st', 0);
+ $sort_key = $request->variable('sk', 't');
+ $sort_dir = $request->variable('sd', 'd');
$this->tpl_name = 'mcp_logs';
$this->page_title = 'MCP_LOGS';
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
$forum_list = array_values(array_intersect(get_forum_list('f_read'), get_forum_list('m_')));
@@ -78,10 +79,11 @@ class mcp_logs
break;
case 'forum_logs':
- $forum_id = request_var('f', 0);
+ $forum_id = $request->variable('f', 0);
if (!in_array($forum_id, $forum_list))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
@@ -89,7 +91,7 @@ class mcp_logs
break;
case 'topic_logs':
- $topic_id = request_var('t', 0);
+ $topic_id = $request->variable('t', 0);
$sql = 'SELECT forum_id
FROM ' . TOPICS_TABLE . '
@@ -100,6 +102,7 @@ class mcp_logs
if (!in_array($forum_id, $forum_list))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
@@ -112,7 +115,7 @@ class mcp_logs
{
if (confirm_box(true))
{
- if ($deletemark && sizeof($marked))
+ if ($deletemark && count($marked))
{
$conditions = array(
'forum_id' => array('IN' => $forum_list),
@@ -123,7 +126,7 @@ class mcp_logs
}
else if ($deleteall)
{
- $keywords = utf8_normalize_nfc(request_var('keywords', '', true));
+ $keywords = $request->variable('keywords', '', true);
$conditions = array(
'forum_id' => array('IN' => $forum_list),
@@ -157,7 +160,7 @@ class mcp_logs
'sd' => $sort_dir,
'i' => $id,
'mode' => $mode,
- 'action' => request_var('action', array('' => ''))))
+ 'action' => $request->variable('action', array('' => ''))))
);
}
}
@@ -174,7 +177,7 @@ class mcp_logs
$sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0;
$sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC');
- $keywords = utf8_normalize_nfc(request_var('keywords', '', true));
+ $keywords = $request->variable('keywords', '', true);
$keywords_param = !empty($keywords) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : '';
// Grab log data
@@ -204,7 +207,7 @@ class mcp_logs
{
$data = array();
- $checks = array('viewtopic', 'viewforum');
+ $checks = array('viewpost', 'viewtopic', 'viewforum');
foreach ($checks as $check)
{
if (isset($row[$check]) && $row[$check])
@@ -218,7 +221,7 @@ class mcp_logs
'IP' => $row['ip'],
'DATE' => $user->format_date($row['time']),
'ACTION' => $row['action'],
- 'DATA' => (sizeof($data)) ? implode(' | ', $data) : '',
+ 'DATA' => (count($data)) ? implode(' | ', $data) : '',
'ID' => $row['id'],
)
);
diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php
index 69c66639df..744eaebd7d 100644
--- a/phpBB/includes/mcp/mcp_main.php
+++ b/phpBB/includes/mcp/mcp_main.php
@@ -28,26 +28,42 @@ class mcp_main
var $p_master;
var $u_action;
- function mcp_main(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $auth, $db, $user, $template, $action;
- global $config, $phpbb_root_path, $phpEx, $request;
+ global $auth, $user, $action;
+ global $phpbb_root_path, $phpEx, $request;
global $phpbb_dispatcher;
$quickmod = ($mode == 'quickmod') ? true : false;
+ /**
+ * Event to perform additional actions before an MCP action is executed.
+ *
+ * @event core.mcp_main_before
+ * @var string action The action that is about to be performed
+ * @var string mode The mode in which the MCP is accessed, e.g. front, forum_view, topic_view, post_details, quickmod
+ * @var boolean quickmod Whether or not the action is performed via QuickMod
+ * @since 3.2.8-RC1
+ */
+ $vars = [
+ 'action',
+ 'mode',
+ 'quickmod',
+ ];
+ extract($phpbb_dispatcher->trigger_event('core.mcp_main_before', compact($vars)));
+
switch ($action)
{
case 'lock':
case 'unlock':
- $topic_ids = (!$quickmod) ? request_var('topic_id_list', array(0)) : array(request_var('t', 0));
+ $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
@@ -58,9 +74,9 @@ class mcp_main
case 'lock_post':
case 'unlock_post':
- $post_ids = (!$quickmod) ? request_var('post_id_list', array(0)) : array(request_var('p', 0));
+ $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0));
- if (!sizeof($post_ids))
+ if (!count($post_ids))
{
trigger_error('NO_POST_SELECTED');
}
@@ -73,9 +89,9 @@ class mcp_main
case 'make_global':
case 'make_normal':
- $topic_ids = (!$quickmod) ? request_var('topic_id_list', array(0)) : array(request_var('t', 0));
+ $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
@@ -86,9 +102,9 @@ class mcp_main
case 'move':
$user->add_lang('viewtopic');
- $topic_ids = (!$quickmod) ? request_var('topic_id_list', array(0)) : array(request_var('t', 0));
+ $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
@@ -99,9 +115,9 @@ class mcp_main
case 'fork':
$user->add_lang('viewtopic');
- $topic_ids = (!$quickmod) ? request_var('topic_id_list', array(0)) : array(request_var('t', 0));
+ $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
@@ -118,7 +134,7 @@ class mcp_main
$topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
$soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false;
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
@@ -135,7 +151,7 @@ class mcp_main
$post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0));
$soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false;
- if (!sizeof($post_ids))
+ if (!count($post_ids))
{
trigger_error('NO_POST_SELECTED');
}
@@ -148,7 +164,7 @@ class mcp_main
$topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
@@ -174,7 +190,10 @@ class mcp_main
switch ($mode)
{
case 'front':
- include($phpbb_root_path . 'includes/mcp/mcp_front.' . $phpEx);
+ if (!function_exists('mcp_front_view'))
+ {
+ include($phpbb_root_path . 'includes/mcp/mcp_front.' . $phpEx);
+ }
$user->add_lang('acp/common');
@@ -185,15 +204,18 @@ class mcp_main
break;
case 'forum_view':
- include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx);
+ if (!function_exists('mcp_forum_view'))
+ {
+ include($phpbb_root_path . 'includes/mcp/mcp_forum.' . $phpEx);
+ }
$user->add_lang('viewforum');
- $forum_id = request_var('f', 0);
+ $forum_id = $request->variable('f', 0);
$forum_info = phpbb_get_forum_data($forum_id, 'm_', true);
- if (!sizeof($forum_info))
+ if (!count($forum_info))
{
$this->main('main', 'front');
return;
@@ -208,7 +230,10 @@ class mcp_main
break;
case 'topic_view':
- include($phpbb_root_path . 'includes/mcp/mcp_topic.' . $phpEx);
+ if (!function_exists('mcp_topic_view'))
+ {
+ include($phpbb_root_path . 'includes/mcp/mcp_topic.' . $phpEx);
+ }
mcp_topic_view($id, $mode, $action);
@@ -217,7 +242,10 @@ class mcp_main
break;
case 'post_details':
- include($phpbb_root_path . 'includes/mcp/mcp_post.' . $phpEx);
+ if (!function_exists('mcp_post_details'))
+ {
+ include($phpbb_root_path . 'includes/mcp/mcp_post.' . $phpEx);
+ }
mcp_post_details($id, $mode, $action);
@@ -262,7 +290,7 @@ class mcp_main
*/
function lock_unlock($action, $ids)
{
- global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_dispatcher;
+ global $user, $db, $request, $phpbb_log, $phpbb_dispatcher;
if ($action == 'lock' || $action == 'unlock')
{
@@ -298,7 +326,7 @@ function lock_unlock($action, $ids)
}
unset($orig_ids);
- $redirect = request_var('redirect', build_url(array('action', 'quickmod')));
+ $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
$redirect = reapply_sid($redirect);
$s_hidden_fields = build_hidden_fields(array(
@@ -306,7 +334,6 @@ function lock_unlock($action, $ids)
'action' => $action,
'redirect' => $redirect)
);
- $success_msg = '';
if (confirm_box(true))
{
@@ -319,7 +346,12 @@ function lock_unlock($action, $ids)
foreach ($data as $id => $row)
{
- add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_' . strtoupper($action), $row['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_' . strtoupper($action), false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $row['topic_id'],
+ 'post_id' => isset($row['post_id']) ? $row['post_id'] : 0,
+ $row['topic_title']
+ ));
}
/**
@@ -338,7 +370,7 @@ function lock_unlock($action, $ids)
);
extract($phpbb_dispatcher->trigger_event('core.mcp_lock_unlock_after', compact($vars)));
- $success_msg = $l_prefix . ((sizeof($ids) == 1) ? '' : 'S') . '_' . (($action == 'lock' || $action == 'lock_post') ? 'LOCKED' : 'UNLOCKED') . '_SUCCESS';
+ $success_msg = $l_prefix . ((count($ids) == 1) ? '' : 'S') . '_' . (($action == 'lock' || $action == 'lock_post') ? 'LOCKED' : 'UNLOCKED') . '_SUCCESS';
meta_refresh(2, $redirect);
$message = $user->lang[$success_msg];
@@ -351,7 +383,7 @@ function lock_unlock($action, $ids)
}
else
{
- confirm_box(false, strtoupper($action) . '_' . $l_prefix . ((sizeof($ids) == 1) ? '' : 'S'), $s_hidden_fields);
+ confirm_box(false, strtoupper($action) . '_' . $l_prefix . ((count($ids) == 1) ? '' : 'S'), $s_hidden_fields);
}
redirect($redirect);
@@ -362,32 +394,32 @@ function lock_unlock($action, $ids)
*/
function change_topic_type($action, $topic_ids)
{
- global $auth, $user, $db, $phpEx, $phpbb_root_path, $request;
+ global $user, $db, $request, $phpbb_log, $phpbb_dispatcher;
switch ($action)
{
case 'make_announce':
$new_topic_type = POST_ANNOUNCE;
$check_acl = 'f_announce';
- $l_new_type = (sizeof($topic_ids) == 1) ? 'MCP_MAKE_ANNOUNCEMENT' : 'MCP_MAKE_ANNOUNCEMENTS';
+ $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_ANNOUNCEMENT' : 'MCP_MAKE_ANNOUNCEMENTS';
break;
case 'make_global':
$new_topic_type = POST_GLOBAL;
- $check_acl = 'f_announce';
- $l_new_type = (sizeof($topic_ids) == 1) ? 'MCP_MAKE_GLOBAL' : 'MCP_MAKE_GLOBALS';
+ $check_acl = 'f_announce_global';
+ $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_GLOBAL' : 'MCP_MAKE_GLOBALS';
break;
case 'make_sticky':
$new_topic_type = POST_STICKY;
$check_acl = 'f_sticky';
- $l_new_type = (sizeof($topic_ids) == 1) ? 'MCP_MAKE_STICKY' : 'MCP_MAKE_STICKIES';
+ $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_STICKY' : 'MCP_MAKE_STICKIES';
break;
default:
$new_topic_type = POST_NORMAL;
$check_acl = false;
- $l_new_type = (sizeof($topic_ids) == 1) ? 'MCP_MAKE_NORMAL' : 'MCP_MAKE_NORMALS';
+ $l_new_type = (count($topic_ids) == 1) ? 'MCP_MAKE_NORMAL' : 'MCP_MAKE_NORMALS';
break;
}
@@ -398,7 +430,7 @@ function change_topic_type($action, $topic_ids)
return;
}
- $redirect = request_var('redirect', build_url(array('action', 'quickmod')));
+ $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
$redirect = reapply_sid($redirect);
$s_hidden_fields = array(
@@ -407,40 +439,75 @@ function change_topic_type($action, $topic_ids)
'action' => $action,
'redirect' => $redirect,
);
- $success_msg = '';
if (confirm_box(true))
{
+
+ /**
+ * Perform additional actions before changing topic(s) type
+ *
+ * @event core.mcp_change_topic_type_before
+ * @var int new_topic_type The candidated topic type.
+ * @var int forum_id The forum ID for the topic ID(s).
+ * @var array topic_ids Array containing the topic ID(s) that will be changed
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'new_topic_type',
+ 'forum_id',
+ 'topic_ids',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.mcp_change_topic_type_before', compact($vars)));
+
+ $db->sql_transaction('begin');
+
$sql = 'UPDATE ' . TOPICS_TABLE . "
SET topic_type = $new_topic_type
WHERE " . $db->sql_in_set('topic_id', $topic_ids);
$db->sql_query($sql);
- if (($new_topic_type == POST_GLOBAL) && sizeof($topic_ids))
+ if (($new_topic_type == POST_GLOBAL) && count($topic_ids))
{
// Delete topic shadows for global announcements
$sql = 'DELETE FROM ' . TOPICS_TABLE . '
WHERE ' . $db->sql_in_set('topic_moved_id', $topic_ids);
$db->sql_query($sql);
-
- $sql = 'UPDATE ' . TOPICS_TABLE . "
- SET topic_type = $new_topic_type
- WHERE " . $db->sql_in_set('topic_id', $topic_ids);
- $db->sql_query($sql);
}
- $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_TYPE_CHANGED' : 'TOPICS_TYPE_CHANGED';
+ $db->sql_transaction('commit');
+
+ $success_msg = (count($topic_ids) == 1) ? 'TOPIC_TYPE_CHANGED' : 'TOPICS_TYPE_CHANGED';
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$data = phpbb_get_topic_data($topic_ids);
foreach ($data as $topic_id => $row)
{
- add_log('mod', $forum_id, $topic_id, 'LOG_TOPIC_TYPE_CHANGED', $row['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_TOPIC_TYPE_CHANGED', false, array(
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ $row['topic_title']
+ ));
}
}
+ /**
+ * Perform additional actions after changing topic types
+ *
+ * @event core.mcp_change_topic_type_after
+ * @var int new_topic_type The newly changed topic type.
+ * @var int forum_id The forum ID where the newly changed topic type belongs to.
+ * @var array topic_ids Array containing the topic IDs that have been changed
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'new_topic_type',
+ 'forum_id',
+ 'topic_ids',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.mcp_change_topic_type_after', compact($vars)));
+
meta_refresh(2, $redirect);
$message = $user->lang[$success_msg];
@@ -474,8 +541,8 @@ function mcp_move_topic($topic_ids)
return;
}
- $to_forum_id = request_var('to_forum_id', 0);
- $redirect = request_var('redirect', build_url(array('action', 'quickmod')));
+ $to_forum_id = $request->variable('to_forum_id', 0);
+ $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
$additional_msg = $success_msg = '';
$s_hidden_fields = build_hidden_fields(array(
@@ -489,7 +556,7 @@ function mcp_move_topic($topic_ids)
{
$forum_data = phpbb_get_forum_data($to_forum_id, 'f_post');
- if (!sizeof($forum_data))
+ if (!count($forum_data))
{
$additional_msg = $user->lang['FORUM_NOT_EXIST'];
}
@@ -684,7 +751,7 @@ function mcp_move_topic($topic_ids)
$sync_sql[$forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted - ' . (int) $topics_moved_softdeleted;
}
- $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_MOVED_SUCCESS' : 'TOPICS_MOVED_SUCCESS';
+ $success_msg = (count($topic_ids) == 1) ? 'TOPIC_MOVED_SUCCESS' : 'TOPICS_MOVED_SUCCESS';
foreach ($sync_sql as $forum_id_key => $array)
{
@@ -707,10 +774,10 @@ function mcp_move_topic($topic_ids)
'ADDITIONAL_MSG' => $additional_msg)
);
- confirm_box(false, 'MOVE_TOPIC' . ((sizeof($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html');
+ confirm_box(false, 'MOVE_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html');
}
- $redirect = request_var('redirect', "index.$phpEx");
+ $redirect = $request->variable('redirect', "index.$phpEx");
$redirect = reapply_sid($redirect);
if (!$success_msg)
@@ -735,7 +802,7 @@ function mcp_move_topic($topic_ids)
*/
function mcp_restore_topic($topic_ids)
{
- global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container;
+ global $user, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log;
if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_approve')))
{
@@ -755,23 +822,29 @@ function mcp_restore_topic($topic_ids)
if (confirm_box(true))
{
- $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_RESTORED_SUCCESS' : 'TOPICS_RESTORED_SUCCESS';
+ $success_msg = (count($topic_ids) == 1) ? 'TOPIC_RESTORED_SUCCESS' : 'TOPICS_RESTORED_SUCCESS';
$data = phpbb_get_topic_data($topic_ids);
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
foreach ($data as $topic_id => $row)
{
$return = $phpbb_content_visibility->set_topic_visibility(ITEM_APPROVED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), '');
if (!empty($return))
{
- add_log('mod', $row['forum_id'], $topic_id, 'LOG_RESTORE_TOPIC', $row['topic_title'], $row['topic_first_poster_name']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_RESTORE_TOPIC', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $topic_id,
+ $row['topic_title'],
+ $row['topic_first_poster_name']
+ ));
}
}
}
else
{
- confirm_box(false, (sizeof($topic_ids) == 1) ? 'RESTORE_TOPIC' : 'RESTORE_TOPICS', $s_hidden_fields);
+ confirm_box(false, (count($topic_ids) == 1) ? 'RESTORE_TOPIC' : 'RESTORE_TOPICS', $s_hidden_fields);
}
$topic_id = $request->variable('t', 0);
@@ -808,7 +881,7 @@ function mcp_restore_topic($topic_ids)
*/
function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_topic')
{
- global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container;
+ global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log;
$check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete';
if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array($check_permission)))
@@ -829,7 +902,7 @@ function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = ''
if (confirm_box(true))
{
- $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_DELETED_SUCCESS' : 'TOPICS_DELETED_SUCCESS';
+ $success_msg = (count($topic_ids) == 1) ? 'TOPIC_DELETED_SUCCESS' : 'TOPICS_DELETED_SUCCESS';
$data = phpbb_get_topic_data($topic_ids);
@@ -837,30 +910,47 @@ function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = ''
{
if ($row['topic_moved_id'])
{
- add_log('mod', $row['forum_id'], $topic_id, 'LOG_DELETE_SHADOW_TOPIC', $row['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_DELETE_SHADOW_TOPIC', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $topic_id,
+ $row['topic_title']
+ ));
}
else
{
// Only soft delete non-shadow topics
if ($is_soft)
{
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
$return = $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), $soft_delete_reason);
if (!empty($return))
{
- add_log('mod', $row['forum_id'], $topic_id, 'LOG_SOFTDELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name'], $soft_delete_reason);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SOFTDELETE_TOPIC', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $topic_id,
+ $row['topic_title'],
+ $row['topic_first_poster_name'],
+ $soft_delete_reason
+ ));
}
}
else
{
- add_log('mod', $row['forum_id'], $topic_id, 'LOG_DELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name'], $soft_delete_reason);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_DELETE_TOPIC', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $topic_id,
+ $row['topic_title'],
+ $row['topic_first_poster_name'],
+ $soft_delete_reason
+ ));
}
}
}
if (!$is_soft)
{
- $return = delete_topics('topic_id', $topic_ids);
+ delete_topics('topic_id', $topic_ids);
}
}
else
@@ -897,13 +987,14 @@ function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = ''
'S_TOPIC_MODE' => true,
'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
- 'DELETE_TOPIC_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_TOPIC_PERMANENTLY', sizeof($topic_ids)),
+ 'DELETE_TOPIC_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_TOPIC_PERMANENTLY', count($topic_ids)),
));
- $l_confirm = (sizeof($topic_ids) == 1) ? 'DELETE_TOPIC' : 'DELETE_TOPICS';
+ $count = count($topic_ids);
+ $l_confirm = $count === 1 ? 'DELETE_TOPIC' : 'DELETE_TOPICS';
if ($only_softdeleted)
{
- $l_confirm .= '_PERMANENTLY';
+ $l_confirm = array($l_confirm . '_PERMANENTLY', $count);
$s_hidden_fields['delete_permanent'] = '1';
}
else if ($only_shadow || !$auth->acl_get('m_softdelete', $forum_id))
@@ -948,7 +1039,7 @@ function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = ''
*/
function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_post')
{
- global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container;
+ global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_log;
$check_permission = ($is_soft) ? 'm_softdelete' : 'm_delete';
if (!phpbb_check_ids($post_ids, POSTS_TABLE, 'post_id', array($check_permission)))
@@ -998,6 +1089,7 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
$approve_log[] = array(
'forum_id' => $post_data['forum_id'],
'topic_id' => $post_data['topic_id'],
+ 'post_id' => $post_id,
'post_subject' => $post_data['post_subject'],
'poster_id' => $post_data['poster_id'],
'post_username' => $post_data['post_username'],
@@ -1005,21 +1097,29 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
);
}
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
foreach ($topic_info as $topic_id => $topic_data)
{
$phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $topic_data['posts'], $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), $soft_delete_reason, isset($topic_data['first_post']), isset($topic_data['last_post']));
}
- $affected_topics = sizeof($topic_info);
+ $affected_topics = count($topic_info);
// None of the topics is really deleted, so a redirect won't hurt much.
$deleted_topics = 0;
- $success_msg = (sizeof($post_info) == 1) ? $user->lang['POST_DELETED_SUCCESS'] : $user->lang['POSTS_DELETED_SUCCESS'];
+ $success_msg = (count($post_info) == 1) ? $user->lang['POST_DELETED_SUCCESS'] : $user->lang['POSTS_DELETED_SUCCESS'];
foreach ($approve_log as $row)
{
$post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username'];
- add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_SOFTDELETE_POST', $row['post_subject'], $post_username, $soft_delete_reason);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SOFTDELETE_POST', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $row['topic_id'],
+ 'post_id' => $row['post_id'],
+ $row['post_subject'],
+ $post_username,
+ $soft_delete_reason
+ ));
}
$topic_id = $request->variable('t', 0);
@@ -1054,7 +1154,7 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
{
$topic_id_list[] = $row['topic_id'];
}
- $affected_topics = sizeof($topic_id_list);
+ $affected_topics = count($topic_id_list);
$db->sql_freeresult($result);
$post_data = phpbb_get_post_data($post_ids);
@@ -1062,7 +1162,14 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
foreach ($post_data as $id => $row)
{
$post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username'];
- add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_DELETE_POST', $row['post_subject'], $post_username, $soft_delete_reason);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_DELETE_POST', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $row['topic_id'],
+ 'post_id' => $row['post_id'],
+ $row['post_subject'],
+ $post_username,
+ $soft_delete_reason
+ ));
}
// Now delete the posts, topics and forums are automatically resync'ed
@@ -1086,7 +1193,7 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
}
$return_link[] = sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>');
- if (sizeof($post_ids) == 1)
+ if (count($post_ids) == 1)
{
if ($deleted_topics)
{
@@ -1135,13 +1242,14 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
'S_SOFTDELETED' => $only_softdeleted,
'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
- 'DELETE_POST_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_POST_PERMANENTLY', sizeof($post_ids)),
+ 'DELETE_POST_PERMANENTLY_EXPLAIN' => $user->lang('DELETE_POST_PERMANENTLY', count($post_ids)),
));
- $l_confirm = (sizeof($post_ids) == 1) ? 'DELETE_POST' : 'DELETE_POSTS';
+ $count = count($post_ids);
+ $l_confirm = $count === 1 ? 'DELETE_POST' : 'DELETE_POSTS';
if ($only_softdeleted)
{
- $l_confirm .= '_PERMANENTLY';
+ $l_confirm = array($l_confirm . '_PERMANENTLY', $count);
$s_hidden_fields['delete_permanent'] = '1';
}
else if (!$auth->acl_get('m_softdelete', $forum_id))
@@ -1177,16 +1285,16 @@ function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '',
function mcp_fork_topic($topic_ids)
{
global $auth, $user, $db, $template, $config;
- global $phpEx, $phpbb_root_path, $phpbb_dispatcher;
+ global $phpEx, $phpbb_root_path, $phpbb_log, $request, $phpbb_dispatcher;
if (!phpbb_check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_')))
{
return;
}
- $to_forum_id = request_var('to_forum_id', 0);
- $forum_id = request_var('f', 0);
- $redirect = request_var('redirect', build_url(array('action', 'quickmod')));
+ $to_forum_id = $request->variable('to_forum_id', 0);
+ $forum_id = $request->variable('f', 0);
+ $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
$additional_msg = $success_msg = '';
$counter = array();
@@ -1201,11 +1309,11 @@ function mcp_fork_topic($topic_ids)
{
$forum_data = phpbb_get_forum_data($to_forum_id, 'f_post');
- if (!sizeof($topic_ids))
+ if (!count($topic_ids))
{
$additional_msg = $user->lang['NO_TOPIC_SELECTED'];
}
- else if (!sizeof($forum_data))
+ else if (!count($forum_data))
{
$additional_msg = $user->lang['FORUM_NOT_EXIST'];
}
@@ -1331,8 +1439,6 @@ function mcp_fork_topic($topic_ids)
if ($topic_row['poll_start'])
{
- $poll_rows = array();
-
$sql = 'SELECT *
FROM ' . POLL_OPTIONS_TABLE . "
WHERE topic_id = $topic_id";
@@ -1365,7 +1471,7 @@ function mcp_fork_topic($topic_ids)
}
$db->sql_freeresult($result);
- if (!sizeof($post_rows))
+ if (!count($post_rows))
{
continue;
}
@@ -1414,6 +1520,24 @@ function mcp_fork_topic($topic_ids)
$db->sql_query('INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
$new_post_id = $db->sql_nextid();
+ /**
+ * Perform actions after forked topic is created.
+ *
+ * @event core.mcp_main_fork_sql_after
+ * @var int new_topic_id The newly created topic ID
+ * @var int to_forum_id The forum ID where the forked topic has been moved to
+ * @var int new_post_id The newly created post ID
+ * @var array row Post data
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'new_topic_id',
+ 'to_forum_id',
+ 'new_post_id',
+ 'row',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.mcp_main_fork_sql_after', compact($vars)));
+
switch ($row['post_visibility'])
{
case ITEM_APPROVED:
@@ -1468,7 +1592,7 @@ function mcp_fork_topic($topic_ids)
}
$db->sql_freeresult($result);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(ATTACHMENTS_TABLE, $sql_ary);
}
@@ -1492,7 +1616,7 @@ function mcp_fork_topic($topic_ids)
}
$db->sql_freeresult($result);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary);
}
@@ -1513,7 +1637,7 @@ function mcp_fork_topic($topic_ids)
}
$db->sql_freeresult($result);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary);
}
@@ -1545,15 +1669,19 @@ function mcp_fork_topic($topic_ids)
sync('topic', 'topic_id', $new_topic_id_list);
sync('forum', 'forum_id', $to_forum_id);
- set_config_count('num_topics', sizeof($new_topic_id_list), true);
- set_config_count('num_posts', $total_posts, true);
+ $config->increment('num_topics', count($new_topic_id_list), false);
+ $config->increment('num_posts', $total_posts, false);
foreach ($new_topic_id_list as $topic_id => $new_topic_id)
{
- add_log('mod', $to_forum_id, $new_topic_id, 'LOG_FORK', $topic_row['forum_name']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_FORK', false, array(
+ 'forum_id' => $to_forum_id,
+ 'topic_id' => $new_topic_id,
+ $topic_row['forum_name']
+ ));
}
- $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_FORKED_SUCCESS' : 'TOPICS_FORKED_SUCCESS';
+ $success_msg = (count($topic_ids) == 1) ? 'TOPIC_FORKED_SUCCESS' : 'TOPICS_FORKED_SUCCESS';
}
else
{
@@ -1563,10 +1691,10 @@ function mcp_fork_topic($topic_ids)
'ADDITIONAL_MSG' => $additional_msg)
);
- confirm_box(false, 'FORK_TOPIC' . ((sizeof($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html');
+ confirm_box(false, 'FORK_TOPIC' . ((count($topic_ids) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_move.html');
}
- $redirect = request_var('redirect', "index.$phpEx");
+ $redirect = $request->variable('redirect', "index.$phpEx");
$redirect = reapply_sid($redirect);
if (!$success_msg)
diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php
index 465ee63a98..a4c2356a43 100644
--- a/phpBB/includes/mcp/mcp_notes.php
+++ b/phpBB/includes/mcp/mcp_notes.php
@@ -28,17 +28,17 @@ class mcp_notes
var $p_master;
var $u_action;
- function mcp_notes(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $auth, $db, $user, $template;
- global $config, $phpbb_root_path, $phpEx;
+ global $user, $template, $request;
+ global $phpbb_root_path, $phpEx;
- $action = request_var('action', array('' => ''));
+ $action = $request->variable('action', array('' => ''));
if (is_array($action))
{
@@ -74,15 +74,17 @@ class mcp_notes
*/
function mcp_notes_user_view($action)
{
- global $phpEx, $phpbb_root_path, $config;
+ global $config, $phpbb_log, $request;
global $template, $db, $user, $auth, $phpbb_container;
- $user_id = request_var('u', 0);
- $username = request_var('username', '', true);
- $start = request_var('start', 0);
- $st = request_var('st', 0);
- $sk = request_var('sk', 'b');
- $sd = request_var('sd', 'd');
+ $user_id = $request->variable('u', 0);
+ $username = $request->variable('username', '', true);
+ $start = $request->variable('start', 0);
+ $st = $request->variable('st', 0);
+ $sk = $request->variable('sk', 'b');
+ $sd = $request->variable('sd', 'd');
+
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
add_form_key('mcp_notes');
@@ -114,8 +116,8 @@ class mcp_notes
$deletemark = ($action == 'del_marked') ? true : false;
$deleteall = ($action == 'del_all') ? true : false;
- $marked = request_var('marknote', array(0));
- $usernote = utf8_normalize_nfc(request_var('usernote', '', true));
+ $marked = $request->variable('marknote', array(0));
+ $usernote = $request->variable('usernote', '', true);
// Handle any actions
if (($deletemark || $deleteall) && $auth->acl_get('a_clearlogs'))
@@ -142,7 +144,7 @@ class mcp_notes
$where_sql";
$db->sql_query($sql);
- add_log('admin', 'LOG_CLEAR_USER', $userrow['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CLEAR_USER', false, array($userrow['username']));
$msg = ($deletemark) ? 'MARKED_NOTES_DELETED' : 'ALL_NOTES_DELETED';
}
@@ -160,10 +162,17 @@ class mcp_notes
{
if (check_form_key('mcp_notes'))
{
- add_log('admin', 'LOG_USER_FEEDBACK', $userrow['username']);
- add_log('mod', 0, 0, 'LOG_USER_FEEDBACK', $userrow['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_FEEDBACK', false, array($userrow['username']));
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_USER_FEEDBACK', false, array(
+ 'forum_id' => 0,
+ 'topic_id' => 0,
+ $userrow['username']
+ ));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_GENERAL', false, array(
+ 'reportee_id' => $user_id,
+ $usernote
+ ));
- add_log('user', $user_id, 'LOG_USER_GENERAL', $usernote);
$msg = $user->lang['USER_FEEDBACK_ADDED'];
}
else
@@ -192,7 +201,7 @@ class mcp_notes
$sql_where = ($st) ? (time() - ($st * 86400)) : 0;
$sql_sort = $sort_by_sql[$sk] . ' ' . (($sd == 'd') ? 'DESC' : 'ASC');
- $keywords = utf8_normalize_nfc(request_var('keywords', '', true));
+ $keywords = $request->variable('keywords', '', true);
$keywords_param = !empty($keywords) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : '';
$log_data = array();
diff --git a/phpBB/includes/mcp/mcp_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php
index d76bedba98..eecfe9cbc8 100644
--- a/phpBB/includes/mcp/mcp_pm_reports.php
+++ b/phpBB/includes/mcp/mcp_pm_reports.php
@@ -28,21 +28,22 @@ class mcp_pm_reports
var $p_master;
var $u_action;
- function mcp_pm_reports(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $auth, $db, $user, $template, $cache;
+ global $auth, $db, $user, $template, $request;
global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);
- $start = request_var('start', 0);
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
+ $start = $request->variable('start', 0);
$this->page_title = 'MCP_PM_REPORTS';
@@ -52,9 +53,9 @@ class mcp_pm_reports
case 'delete':
include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $report_id_list = request_var('report_id_list', array(0));
+ $report_id_list = $request->variable('report_id_list', array(0));
- if (!sizeof($report_id_list))
+ if (!count($report_id_list))
{
trigger_error('NO_REPORT_SELECTED');
}
@@ -75,7 +76,7 @@ class mcp_pm_reports
$user->add_lang(array('posting', 'viewforum', 'viewtopic', 'ucp'));
- $report_id = request_var('r', 0);
+ $report_id = $request->variable('r', 0);
$sql = 'SELECT r.pm_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour
FROM ' . REPORTS_TABLE . ' r, ' . REPORTS_REASONS_TABLE . ' rr, ' . USERS_TABLE . ' u
@@ -93,16 +94,17 @@ class mcp_pm_reports
trigger_error('NO_REPORT');
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
- $phpbb_notifications->mark_notifications_read_by_parent('notification.type.report_pm', $report_id, $user->data['user_id']);
+ $phpbb_notifications->mark_notifications_by_parent('report_pm', $report_id, $user->data['user_id']);
$pm_id = $report['pm_id'];
$report_id = $report['report_id'];
$pm_info = phpbb_get_pm_data(array($pm_id));
- if (!sizeof($pm_info))
+ if (!count($pm_info))
{
trigger_error('NO_REPORT_SELECTED');
}
@@ -139,7 +141,7 @@ class mcp_pm_reports
}
$db->sql_freeresult($result);
- if (sizeof($attachments))
+ if (count($attachments))
{
$update_count = array();
parse_attachments(0, $message, $attachments, $update_count);
@@ -199,7 +201,7 @@ class mcp_pm_reports
'POST_SUBJECT' => ($pm_info['message_subject']) ? $pm_info['message_subject'] : $user->lang['NO_SUBJECT'],
'POST_DATE' => $user->format_date($pm_info['message_time']),
'POST_IP' => $pm_info['author_ip'],
- 'POST_IPADDR' => ($auth->acl_getf_global('m_info') && request_var('lookup', '')) ? @gethostbyaddr($pm_info['author_ip']) : '',
+ 'POST_IPADDR' => ($auth->acl_getf_global('m_info') && $request->variable('lookup', '')) ? @gethostbyaddr($pm_info['author_ip']) : '',
'POST_ID' => $pm_info['msg_id'],
'U_LOOKUP_IP' => ($auth->acl_getf_global('m_info')) ? $this->u_action . '&amp;r=' . $report_id . '&amp;pm=' . $pm_id . '&amp;lookup=' . $pm_info['author_ip'] . '#ip' : '',
@@ -249,7 +251,7 @@ class mcp_pm_reports
}
$db->sql_freeresult($result);
- if (sizeof($report_ids))
+ if (count($report_ids))
{
$sql = 'SELECT p.*, u.username, u.username_clean, u.user_colour, r.user_id as reporter_id, ru.username as reporter_name, ru.user_colour as reporter_colour, r.report_time, r.report_id
FROM ' . REPORTS_TABLE . ' r, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u, ' . USERS_TABLE . ' ru
@@ -268,7 +270,7 @@ class mcp_pm_reports
}
$db->sql_freeresult($result);
- if (sizeof($pm_list))
+ if (count($pm_list))
{
$address_list = get_recipient_strings($pm_by_id);
diff --git a/phpBB/includes/mcp/mcp_post.php b/phpBB/includes/mcp/mcp_post.php
index 1cf4a74234..8d278079fb 100644
--- a/phpBB/includes/mcp/mcp_post.php
+++ b/phpBB/includes/mcp/mcp_post.php
@@ -25,20 +25,20 @@ if (!defined('IN_PHPBB'))
function mcp_post_details($id, $mode, $action)
{
global $phpEx, $phpbb_root_path, $config, $request;
- global $template, $db, $user, $auth, $cache, $phpbb_container;
- global $phpbb_dispatcher;
+ global $template, $db, $user, $auth;
+ global $phpbb_container, $phpbb_dispatcher;
$user->add_lang('posting');
- $post_id = request_var('p', 0);
- $start = request_var('start', 0);
+ $post_id = $request->variable('p', 0);
+ $start = $request->variable('start', 0);
// Get post data
$post_info = phpbb_get_post_data(array($post_id), false, true);
add_form_key('mcp_post_details');
- if (!sizeof($post_info))
+ if (!count($post_info))
{
trigger_error('POST_NOT_EXIST');
}
@@ -52,7 +52,7 @@ function mcp_post_details($id, $mode, $action)
if ($auth->acl_get('m_info', $post_info['forum_id']))
{
- $ip = request_var('ip', '');
+ $ip = $request->variable('ip', '');
if (!function_exists('user_ipwhois'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
@@ -76,12 +76,12 @@ function mcp_post_details($id, $mode, $action)
if ($action == 'chgposter')
{
- $username = request_var('username', '', true);
+ $username = $request->variable('username', '', true);
$sql_where = "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
}
else
{
- $new_user_id = request_var('u', 0);
+ $new_user_id = $request->variable('u', 0);
$sql_where = 'user_id = ' . $new_user_id;
}
@@ -131,7 +131,6 @@ function mcp_post_details($id, $mode, $action)
$users_ary = $usernames_ary = array();
$attachments = $extensions = array();
$post_id = $post_info['post_id'];
- $topic_tracking_info = array();
// Get topic tracking info
if ($config['load_db_lastread'])
@@ -153,8 +152,6 @@ function mcp_post_details($id, $mode, $action)
if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id']))
{
- $extensions = $cache->obtain_attach_extensions($post_info['forum_id']);
-
$sql = 'SELECT *
FROM ' . ATTACHMENTS_TABLE . '
WHERE post_msg_id = ' . $post_id . '
@@ -168,7 +165,7 @@ function mcp_post_details($id, $mode, $action)
}
$db->sql_freeresult($result);
- if (sizeof($attachments))
+ if (count($attachments))
{
$user->add_lang('viewtopic');
$update_count = array();
@@ -216,6 +213,10 @@ function mcp_post_details($id, $mode, $action)
$l_deleted_by = '';
}
+ // parse signature
+ $parse_flags = ($post_info['user_sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $post_info['user_sig'] = generate_text_for_display($post_info['user_sig'], $post_info['user_sig_bbcode_uid'], $post_info['user_sig_bbcode_bitfield'], $parse_flags, true);
+
$mcp_post_template_data = array(
'U_MCP_ACTION' => "$url&amp;i=main&amp;quickmod=1&amp;mode=post_details", // Use this for mode paramaters
'U_POST_ACTION' => "$url&amp;i=$id&amp;mode=post_details", // Use this for action parameters
@@ -263,8 +264,9 @@ function mcp_post_details($id, $mode, $action)
'POST_SUBJECT' => $post_info['post_subject'],
'POST_DATE' => $user->format_date($post_info['post_time']),
'POST_IP' => $post_info['poster_ip'],
- 'POST_IPADDR' => ($auth->acl_get('m_info', $post_info['forum_id']) && request_var('lookup', '')) ? @gethostbyaddr($post_info['poster_ip']) : '',
+ 'POST_IPADDR' => ($auth->acl_get('m_info', $post_info['forum_id']) && $request->variable('lookup', '')) ? @gethostbyaddr($post_info['poster_ip']) : '',
'POST_ID' => $post_info['post_id'],
+ 'SIGNATURE' => $post_info['user_sig'],
'U_LOOKUP_IP' => ($auth->acl_get('m_info', $post_info['forum_id'])) ? "$url&amp;i=$id&amp;mode=$mode&amp;lookup={$post_info['poster_ip']}#ip" : '',
'U_WHOIS' => ($auth->acl_get('m_info', $post_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&amp;mode=$mode&amp;action=whois&amp;p=$post_id&amp;ip={$post_info['poster_ip']}") : '',
@@ -412,7 +414,7 @@ function mcp_post_details($id, $mode, $action)
);
}
- if (sizeof($users_ary))
+ if (count($users_ary))
{
// Get the usernames
$sql = 'SELECT user_id, username
@@ -498,7 +500,7 @@ function mcp_post_details($id, $mode, $action)
$user_select = '';
- if (sizeof($usernames_ary))
+ if (count($usernames_ary))
{
ksort($usernames_ary);
@@ -556,7 +558,7 @@ function phpbb_get_num_ips_for_poster(\phpbb\db\driver\driver_interface $db, $po
*/
function change_poster(&$post_info, $userdata)
{
- global $auth, $db, $config, $phpbb_root_path, $phpEx, $user, $phpbb_dispatcher;
+ global $auth, $db, $config, $phpbb_root_path, $phpEx, $user, $phpbb_log, $phpbb_dispatcher;
if (empty($userdata) || $userdata['user_id'] == $post_info['user_id'])
{
@@ -659,7 +661,7 @@ function change_poster(&$post_info, $userdata)
// Renew post info
$post_info = phpbb_get_post_data(array($post_id), false, true);
- if (!sizeof($post_info))
+ if (!count($post_info))
{
trigger_error('POST_NOT_EXIST');
}
@@ -667,5 +669,12 @@ function change_poster(&$post_info, $userdata)
$post_info = $post_info[$post_id];
// Now add log entry
- add_log('mod', $post_info['forum_id'], $post_info['topic_id'], 'LOG_MCP_CHANGE_POSTER', $post_info['topic_title'], $from_username, $to_username);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MCP_CHANGE_POSTER', false, array(
+ 'forum_id' => $post_info['forum_id'],
+ 'topic_id' => $post_info['topic_id'],
+ 'post_id' => $post_info['post_id'],
+ $post_info['topic_title'],
+ $from_username,
+ $to_username
+ ));
}
diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php
index 3567e545f0..dec583f6f4 100644
--- a/phpBB/includes/mcp/mcp_queue.php
+++ b/phpBB/includes/mcp/mcp_queue.php
@@ -28,21 +28,21 @@ class mcp_queue
var $p_master;
var $u_action;
- public function mcp_queue(&$p_master)
+ public function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
public function main($id, $mode)
{
- global $auth, $db, $user, $template, $cache, $request;
+ global $auth, $db, $user, $template, $request;
global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
global $phpbb_dispatcher;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
- $forum_id = request_var('f', 0);
- $start = request_var('start', 0);
+ $forum_id = $request->variable('f', 0);
+ $start = $request->variable('start', 0);
$this->page_title = 'MCP_QUEUE';
@@ -104,7 +104,7 @@ class mcp_queue
if (!empty($topic_id_list) && $mode == 'deleted_topics')
{
- if (!function_exists('mcp_delete_topics'))
+ if (!function_exists('mcp_delete_topic'))
{
global $phpbb_root_path, $phpEx;
include($phpbb_root_path . 'includes/mcp/mcp_main.' . $phpEx);
@@ -154,9 +154,10 @@ class mcp_queue
$user->add_lang(array('posting', 'viewtopic'));
- $post_id = request_var('p', 0);
- $topic_id = request_var('t', 0);
+ $post_id = $request->variable('p', 0);
+ $topic_id = $request->variable('t', 0);
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
if ($topic_id)
@@ -166,7 +167,7 @@ class mcp_queue
{
$post_id = (int) $topic_info[$topic_id]['topic_first_post_id'];
- $phpbb_notifications->mark_notifications_read('notification.type.topic_in_queue', $topic_id, $user->data['user_id']);
+ $phpbb_notifications->mark_notifications('topic_in_queue', $topic_id, $user->data['user_id']);
}
else
{
@@ -174,11 +175,11 @@ class mcp_queue
}
}
- $phpbb_notifications->mark_notifications_read('notification.type.post_in_queue', $post_id, $user->data['user_id']);
+ $phpbb_notifications->mark_notifications('post_in_queue', $post_id, $user->data['user_id']);
$post_info = phpbb_get_post_data(array($post_id), 'm_approve', true);
- if (!sizeof($post_info))
+ if (!count($post_info))
{
trigger_error('NO_POST_SELECTED');
}
@@ -194,7 +195,7 @@ class mcp_queue
));
}
- $extensions = $attachments = $topic_tracking_info = array();
+ $attachments = $topic_tracking_info = array();
// Get topic tracking info
if ($config['load_db_lastread'])
@@ -216,8 +217,6 @@ class mcp_queue
if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id']))
{
- $extensions = $cache->obtain_attach_extensions($post_info['forum_id']);
-
$sql = 'SELECT *
FROM ' . ATTACHMENTS_TABLE . '
WHERE post_msg_id = ' . $post_id . '
@@ -231,7 +230,7 @@ class mcp_queue
}
$db->sql_freeresult($result);
- if (sizeof($attachments))
+ if (count($attachments))
{
$update_count = array();
parse_attachments($post_info['forum_id'], $message, $attachments, $update_count);
@@ -281,7 +280,7 @@ class mcp_queue
$post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&amp;p=' . $post_info['post_id'] . '#p' . $post_info['post_id']);
$topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&amp;t=' . $post_info['topic_id']);
- $template->assign_vars(array(
+ $post_data = array(
'S_MCP_QUEUE' => true,
'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&amp;p=$post_id&amp;f=$forum_id"),
'S_CAN_DELETE_POST' => $auth->acl_get('m_delete', $post_info['forum_id']),
@@ -320,12 +319,40 @@ class mcp_queue
'POST_SUBJECT' => $post_info['post_subject'],
'POST_DATE' => $user->format_date($post_info['post_time']),
'POST_IP' => $post_info['poster_ip'],
- 'POST_IPADDR' => ($auth->acl_get('m_info', $post_info['forum_id']) && request_var('lookup', '')) ? @gethostbyaddr($post_info['poster_ip']) : '',
+ 'POST_IPADDR' => ($auth->acl_get('m_info', $post_info['forum_id']) && $request->variable('lookup', '')) ? @gethostbyaddr($post_info['poster_ip']) : '',
'POST_ID' => $post_info['post_id'],
'S_FIRST_POST' => ($post_info['topic_first_post_id'] == $post_id),
'U_LOOKUP_IP' => ($auth->acl_get('m_info', $post_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=approve_details&amp;f=' . $post_info['forum_id'] . '&amp;p=' . $post_id . '&amp;lookup=' . $post_info['poster_ip']) . '#ip' : '',
- ));
+ );
+
+ /**
+ * Alter post awaiting approval template before it is rendered
+ *
+ * @event core.mcp_queue_approve_details_template
+ * @var int post_id Post ID
+ * @var int topic_id Topic ID
+ * @var array topic_info Topic data
+ * @var array post_info Post data
+ * @var array post_data Post template data
+ * @var string message Post message
+ * @var string post_url Post URL
+ * @var string topic_url Topic URL
+ * @since 3.2.2-RC1
+ */
+ $vars = array(
+ 'post_id',
+ 'topic_id',
+ 'topic_info',
+ 'post_info',
+ 'post_data',
+ 'message',
+ 'post_url',
+ 'topic_url',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.mcp_queue_approve_details_template', compact($vars)));
+
+ $template->assign_vars($post_data);
break;
@@ -342,13 +369,15 @@ class mcp_queue
$topic_id = $request->variable('t', 0);
$forum_info = array();
+
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
if ($topic_id)
{
$topic_info = phpbb_get_topic_data(array($topic_id));
- if (!sizeof($topic_info))
+ if (!count($topic_info))
{
trigger_error('TOPIC_NOT_EXIST');
}
@@ -378,7 +407,7 @@ class mcp_queue
$forum_list[] = $row['forum_id'];
}
- if (!sizeof($forum_list))
+ if (!count($forum_list))
{
trigger_error('NOT_MODERATOR');
}
@@ -394,12 +423,11 @@ class mcp_queue
{
$forum_info = phpbb_get_forum_data(array($forum_id), $m_perm);
- if (!sizeof($forum_info))
+ if (!count($forum_info))
{
trigger_error('NOT_MODERATOR');
}
- $forum_info = $forum_info[$forum_id];
$forum_list = $forum_id;
}
@@ -414,7 +442,6 @@ class mcp_queue
$sort_by_sql = $sort_order_sql = array();
phpbb_mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id);
- $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total;
$limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : '';
$forum_names = array();
@@ -466,7 +493,7 @@ class mcp_queue
}
$db->sql_freeresult($result);
- if (sizeof($post_ids))
+ if (count($post_ids))
{
$sql = 'SELECT t.topic_id, t.topic_title, t.forum_id, p.post_id, p.post_subject, p.post_username, p.poster_id, p.post_time, p.post_attachment, u.username, u.username_clean, u.user_colour
FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . USERS_TABLE . ' u
@@ -474,6 +501,29 @@ class mcp_queue
AND t.topic_id = p.topic_id
AND u.user_id = p.poster_id
ORDER BY ' . $sort_order_sql;
+
+ /**
+ * Alter sql query to get information on all posts in queue
+ *
+ * @event core.mcp_queue_get_posts_for_posts_query_before
+ * @var string sql String with the query to be executed
+ * @var array forum_list List of forums that contain the posts
+ * @var int visibility_const Integer with one of the possible ITEM_* constant values
+ * @var int topic_id topic_id in the page request
+ * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string)
+ * @var string sort_order_sql String with the ORDER BY SQL code used in this query
+ * @since 3.2.3-RC2
+ */
+ $vars = array(
+ 'sql',
+ 'forum_list',
+ 'visibility_const',
+ 'topic_id',
+ 'limit_time_sql',
+ 'sort_order_sql',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.mcp_queue_get_posts_for_posts_query_before', compact($vars)));
+
$result = $db->sql_query($sql);
$post_data = $rowset = array();
@@ -538,7 +588,7 @@ class mcp_queue
$db->sql_freeresult($result);
}
- if (sizeof($forum_names))
+ if (count($forum_names))
{
// Select the names for the forum_ids
$sql = 'SELECT forum_id, forum_name
@@ -561,7 +611,7 @@ class mcp_queue
$row['post_username'] = $row['username'] ?: $user->lang['GUEST'];
}
- $template->assign_block_vars('postrow', array(
+ $post_row = array(
'U_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . '&amp;t=' . $row['topic_id']),
'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']),
'U_VIEWPOST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id'] . '&amp;p=' . $row['post_id']) . (($mode == 'unapproved_posts') ? '#p' . $row['post_id'] : ''),
@@ -578,8 +628,26 @@ class mcp_queue
'POST_SUBJECT' => ($row['post_subject'] != '') ? $row['post_subject'] : $user->lang['NO_SUBJECT'],
'TOPIC_TITLE' => $row['topic_title'],
'POST_TIME' => $user->format_date($row['post_time']),
- 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['post_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '',
- ));
+ 'S_HAS_ATTACHMENTS' => $auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['post_attachment'],
+ );
+
+ /**
+ * Alter sql query to get information on all topics in the list of forums provided.
+ *
+ * @event core.mcp_queue_get_posts_modify_post_row
+ * @var array post_row Template variables for current post
+ * @var array row Post data
+ * @var array forum_names Forum names
+ * @since 3.2.3-RC2
+ */
+ $vars = array(
+ 'post_row',
+ 'row',
+ 'forum_names',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.mcp_queue_get_posts_modify_post_row', compact($vars)));
+
+ $template->assign_block_vars('postrow', $post_row);
}
unset($rowset, $forum_names);
@@ -618,17 +686,18 @@ class mcp_queue
*/
static public function approve_posts($action, $post_id_list, $id, $mode)
{
- global $db, $template, $user, $config, $request, $phpbb_container, $phpbb_dispatcher;
- global $phpEx, $phpbb_root_path;
+ global $template, $user, $request, $phpbb_container, $phpbb_dispatcher;
+ global $phpEx, $phpbb_root_path, $phpbb_log;
if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
$redirect = $request->variable('redirect', build_url(array('quickmod')));
$redirect = reapply_sid($redirect);
- $success_msg = $post_url = '';
+ $post_url = '';
$approve_log = array();
$num_topics = 0;
@@ -677,10 +746,12 @@ class mcp_queue
$approve_log[] = array(
'forum_id' => $post_data['forum_id'],
'topic_id' => $post_data['topic_id'],
+ 'post_id' => $post_id,
'post_subject' => $post_data['post_subject'],
);
}
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
foreach ($topic_info as $topic_id => $topic_data)
{
@@ -689,12 +760,18 @@ class mcp_queue
foreach ($approve_log as $log_data)
{
- add_log('mod', $log_data['forum_id'], $log_data['topic_id'], 'LOG_POST_' . strtoupper($action) . 'D', $log_data['post_subject']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_POST_' . strtoupper($action) . 'D', false, array(
+ 'forum_id' => $log_data['forum_id'],
+ 'topic_id' => $log_data['topic_id'],
+ 'post_id' => $log_data['post_id'],
+ $log_data['post_subject']
+ ));
}
// Only send out the mails, when the posts are being approved
if ($action == 'approve')
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
// Handle notifications
@@ -731,7 +808,7 @@ class mcp_queue
$phpbb_notifications->add_notifications(array('notification.type.quote'), $post_data);
$phpbb_notifications->delete_notifications('notification.type.post_in_queue', $post_id);
- $phpbb_notifications->mark_notifications_read(array(
+ $phpbb_notifications->mark_notifications(array(
'notification.type.quote',
'notification.type.bookmark',
'notification.type.post',
@@ -763,7 +840,7 @@ class mcp_queue
}
else
{
- $success_msg = (sizeof($post_info) == 1) ? 'POST_' . strtoupper($action) . 'D_SUCCESS' : 'POSTS_' . strtoupper($action) . 'D_SUCCESS';
+ $success_msg = (count($post_info) == 1) ? 'POST_' . strtoupper($action) . 'D_SUCCESS' : 'POSTS_' . strtoupper($action) . 'D_SUCCESS';
}
/**
@@ -806,7 +883,7 @@ class mcp_queue
$message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>');
// If approving one post, also give links back to post...
- if (sizeof($post_info) == 1 && $post_url)
+ if (count($post_info) == 1 && $post_url)
{
$message .= '<br /><br />' . $user->lang('RETURN_POST', '<a href="' . $post_url . '">', '</a>');
}
@@ -839,14 +916,14 @@ class mcp_queue
// Create the confirm box message
$action_msg = strtoupper($action);
- $num_posts = sizeof($post_id_list) - $num_topics;
+ $num_posts = count($post_id_list) - $num_topics;
if ($num_topics > 0 && $num_posts <= 0)
{
$action_msg .= '_TOPIC' . (($num_topics == 1) ? '' : 'S');
}
else
{
- $action_msg .= '_POST' . ((sizeof($post_id_list) == 1) ? '' : 'S');
+ $action_msg .= '_POST' . ((count($post_id_list) == 1) ? '' : 'S');
}
confirm_box(false, $action_msg, $s_hidden_fields, 'mcp_approve.html');
}
@@ -865,11 +942,12 @@ class mcp_queue
*/
static public function approve_topics($action, $topic_id_list, $id, $mode)
{
- global $db, $template, $user, $config;
+ global $db, $template, $user, $phpbb_log;
global $phpEx, $phpbb_root_path, $request, $phpbb_container, $phpbb_dispatcher;
if (!phpbb_check_ids($topic_id_list, TOPICS_TABLE, 'topic_id', array('m_approve')))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
@@ -892,6 +970,7 @@ class mcp_queue
{
$notify_poster = ($action == 'approve' && isset($_REQUEST['notify_poster'])) ? true : false;
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
$first_post_ids = array();
@@ -909,14 +988,18 @@ class mcp_queue
);
}
- if (sizeof($topic_info) >= 1)
+ if (count($topic_info) >= 1)
{
- $success_msg = (sizeof($topic_info) == 1) ? 'TOPIC_' . strtoupper($action) . 'D_SUCCESS' : 'TOPICS_' . strtoupper($action) . 'D_SUCCESS';
+ $success_msg = (count($topic_info) == 1) ? 'TOPIC_' . strtoupper($action) . 'D_SUCCESS' : 'TOPICS_' . strtoupper($action) . 'D_SUCCESS';
}
foreach ($approve_log as $log_data)
{
- add_log('mod', $log_data['forum_id'], $log_data['topic_id'], 'LOG_TOPIC_' . strtoupper($action) . 'D', $log_data['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_TOPIC_' . strtoupper($action) . 'D', false, array(
+ 'forum_id' => $log_data['forum_id'],
+ 'topic_id' => $log_data['topic_id'],
+ $log_data['topic_title']
+ ));
}
// Only send out the mails, when the posts are being approved
@@ -935,6 +1018,7 @@ class mcp_queue
$db->sql_freeresult($result);
// Handle notifications
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
foreach ($topic_info as $topic_id => $topic_data)
@@ -961,8 +1045,8 @@ class mcp_queue
), $topic_data);
}
- $phpbb_notifications->mark_notifications_read('notification.type.quote', $topic_data['post_id'], $user->data['user_id']);
- $phpbb_notifications->mark_notifications_read('notification.type.topic', $topic_id, $user->data['user_id']);
+ $phpbb_notifications->mark_notifications('quote', $topic_data['post_id'], $user->data['user_id']);
+ $phpbb_notifications->mark_notifications('topic', $topic_id, $user->data['user_id']);
if ($notify_poster)
{
@@ -1009,7 +1093,7 @@ class mcp_queue
$message .= '<br /><br />' . $user->lang('RETURN_PAGE', '<a href="' . $redirect . '">', '</a>');
// If approving one topic, also give links back to topic...
- if (sizeof($topic_info) == 1 && $topic_url)
+ if (count($topic_info) == 1 && $topic_url)
{
$message .= '<br /><br />' . $user->lang('RETURN_TOPIC', '<a href="' . $topic_url . '">', '</a>');
}
@@ -1040,7 +1124,7 @@ class mcp_queue
'S_' . strtoupper($action) => true,
));
- confirm_box(false, strtoupper($action) . '_TOPIC' . ((sizeof($topic_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html');
+ confirm_box(false, strtoupper($action) . '_TOPIC' . ((count($topic_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html');
}
redirect($redirect);
@@ -1056,11 +1140,12 @@ class mcp_queue
*/
static public function disapprove_posts($post_id_list, $id, $mode)
{
- global $db, $template, $user, $config, $phpbb_container, $phpbb_dispatcher;
- global $phpEx, $phpbb_root_path, $request;
+ global $db, $template, $user, $phpbb_container, $phpbb_dispatcher;
+ global $phpEx, $phpbb_root_path, $request, $phpbb_log;
if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
@@ -1068,7 +1153,7 @@ class mcp_queue
$redirect = reapply_sid($redirect);
$reason = $request->variable('reason', '', true);
$reason_id = $request->variable('reason_id', 0);
- $success_msg = $additional_msg = '';
+ $additional_msg = '';
$s_hidden_fields = build_hidden_fields(array(
'i' => $id,
@@ -1126,7 +1211,7 @@ class mcp_queue
if (confirm_box(true))
{
- $disapprove_log = $disapprove_log_topics = $disapprove_log_posts = array();
+ $disapprove_log_topics = $disapprove_log_posts = array();
$topic_posts_unapproved = $post_disapprove_list = $topic_information = array();
// Build a list of posts to be disapproved and get the related topics real replies count
@@ -1190,8 +1275,8 @@ class mcp_queue
}
// Get disapproved posts/topics counts separately
- $num_disapproved_topics = sizeof($disapprove_log_topics);
- $num_disapproved_posts = sizeof($disapprove_log_posts);
+ $num_disapproved_topics = count($disapprove_log_topics);
+ $num_disapproved_posts = count($disapprove_log_posts);
// Build the whole log
$disapprove_log = array_merge($disapprove_log_topics, $disapprove_log_posts);
@@ -1200,7 +1285,7 @@ class mcp_queue
unset($post_data, $disapprove_log_topics, $disapprove_log_posts);
// Let's do the job - delete disapproved posts
- if (sizeof($post_disapprove_list))
+ if (count($post_disapprove_list))
{
if (!function_exists('delete_posts'))
{
@@ -1217,16 +1302,28 @@ class mcp_queue
if ($is_disapproving)
{
$l_log_message = ($log_data['type'] == 'topic') ? 'LOG_TOPIC_DISAPPROVED' : 'LOG_POST_DISAPPROVED';
- add_log('mod', $log_data['forum_id'], $log_data['topic_id'], $l_log_message, $log_data['post_subject'], $disapprove_reason, $log_data['post_username']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, $l_log_message, false, array(
+ 'forum_id' => $log_data['forum_id'],
+ 'topic_id' => $log_data['topic_id'],
+ $log_data['post_subject'],
+ $disapprove_reason,
+ $log_data['post_username']
+ ));
}
else
{
$l_log_message = ($log_data['type'] == 'topic') ? 'LOG_DELETE_TOPIC' : 'LOG_DELETE_POST';
- add_log('mod', $log_data['forum_id'], $log_data['topic_id'], $l_log_message, $log_data['post_subject'], $log_data['post_username']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, $l_log_message, false, array(
+ 'forum_id' => $log_data['forum_id'],
+ 'topic_id' => $log_data['topic_id'],
+ $log_data['post_subject'],
+ $log_data['post_username']
+ ));
}
}
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$lang_reasons = array();
@@ -1388,11 +1485,6 @@ class mcp_queue
}
else
{
- if (!function_exists('display_reasons'))
- {
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
- }
-
$show_notify = false;
foreach ($post_info as $post_data)
@@ -1412,7 +1504,7 @@ class mcp_queue
$confirm_template = 'mcp_approve.html';
if ($is_disapproving)
{
- display_reasons($reason_id);
+ $phpbb_container->get('phpbb.report.report_reason_list_provider')->display_reasons($reason_id);
}
else
{
@@ -1421,7 +1513,7 @@ class mcp_queue
$l_confirm_msg = 'DELETE_POST_PERMANENTLY';
$confirm_template = 'confirm_delete_body.html';
}
- $l_confirm_msg .= ((sizeof($post_id_list) == 1) ? '' : 'S');
+ $l_confirm_msg .= ((count($post_id_list) == 1) ? '' : 'S');
$template->assign_vars(array(
'S_NOTIFY_POSTER' => $show_notify,
diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php
index 6bb606a990..4600257344 100644
--- a/phpBB/includes/mcp/mcp_reports.php
+++ b/phpBB/includes/mcp/mcp_reports.php
@@ -28,20 +28,20 @@ class mcp_reports
var $p_master;
var $u_action;
- function mcp_reports(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $auth, $db, $user, $template, $cache;
+ global $auth, $db, $user, $template, $request;
global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container, $phpbb_dispatcher;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
- $forum_id = request_var('f', 0);
- $start = request_var('start', 0);
+ $forum_id = $request->variable('f', 0);
+ $start = $request->variable('start', 0);
$this->page_title = 'MCP_REPORTS';
@@ -51,9 +51,9 @@ class mcp_reports
case 'delete':
include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $report_id_list = request_var('report_id_list', array(0));
+ $report_id_list = $request->variable('report_id_list', array(0));
- if (!sizeof($report_id_list))
+ if (!count($report_id_list))
{
trigger_error('NO_REPORT_SELECTED');
}
@@ -69,10 +69,11 @@ class mcp_reports
$user->add_lang(array('posting', 'viewforum', 'viewtopic'));
- $post_id = request_var('p', 0);
+ $post_id = $request->variable('p', 0);
// closed reports are accessed by report id
- $report_id = request_var('r', 0);
+ $report_id = $request->variable('r', 0);
+
$sql_ary = array(
'SELECT' => 'r.post_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, r.reported_post_text, r.reported_post_uid, r.reported_post_bitfield, r.reported_post_enable_magic_url, r.reported_post_enable_smilies, r.reported_post_enable_bbcode, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour',
@@ -138,9 +139,10 @@ class mcp_reports
trigger_error('NO_REPORT');
}
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
- $phpbb_notifications->mark_notifications_read('notification.type.report_post', $post_id, $user->data['user_id']);
+ $phpbb_notifications->mark_notifications('report_post', $post_id, $user->data['user_id']);
if (!$report_id && $report['report_closed'])
{
@@ -156,7 +158,7 @@ class mcp_reports
$post_info = phpbb_get_post_data(array($post_id), 'm_report', true);
- if (!sizeof($post_info))
+ if (!count($post_info))
{
trigger_error('NO_REPORT_SELECTED');
}
@@ -180,7 +182,7 @@ class mcp_reports
));
}
- $topic_tracking_info = $extensions = $attachments = array();
+ $attachments = array();
// Get topic tracking info
if ($config['load_db_lastread'])
{
@@ -220,7 +222,7 @@ class mcp_reports
}
$db->sql_freeresult($result);
- if (sizeof($attachments))
+ if (count($attachments))
{
$update_count = array();
parse_attachments($post_info['forum_id'], $message, $attachments, $update_count);
@@ -240,7 +242,14 @@ class mcp_reports
}
}
- $template->assign_vars(array(
+ // parse signature
+ $parse_flags = ($post_info['user_sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $post_info['user_sig'] = generate_text_for_display($post_info['user_sig'], $post_info['user_sig_bbcode_uid'], $post_info['user_sig_bbcode_bitfield'], $parse_flags, true);
+
+ $topic_id = (int) $post_info['topic_id'];
+
+ // So it can be sent through the event below.
+ $report_template = array(
'S_MCP_REPORT' => true,
'S_CLOSE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=report_details&amp;f=' . $post_info['forum_id'] . '&amp;p=' . $post_id),
'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']),
@@ -287,11 +296,38 @@ class mcp_reports
'POST_SUBJECT' => ($post_info['post_subject']) ? $post_info['post_subject'] : $user->lang['NO_SUBJECT'],
'POST_DATE' => $user->format_date($post_info['post_time']),
'POST_IP' => $post_info['poster_ip'],
- 'POST_IPADDR' => ($auth->acl_get('m_info', $post_info['forum_id']) && request_var('lookup', '')) ? @gethostbyaddr($post_info['poster_ip']) : '',
+ 'POST_IPADDR' => ($auth->acl_get('m_info', $post_info['forum_id']) && $request->variable('lookup', '')) ? @gethostbyaddr($post_info['poster_ip']) : '',
'POST_ID' => $post_info['post_id'],
+ 'SIGNATURE' => $post_info['user_sig'],
'U_LOOKUP_IP' => ($auth->acl_get('m_info', $post_info['forum_id'])) ? $this->u_action . '&amp;r=' . $report_id . '&amp;p=' . $post_id . '&amp;f=' . $forum_id . '&amp;lookup=' . $post_info['poster_ip'] . '#ip' : '',
- ));
+ );
+
+ /**
+ * Event to add/modify MCP report details template data.
+ *
+ * @event core.mcp_report_template_data
+ * @var int forum_id The forum_id, the number in the f GET parameter
+ * @var int topic_id The topic_id of the report being viewed
+ * @var int post_id The post_id of the report being viewed (if 0, it is meaningless)
+ * @var int report_id The report_id of the report being viewed
+ * @var array report Array with the report data
+ * @var array report_template Array with the report template data
+ * @var array post_info Array with the reported post data
+ * @since 3.2.5-RC1
+ */
+ $vars = array(
+ 'forum_id',
+ 'topic_id',
+ 'post_id',
+ 'report_id',
+ 'report',
+ 'report_template',
+ 'post_info',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.mcp_report_template_data', compact($vars)));
+
+ $template->assign_vars($report_template);
$this->tpl_name = 'mcp_post';
@@ -299,7 +335,7 @@ class mcp_reports
case 'reports':
case 'reports_closed':
- $topic_id = request_var('t', 0);
+ $topic_id = $request->variable('t', 0);
$forum_info = array();
$forum_list_reports = get_forum_list('m_report', false, true);
@@ -319,7 +355,7 @@ class mcp_reports
{
$topic_info = phpbb_get_topic_data(array($topic_id));
- if (!sizeof($topic_info))
+ if (!count($topic_info))
{
trigger_error('TOPIC_NOT_EXIST');
}
@@ -344,13 +380,11 @@ class mcp_reports
$forum_list[] = $row['forum_id'];
}
- if (!sizeof($forum_list))
+ if (!count($forum_list))
{
trigger_error('NOT_MODERATOR');
}
- $global_id = $forum_list[0];
-
$sql = 'SELECT SUM(forum_topics_approved) as sum_forum_topics
FROM ' . FORUMS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_list);
@@ -362,18 +396,18 @@ class mcp_reports
{
$forum_info = phpbb_get_forum_data(array($forum_id), 'm_report');
- if (!sizeof($forum_info))
+ if (!count($forum_info))
{
trigger_error('NOT_MODERATOR');
}
- $forum_info = $forum_info[$forum_id];
$forum_list = array($forum_id);
}
+ /* @var $pagination \phpbb\pagination */
+ $pagination = $phpbb_container->get('pagination');
$forum_list[] = 0;
$forum_data = array();
- $pagination = $phpbb_container->get('pagination');
$forum_options = '<option value="0"' . (($forum_id == 0) ? ' selected="selected"' : '') . '>' . $user->lang['ALL_FORUMS'] . '</option>';
foreach ($forum_list_reports as $row)
@@ -388,7 +422,6 @@ class mcp_reports
$sort_by_sql = $sort_order_sql = array();
phpbb_mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id);
- $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total;
$limit_time_sql = ($sort_days) ? 'AND r.report_time >= ' . (time() - ($sort_days * 86400)) : '';
if ($mode == 'reports')
@@ -444,7 +477,7 @@ class mcp_reports
}
$db->sql_freeresult($result);
- if (sizeof($report_ids))
+ if (count($report_ids))
{
$sql = 'SELECT t.forum_id, t.topic_id, t.topic_title, p.post_id, p.post_subject, p.post_username, p.poster_id, p.post_time, p.post_attachment, u.username, u.username_clean, u.user_colour, r.user_id as reporter_id, ru.username as reporter_name, ru.user_colour as reporter_colour, r.report_time, r.report_id
FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . USERS_TABLE . ' u, ' . USERS_TABLE . ' ru
@@ -457,7 +490,6 @@ class mcp_reports
ORDER BY ' . $sort_order_sql;
$result = $db->sql_query($sql);
- $report_data = $rowset = array();
while ($row = $db->sql_fetchrow($result))
{
$template->assign_block_vars('postrow', array(
@@ -519,7 +551,7 @@ class mcp_reports
*/
function close_report($report_id_list, $mode, $action, $pm = false)
{
- global $db, $template, $user, $config, $auth;
+ global $db, $user, $auth, $phpbb_log, $request;
global $phpEx, $phpbb_root_path, $phpbb_container;
$pm_where = ($pm) ? ' AND r.post_id = 0 ' : ' AND r.pm_id = 0 ';
@@ -544,6 +576,7 @@ function close_report($report_id_list, $mode, $action, $pm = false)
{
if (!$auth->acl_getf_global('m_report'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
}
@@ -551,25 +584,26 @@ function close_report($report_id_list, $mode, $action, $pm = false)
{
if (!phpbb_check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_report')))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
}
if ($action == 'delete' && strpos($user->data['session_page'], 'mode=report_details') !== false)
{
- $redirect = request_var('redirect', build_url(array('mode', 'r', 'quickmod')) . '&amp;mode=reports');
+ $redirect = $request->variable('redirect', build_url(array('mode', 'r', 'quickmod')) . '&amp;mode=reports');
}
else if ($action == 'delete' && strpos($user->data['session_page'], 'mode=pm_report_details') !== false)
{
- $redirect = request_var('redirect', build_url(array('mode', 'r', 'quickmod')) . '&amp;mode=pm_reports');
+ $redirect = $request->variable('redirect', build_url(array('mode', 'r', 'quickmod')) . '&amp;mode=pm_reports');
}
- else if ($action == 'close' && !request_var('r', 0))
+ else if ($action == 'close' && !$request->variable('r', 0))
{
- $redirect = request_var('redirect', build_url(array('mode', 'p', 'quickmod')) . '&amp;mode=' . $module);
+ $redirect = $request->variable('redirect', build_url(array('mode', 'p', 'quickmod')) . '&amp;mode=' . $module);
}
else
{
- $redirect = request_var('redirect', build_url(array('quickmod')));
+ $redirect = $request->variable('redirect', build_url(array('quickmod')));
}
$success_msg = '';
$forum_ids = array();
@@ -617,12 +651,12 @@ function close_report($report_id_list, $mode, $action, $pm = false)
}
$db->sql_freeresult($result);
- if (sizeof($reports))
+ if (count($reports))
{
$close_report_posts = array_unique($close_report_posts);
$close_report_topics = array_unique($close_report_topics);
- if (!$pm && sizeof($close_report_posts))
+ if (!$pm && count($close_report_posts))
{
// Get a list of topics that still contain reported posts
$sql = 'SELECT DISTINCT topic_id
@@ -658,7 +692,7 @@ function close_report($report_id_list, $mode, $action, $pm = false)
}
$db->sql_query($sql);
- if (sizeof($close_report_posts))
+ if (count($close_report_posts))
{
if ($pm)
{
@@ -679,7 +713,7 @@ function close_report($report_id_list, $mode, $action, $pm = false)
WHERE ' . $db->sql_in_set('post_id', $close_report_posts);
$db->sql_query($sql);
- if (sizeof($close_report_topics))
+ if (count($close_report_topics))
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET topic_reported = 0
@@ -694,24 +728,34 @@ function close_report($report_id_list, $mode, $action, $pm = false)
}
unset($close_report_posts, $close_report_topics);
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
foreach ($reports as $report)
{
if ($pm)
{
- add_log('mod', 0, 0, 'LOG_PM_REPORT_' . strtoupper($action) . 'D', $post_info[$report['pm_id']]['message_subject']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_PM_REPORT_' . strtoupper($action) . 'D', false, array(
+ 'forum_id' => 0,
+ 'topic_id' => 0,
+ $post_info[$report['pm_id']]['message_subject']
+ ));
$phpbb_notifications->delete_notifications('notification.type.report_pm', $report['pm_id']);
}
else
{
- add_log('mod', $post_info[$report['post_id']]['forum_id'], $post_info[$report['post_id']]['topic_id'], 'LOG_REPORT_' . strtoupper($action) . 'D', $post_info[$report['post_id']]['post_subject']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_REPORT_' . strtoupper($action) . 'D', false, array(
+ 'forum_id' => $post_info[$report['post_id']]['forum_id'],
+ 'topic_id' => $post_info[$report['post_id']]['topic_id'],
+ 'post_id' => $report['post_id'],
+ $post_info[$report['post_id']]['post_subject']
+ ));
$phpbb_notifications->delete_notifications('notification.type.report_post', $report['post_id']);
}
}
// Notify reporters
- if (sizeof($notify_reporters))
+ if (count($notify_reporters))
{
foreach ($notify_reporters as $report_id => $reporter)
{
@@ -751,14 +795,14 @@ function close_report($report_id_list, $mode, $action, $pm = false)
unset($notify_reporters, $post_info, $reports);
- $success_msg = (sizeof($report_id_list) == 1) ? "{$pm_prefix}REPORT_" . strtoupper($action) . 'D_SUCCESS' : "{$pm_prefix}REPORTS_" . strtoupper($action) . 'D_SUCCESS';
+ $success_msg = (count($report_id_list) == 1) ? "{$pm_prefix}REPORT_" . strtoupper($action) . 'D_SUCCESS' : "{$pm_prefix}REPORTS_" . strtoupper($action) . 'D_SUCCESS';
}
else
{
- confirm_box(false, $user->lang[strtoupper($action) . "_{$pm_prefix}REPORT" . ((sizeof($report_id_list) == 1) ? '' : 'S') . '_CONFIRM'], $s_hidden_fields);
+ confirm_box(false, $user->lang[strtoupper($action) . "_{$pm_prefix}REPORT" . ((count($report_id_list) == 1) ? '' : 'S') . '_CONFIRM'], $s_hidden_fields);
}
- $redirect = request_var('redirect', "index.$phpEx");
+ $redirect = $request->variable('redirect', "index.$phpEx");
$redirect = reapply_sid($redirect);
if (!$success_msg)
@@ -774,12 +818,12 @@ function close_report($report_id_list, $mode, $action, $pm = false)
if (!$pm)
{
- if (sizeof($forum_ids) === 1)
+ if (count($forum_ids) === 1)
{
$return_forum = sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . current($forum_ids)) . '">', '</a>') . '<br /><br />';
}
- if (sizeof($topic_ids) === 1)
+ if (count($topic_ids) === 1)
{
$return_topic = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . current($topic_ids) . '&amp;f=' . current($forum_ids)) . '">', '</a>') . '<br /><br />';
}
diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php
index d5415302c8..83ad56f3e4 100644
--- a/phpBB/includes/mcp/mcp_topic.php
+++ b/phpBB/includes/mcp/mcp_topic.php
@@ -24,18 +24,19 @@ if (!defined('IN_PHPBB'))
*/
function mcp_topic_view($id, $mode, $action)
{
- global $phpEx, $phpbb_root_path, $config;
- global $template, $db, $user, $auth, $cache, $phpbb_container, $phpbb_dispatcher;
+ global $phpEx, $phpbb_root_path, $config, $request;
+ global $template, $db, $user, $auth, $phpbb_container, $phpbb_dispatcher;
$url = append_sid("{$phpbb_root_path}mcp.$phpEx?" . phpbb_extra_url());
- $user->add_lang('viewtopic');
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
+ $user->add_lang('viewtopic');
- $topic_id = request_var('t', 0);
+ $topic_id = $request->variable('t', 0);
$topic_info = phpbb_get_topic_data(array($topic_id), false, true);
- if (!sizeof($topic_info))
+ if (!count($topic_info))
{
trigger_error('TOPIC_NOT_EXIST');
}
@@ -43,16 +44,16 @@ function mcp_topic_view($id, $mode, $action)
$topic_info = $topic_info[$topic_id];
// Set up some vars
- $icon_id = request_var('icon', 0);
- $subject = utf8_normalize_nfc(request_var('subject', '', true));
- $start = request_var('start', 0);
- $sort_days_old = request_var('st_old', 0);
- $forum_id = request_var('f', 0);
- $to_topic_id = request_var('to_topic_id', 0);
- $to_forum_id = request_var('to_forum_id', 0);
+ $icon_id = $request->variable('icon', 0);
+ $subject = $request->variable('subject', '', true);
+ $start = $request->variable('start', 0);
+ $sort_days_old = $request->variable('st_old', 0);
+ $forum_id = $request->variable('f', 0);
+ $to_topic_id = $request->variable('to_topic_id', 0);
+ $to_forum_id = $request->variable('to_forum_id', 0);
$sort = isset($_POST['sort']) ? true : false;
- $submitted_id_list = request_var('post_ids', array(0));
- $checked_ids = $post_id_list = request_var('post_id_list', array(0));
+ $submitted_id_list = $request->variable('post_ids', array(0));
+ $checked_ids = $post_id_list = $request->variable('post_id_list', array(0));
// Resync Topic?
if ($action == 'resync')
@@ -92,11 +93,15 @@ function mcp_topic_view($id, $mode, $action)
// Restore or pprove posts?
if (($action == 'restore' || $action == 'approve') && $auth->acl_get('m_approve', $topic_info['forum_id']))
{
- include($phpbb_root_path . 'includes/mcp/mcp_queue.' . $phpEx);
+ if (!class_exists('mcp_queue'))
+ {
+ include($phpbb_root_path . 'includes/mcp/mcp_queue.' . $phpEx);
+ }
+
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- if (!sizeof($post_id_list))
+ if (!count($post_id_list))
{
trigger_error('NO_POST_SELECTED');
}
@@ -116,15 +121,16 @@ function mcp_topic_view($id, $mode, $action)
$sort_by_sql = $sort_order_sql = array();
phpbb_mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $topic_info['forum_id'], $topic_id, $where_sql);
- $limit_time_sql = ($sort_days) ? 'AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
+ $limit_time_sql = ($sort_days) ? 'AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
if ($total == -1)
{
$total = $phpbb_content_visibility->get_count('topic_posts', $topic_info, $topic_info['forum_id']);
}
- $posts_per_page = max(0, request_var('posts_per_page', intval($config['posts_per_page'])));
+ $posts_per_page = max(0, $request->variable('posts_per_page', intval($config['posts_per_page'])));
if ($posts_per_page == 0)
{
$posts_per_page = $total;
@@ -136,14 +142,36 @@ function mcp_topic_view($id, $mode, $action)
}
$start = $pagination->validate_start($start, $posts_per_page, $total);
- $sql = 'SELECT u.username, u.username_clean, u.user_colour, p.*
- FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
- WHERE ' . (($action == 'reports') ? 'p.post_reported = 1 AND ' : '') . '
+ $sql_where = (($action == 'reports') ? 'p.post_reported = 1 AND ' : '') . '
p.topic_id = ' . $topic_id . '
AND ' . $phpbb_content_visibility->get_visibility_sql('post', $topic_info['forum_id'], 'p.') . '
AND p.poster_id = u.user_id ' .
- $limit_time_sql . '
- ORDER BY ' . $sort_order_sql;
+ $limit_time_sql;
+
+ $sql_ary = array(
+ 'SELECT' => 'u.username, u.username_clean, u.user_colour, p.*',
+ 'FROM' => array(
+ POSTS_TABLE => 'p',
+ USERS_TABLE => 'u'
+ ),
+ 'LEFT_JOIN' => array(),
+ 'WHERE' => $sql_where,
+ 'ORDER_BY' => $sort_order_sql,
+ );
+
+ /**
+ * Event to modify the SQL query before the MCP topic review posts is queried
+ *
+ * @event core.mcp_topic_modify_sql_ary
+ * @var array sql_ary The SQL array to get the data of the MCP topic review posts
+ * @since 3.2.8-RC1
+ */
+ $vars = array('sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.mcp_topic_modify_sql_ary', compact($vars)));
+
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ unset($sql_ary);
+
$result = $db->sql_query_limit($sql, $posts_per_page, $start);
$rowset = $post_id_list = array();
@@ -154,8 +182,6 @@ function mcp_topic_view($id, $mode, $action)
}
$db->sql_freeresult($result);
- $topic_tracking_info = array();
-
// Get topic tracking info
if ($config['load_db_lastread'])
{
@@ -171,11 +197,9 @@ function mcp_topic_view($id, $mode, $action)
$has_unapproved_posts = $has_deleted_posts = false;
// Grab extensions
- $extensions = $attachments = array();
- if ($topic_info['topic_attachment'] && sizeof($post_id_list))
+ $attachments = array();
+ if ($topic_info['topic_attachment'] && count($post_id_list))
{
- $extensions = $cache->obtain_attach_extensions($topic_info['forum_id']);
-
// Get attachments...
if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $topic_info['forum_id']))
{
@@ -269,8 +293,6 @@ function mcp_topic_view($id, $mode, $action)
'U_MCP_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=report_details&amp;f=' . $topic_info['forum_id'] . '&amp;p=' . $row['post_id']) : '',
);
- $current_row_number = $i;
-
/**
* Event to modify the template data block for topic reviews in the MCP
*
@@ -330,7 +352,7 @@ function mcp_topic_view($id, $mode, $action)
{
$to_topic_info = phpbb_get_topic_data(array($to_topic_id), 'm_merge');
- if (!sizeof($to_topic_info))
+ if (!count($to_topic_info))
{
$to_topic_id = 0;
}
@@ -406,14 +428,13 @@ function mcp_topic_view($id, $mode, $action)
*/
function split_topic($action, $topic_id, $to_forum_id, $subject)
{
- global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $config;
- global $phpbb_dispatcher;
+ global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $config, $phpbb_log, $request, $phpbb_dispatcher;
- $post_id_list = request_var('post_id_list', array(0));
- $forum_id = request_var('forum_id', 0);
- $start = request_var('start', 0);
+ $post_id_list = $request->variable('post_id_list', array(0));
+ $forum_id = $request->variable('forum_id', 0);
+ $start = $request->variable('start', 0);
- if (!sizeof($post_id_list))
+ if (!count($post_id_list))
{
$template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']);
return;
@@ -427,7 +448,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
$post_id = $post_id_list[0];
$post_info = phpbb_get_post_data(array($post_id));
- if (!sizeof($post_info))
+ if (!count($post_info))
{
$template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']);
return;
@@ -451,7 +472,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
$forum_info = phpbb_get_forum_data(array($to_forum_id), 'f_post');
- if (!sizeof($forum_info))
+ if (!count($forum_info))
{
$template->assign_var('MESSAGE', $user->lang['USER_CANNOT_POST']);
return;
@@ -465,7 +486,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
return;
}
- $redirect = request_var('redirect', build_url(array('quickmod')));
+ $redirect = $request->variable('redirect', build_url(array('quickmod')));
$s_hidden_fields = build_hidden_fields(array(
'i' => 'main',
@@ -478,9 +499,8 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
'redirect' => $redirect,
'subject' => $subject,
'to_forum_id' => $to_forum_id,
- 'icon' => request_var('icon', 0))
+ 'icon' => $request->variable('icon', 0))
);
- $success_msg = $return_link = '';
if (confirm_box(true))
{
@@ -536,12 +556,12 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
$db->sql_freeresult($result);
}
- if (!sizeof($post_id_list))
+ if (!count($post_id_list))
{
trigger_error('NO_POST_SELECTED');
}
- $icon_id = request_var('icon', 0);
+ $icon_id = $request->variable('icon', 0);
$sql_ary = array(
'forum_id' => $to_forum_id,
@@ -559,8 +579,16 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
$topic_info = phpbb_get_topic_data(array($topic_id));
$topic_info = $topic_info[$topic_id];
- add_log('mod', $to_forum_id, $to_topic_id, 'LOG_SPLIT_DESTINATION', $subject);
- add_log('mod', $forum_id, $topic_id, 'LOG_SPLIT_SOURCE', $topic_info['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SPLIT_DESTINATION', false, array(
+ 'forum_id' => $to_forum_id,
+ 'topic_id' => $to_topic_id,
+ $subject
+ ));
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_SPLIT_SOURCE', false, array(
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ $topic_info['topic_title']
+ ));
// Change topic title of first post
$sql = 'UPDATE ' . POSTS_TABLE . "
@@ -626,7 +654,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
}
$db->sql_freeresult($result);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary);
}
@@ -647,7 +675,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
}
$db->sql_freeresult($result);
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary);
}
@@ -655,11 +683,11 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
$success_msg = 'TOPIC_SPLIT_SUCCESS';
// Update forum statistics
- set_config_count('num_topics', 1, true);
+ $config->increment('num_topics', 1, false);
// Link back to both topics
$return_link = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&amp;t=' . $post_info['topic_id']) . '">', '</a>') . '<br /><br />' . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&amp;t=' . $to_topic_id) . '">', '</a>');
- $redirect = request_var('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&amp;t=$to_topic_id");
+ $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&amp;t=$to_topic_id");
$redirect = reapply_sid($redirect);
meta_refresh(3, $redirect);
@@ -676,7 +704,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
*/
function merge_posts($topic_id, $to_topic_id)
{
- global $db, $template, $user, $phpEx, $phpbb_root_path, $auth, $phpbb_dispatcher;
+ global $db, $template, $user, $phpEx, $phpbb_root_path, $phpbb_log, $request, $phpbb_dispatcher;
if (!$to_topic_id)
{
@@ -688,7 +716,7 @@ function merge_posts($topic_id, $to_topic_id)
$topic_data = phpbb_get_topic_data($sync_topics, 'm_merge');
- if (!sizeof($topic_data) || empty($topic_data[$to_topic_id]))
+ if (!count($topic_data) || empty($topic_data[$to_topic_id]))
{
$template->assign_var('MESSAGE', $user->lang['NO_FINAL_TOPIC_SELECTED']);
return;
@@ -702,10 +730,10 @@ function merge_posts($topic_id, $to_topic_id)
$topic_data = $topic_data[$to_topic_id];
- $post_id_list = request_var('post_id_list', array(0));
- $start = request_var('start', 0);
+ $post_id_list = $request->variable('post_id_list', array(0));
+ $start = $request->variable('start', 0);
- if (!sizeof($post_id_list))
+ if (!count($post_id_list))
{
$template->assign_var('MESSAGE', $user->lang['NO_POST_SELECTED']);
return;
@@ -716,7 +744,7 @@ function merge_posts($topic_id, $to_topic_id)
return;
}
- $redirect = request_var('redirect', build_url(array('quickmod')));
+ $redirect = $request->variable('redirect', build_url(array('quickmod')));
$s_hidden_fields = build_hidden_fields(array(
'i' => 'main',
@@ -728,14 +756,19 @@ function merge_posts($topic_id, $to_topic_id)
'redirect' => $redirect,
't' => $topic_id)
);
- $success_msg = $return_link = '';
+ $return_link = '';
if (confirm_box(true))
{
$to_forum_id = $topic_data['forum_id'];
move_posts($post_id_list, $to_topic_id, false);
- add_log('mod', $to_forum_id, $to_topic_id, 'LOG_MERGE', $topic_data['topic_title']);
+
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_MERGE', false, array(
+ 'forum_id' => $to_forum_id,
+ 'topic_id' => $to_topic_id,
+ $topic_data['topic_title']
+ ));
// Message and return links
$success_msg = 'POSTS_MERGED_SUCCESS';
@@ -774,7 +807,7 @@ function merge_posts($topic_id, $to_topic_id)
// Link to the new topic
$return_link .= (($return_link) ? '<br /><br />' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&amp;t=' . $to_topic_id) . '">', '</a>');
- $redirect = request_var('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&amp;t=$to_topic_id");
+ $redirect = $request->variable('redirect', "{$phpbb_root_path}viewtopic.$phpEx?f=$to_forum_id&amp;t=$to_topic_id");
$redirect = reapply_sid($redirect);
/**
diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php
index 33c898ffc2..df175133fc 100644
--- a/phpBB/includes/mcp/mcp_warn.php
+++ b/phpBB/includes/mcp/mcp_warn.php
@@ -28,17 +28,16 @@ class mcp_warn
var $p_master;
var $u_action;
- function mcp_warn(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
{
- global $auth, $db, $user, $template;
- global $config, $phpbb_root_path, $phpEx;
+ global $request;
- $action = request_var('action', array('' => ''));
+ $action = $request->variable('action', array('' => ''));
if (is_array($action))
{
@@ -78,8 +77,8 @@ class mcp_warn
*/
function mcp_warn_front_view()
{
- global $phpEx, $phpbb_root_path, $config;
- global $template, $db, $user, $auth;
+ global $phpEx, $phpbb_root_path;
+ global $template, $db, $user;
$template->assign_vars(array(
'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=mcp&amp;field=username&amp;select_single=true'),
@@ -132,15 +131,16 @@ class mcp_warn
function mcp_warn_list_view($action)
{
global $phpEx, $phpbb_root_path, $config, $phpbb_container;
- global $template, $db, $user, $auth;
+ global $template, $user, $auth, $request;
- $user->add_lang('memberlist');
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
+ $user->add_lang('memberlist');
- $start = request_var('start', 0);
- $st = request_var('st', 0);
- $sk = request_var('sk', 'b');
- $sd = request_var('sd', 'd');
+ $start = $request->variable('start', 0);
+ $st = $request->variable('st', 0);
+ $sk = $request->variable('sk', 'b');
+ $sd = $request->variable('sd', 'd');
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_WARNINGS']);
@@ -189,13 +189,13 @@ class mcp_warn
*/
function mcp_warn_post_view($action)
{
- global $phpEx, $phpbb_root_path, $config;
- global $template, $db, $user, $auth, $phpbb_dispatcher;
+ global $phpEx, $phpbb_root_path, $config, $request;
+ global $template, $db, $user, $phpbb_dispatcher;
- $post_id = request_var('p', 0);
- $forum_id = request_var('f', 0);
+ $post_id = $request->variable('p', 0);
+ $forum_id = $request->variable('f', 0);
$notify = (isset($_REQUEST['notify_user'])) ? true : false;
- $warning = utf8_normalize_nfc(request_var('warning', '', true));
+ $warning = $request->variable('warning', '', true);
$sql = 'SELECT u.*, p.*
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
@@ -369,13 +369,13 @@ class mcp_warn
*/
function mcp_warn_user_view($action)
{
- global $phpEx, $phpbb_root_path, $config, $module;
- global $template, $db, $user, $auth, $phpbb_dispatcher;
+ global $phpEx, $phpbb_root_path, $config, $request;
+ global $template, $db, $user, $phpbb_dispatcher;
- $user_id = request_var('u', 0);
- $username = request_var('username', '', true);
+ $user_id = $request->variable('u', 0);
+ $username = $request->variable('username', '', true);
$notify = (isset($_REQUEST['notify_user'])) ? true : false;
- $warning = utf8_normalize_nfc(request_var('warning', '', true));
+ $warning = $request->variable('warning', '', true);
$sql_where = ($user_id) ? "user_id = $user_id" : "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
@@ -522,8 +522,8 @@ class mcp_warn
*/
function add_warning($user_row, $warning, $send_pm = true, $post_id = 0)
{
- global $phpEx, $phpbb_root_path, $config;
- global $template, $db, $user, $auth;
+ global $phpEx, $phpbb_root_path, $config, $phpbb_log;
+ global $db, $user;
if ($send_pm)
{
@@ -572,8 +572,11 @@ function add_warning($user_row, $warning, $send_pm = true, $post_id = 0)
submit_pm('post', $warn_pm_subject, $pm_data, false);
}
- add_log('admin', 'LOG_USER_WARNING', $user_row['username']);
- $log_id = add_log('user', $user_row['user_id'], 'LOG_USER_WARNING_BODY', $warning);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_WARNING', false, array($user_row['username']));
+ $log_id = $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_WARNING_BODY', false, array(
+ 'reportee_id' => $user_row['user_id'],
+ $warning
+ ));
$sql_ary = array(
'user_id' => $user_row['user_id'],
@@ -598,5 +601,10 @@ function add_warning($user_row, $warning, $send_pm = true, $post_id = 0)
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_USER_WARNING', $user_row['username']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_USER_WARNING', false, array(
+ 'forum_id' => $row['forum_id'],
+ 'topic_id' => $row['topic_id'],
+ 'post_id' => $post_id,
+ $user_row['username']
+ ));
}
diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php
index bbd5e84233..e1c28223dc 100644
--- a/phpBB/includes/message_parser.php
+++ b/phpBB/includes/message_parser.php
@@ -83,7 +83,14 @@ class bbcode_firstpass extends bbcode
// it should not demand recompilation
if (preg_match($regexp, $this->message))
{
- $this->message = preg_replace($regexp, $replacement, $this->message);
+ if (is_callable($replacement))
+ {
+ $this->message = preg_replace_callback($regexp, $replacement, $this->message);
+ }
+ else
+ {
+ $this->message = preg_replace($regexp, $replacement, $this->message);
+ }
$bitfield->set($bbcode_data['bbcode_id']);
}
}
@@ -123,6 +130,8 @@ class bbcode_firstpass extends bbcode
static $rowset;
+ $bbcode_class = $this;
+
// This array holds all bbcode data. BBCodes will be processed in this
// order, so it is important to keep [code] in first position and
// [quote] in second position.
@@ -132,19 +141,71 @@ class bbcode_firstpass extends bbcode
// To perform custom validation in extension, use $this->validate_bbcode_by_extension()
// method which accepts variable number of parameters
$this->bbcodes = array(
- 'code' => array('bbcode_id' => 8, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#uise' => "\$this->bbcode_code('\$1', '\$2')")),
- 'quote' => array('bbcode_id' => 0, 'regexp' => array('#\[quote(?:=&quot;(.*?)&quot;)?\](.+)\[/quote\]#uise' => "\$this->bbcode_quote('\$0')")),
- 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uise' => "\$this->bbcode_attachment('\$1', '\$2')")),
- 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->bbcode_strong('\$1')")),
- 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#uise' => "\$this->bbcode_italic('\$1')")),
- 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiUe' => "\$this->validate_url('\$2', ('\$3') ? '\$3' : '\$4')")),
- 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](.*)\[/img\]#uiUe' => "\$this->bbcode_img('\$1')")),
- 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#uise' => "\$this->bbcode_size('\$1', '\$2')")),
- 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!uise' => "\$this->bbcode_color('\$1', '\$2')")),
- 'u' => array('bbcode_id' => 7, 'regexp' => array('#\[u\](.*?)\[/u\]#uise' => "\$this->bbcode_underline('\$1')")),
- 'list' => array('bbcode_id' => 9, 'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#uise' => "\$this->bbcode_parse_list('\$0')")),
- 'email' => array('bbcode_id' => 10, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#uise' => "\$this->validate_email('\$1', '\$2')")),
- 'flash' => array('bbcode_id' => 11, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#uie' => "\$this->bbcode_flash('\$1', '\$2', '\$3')"))
+ 'code' => array('bbcode_id' => BBCODE_ID_CODE, 'regexp' => array('#\[code(?:=([a-z]+))?\](.+\[/code\])#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_code($match[1], $match[2]);
+ }
+ )),
+ 'quote' => array('bbcode_id' => BBCODE_ID_QUOTE, 'regexp' => array('#\[quote(?:=&quot;(.*?)&quot;)?\](.+)\[/quote\]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_quote($match[0]);
+ }
+ )),
+ 'attachment' => array('bbcode_id' => BBCODE_ID_ATTACH, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_attachment($match[1], $match[2]);
+ }
+ )),
+ 'b' => array('bbcode_id' => BBCODE_ID_B, 'regexp' => array('#\[b\](.*?)\[/b\]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_strong($match[1]);
+ }
+ )),
+ 'i' => array('bbcode_id' => BBCODE_ID_I, 'regexp' => array('#\[i\](.*?)\[/i\]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_italic($match[1]);
+ }
+ )),
+ 'url' => array('bbcode_id' => BBCODE_ID_URL, 'regexp' => array('#\[url(=(.*))?\](?(1)((?s).*(?-s))|(.*))\[/url\]#uiU' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->validate_url($match[2], ($match[3]) ? $match[3] : $match[4]);
+ }
+ )),
+ 'img' => array('bbcode_id' => BBCODE_ID_IMG, 'regexp' => array('#\[img\](.*)\[/img\]#uiU' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_img($match[1]);
+ }
+ )),
+ 'size' => array('bbcode_id' => BBCODE_ID_SIZE, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_size($match[1], $match[2]);
+ }
+ )),
+ 'color' => array('bbcode_id' => BBCODE_ID_COLOR, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_color($match[1], $match[2]);
+ }
+ )),
+ 'u' => array('bbcode_id' => BBCODE_ID_U, 'regexp' => array('#\[u\](.*?)\[/u\]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_underline($match[1]);
+ }
+ )),
+ 'list' => array('bbcode_id' => BBCODE_ID_LIST, 'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_parse_list($match[0]);
+ }
+ )),
+ 'email' => array('bbcode_id' => BBCODE_ID_EMAIL, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#uis' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->validate_email($match[1], $match[2]);
+ }
+ )),
+ 'flash' => array('bbcode_id' => BBCODE_ID_FLASH, 'regexp' => array('#\[flash=([0-9]+),([0-9]+)\](.*?)\[/flash\]#ui' => function ($match) use($bbcode_class)
+ {
+ return $bbcode_class->bbcode_flash($match[1], $match[2], $match[3]);
+ }
+ ))
);
// Zero the parsed items array
@@ -342,22 +403,23 @@ class bbcode_firstpass extends bbcode
if ($config['max_' . $this->mode . '_img_height'] || $config['max_' . $this->mode . '_img_width'])
{
- $stats = @getimagesize(htmlspecialchars_decode($in));
+ $imagesize = new \FastImageSize\FastImageSize();
+ $size_info = $imagesize->getImageSize(htmlspecialchars_decode($in));
- if ($stats === false)
+ if ($size_info === false)
{
$error = true;
$this->warn_msg[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
}
else
{
- if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $stats[1])
+ if ($config['max_' . $this->mode . '_img_height'] && $config['max_' . $this->mode . '_img_height'] < $size_info['height'])
{
$error = true;
$this->warn_msg[] = $user->lang('MAX_IMG_HEIGHT_EXCEEDED', (int) $config['max_' . $this->mode . '_img_height']);
}
- if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $stats[0])
+ if ($config['max_' . $this->mode . '_img_width'] && $config['max_' . $this->mode . '_img_width'] < $size_info['width'])
{
$error = true;
$this->warn_msg[] = $user->lang('MAX_IMG_WIDTH_EXCEEDED', (int) $config['max_' . $this->mode . '_img_width']);
@@ -643,10 +705,10 @@ class bbcode_firstpass extends bbcode
if ($tok == ']')
{
// if $tok is ']' the buffer holds a tag
- if (strtolower($buffer) == '/list' && sizeof($list_end_tags))
+ if (strtolower($buffer) == '/list' && count($list_end_tags))
{
// valid [/list] tag, check nesting so that we don't hit false positives
- if (sizeof($item_end_tags) && sizeof($item_end_tags) >= sizeof($list_end_tags))
+ if (count($item_end_tags) && count($item_end_tags) >= count($list_end_tags))
{
// current li tag has not been closed
$out = preg_replace('/\n?\[$/', '[', $out) . array_pop($item_end_tags) . '][';
@@ -671,10 +733,10 @@ class bbcode_firstpass extends bbcode
}
else
{
- if (($buffer == '*' || substr($buffer, -2) == '[*') && sizeof($list_end_tags))
+ if (($buffer == '*' || substr($buffer, -2) == '[*') && count($list_end_tags))
{
// the buffer holds a bullet tag and we have a [list] tag open
- if (sizeof($item_end_tags) >= sizeof($list_end_tags))
+ if (count($item_end_tags) >= count($list_end_tags))
{
if (substr($buffer, -2) == '[*')
{
@@ -718,11 +780,11 @@ class bbcode_firstpass extends bbcode
while ($in);
// do we have some tags open? close them now
- if (sizeof($item_end_tags))
+ if (count($item_end_tags))
{
$out .= '[' . implode('][', $item_end_tags) . ']';
}
- if (sizeof($list_end_tags))
+ if (count($list_end_tags))
{
$out .= '[' . implode('][', $list_end_tags) . ']';
}
@@ -736,8 +798,6 @@ class bbcode_firstpass extends bbcode
*/
function bbcode_quote($in)
{
- global $config, $user;
-
$in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in)));
if (!$in)
@@ -746,7 +806,9 @@ class bbcode_firstpass extends bbcode
}
// To let the parser not catch tokens within quote_username quotes we encode them before we start this...
- $in = preg_replace('#quote=&quot;(.*?)&quot;\]#ie', "'quote=&quot;' . str_replace(array('[', ']', '\\\"'), array('&#91;', '&#93;', '\"'), '\$1') . '&quot;]'", $in);
+ $in = preg_replace_callback('#quote=&quot;(.*?)&quot;\]#i', function ($match) {
+ return 'quote=&quot;' . str_replace(array('[', ']', '\\\"'), array('&#91;', '&#93;', '\"'), $match[1]) . '&quot;]';
+ }, $in);
$tok = ']';
$out = '[';
@@ -773,7 +835,7 @@ class bbcode_firstpass extends bbcode
if ($tok == ']')
{
- if (strtolower($buffer) == '/quote' && sizeof($close_tags) && substr($out, -1, 1) == '[')
+ if (strtolower($buffer) == '/quote' && count($close_tags) && substr($out, -1, 1) == '[')
{
// we have found a closing tag
$out .= array_pop($close_tags) . ']';
@@ -887,7 +949,7 @@ class bbcode_firstpass extends bbcode
$out .= $buffer;
- if (sizeof($close_tags))
+ if (count($close_tags))
{
$out .= '[' . implode('][', $close_tags) . ']';
}
@@ -945,8 +1007,6 @@ class bbcode_firstpass extends bbcode
*/
function validate_url($var1, $var2)
{
- global $config;
-
$var1 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var1)));
$var2 = str_replace("\r\n", "\n", str_replace('\"', '"', trim($var2)));
@@ -1012,7 +1072,7 @@ class bbcode_firstpass extends bbcode
if ($config['force_server_vars'])
{
- $check_path = $config['script_path'];
+ $check_path = !empty($config['script_path']) ? $config['script_path'] : '/';
}
else
{
@@ -1077,15 +1137,9 @@ class parse_message extends bbcode_firstpass
protected $plupload;
/**
- * The mimetype guesser object used for attachment mimetypes
- * @var \phpbb\mimetype\guesser
- */
- protected $mimetype_guesser;
-
- /**
* Init - give message here or manually
*/
- function parse_message($message = '')
+ function __construct($message = '')
{
// Init BBCode UID
$this->bbcode_uid = substr(base_convert(unique_id(), 16, 36), 0, BBCODE_UID_LEN);
@@ -1097,7 +1151,7 @@ class parse_message extends bbcode_firstpass
*/
function parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post')
{
- global $config, $db, $user, $phpbb_dispatcher;
+ global $config, $user, $phpbb_dispatcher, $phpbb_container;
$this->mode = $mode;
@@ -1126,12 +1180,6 @@ class parse_message extends bbcode_firstpass
$this->decode_message();
}
- // Do some general 'cleanup' first before processing message,
- // e.g. remove excessive newlines(?), smilies(?)
- $match = array('#(script|about|applet|activex|chrome):#i');
- $replace = array("\\1&#058;");
- $this->message = preg_replace($match, $replace, trim($this->message));
-
// Store message length...
$message_length = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message));
@@ -1204,56 +1252,29 @@ class parse_message extends bbcode_firstpass
return (!$update_this_message) ? $return_message : $this->warn_msg;
}
- // Prepare BBcode (just prepares some tags for better parsing)
- if ($allow_bbcode && strpos($this->message, '[') !== false)
- {
- $this->bbcode_init();
- $disallow = array('img', 'flash', 'quote', 'url');
- foreach ($disallow as $bool)
- {
- if (!${'allow_' . $bool . '_bbcode'})
- {
- $this->bbcodes[$bool]['disabled'] = true;
- }
- }
-
- $this->prepare_bbcodes();
- }
-
- // Parse smilies
- if ($allow_smilies)
- {
- $this->smilies($config['max_' . $mode . '_smilies']);
- }
+ // Get the parser
+ $parser = $phpbb_container->get('text_formatter.parser');
- $num_urls = 0;
+ // Set the parser's options
+ ($allow_bbcode) ? $parser->enable_bbcodes() : $parser->disable_bbcodes();
+ ($allow_magic_url) ? $parser->enable_magic_url() : $parser->disable_magic_url();
+ ($allow_smilies) ? $parser->enable_smilies() : $parser->disable_smilies();
+ ($allow_img_bbcode) ? $parser->enable_bbcode('img') : $parser->disable_bbcode('img');
+ ($allow_flash_bbcode) ? $parser->enable_bbcode('flash') : $parser->disable_bbcode('flash');
+ ($allow_quote_bbcode) ? $parser->enable_bbcode('quote') : $parser->disable_bbcode('quote');
+ ($allow_url_bbcode) ? $parser->enable_bbcode('url') : $parser->disable_bbcode('url');
- // Parse BBCode
- if ($allow_bbcode && strpos($this->message, '[') !== false)
- {
- $this->parse_bbcode();
- $num_urls += $this->parsed_items['url'];
- }
+ // Set some config values
+ $parser->set_vars(array(
+ 'max_font_size' => $config['max_' . $this->mode . '_font_size'],
+ 'max_img_height' => $config['max_' . $this->mode . '_img_height'],
+ 'max_img_width' => $config['max_' . $this->mode . '_img_width'],
+ 'max_smilies' => $config['max_' . $this->mode . '_smilies'],
+ 'max_urls' => $config['max_' . $this->mode . '_urls']
+ ));
- // Parse URL's
- if ($allow_magic_url)
- {
- $this->magic_url(generate_board_url());
-
- if ($config['max_' . $mode . '_urls'])
- {
- $num_urls += preg_match_all('#\<!-- ([lmwe]) --\>.*?\<!-- \1 --\>#', $this->message, $matches);
- }
- }
-
- // Check for out-of-bounds characters that are currently
- // not supported by utf8_bin in MySQL
- if (preg_match_all('/[\x{10000}-\x{10FFFF}]/u', $this->message, $matches))
- {
- $character_list = implode('<br />', $matches[0]);
- $this->warn_msg[] = $user->lang('UNSUPPORTED_CHARACTERS_MESSAGE', $character_list);
- return $update_this_message ? $this->warn_msg : $return_message;
- }
+ // Parse this message
+ $this->message = $parser->parse(htmlspecialchars_decode($this->message, ENT_QUOTES));
// Remove quotes that are nested too deep
if ($config['max_quote_depth'] > 0)
@@ -1269,10 +1290,27 @@ class parse_message extends bbcode_firstpass
return (!$update_this_message) ? $return_message : $this->warn_msg;
}
- // Check number of links
- if ($config['max_' . $mode . '_urls'] && $num_urls > $config['max_' . $mode . '_urls'])
+ // Remove quotes that are nested too deep
+ if ($config['max_quote_depth'] > 0)
+ {
+ $this->message = $phpbb_container->get('text_formatter.utils')->remove_bbcode(
+ $this->message,
+ 'quote',
+ $config['max_quote_depth']
+ );
+ }
+
+ // Check for errors
+ $errors = $parser->get_errors();
+ if ($errors)
{
- $this->warn_msg[] = sprintf($user->lang['TOO_MANY_URLS'], $config['max_' . $mode . '_urls']);
+ foreach ($errors as $i => $args)
+ {
+ // Translate each error with $user->lang()
+ $errors[$i] = call_user_func_array(array($user, 'lang'), $args);
+ }
+ $this->warn_msg = array_merge($this->warn_msg, $errors);
+
return (!$update_this_message) ? $return_message : $this->warn_msg;
}
@@ -1292,7 +1330,7 @@ class parse_message extends bbcode_firstpass
*/
function format_display($allow_bbcode, $allow_magic_url, $allow_smilies, $update_this_message = true)
{
- global $phpbb_dispatcher;
+ global $phpbb_container, $phpbb_dispatcher;
// If false, then the parsed message get returned but internal message not processed.
if (!$update_this_message)
@@ -1324,26 +1362,25 @@ class parse_message extends bbcode_firstpass
$this->bbcode_uid = $uid;
unset($text, $uid);
- if ($this->message_status == 'plain')
+ // NOTE: message_status is unreliable for detecting unparsed text because some callers
+ // change $this->message without resetting $this->message_status to 'plain' so we
+ // inspect the message instead
+ //if ($this->message_status == 'plain')
+ if (!preg_match('/^<[rt][ >]/', $this->message))
{
// Force updating message - of course.
$this->parse($allow_bbcode, $allow_magic_url, $allow_smilies, $this->allow_img_bbcode, $this->allow_flash_bbcode, $this->allow_quote_bbcode, $this->allow_url_bbcode, true);
}
- // Replace naughty words such as farty pants
- $this->message = censor_text($this->message);
-
- // Parse BBcode
- if ($allow_bbcode)
+ // There's a bug when previewing a topic with no poll, because the empty title of the poll
+ // gets parsed but $this->message still ends up empty. This fixes it, until a proper fix is
+ // devised
+ if ($this->message === '')
{
- $this->bbcode_cache_init();
-
- // We are giving those parameters to be able to use the bbcode class on its own
- $this->bbcode_second_pass($this->message, $this->bbcode_uid);
+ $this->message = $phpbb_container->get('text_formatter.parser')->parse($this->message);
}
- $this->message = bbcode_nl2br($this->message);
- $this->message = smiley_text($this->message, !$allow_smilies);
+ $this->message = $phpbb_container->get('text_formatter.renderer')->render($this->message);
$text = $this->message;
$uid = $this->bbcode_uid;
@@ -1433,7 +1470,6 @@ class parse_message extends bbcode_firstpass
// For now setting the ttl to 10 minutes
switch ($db->get_sql_layer())
{
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$sql = 'SELECT *
@@ -1464,7 +1500,7 @@ class parse_message extends bbcode_firstpass
$db->sql_freeresult($result);
}
- if (sizeof($match))
+ if (count($match))
{
if ($max_smilies)
{
@@ -1489,16 +1525,46 @@ class parse_message extends bbcode_firstpass
}
/**
+ * Check attachment form token depending on submit type
+ *
+ * @param \phpbb\language\language $language Language
+ * @param \phpbb\request\request_interface $request Request
+ * @param string $form_name Form name for checking form key
+ *
+ * @return bool True if form token is not needed or valid, false if needed and invalid
+ */
+ function check_attachment_form_token(\phpbb\language\language $language, \phpbb\request\request_interface $request, $form_name)
+ {
+ $add_file = $request->is_set_post('add_file');
+ $delete_file = $request->is_set_post('delete_file');
+
+ if (($add_file || $delete_file) && !check_form_key($form_name))
+ {
+ $this->warn_msg[] = $language->lang('FORM_INVALID');
+
+ if ($request->is_ajax() && $this->plupload)
+ {
+ $this->plupload->emit_error(-400, 'FORM_INVALID');
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
* Parse Attachments
*/
function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false)
{
global $config, $auth, $user, $phpbb_root_path, $phpEx, $db, $request;
+ global $phpbb_container, $phpbb_dispatcher;
$error = array();
- $num_attachments = sizeof($this->attachment_data);
- $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true));
+ $num_attachments = count($this->attachment_data);
+ $this->filename_data['filecomment'] = $request->variable('filecomment', '', true);
$upload = $request->file($form_name);
$upload_file = (!empty($upload) && $upload['name'] !== 'none' && trim($upload['name']));
@@ -1506,7 +1572,7 @@ class parse_message extends bbcode_firstpass
$delete_file = (isset($_POST['delete_file'])) ? true : false;
// First of all adjust comments if changed
- $actual_comment_list = utf8_normalize_nfc(request_var('comment_list', array(''), true));
+ $actual_comment_list = $request->variable('comment_list', array(''), true);
foreach ($actual_comment_list as $comment_key => $comment)
{
@@ -1529,10 +1595,12 @@ class parse_message extends bbcode_firstpass
{
if ($num_attachments < $cfg['max_attachments'] || $auth->acl_get('a_') || $auth->acl_get('m_', $forum_id))
{
- $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $filedata = $attachment_manager->upload($form_name, $forum_id, false, '', $is_message);
$error = $filedata['error'];
- if ($filedata['post_attach'] && !sizeof($error))
+ if ($filedata['post_attach'] && !count($error))
{
$sql_ary = array(
'physical_filename' => $filedata['physical_filename'],
@@ -1548,6 +1616,16 @@ class parse_message extends bbcode_firstpass
'poster_id' => $user->data['user_id'],
);
+ /**
+ * Modify attachment sql array on submit
+ *
+ * @event core.modify_attachment_sql_ary_on_submit
+ * @var array sql_ary Array containing SQL data
+ * @since 3.2.6-RC1
+ */
+ $vars = array('sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.modify_attachment_sql_ary_on_submit', compact($vars)));
+
$db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
$new_entry = array(
@@ -1559,7 +1637,23 @@ class parse_message extends bbcode_firstpass
);
$this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data);
- $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message);
+
+ /**
+ * Modify attachment data on submit
+ *
+ * @event core.modify_attachment_data_on_submit
+ * @var array attachment_data Array containing attachment data
+ * @since 3.2.2-RC1
+ */
+ $attachment_data = $this->attachment_data;
+ $vars = array('attachment_data');
+ extract($phpbb_dispatcher->trigger_event('core.modify_attachment_data_on_submit', compact($vars)));
+ $this->attachment_data = $attachment_data;
+ unset($attachment_data);
+
+ $this->message = preg_replace_callback('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#', function ($match) {
+ return '[attachment='.($match[1] + 1).']' . $match[2] . '[/attachment]';
+ }, $this->message);
$this->filename_data['filecomment'] = '';
@@ -1580,7 +1674,7 @@ class parse_message extends bbcode_firstpass
}
}
- if ($preview || $refresh || sizeof($error))
+ if ($preview || $refresh || count($error))
{
if (isset($this->plupload) && $this->plupload->is_active())
{
@@ -1592,11 +1686,14 @@ class parse_message extends bbcode_firstpass
{
include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
- $index = array_keys(request_var('delete_file', array(0 => 0)));
+ $index = array_keys($request->variable('delete_file', array(0 => 0)));
$index = (!empty($index)) ? $index[0] : false;
if ($index !== false && !empty($this->attachment_data[$index]))
{
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+
// delete selected attachment
if ($this->attachment_data[$index]['is_orphan'])
{
@@ -1611,11 +1708,11 @@ class parse_message extends bbcode_firstpass
if ($row)
{
- phpbb_unlink($row['physical_filename'], 'file');
+ $attachment_manager->unlink($row['physical_filename'], 'file');
if ($row['thumbnail'])
{
- phpbb_unlink($row['physical_filename'], 'thumbnail');
+ $attachment_manager->unlink($row['physical_filename'], 'thumbnail');
}
$db->sql_query('DELETE FROM ' . ATTACHMENTS_TABLE . ' WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id']);
@@ -1623,11 +1720,13 @@ class parse_message extends bbcode_firstpass
}
else
{
- delete_attachments('attach', array(intval($this->attachment_data[$index]['attach_id'])));
+ $attachment_manager->delete('attach', $this->attachment_data[$index]['attach_id']);
}
unset($this->attachment_data[$index]);
- $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "(\\1 == \$index) ? '' : ((\\1 > \$index) ? '[attachment=' . (\\1 - 1) . ']\\2[/attachment]' : '\\0')", $this->message);
+ $this->message = preg_replace_callback('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#', function ($match) use($index) {
+ return ($match[1] == $index) ? '' : (($match[1] > $index) ? '[attachment=' . ($match[1] - 1) . ']' . $match[2] . '[/attachment]' : $match[0]);
+ }, $this->message);
// Reindex Array
$this->attachment_data = array_values($this->attachment_data);
@@ -1641,10 +1740,12 @@ class parse_message extends bbcode_firstpass
{
if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id))
{
- $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message, false, $this->mimetype_guesser, $this->plupload);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $filedata = $attachment_manager->upload($form_name, $forum_id, false, '', $is_message);
$error = array_merge($error, $filedata['error']);
- if (!sizeof($error))
+ if (!count($error))
{
$sql_ary = array(
'physical_filename' => $filedata['physical_filename'],
@@ -1660,6 +1761,16 @@ class parse_message extends bbcode_firstpass
'poster_id' => $user->data['user_id'],
);
+ /**
+ * Modify attachment sql array on upload
+ *
+ * @event core.modify_attachment_sql_ary_on_upload
+ * @var array sql_ary Array containing SQL data
+ * @since 3.2.6-RC1
+ */
+ $vars = array('sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.modify_attachment_sql_ary_on_upload', compact($vars)));
+
$db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
$new_entry = array(
@@ -1671,7 +1782,23 @@ class parse_message extends bbcode_firstpass
);
$this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data);
- $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "'[attachment='.(\\1 + 1).']\\2[/attachment]'", $this->message);
+
+ /**
+ * Modify attachment data on upload
+ *
+ * @event core.modify_attachment_data_on_upload
+ * @var array attachment_data Array containing attachment data
+ * @since 3.2.2-RC1
+ */
+ $attachment_data = $this->attachment_data;
+ $vars = array('attachment_data');
+ extract($phpbb_dispatcher->trigger_event('core.modify_attachment_data_on_upload', compact($vars)));
+ $this->attachment_data = $attachment_data;
+ unset($attachment_data);
+
+ $this->message = preg_replace_callback('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#', function ($match) {
+ return '[attachment=' . ($match[1] + 1) . ']' . $match[2] . '[/attachment]';
+ }, $this->message);
$this->filename_data['filecomment'] = '';
if (isset($this->plupload) && $this->plupload->is_active())
@@ -1715,16 +1842,16 @@ class parse_message extends bbcode_firstpass
*/
function get_submitted_attachment_data($check_user_id = false)
{
- global $user, $db, $phpbb_root_path, $phpEx, $config;
+ global $user, $db;
global $request;
- $this->filename_data['filecomment'] = utf8_normalize_nfc(request_var('filecomment', '', true));
+ $this->filename_data['filecomment'] = $request->variable('filecomment', '', true);
$attachment_data = $request->variable('attachment_data', array(0 => array('' => '')), true, \phpbb\request\request_interface::POST);
$this->attachment_data = array();
$check_user_id = ($check_user_id === false) ? $user->data['user_id'] : $check_user_id;
- if (!sizeof($attachment_data))
+ if (!count($attachment_data))
{
return;
}
@@ -1744,7 +1871,7 @@ class parse_message extends bbcode_firstpass
}
// Regenerate already posted attachments
- if (sizeof($not_orphan))
+ if (count($not_orphan))
{
// Get the attachment data, based on the poster id...
$sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize
@@ -1764,13 +1891,13 @@ class parse_message extends bbcode_firstpass
$db->sql_freeresult($result);
}
- if (sizeof($not_orphan))
+ if (count($not_orphan))
{
trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR);
}
// Regenerate newly uploaded attachments
- if (sizeof($orphan))
+ if (count($orphan))
{
$sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment, filesize
FROM ' . ATTACHMENTS_TABLE . '
@@ -1790,7 +1917,7 @@ class parse_message extends bbcode_firstpass
$db->sql_freeresult($result);
}
- if (sizeof($orphan))
+ if (count($orphan))
{
trigger_error('NO_ACCESS_ATTACHMENT', E_USER_ERROR);
}
@@ -1803,28 +1930,26 @@ class parse_message extends bbcode_firstpass
*/
function parse_poll(&$poll)
{
- global $auth, $user, $config;
+ global $user, $config;
$poll_max_options = $poll['poll_max_options'];
- // Parse Poll Option text ;)
+ // Parse Poll Option text
$tmp_message = $this->message;
- $this->message = $poll['poll_option_text'];
- $bbcode_bitfield = $this->bbcode_bitfield;
- $poll['poll_option_text'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll');
+ $poll['poll_options'] = preg_split('/\s*?\n\s*/', trim($poll['poll_option_text']));
+ $poll['poll_options_size'] = count($poll['poll_options']);
- $bbcode_bitfield = base64_encode(base64_decode($bbcode_bitfield) | base64_decode($this->bbcode_bitfield));
- $this->message = $tmp_message;
+ foreach ($poll['poll_options'] as &$poll_option)
+ {
+ $this->message = $poll_option;
+ $poll_option = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll');
+ }
+ unset($poll_option);
+ $poll['poll_option_text'] = implode("\n", $poll['poll_options']);
// Parse Poll Title
- $tmp_message = $this->message;
$this->message = $poll['poll_title'];
- $this->bbcode_bitfield = $bbcode_bitfield;
-
- $poll['poll_options'] = preg_split('/\s*?\n\s*/', trim($poll['poll_option_text']));
- $poll['poll_options_size'] = sizeof($poll['poll_options']);
-
if (!$poll['poll_title'] && $poll['poll_options_size'])
{
$this->warn_msg[] = $user->lang['NO_POLL_TITLE'];
@@ -1842,11 +1967,7 @@ class parse_message extends bbcode_firstpass
}
}
- $this->bbcode_bitfield = base64_encode(base64_decode($bbcode_bitfield) | base64_decode($this->bbcode_bitfield));
- $this->message = $tmp_message;
- unset($tmp_message);
-
- if (sizeof($poll['poll_options']) == 1)
+ if (count($poll['poll_options']) == 1)
{
$this->warn_msg[] = $user->lang['TOO_FEW_POLL_OPTIONS'];
}
@@ -1860,6 +1981,8 @@ class parse_message extends bbcode_firstpass
}
$poll['poll_max_options'] = ($poll['poll_max_options'] < 1) ? 1 : (($poll['poll_max_options'] > $config['max_poll_options']) ? $config['max_poll_options'] : $poll['poll_max_options']);
+
+ $this->message = $tmp_message;
}
/**
@@ -1870,6 +1993,19 @@ class parse_message extends bbcode_firstpass
*/
public function remove_nested_quotes($max_depth)
{
+ global $phpbb_container;
+
+ if (preg_match('#^<[rt][ >]#', $this->message))
+ {
+ $this->message = $phpbb_container->get('text_formatter.utils')->remove_bbcode(
+ $this->message,
+ 'quote',
+ $max_depth
+ );
+
+ return;
+ }
+
// Capture all [quote] and [/quote] tags
preg_match_all('(\\[/?quote(?:=&quot;(.*?)&quot;)?:' . $this->bbcode_uid . '\\])', $this->message, $matches, PREG_OFFSET_CAPTURE);
@@ -1919,18 +2055,6 @@ class parse_message extends bbcode_firstpass
}
/**
- * Setter function for passing the mimetype_guesser object
- *
- * @param \phpbb\mimetype\guesser $mimetype_guesser The mimetype_guesser object
- *
- * @return null
- */
- public function set_mimetype_guesser(\phpbb\mimetype\guesser $mimetype_guesser)
- {
- $this->mimetype_guesser = $mimetype_guesser;
- }
-
- /**
* Function to perform custom bbcode validation by extensions
* can be used in bbcode_init() to assign regexp replacement
* Example: 'regexp' => array('#\[b\](.*?)\[/b\]#uise' => "\$this->validate_bbcode_by_extension('\$1')")
diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php
index 63ea432863..2f80582918 100644
--- a/phpBB/includes/questionnaire/questionnaire.php
+++ b/phpBB/includes/questionnaire/questionnaire.php
@@ -40,15 +40,15 @@ class phpbb_questionnaire_data_collector
*
* @param string
*/
- function phpbb_questionnaire_data_collector($install_id)
+ function __construct($install_id)
{
$this->install_id = $install_id;
$this->providers = array();
}
- function add_data_provider(&$provider)
+ function add_data_provider($provider)
{
- $this->providers[] = &$provider;
+ $this->providers[] = $provider;
}
/**
@@ -80,7 +80,7 @@ class phpbb_questionnaire_data_collector
{
foreach (array_keys($this->providers) as $key)
{
- $provider = &$this->providers[$key];
+ $provider = $this->providers[$key];
$this->data[$provider->get_identifier()] = $provider->get_data();
}
$this->data['install_id'] = $this->install_id;
@@ -190,7 +190,6 @@ class phpbb_questionnaire_system_data_provider
// - 192.168.0.0/16
if ($ip_address_ary[0] == '10' ||
($ip_address_ary[0] == '172' && intval($ip_address_ary[1]) > 15 && intval($ip_address_ary[1]) < 32) ||
- ($ip_address_ary[0] == '192' && $ip_address_ary[1] == '168') ||
($ip_address_ary[0] == '192' && $ip_address_ary[1] == '168'))
{
return true;
@@ -224,13 +223,13 @@ class phpbb_questionnaire_phpbb_data_provider
*
* @param array $config
*/
- function phpbb_questionnaire_phpbb_data_provider($config)
+ function __construct($config)
{
// generate a unique id if necessary
if (empty($config['questionnaire_unique_id']))
{
$this->unique_id = unique_id();
- set_config('questionnaire_unique_id', $this->unique_id);
+ $config->set('questionnaire_unique_id', $this->unique_id);
}
else
{
@@ -257,7 +256,7 @@ class phpbb_questionnaire_phpbb_data_provider
*/
function get_data()
{
- global $phpbb_root_path, $phpEx, $phpbb_config_php_file;
+ global $phpbb_config_php_file;
extract($phpbb_config_php_file->get_all());
unset($dbhost, $dbport, $dbname, $dbuser, $dbpasswd); // Just a precaution
@@ -338,7 +337,7 @@ class phpbb_questionnaire_phpbb_data_provider
'edit_time' => true,
'email_check_mx' => true,
'email_enable' => true,
- 'email_function_name' => true,
+ 'email_force_sender' => true,
'email_package_size' => true,
'enable_confirm' => true,
'enable_pm_icons' => true,
@@ -370,7 +369,6 @@ class phpbb_questionnaire_phpbb_data_provider
'hot_threshold' => true,
'img_create_thumbnail' => true,
'img_display_inlined' => true,
- 'img_imagick' => true,
'img_link_height' => true,
'img_link_width' => true,
'img_max_height' => true,
diff --git a/phpBB/includes/sphinxapi.php b/phpBB/includes/sphinxapi.php
index 6c3b66710c..b63a85a90f 100644
--- a/phpBB/includes/sphinxapi.php
+++ b/phpBB/includes/sphinxapi.php
@@ -126,7 +126,7 @@ define ( "SPH_GROUPBY_ATTRPAIR", 5 );
function sphPackI64 ( $v )
{
assert ( is_numeric($v) );
-
+
// x64
if ( PHP_INT_SIZE>=8 )
{
@@ -138,7 +138,7 @@ function sphPackI64 ( $v )
if ( is_int($v) )
return pack ( "NN", $v < 0 ? -1 : 0, $v );
- // x32, bcmath
+ // x32, bcmath
if ( function_exists("bcmul") )
{
if ( bccomp ( $v, 0 ) == -1 )
@@ -175,16 +175,16 @@ function sphPackI64 ( $v )
function sphPackU64 ( $v )
{
assert ( is_numeric($v) );
-
+
// x64
if ( PHP_INT_SIZE>=8 )
{
assert ( $v>=0 );
-
+
// x64, int
if ( is_int($v) )
return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
-
+
// x64, bcmath
if ( function_exists("bcmul") )
{
@@ -192,12 +192,12 @@ function sphPackU64 ( $v )
$l = bcmod ( $v, 4294967296 );
return pack ( "NN", $h, $l );
}
-
+
// x64, no-bcmath
$p = max ( 0, strlen($v) - 13 );
$lo = (int)substr ( $v, $p );
$hi = (int)substr ( $v, 0, $p );
-
+
$m = $lo + $hi*1316134912;
$l = $m % 4294967296;
$h = $hi*2328 + (int)($m/4294967296);
@@ -208,7 +208,7 @@ function sphPackU64 ( $v )
// x32, int
if ( is_int($v) )
return pack ( "NN", 0, $v );
-
+
// x32, bcmath
if ( function_exists("bcmul") )
{
@@ -221,7 +221,7 @@ function sphPackU64 ( $v )
$p = max(0, strlen($v) - 13);
$lo = (float)substr($v, $p);
$hi = (float)substr($v, 0, $p);
-
+
$m = $lo + $hi*1316134912.0;
$q = floor($m / 4294967296.0);
$l = $m - ($q * 4294967296.0);
@@ -277,11 +277,11 @@ function sphUnpackU64 ( $v )
// x32, bcmath
if ( function_exists("bcmul") )
return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
-
+
// x32, no-bcmath
$hi = (float)$hi;
$lo = (float)$lo;
-
+
$q = floor($hi/10000000.0);
$r = $hi - $q*10000000.0;
$m = $lo + $r*4967296.0;
@@ -324,7 +324,7 @@ function sphUnpackI64 ( $v )
return $lo;
return sprintf ( "%.0f", $lo - 4294967296.0 );
}
-
+
$neg = "";
$c = 0;
if ( $hi<0 )
@@ -333,7 +333,7 @@ function sphUnpackI64 ( $v )
$lo = ~$lo;
$c = 1;
$neg = "-";
- }
+ }
$hi = sprintf ( "%u", $hi );
$lo = sprintf ( "%u", $lo );
@@ -345,7 +345,7 @@ function sphUnpackI64 ( $v )
// x32, no-bcmath
$hi = (float)$hi;
$lo = (float)$lo;
-
+
$q = floor($hi/10000000.0);
$r = $hi - $q*10000000.0;
$m = $lo + $r*4967296.0;
@@ -427,7 +427,7 @@ class SphinxClient
/////////////////////////////////////////////////////////////////////////////
/// create a new client object and fill defaults
- function SphinxClient ()
+ function __construct ()
{
// per-client-object settings
$this->_host = "localhost";
@@ -510,7 +510,7 @@ class SphinxClient
$this->_path = $host;
return;
}
-
+
assert ( is_int($port) );
$this->_host = $host;
$this->_port = $port;
@@ -590,14 +590,14 @@ class SphinxClient
$fp = @fsockopen ( $host, $port, $errno, $errstr );
else
$fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout );
-
+
if ( !$fp )
{
if ( $this->_path )
$location = $this->_path;
else
$location = "{$this->_host}:{$this->_port}";
-
+
$errstr = trim ( $errstr );
$this->_error = "connection to $location failed (errno=$errno, msg=$errstr)";
$this->_connerror = true;
@@ -1236,7 +1236,7 @@ class SphinxClient
if ( $type==SPH_ATTR_FLOAT )
{
list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- list(,$fval) = unpack ( "f*", pack ( "L", $uval ) );
+ list(,$fval) = unpack ( "f*", pack ( "L", $uval ) );
$attrvals[$attr] = $fval;
continue;
}
@@ -1264,7 +1264,7 @@ class SphinxClient
} else if ( $type==SPH_ATTR_STRING )
{
$attrvals[$attr] = substr ( $response, $p, $val );
- $p += $val;
+ $p += $val;
} else
{
$attrvals[$attr] = sphFixUint($val);
@@ -1345,7 +1345,7 @@ class SphinxClient
if ( !isset($opts["passage_boundary"]) ) $opts["passage_boundary"] = "none";
if ( !isset($opts["emit_zones"]) ) $opts["emit_zones"] = false;
if ( !isset($opts["load_files_scattered"]) ) $opts["load_files_scattered"] = false;
-
+
/////////////////
// build request
@@ -1634,7 +1634,7 @@ class SphinxClient
fclose ( $this->_socket );
$this->_socket = false;
-
+
return true;
}
@@ -1659,7 +1659,6 @@ class SphinxClient
return false;
}
- $res = substr ( $response, 4 ); // just ignore length, error handling, etc
$p = 0;
list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
diff --git a/phpBB/includes/startup.php b/phpBB/includes/startup.php
index 7353b90d99..66f85657a5 100644
--- a/phpBB/includes/startup.php
+++ b/phpBB/includes/startup.php
@@ -19,123 +19,34 @@ if (!defined('IN_PHPBB'))
}
// Report all errors, except notices and deprecation messages
-if (!defined('E_DEPRECATED'))
-{
- define('E_DEPRECATED', 8192);
-}
$level = E_ALL & ~E_NOTICE & ~E_DEPRECATED;
error_reporting($level);
-/*
-* Remove variables created by register_globals from the global scope
-* Thanks to Matt Kavanagh
+/**
+* Minimum Requirement: PHP 5.4.0
*/
-function deregister_globals()
+if (version_compare(PHP_VERSION, '5.4') < 0)
{
- $not_unset = array(
- 'GLOBALS' => true,
- '_GET' => true,
- '_POST' => true,
- '_COOKIE' => true,
- '_REQUEST' => true,
- '_SERVER' => true,
- '_SESSION' => true,
- '_ENV' => true,
- '_FILES' => true,
- 'phpEx' => true,
- 'phpbb_root_path' => true
- );
-
- // Not only will array_merge and array_keys give a warning if
- // a parameter is not an array, array_merge will actually fail.
- // So we check if _SESSION has been initialised.
- if (!isset($_SESSION) || !is_array($_SESSION))
- {
- $_SESSION = array();
- }
-
- // Merge all into one extremely huge array; unset this later
- $input = array_merge(
- array_keys($_GET),
- array_keys($_POST),
- array_keys($_COOKIE),
- array_keys($_SERVER),
- array_keys($_SESSION),
- array_keys($_ENV),
- array_keys($_FILES)
- );
-
- foreach ($input as $varname)
- {
- if (isset($not_unset[$varname]))
- {
- // Hacking attempt. No point in continuing.
- if (isset($_COOKIE[$varname]))
- {
- echo "Clear your cookies. ";
- }
- echo "Malicious variable name detected. Contact the administrator and ask them to disable register_globals.";
- exit;
- }
-
- unset($GLOBALS[$varname]);
- }
-
- unset($input);
+ die('You are running an unsupported PHP version. Please upgrade to PHP 5.4.0 or higher before trying to install or update to phpBB 3.2');
}
+// Register globals and magic quotes have been dropped in PHP 5.4 so no need for extra checks
-// Register globals and magic quotes have been dropped in PHP 5.4
-if (version_compare(PHP_VERSION, '5.4.0-dev', '>='))
-{
- /**
- * @ignore
- */
- define('STRIP', false);
-}
-else
-{
- if (get_magic_quotes_runtime())
- {
- // Deactivate
- @set_magic_quotes_runtime(0);
- }
- // Be paranoid with passed vars
- if (@ini_get('register_globals') == '1' || strtolower(@ini_get('register_globals')) == 'on' || !function_exists('ini_get'))
- {
- deregister_globals();
- }
+// In PHP 5.3.0 the error level has been raised to E_WARNING which causes problems
+// because we show E_WARNING errors and do not set a default timezone.
+// This is because we have our own timezone handling and work in UTC only anyway.
- define('STRIP', (get_magic_quotes_gpc()) ? true : false);
-}
+// So what we basically want to do is set our timezone to UTC,
+// but we don't know what other scripts (such as bridges) are involved,
+// so we check whether a timezone is already set by calling date_default_timezone_get().
-// Prevent date/time functions from throwing E_WARNING on PHP 5.3 by setting a default timezone
-if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get'))
-{
- // For PHP 5.1.0 the date/time functions have been rewritten
- // and setting a timezone is required prior to calling any date/time function.
-
- // Since PHP 5.2.0 calls to date/time functions without having a timezone set
- // result in E_STRICT errors being thrown.
- // Note: We already exclude E_STRICT errors
- // (to be exact: they are not included in E_ALL in PHP 5.2)
-
- // In PHP 5.3.0 the error level has been raised to E_WARNING which causes problems
- // because we show E_WARNING errors and do not set a default timezone.
- // This is because we have our own timezone handling and work in UTC only anyway.
+// Unfortunately, date_default_timezone_get() itself might throw E_WARNING
+// if no timezone has been set, so we have to keep it quiet with @.
- // So what we basically want to do is set our timezone to UTC,
- // but we don't know what other scripts (such as bridges) are involved,
- // so we check whether a timezone is already set by calling date_default_timezone_get().
-
- // Unfortunately, date_default_timezone_get() itself might throw E_WARNING
- // if no timezone has been set, so we have to keep it quiet with @.
-
- // date_default_timezone_get() tries to guess the correct timezone first
- // and then falls back to UTC when everything fails.
- // We just set the timezone to whatever date_default_timezone_get() returns.
- date_default_timezone_set(@date_default_timezone_get());
-}
+// date_default_timezone_get() tries to guess the correct timezone first
+// and then falls back to UTC when everything fails.
+// We just set the timezone to whatever date_default_timezone_get() returns.
+date_default_timezone_set(@date_default_timezone_get());
// Autoloading of dependencies.
// Three options are supported:
@@ -172,5 +83,4 @@ else
require($phpbb_root_path . 'vendor/autoload.php');
}
-$starttime = explode(' ', microtime());
-$starttime = $starttime[1] + $starttime[0];
+$starttime = microtime(true);
diff --git a/phpBB/includes/ucp/info/ucp_attachments.php b/phpBB/includes/ucp/info/ucp_attachments.php
index 2e20106f5c..96e7956db9 100644
--- a/phpBB/includes/ucp/info/ucp_attachments.php
+++ b/phpBB/includes/ucp/info/ucp_attachments.php
@@ -18,7 +18,6 @@ class ucp_attachments_info
return array(
'filename' => 'ucp_attachments',
'title' => 'UCP_ATTACHMENTS',
- 'version' => '1.0.0',
'modes' => array(
'attachments' => array('title' => 'UCP_MAIN_ATTACHMENTS', 'auth' => 'acl_u_attach', 'cat' => array('UCP_MAIN')),
),
diff --git a/phpBB/includes/ucp/info/ucp_auth_link.php b/phpBB/includes/ucp/info/ucp_auth_link.php
index 9ec4cb7b3a..57c9269c5e 100644
--- a/phpBB/includes/ucp/info/ucp_auth_link.php
+++ b/phpBB/includes/ucp/info/ucp_auth_link.php
@@ -18,7 +18,6 @@ class ucp_auth_link_info
return array(
'filename' => 'ucp_auth_link',
'title' => 'UCP_AUTH_LINK',
- 'version' => '1.0.0',
'modes' => array(
'auth_link' => array('title' => 'UCP_AUTH_LINK_MANAGE', 'auth' => 'authmethod_oauth', 'cat' => array('UCP_PROFILE')),
),
diff --git a/phpBB/includes/ucp/info/ucp_groups.php b/phpBB/includes/ucp/info/ucp_groups.php
index 6da2a4fe38..42eb285075 100644
--- a/phpBB/includes/ucp/info/ucp_groups.php
+++ b/phpBB/includes/ucp/info/ucp_groups.php
@@ -18,7 +18,6 @@ class ucp_groups_info
return array(
'filename' => 'ucp_groups',
'title' => 'UCP_USERGROUPS',
- 'version' => '1.0.0',
'modes' => array(
'membership' => array('title' => 'UCP_USERGROUPS_MEMBER', 'auth' => '', 'cat' => array('UCP_USERGROUPS')),
'manage' => array('title' => 'UCP_USERGROUPS_MANAGE', 'auth' => '', 'cat' => array('UCP_USERGROUPS')),
diff --git a/phpBB/includes/ucp/info/ucp_main.php b/phpBB/includes/ucp/info/ucp_main.php
index de8e7d5602..e967b8445f 100644
--- a/phpBB/includes/ucp/info/ucp_main.php
+++ b/phpBB/includes/ucp/info/ucp_main.php
@@ -18,7 +18,6 @@ class ucp_main_info
return array(
'filename' => 'ucp_main',
'title' => 'UCP_MAIN',
- 'version' => '1.0.0',
'modes' => array(
'front' => array('title' => 'UCP_MAIN_FRONT', 'auth' => '', 'cat' => array('UCP_MAIN')),
'subscribed' => array('title' => 'UCP_MAIN_SUBSCRIBED', 'auth' => '', 'cat' => array('UCP_MAIN')),
diff --git a/phpBB/includes/ucp/info/ucp_notifications.php b/phpBB/includes/ucp/info/ucp_notifications.php
index 0cc011d96e..94e0467ccb 100644
--- a/phpBB/includes/ucp/info/ucp_notifications.php
+++ b/phpBB/includes/ucp/info/ucp_notifications.php
@@ -18,10 +18,9 @@ class ucp_notifications_info
return array(
'filename' => 'ucp_notifications',
'title' => 'UCP_NOTIFICATION_OPTIONS',
- 'version' => '1.0.0',
'modes' => array(
'notification_options' => array('title' => 'UCP_NOTIFICATION_OPTIONS', 'auth' => '', 'cat' => array('UCP_PREFS')),
- 'notification_list' => array('title' => 'UCP_NOTIFICATION_LIST', 'auth' => '', 'cat' => array('UCP_MAIN')),
+ 'notification_list' => array('title' => 'UCP_NOTIFICATION_LIST', 'auth' => 'cfg_allow_board_notifications', 'cat' => array('UCP_MAIN')),
),
);
}
diff --git a/phpBB/includes/ucp/info/ucp_pm.php b/phpBB/includes/ucp/info/ucp_pm.php
index 6aa1669cb6..26bd670fc5 100644
--- a/phpBB/includes/ucp/info/ucp_pm.php
+++ b/phpBB/includes/ucp/info/ucp_pm.php
@@ -18,7 +18,6 @@ class ucp_pm_info
return array(
'filename' => 'ucp_pm',
'title' => 'UCP_PM',
- 'version' => '1.0.0',
'modes' => array(
'view' => array('title' => 'UCP_PM_VIEW', 'auth' => 'cfg_allow_privmsg', 'display' => false, 'cat' => array('UCP_PM')),
'compose' => array('title' => 'UCP_PM_COMPOSE', 'auth' => 'cfg_allow_privmsg', 'cat' => array('UCP_PM')),
diff --git a/phpBB/includes/ucp/info/ucp_prefs.php b/phpBB/includes/ucp/info/ucp_prefs.php
index 5c2d29ac73..4793aa2649 100644
--- a/phpBB/includes/ucp/info/ucp_prefs.php
+++ b/phpBB/includes/ucp/info/ucp_prefs.php
@@ -18,7 +18,6 @@ class ucp_prefs_info
return array(
'filename' => 'ucp_prefs',
'title' => 'UCP_PREFS',
- 'version' => '1.0.0',
'modes' => array(
'personal' => array('title' => 'UCP_PREFS_PERSONAL', 'auth' => '', 'cat' => array('UCP_PREFS')),
'post' => array('title' => 'UCP_PREFS_POST', 'auth' => '', 'cat' => array('UCP_PREFS')),
diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php
index 919de99a96..fc2792224d 100644
--- a/phpBB/includes/ucp/info/ucp_profile.php
+++ b/phpBB/includes/ucp/info/ucp_profile.php
@@ -18,7 +18,6 @@ class ucp_profile_info
return array(
'filename' => 'ucp_profile',
'title' => 'UCP_PROFILE',
- 'version' => '1.0.0',
'modes' => array(
'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => 'acl_u_chgprofileinfo', 'cat' => array('UCP_PROFILE')),
'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')),
diff --git a/phpBB/includes/ucp/info/ucp_zebra.php b/phpBB/includes/ucp/info/ucp_zebra.php
index 99d4a4f4c0..69274c2866 100644
--- a/phpBB/includes/ucp/info/ucp_zebra.php
+++ b/phpBB/includes/ucp/info/ucp_zebra.php
@@ -18,7 +18,6 @@ class ucp_zebra_info
return array(
'filename' => 'ucp_zebra',
'title' => 'UCP_ZEBRA',
- 'version' => '1.0.0',
'modes' => array(
'friends' => array('title' => 'UCP_ZEBRA_FRIENDS', 'auth' => '', 'cat' => array('UCP_ZEBRA')),
'foes' => array('title' => 'UCP_ZEBRA_FOES', 'auth' => '', 'cat' => array('UCP_ZEBRA')),
diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php
index 1f5ce93277..7a90f2e3b1 100644
--- a/phpBB/includes/ucp/ucp_activate.php
+++ b/phpBB/includes/ucp/ucp_activate.php
@@ -29,11 +29,11 @@ class ucp_activate
function main($id, $mode)
{
- global $config, $phpbb_root_path, $phpEx;
- global $db, $user, $auth, $template, $phpbb_container, $phpbb_dispatcher;
+ global $config, $phpbb_root_path, $phpEx, $request;
+ global $db, $user, $auth, $phpbb_container, $phpbb_log, $phpbb_dispatcher;
- $user_id = request_var('u', 0);
- $key = request_var('k', '');
+ $user_id = $request->variable('u', 0);
+ $key = $request->variable('k', '');
$sql = 'SELECT user_id, username, user_type, user_email, user_newpasswd, user_lang, user_notify_type, user_actkey, user_inactive_reason
FROM ' . USERS_TABLE . "
@@ -67,6 +67,7 @@ class ucp_activate
{
login_box('', $user->lang['NO_AUTH_OPERATION']);
}
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_OPERATION');
}
@@ -86,7 +87,12 @@ class ucp_activate
WHERE user_id = ' . $user_row['user_id'];
$db->sql_query($sql);
- add_log('user', $user_row['user_id'], 'LOG_USER_NEW_PASSWORD', $user_row['username']);
+ $user->reset_login_keys($user_row['user_id']);
+
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_NEW_PASSWORD', false, array(
+ 'reportee_id' => $user_row['user_id'],
+ $user_row['username']
+ ));
}
if (!$update_password)
@@ -101,15 +107,19 @@ class ucp_activate
$db->sql_query($sql);
// Create the correct logs
- add_log('user', $user_row['user_id'], 'LOG_USER_ACTIVE_USER');
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_ACTIVE_USER', false, array(
+ 'reportee_id' => $user_row['user_id']
+ ));
+
if ($auth->acl_get('a_user'))
{
- add_log('admin', 'LOG_USER_ACTIVE', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_USER_ACTIVE', false, array($user_row['username']));
}
}
if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !$update_password)
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']);
diff --git a/phpBB/includes/ucp/ucp_attachments.php b/phpBB/includes/ucp/ucp_attachments.php
index 42724209aa..7808fed325 100644
--- a/phpBB/includes/ucp/ucp_attachments.php
+++ b/phpBB/includes/ucp/ucp_attachments.php
@@ -29,35 +29,45 @@ class ucp_attachments
function main($id, $mode)
{
- global $template, $user, $db, $config, $phpEx, $phpbb_root_path, $phpbb_container;
+ global $template, $user, $db, $config, $phpEx, $phpbb_root_path, $phpbb_container, $request, $auth;
- $start = request_var('start', 0);
- $sort_key = request_var('sk', 'a');
- $sort_dir = request_var('sd', 'a');
+ $start = $request->variable('start', 0);
+ $sort_key = $request->variable('sk', 'a');
+ $sort_dir = $request->variable('sd', 'a');
$delete = (isset($_POST['delete'])) ? true : false;
- $confirm = (isset($_POST['confirm'])) ? true : false;
- $delete_ids = array_keys(request_var('attachment', array(0)));
+ $delete_ids = array_keys($request->variable('attachment', array(0)));
- if ($delete && sizeof($delete_ids))
+ if ($delete && count($delete_ids))
{
// Validate $delete_ids...
- $sql = 'SELECT attach_id
- FROM ' . ATTACHMENTS_TABLE . '
- WHERE poster_id = ' . $user->data['user_id'] . '
- AND is_orphan = 0
- AND ' . $db->sql_in_set('attach_id', $delete_ids);
+ $sql = 'SELECT a.attach_id, p.post_edit_locked, t.topic_status, f.forum_id, f.forum_status
+ FROM ' . ATTACHMENTS_TABLE . ' a
+ LEFT JOIN ' . POSTS_TABLE . ' p
+ ON (a.post_msg_id = p.post_id AND a.in_message = 0)
+ LEFT JOIN ' . TOPICS_TABLE . ' t
+ ON (t.topic_id = p.topic_id AND a.in_message = 0)
+ LEFT JOIN ' . FORUMS_TABLE . ' f
+ ON (f.forum_id = t.forum_id AND a.in_message = 0)
+ WHERE a.poster_id = ' . $user->data['user_id'] . '
+ AND a.is_orphan = 0
+ AND ' . $db->sql_in_set('a.attach_id', $delete_ids);
$result = $db->sql_query($sql);
$delete_ids = array();
while ($row = $db->sql_fetchrow($result))
{
+ if (!$auth->acl_get('m_edit', $row['forum_id']) && ($row['forum_status'] == ITEM_LOCKED || $row['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']))
+ {
+ continue;
+ }
+
$delete_ids[] = $row['attach_id'];
}
$db->sql_freeresult($result);
}
- if ($delete && sizeof($delete_ids))
+ if ($delete && count($delete_ids))
{
$s_hidden_fields = array(
'delete' => 1
@@ -70,20 +80,18 @@ class ucp_attachments
if (confirm_box(true))
{
- if (!function_exists('delete_attachments'))
- {
- include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
- }
-
- delete_attachments('attach', $delete_ids);
+ /** @var \phpbb\attachment\manager $attachment_manager */
+ $attachment_manager = $phpbb_container->get('attachment.manager');
+ $attachment_manager->delete('attach', $delete_ids);
+ unset($attachment_manager);
meta_refresh(3, $this->u_action);
- $message = ((sizeof($delete_ids) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']) . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ $message = ((count($delete_ids) == 1) ? $user->lang['ATTACHMENT_DELETED'] : $user->lang['ATTACHMENTS_DELETED']) . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
trigger_error($message);
}
else
{
- confirm_box(false, (sizeof($delete_ids) == 1) ? 'DELETE_ATTACHMENT' : 'DELETE_ATTACHMENTS', build_hidden_fields($s_hidden_fields));
+ confirm_box(false, (count($delete_ids) == 1) ? 'DELETE_ATTACHMENT' : 'DELETE_ATTACHMENTS', build_hidden_fields($s_hidden_fields));
}
}
@@ -123,13 +131,16 @@ class ucp_attachments
$db->sql_freeresult($result);
// Ensure start is a valid value
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
$start = $pagination->validate_start($start, $config['topics_per_page'], $num_attachments);
- $sql = 'SELECT a.*, t.topic_title, p.message_subject as message_title
+ $sql = 'SELECT a.*, t.topic_title, pr.message_subject as message_title, p.post_edit_locked, t.topic_status, f.forum_id, f.forum_status
FROM ' . ATTACHMENTS_TABLE . ' a
+ LEFT JOIN ' . POSTS_TABLE . ' p ON (a.post_msg_id = p.post_id AND a.in_message = 0)
LEFT JOIN ' . TOPICS_TABLE . ' t ON (a.topic_id = t.topic_id AND a.in_message = 0)
- LEFT JOIN ' . PRIVMSGS_TABLE . ' p ON (a.post_msg_id = p.msg_id AND a.in_message = 1)
+ LEFT JOIN ' . FORUMS_TABLE . ' f ON (f.forum_id = t.forum_id AND a.in_message = 0)
+ LEFT JOIN ' . PRIVMSGS_TABLE . ' pr ON (a.post_msg_id = pr.msg_id AND a.in_message = 1)
WHERE a.poster_id = ' . $user->data['user_id'] . "
AND a.is_orphan = 0
ORDER BY $order_by";
@@ -166,6 +177,7 @@ class ucp_attachments
'TOPIC_ID' => $row['topic_id'],
'S_IN_MESSAGE' => $row['in_message'],
+ 'S_LOCKED' => !$row['in_message'] && !$auth->acl_get('m_edit', $row['forum_id']) && ($row['forum_status'] == ITEM_LOCKED || $row['topic_status'] == ITEM_LOCKED || $row['post_edit_locked']),
'U_VIEW_ATTACHMENT' => append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $row['attach_id']),
'U_VIEW_TOPIC' => $view_topic)
diff --git a/phpBB/includes/ucp/ucp_auth_link.php b/phpBB/includes/ucp/ucp_auth_link.php
index 748f0fdec2..e069f15eb2 100644
--- a/phpBB/includes/ucp/ucp_auth_link.php
+++ b/phpBB/includes/ucp/ucp_auth_link.php
@@ -38,6 +38,7 @@ class ucp_auth_link
$error = array();
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$auth_provider = $provider_collection->get_provider();
@@ -54,14 +55,14 @@ class ucp_auth_link
$submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST);
// This path is only for primary actions
- if (!sizeof($error) && $submit)
+ if (!count($error) && $submit)
{
if (!check_form_key('ucp_auth_link'))
{
$error[] = 'FORM_INVALID';
}
- if (!sizeof($error))
+ if (!count($error))
{
// Any post data could be necessary for auth (un)linking
$link_data = $request->get_super_global(\phpbb\request\request_interface::POST);
diff --git a/phpBB/includes/ucp/ucp_confirm.php b/phpBB/includes/ucp/ucp_confirm.php
index 7392f8dea8..cdf4de65fd 100644
--- a/phpBB/includes/ucp/ucp_confirm.php
+++ b/phpBB/includes/ucp/ucp_confirm.php
@@ -36,10 +36,10 @@ class ucp_confirm
function main($id, $mode)
{
- global $db, $user, $phpbb_root_path, $config, $phpEx, $phpbb_container;
+ global $config, $phpbb_container, $request;
$captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']);
- $captcha->init(request_var('type', 0));
+ $captcha->init($request->variable('type', 0));
$captcha->execute();
garbage_collection();
diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php
index 86a8226d5b..cf6e049748 100644
--- a/phpBB/includes/ucp/ucp_groups.php
+++ b/phpBB/includes/ucp/ucp_groups.php
@@ -30,16 +30,20 @@ class ucp_groups
{
global $config, $phpbb_root_path, $phpEx, $phpbb_admin_path;
global $db, $user, $auth, $cache, $template;
- global $request, $phpbb_container;
+ global $request, $phpbb_container, $phpbb_log;
+
+ /** @var \phpbb\language\language $language Language object */
+ $language = $phpbb_container->get('language');
$user->add_lang('groups');
$return_page = '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $this->u_action . '">', '</a>');
- $mark_ary = request_var('mark', array(0));
+ $mark_ary = $request->variable('mark', array(0));
$submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST);
- $delete = $request->variable('delete', false, false, \phpbb\request\request_interface::POST);
- $error = $data = array();
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
switch ($mode)
{
@@ -49,8 +53,8 @@ class ucp_groups
if ($submit || isset($_POST['change_default']))
{
- $action = (isset($_POST['change_default'])) ? 'change_default' : request_var('action', '');
- $group_id = ($action == 'change_default') ? request_var('default', 0) : request_var('selected', 0);
+ $action = (isset($_POST['change_default'])) ? 'change_default' : $request->variable('action', '');
+ $group_id = ($action == 'change_default') ? $request->variable('default', 0) : $request->variable('selected', 0);
if (!$group_id)
{
@@ -65,12 +69,12 @@ class ucp_groups
$group_row = array();
while ($row = $db->sql_fetchrow($result))
{
- $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $row['group_name'] = $group_helper->get_name($row['group_name']);
$group_row[$row['group_id']] = $row;
}
$db->sql_freeresult($result);
- if (!sizeof($group_row))
+ if (!count($group_row))
{
trigger_error('GROUP_NOT_EXIST');
}
@@ -86,6 +90,7 @@ class ucp_groups
if (!$auth->acl_get('u_chggrp'))
{
+ send_status_line(403, 'Forbidden');
trigger_error($user->lang['NOT_AUTHORISED'] . $return_page);
}
@@ -99,7 +104,10 @@ class ucp_groups
{
group_user_attributes('default', $group_id, $user->data['user_id']);
- add_log('user', $user->data['user_id'], 'LOG_USER_GROUP_CHANGE', sprintf($user->lang['USER_GROUP_CHANGE'], $group_row[$user->data['group_id']]['group_name'], $group_row[$group_id]['group_name']));
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_GROUP_CHANGE', false, array(
+ 'reportee_id' => $user->data['user_id'],
+ sprintf($user->lang['USER_GROUP_CHANGE'], $group_row[$user->data['group_id']]['group_name'], $group_row[$group_id]['group_name'])
+ ));
meta_refresh(3, $this->u_action);
trigger_error($user->lang['CHANGED_DEFAULT_GROUP'] . $return_page);
@@ -146,7 +154,10 @@ class ucp_groups
{
group_user_del($group_id, $user->data['user_id']);
- add_log('user', $user->data['user_id'], 'LOG_USER_GROUP_RESIGN', $group_row[$group_id]['group_name']);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_GROUP_RESIGN', false, array(
+ 'reportee_id' => $user->data['user_id'],
+ $group_row[$group_id]['group_name']
+ ));
meta_refresh(3, $this->u_action);
trigger_error($user->lang[($row['user_pending']) ? 'GROUP_RESIGNED_PENDING' : 'GROUP_RESIGNED_MEMBERSHIP'] . $return_page);
@@ -202,7 +213,10 @@ class ucp_groups
group_user_add($group_id, $user->data['user_id'], false, false, false, 0, 1);
}
- add_log('user', $user->data['user_id'], 'LOG_USER_GROUP_JOIN' . (($group_row[$group_id]['group_type'] == GROUP_FREE) ? '' : '_PENDING'), $group_row[$group_id]['group_name']);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_GROUP_JOIN' . (($group_row[$group_id]['group_type'] == GROUP_FREE) ? '' : '_PENDING'), false, array(
+ 'reportee_id' => $user->data['user_id'],
+ $group_row[$group_id]['group_name']
+ ));
meta_refresh(3, $this->u_action);
trigger_error($user->lang[($group_row[$group_id]['group_type'] == GROUP_FREE) ? 'GROUP_JOINED' : 'GROUP_JOINED_PENDING'] . $return_page);
@@ -237,7 +251,10 @@ class ucp_groups
{
group_user_attributes('demote', $group_id, $user->data['user_id']);
- add_log('user', $user->data['user_id'], 'LOG_USER_GROUP_DEMOTE', $group_row[$group_id]['group_name']);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_GROUP_DEMOTE', false, array(
+ 'reportee_id' => $user->data['user_id'],
+ $group_row[$group_id]['group_name']
+ ));
meta_refresh(3, $this->u_action);
trigger_error($user->lang['USER_GROUP_DEMOTED'] . $return_page);
@@ -295,7 +312,7 @@ class ucp_groups
$template->assign_block_vars($block, array(
'GROUP_ID' => $row['group_id'],
- 'GROUP_NAME' => ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'],
+ 'GROUP_NAME' => $group_helper->get_name($row['group_name']),
'GROUP_DESC' => ($row['group_type'] <> GROUP_SPECIAL) ? generate_text_for_display($row['group_desc'], $row['group_desc_uid'], $row['group_desc_bitfield'], $row['group_desc_options']) : $user->lang['GROUP_IS_SPECIAL'],
'GROUP_SPECIAL' => ($row['group_type'] <> GROUP_SPECIAL) ? false : true,
'GROUP_STATUS' => $user->lang['GROUP_IS_' . $group_status],
@@ -316,7 +333,7 @@ class ucp_groups
$sql = 'SELECT group_id, group_name, group_colour, group_desc, group_desc_uid, group_desc_bitfield, group_desc_options, group_type, group_founder_manage
FROM ' . GROUPS_TABLE . '
- WHERE ' . ((sizeof($group_id_ary)) ? $db->sql_in_set('group_id', $group_id_ary, true) . ' AND ' : '') . "
+ WHERE ' . ((count($group_id_ary)) ? $db->sql_in_set('group_id', $group_id_ary, true) . ' AND ' : '') . "
group_type $sql_and
ORDER BY group_type DESC, group_name";
$result = $db->sql_query($sql);
@@ -349,7 +366,7 @@ class ucp_groups
$template->assign_block_vars('nonmember', array(
'GROUP_ID' => $row['group_id'],
- 'GROUP_NAME' => ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'],
+ 'GROUP_NAME' => $group_helper->get_name($row['group_name']),
'GROUP_DESC' => ($row['group_type'] <> GROUP_SPECIAL) ? generate_text_for_display($row['group_desc'], $row['group_desc_uid'], $row['group_desc_bitfield'], $row['group_desc_options']) : $user->lang['GROUP_IS_SPECIAL'],
'GROUP_SPECIAL' => ($row['group_type'] <> GROUP_SPECIAL) ? false : true,
'GROUP_CLOSED' => ($row['group_type'] <> GROUP_CLOSED || $auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? false : true,
@@ -379,10 +396,13 @@ class ucp_groups
case 'manage':
$this->page_title = 'UCP_USERGROUPS_MANAGE';
- $action = (isset($_POST['addusers'])) ? 'addusers' : request_var('action', '');
- $group_id = request_var('g', 0);
+ $action = (isset($_POST['addusers'])) ? 'addusers' : $request->variable('action', '');
+ $group_id = $request->variable('g', 0);
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ if (!function_exists('phpbb_get_user_rank'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
add_form_key('ucp_groups');
@@ -414,7 +434,7 @@ class ucp_groups
$avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true);
$template->assign_vars(array(
- 'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
+ 'GROUP_NAME' => $group_helper->get_name($group_name),
'GROUP_INTERNAL_NAME' => $group_name,
'GROUP_COLOUR' => (isset($group_row['group_colour'])) ? $group_row['group_colour'] : '',
'GROUP_DESC_DISP' => generate_text_for_display($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_bitfield'], $group_row['group_desc_options']),
@@ -447,11 +467,8 @@ class ucp_groups
trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page);
}
- $file_uploads = (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on') ? true : false;
$user->add_lang(array('acp/groups', 'acp/common'));
- $data = $submit_ary = array();
-
$update = (isset($_POST['update'])) ? true : false;
$error = array();
@@ -499,29 +516,33 @@ class ucp_groups
// Did we submit?
if ($update)
{
- $group_name = utf8_normalize_nfc(request_var('group_name', '', true));
- $group_desc = utf8_normalize_nfc(request_var('group_desc', '', true));
- $group_type = request_var('group_type', GROUP_FREE);
+ $group_name = $request->variable('group_name', '', true);
+ $group_desc = $request->variable('group_desc', '', true);
+ $group_type = $request->variable('group_type', GROUP_FREE);
- $allow_desc_bbcode = request_var('desc_parse_bbcode', false);
- $allow_desc_urls = request_var('desc_parse_urls', false);
- $allow_desc_smilies = request_var('desc_parse_smilies', false);
+ $allow_desc_bbcode = $request->variable('desc_parse_bbcode', false);
+ $allow_desc_urls = $request->variable('desc_parse_urls', false);
+ $allow_desc_smilies = $request->variable('desc_parse_smilies', false);
$submit_ary = array(
- 'colour' => request_var('group_colour', ''),
- 'rank' => request_var('group_rank', 0),
+ 'colour' => $request->variable('group_colour', ''),
+ 'rank' => $request->variable('group_rank', 0),
'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 0,
- 'message_limit' => request_var('group_message_limit', 0),
- 'max_recipients'=> request_var('group_max_recipients', 0),
+ 'message_limit' => $request->variable('group_message_limit', 0),
+ 'max_recipients'=> $request->variable('group_max_recipients', 0),
'legend' => $group_row['group_legend'],
'teampage' => $group_row['group_teampage'],
);
- if ($config['allow_avatar'])
+ if (!check_form_key('ucp_groups'))
+ {
+ $error[] = $user->lang['FORM_INVALID'];
+ }
+
+ if (!count($error) && $config['allow_avatar'])
{
// Handle avatar
$driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
- $config_name = preg_replace('#^avatar\.driver.#', '', $driver_name);
if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
{
@@ -540,11 +561,6 @@ class ucp_groups
$error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
- if (!check_form_key('ucp_groups'))
- {
- $error[] = $user->lang['FORM_INVALID'];
- }
-
// Validate submitted colour value
if ($colour_error = validate_data($submit_ary, array('colour' => array('hex_colour', true))))
{
@@ -552,7 +568,7 @@ class ucp_groups
$error = array_merge($error, $colour_error);
}
- if (!sizeof($error))
+ if (!count($error))
{
// Only set the rank, colour, etc. if it's changed or if we're adding a new
// group. This prevents existing group members being updated if no changes
@@ -595,7 +611,7 @@ class ucp_groups
}
}
- if (sizeof($error))
+ if (count($error))
{
$error = array_map(array(&$user, 'lang'), $error);
$group_rank = $submit_ary['rank'];
@@ -610,7 +626,6 @@ class ucp_groups
}
else if (!$group_id)
{
- $group_name = utf8_normalize_nfc(request_var('group_name', '', true));
$group_desc_data = array(
'text' => '',
'allow_bbcode' => true,
@@ -694,12 +709,12 @@ class ucp_groups
'S_EDIT' => true,
'S_INCLUDE_SWATCH' => true,
'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
- 'S_ERROR' => (sizeof($error)) ? true : false,
+ 'S_ERROR' => (count($error)) ? true : false,
'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false,
'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
'S_GROUP_MANAGE' => true,
- 'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR_MSG' => (count($error)) ? implode('<br />', $error) : '',
'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '',
'GROUP_MESSAGE_LIMIT' => (isset($group_row['group_message_limit'])) ? $group_row['group_message_limit'] : 0,
'GROUP_MAX_RECIPIENTS' => (isset($group_row['group_max_recipients'])) ? $group_row['group_max_recipients'] : 0,
@@ -747,7 +762,7 @@ class ucp_groups
}
$user->add_lang(array('acp/groups', 'acp/common'));
- $start = request_var('start', 0);
+ $start = $request->variable('start', 0);
// Grab the leaders - always, on every page...
$sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_colour, u.user_regdate, u.user_posts, u.group_id, ug.group_leader, ug.user_pending
@@ -836,6 +851,7 @@ class ucp_groups
$s_action_options .= '<option value="' . $option . '">' . $user->lang['GROUP_' . $lang] . '</option>';
}
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
$base_url = $this->u_action . "&amp;action=$action&amp;g=$group_id";
$start = $pagination->validate_start($start, $config['topics_per_page'], $total_members);
@@ -859,6 +875,11 @@ class ucp_groups
trigger_error($user->lang['NO_GROUP'] . $return_page);
}
+ if (!check_form_key('ucp_groups'))
+ {
+ trigger_error($user->lang('FORM_INVALID') . $return_page);
+ }
+
if (!($row = group_memberships($group_id, $user->data['user_id'])))
{
trigger_error($user->lang['NOT_MEMBER_OF_GROUP'] . $return_page);
@@ -897,11 +918,11 @@ class ucp_groups
trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page);
}
- $group_row['group_name'] = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_row['group_name'] = $group_helper->get_name($group_row['group_name']);
if (confirm_box(true))
{
- if (!sizeof($mark_ary))
+ if (!count($mark_ary))
{
$start = 0;
@@ -924,7 +945,7 @@ class ucp_groups
group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row);
- $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200;
+ $start = (count($mark_ary) < 200) ? 0 : $start + 200;
}
else
{
@@ -976,7 +997,7 @@ class ucp_groups
trigger_error($user->lang['NOT_LEADER_OF_GROUP'] . $return_page);
}
- $group_row['group_name'] = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_row['group_name'] = $group_helper->get_name($group_row['group_name']);
if (confirm_box(true))
{
@@ -1014,7 +1035,7 @@ class ucp_groups
$user->add_lang(array('acp/groups', 'acp/common'));
- $names = utf8_normalize_nfc(request_var('usernames', '', true));
+ $names = $request->variable('usernames', '', true);
if (!$group_id)
{
@@ -1038,19 +1059,33 @@ class ucp_groups
}
$name_ary = array_unique(explode("\n", $names));
- $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ $group_name = $group_helper->get_name($group_row['group_name']);
- $default = request_var('default', 0);
+ $default = $request->variable('default', 0);
if (confirm_box(true))
{
+ $return_manage_page = '<br /><br />' . $language->lang('RETURN_PAGE', '<a href="' . $this->u_action . '&amp;action=list&amp;g=' . $group_id . '">', '</a>');
+
// Add user/s to group
if ($error = group_user_add($group_id, false, $name_ary, $group_name, $default, 0, 0, $group_row))
{
- trigger_error($user->lang[$error] . $return_page);
+ $display_message = $language->lang($error);
+
+ if ($error == 'GROUP_USERS_INVALID')
+ {
+ // Find which users don't exist
+ $actual_name_ary = $name_ary;
+ $actual_user_id_ary = [];
+ user_get_id_name($actual_user_id_ary, $actual_name_ary, false, true);
+
+ $display_message = $language->lang('GROUP_USERS_INVALID', implode($language->lang('COMMA_SEPARATOR'), array_udiff($name_ary, $actual_name_ary, 'strcasecmp')));
+ }
+
+ trigger_error($display_message . $return_manage_page);
}
- trigger_error($user->lang['GROUP_USERS_ADDED'] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $this->u_action . '&amp;action=list&amp;g=' . $group_id . '">', '</a>'));
+ trigger_error($language->lang('GROUP_USERS_ADDED') . $return_manage_page);
}
else
{
@@ -1063,7 +1098,7 @@ class ucp_groups
'action' => $action
);
- confirm_box(false, $user->lang('GROUP_CONFIRM_ADD_USERS', sizeof($name_ary), implode($user->lang['COMMA_SEPARATOR'], $name_ary)), build_hidden_fields($s_hidden_fields));
+ confirm_box(false, $user->lang('GROUP_CONFIRM_ADD_USERS', count($name_ary), implode($user->lang['COMMA_SEPARATOR'], $name_ary)), build_hidden_fields($s_hidden_fields));
}
trigger_error($user->lang['NO_USERS_ADDED'] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $this->u_action . '&amp;action=list&amp;g=' . $group_id . '">', '</a>'));
@@ -1084,7 +1119,7 @@ class ucp_groups
while ($value = $db->sql_fetchrow($result))
{
$template->assign_block_vars('leader', array(
- 'GROUP_NAME' => ($value['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $value['group_name']] : $value['group_name'],
+ 'GROUP_NAME' => $group_helper->get_name($value['group_name']),
'GROUP_DESC' => generate_text_for_display($value['group_desc'], $value['group_desc_uid'], $value['group_desc_bitfield'], $value['group_desc_options']),
'GROUP_TYPE' => $value['group_type'],
'GROUP_ID' => $value['group_id'],
diff --git a/phpBB/includes/ucp/ucp_login_link.php b/phpBB/includes/ucp/ucp_login_link.php
index bfe4804286..c1f307eeb5 100644
--- a/phpBB/includes/ucp/ucp_login_link.php
+++ b/phpBB/includes/ucp/ucp_login_link.php
@@ -39,7 +39,7 @@ class ucp_login_link
*/
function main($id, $mode)
{
- global $phpbb_container, $request, $template, $user;
+ global $phpbb_container, $request, $template, $user, $phpbb_dispatcher;
global $phpbb_root_path, $phpEx;
// Initialize necessary variables
@@ -57,6 +57,7 @@ class ucp_login_link
}
// Use the auth_provider requested even if different from configured
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$auth_provider = $provider_collection->get_provider($request->variable('auth_provider', ''));
@@ -98,7 +99,7 @@ class ucp_login_link
else
{
// Finish login
- $result = $user->session_create($login_result['user_row']['user_id'], false, false, true);
+ $user->session_create($login_result['user_row']['user_id'], false, false, true);
// Perform a redirect as the account has been linked
$this->perform_redirect();
@@ -107,7 +108,7 @@ class ucp_login_link
}
}
- $template->assign_vars(array(
+ $tpl_ary = array(
// Common template elements
'LOGIN_LINK_ERROR' => $login_link_error,
'PASSWORD_CREDENTIAL' => 'login_password',
@@ -120,7 +121,24 @@ class ucp_login_link
// Login elements
'LOGIN_ERROR' => $login_error,
'LOGIN_USERNAME' => $login_username,
- ));
+ );
+
+ /**
+ * Event to perform additional actions before ucp_login_link is displayed
+ *
+ * @event core.ucp_login_link_template_after
+ * @var array data Login link data
+ * @var \phpbb\auth\provider_interface auth_provider Auth provider
+ * @var string login_link_error Login link error
+ * @var string login_error Login error
+ * @var string login_username Login username
+ * @var array tpl_ary Template variables
+ * @since 3.2.4-RC1
+ */
+ $vars = array('data', 'auth_provider', 'login_link_error', 'login_error', 'login_username', 'tpl_ary');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_login_link_template_after', compact($vars)));
+
+ $template->assign_vars($tpl_ary);
$this->tpl_name = 'ucp_login_link';
$this->page_title = 'UCP_LOGIN_LINK';
@@ -181,7 +199,7 @@ class ucp_login_link
*/
protected function process_login_result($result)
{
- global $config, $request, $template, $user, $phpbb_container;
+ global $config, $template, $user, $phpbb_container;
$login_error = null;
diff --git a/phpBB/includes/ucp/ucp_main.php b/phpBB/includes/ucp/ucp_main.php
index 8584a9a0fd..36f45f3f46 100644
--- a/phpBB/includes/ucp/ucp_main.php
+++ b/phpBB/includes/ucp/ucp_main.php
@@ -28,9 +28,9 @@ class ucp_main
var $p_master;
var $u_action;
- function ucp_main(&$p_master)
+ function __construct($p_master)
{
- $this->p_master = &$p_master;
+ $this->p_master = $p_master;
}
function main($id, $mode)
@@ -77,6 +77,22 @@ class ucp_main
// If the user can't see any forums, he can't read any posts because fid of 0 is invalid
if (!empty($forum_ary))
{
+ /**
+ * Modify sql variables before query is processed
+ *
+ * @event core.ucp_main_front_modify_sql
+ * @var string sql_select SQL select
+ * @var string sql_from SQL from
+ * @var array forum_ary Forum array
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'sql_select',
+ 'sql_from',
+ 'forum_ary',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.ucp_main_front_modify_sql', compact($vars)));
+
$sql = "SELECT t.* $sql_select
FROM $sql_from
WHERE t.topic_type = " . POST_GLOBAL . '
@@ -144,7 +160,7 @@ class ucp_main
$folder_img .= '_mine';
}
- $template->assign_block_vars('topicrow', array(
+ $topicrow = array(
'FORUM_ID' => $forum_id,
'TOPIC_ID' => $topic_id,
'TOPIC_AUTHOR' => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
@@ -171,8 +187,30 @@ class ucp_main
'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;p=" . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'],
'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=unread") . '#unread',
- 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id"))
+ 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id"),
);
+
+ /**
+ * Add template variables to a front topics row.
+ *
+ * @event core.ucp_main_front_modify_template_vars
+ * @var array topicrow Array containing the template variables for the row
+ * @var array row Array containing the subscribed forum row data
+ * @var int forum_id Forum ID
+ * @var string folder_img Folder image
+ * @var string folder_alt Alt text for the folder image
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'topicrow',
+ 'row',
+ 'forum_id',
+ 'folder_img',
+ 'folder_alt',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.ucp_main_front_modify_template_vars', compact($vars)));
+
+ $template->assign_block_vars('topicrow', $topicrow);
}
if ($config['load_user_activity'])
@@ -207,7 +245,10 @@ class ucp_main
case 'subscribed':
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ if (!function_exists('topic_status'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
$user->add_lang('viewforum');
@@ -227,14 +268,13 @@ class ucp_main
{
if (check_form_key('ucp_front_subscribed'))
{
- $forums = array_keys(request_var('f', array(0 => 0)));
- $topics = array_keys(request_var('t', array(0 => 0)));
- $msg = '';
+ $forums = array_keys($request->variable('f', array(0 => 0)));
+ $topics = array_keys($request->variable('t', array(0 => 0)));
- if (sizeof($forums) || sizeof($topics))
+ if (count($forums) || count($topics))
{
$l_unwatch = '';
- if (sizeof($forums))
+ if (count($forums))
{
$sql = 'DELETE FROM ' . FORUMS_WATCH_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forums) . '
@@ -244,7 +284,7 @@ class ucp_main
$l_unwatch .= '_FORUMS';
}
- if (sizeof($topics))
+ if (count($topics))
{
$sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . '
WHERE ' . $db->sql_in_set('topic_id', $topics) . '
@@ -444,17 +484,20 @@ class ucp_main
break;
}
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ if (!function_exists('topic_status'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
$user->add_lang('viewforum');
if (isset($_POST['unbookmark']))
{
$s_hidden_fields = array('unbookmark' => 1);
- $topics = (isset($_POST['t'])) ? array_keys(request_var('t', array(0 => 0))) : array();
+ $topics = (isset($_POST['t'])) ? array_keys($request->variable('t', array(0 => 0))) : array();
$url = $this->u_action;
- if (!sizeof($topics))
+ if (!count($topics))
{
trigger_error('NO_BOOKMARKS_SELECTED');
}
@@ -503,13 +546,16 @@ class ucp_main
$draft_subject = $draft_message = '';
add_form_key('ucp_draft');
+ include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx);
+ $message_parser = new parse_message();
+
if ($delete)
{
if (check_form_key('ucp_draft'))
{
- $drafts = array_keys(request_var('d', array(0 => 0)));
+ $drafts = array_keys($request->variable('d', array(0 => 0)));
- if (sizeof($drafts))
+ if (count($drafts))
{
$sql = 'DELETE FROM ' . DRAFTS_TABLE . '
WHERE ' . $db->sql_in_set('draft_id', $drafts) . '
@@ -530,15 +576,25 @@ class ucp_main
if ($submit && $edit)
{
- $draft_subject = utf8_normalize_nfc(request_var('subject', '', true));
- $draft_message = utf8_normalize_nfc(request_var('message', '', true));
+ $draft_subject = $request->variable('subject', '', true);
+ $draft_message = $request->variable('message', '', true);
if (check_form_key('ucp_draft'))
{
if ($draft_message && $draft_subject)
{
+ // $auth->acl_gets can't be used here because it will check for global forum permissions in this case
+ // In general we don't need too harsh checking here for permissions, as this will be handled later when submitting
+ $bbcode_status = $auth->acl_get('u_pm_bbcode') || $auth->acl_getf_global('f_bbcode');
+ $smilies_status = $auth->acl_get('u_pm_smilies') || $auth->acl_getf_global('f_smilies');
+ $img_status = $auth->acl_get('u_pm_img') || $auth->acl_getf_global('f_img');
+ $flash_status = $auth->acl_get('u_pm_flash') || $auth->acl_getf_global('f_flash');
+
+ $message_parser->message = $draft_message;
+ $message_parser->parse($bbcode_status, $config['allow_post_links'], $smilies_status, $img_status, $flash_status, true, $config['allow_post_links']);
+
$draft_row = array(
'draft_subject' => $draft_subject,
- 'draft_message' => $draft_message
+ 'draft_message' => $message_parser->message,
);
$sql = 'UPDATE ' . DRAFTS_TABLE . '
@@ -595,7 +651,7 @@ class ucp_main
}
$db->sql_freeresult($result);
- if (sizeof($topic_ids))
+ if (count($topic_ids))
{
$sql = 'SELECT topic_id, forum_id, topic_title
FROM ' . TOPICS_TABLE . '
@@ -640,9 +696,16 @@ class ucp_main
$insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&amp;mode=compose&amp;d=" . $draft['draft_id']);
}
+ if (!$submit)
+ {
+ $message_parser->message = $draft['draft_message'];
+ $message_parser->decode_message();
+ $draft_message = $message_parser->message;
+ }
+
$template_row = array(
'DATE' => $user->format_date($draft['save_time']),
- 'DRAFT_MESSAGE' => ($submit) ? $draft_message : $draft['draft_message'],
+ 'DRAFT_MESSAGE' => $draft_message,
'DRAFT_SUBJECT' => ($submit) ? $draft_subject : $draft['draft_subject'],
'TITLE' => $title,
@@ -695,9 +758,10 @@ class ucp_main
{
global $user, $db, $template, $config, $cache, $auth, $phpbb_root_path, $phpEx, $phpbb_container, $request, $phpbb_dispatcher;
- $table = ($mode == 'subscribed') ? TOPICS_WATCH_TABLE : BOOKMARKS_TABLE;
- $start = request_var('start', 0);
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
+ $table = ($mode == 'subscribed') ? TOPICS_WATCH_TABLE : BOOKMARKS_TABLE;
+ $start = $request->variable('start', 0);
// Grab icons
$icons = $cache->obtain_icons();
@@ -852,6 +916,7 @@ class ucp_main
}
}
+ /* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
foreach ($topic_list as $topic_id)
diff --git a/phpBB/includes/ucp/ucp_notifications.php b/phpBB/includes/ucp/ucp_notifications.php
index 66dc651447..a6d925f95e 100644
--- a/phpBB/includes/ucp/ucp_notifications.php
+++ b/phpBB/includes/ucp/ucp_notifications.php
@@ -34,7 +34,10 @@ class ucp_notifications
$form_time = $request->variable('form_time', 0);
$form_time = ($form_time <= 0 || $form_time > time()) ? time() : $form_time;
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
switch ($mode)
@@ -67,15 +70,6 @@ class ucp_notifications
$phpbb_notifications->delete_subscription($type, 0, $method_data['id']);
}
}
-
- if ($request->is_set_post(str_replace('.', '_', $type) . '_notification') && !isset($subscriptions[$type]))
- {
- $phpbb_notifications->add_subscription($type);
- }
- else if (!$request->is_set_post(str_replace('.', '_', $type) . '_notification') && isset($subscriptions[$type]))
- {
- $phpbb_notifications->delete_subscription($type);
- }
}
}
@@ -97,7 +91,7 @@ class ucp_notifications
// Mark all items read
if ($request->variable('mark', '') == 'all' && check_link_hash($request->variable('token', ''), 'mark_all_notifications_read'))
{
- $phpbb_notifications->mark_notifications_read(false, false, $user->data['user_id'], $form_time);
+ $phpbb_notifications->mark_notifications(false, false, $user->data['user_id'], $form_time);
meta_refresh(3, $this->u_action);
$message = $user->lang['NOTIFICATIONS_MARK_ALL_READ_SUCCESS'];
@@ -128,11 +122,11 @@ class ucp_notifications
if (!empty($mark_read))
{
- $phpbb_notifications->mark_notifications_read_by_id($mark_read, $form_time);
+ $phpbb_notifications->mark_notifications_by_id('notification.method.board', $mark_read, $form_time);
}
}
- $notifications = $phpbb_notifications->load_notifications(array(
+ $notifications = $phpbb_notifications->load_notifications('notification.method.board', array(
'start' => $start,
'limit' => $config['topics_per_page'],
'count_total' => true,
@@ -186,15 +180,13 @@ class ucp_notifications
'GROUP_NAME' => $user->lang($group),
));
- foreach ($subscription_types as $type => $data)
+ foreach ($subscription_types as $type => $type_data)
{
$template->assign_block_vars($block, array(
'TYPE' => $type,
- 'NAME' => $user->lang($data['lang']),
- 'EXPLAIN' => (isset($user->lang[$data['lang'] . '_EXPLAIN'])) ? $user->lang($data['lang'] . '_EXPLAIN') : '',
-
- 'SUBSCRIBED' => (isset($subscriptions[$type])) ? true : false,
+ 'NAME' => $user->lang($type_data['lang']),
+ 'EXPLAIN' => (isset($user->lang[$type_data['lang'] . '_EXPLAIN'])) ? $user->lang($type_data['lang'] . '_EXPLAIN') : '',
));
foreach ($notification_methods as $method => $method_data)
@@ -204,6 +196,8 @@ class ucp_notifications
'NAME' => $user->lang($method_data['lang']),
+ 'AVAILABLE' => $method_data['method']->is_available($type_data['type']),
+
'SUBSCRIBED' => (isset($subscriptions[$type]) && in_array($method_data['id'], $subscriptions[$type])) ? true : false,
));
}
@@ -211,7 +205,7 @@ class ucp_notifications
}
$template->assign_vars(array(
- strtoupper($block) . '_COLS' => sizeof($notification_methods) + 2,
+ strtoupper($block) . '_COLS' => count($notification_methods) + 1,
));
}
diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php
index f026cd3eb3..00d1ce7149 100644
--- a/phpBB/includes/ucp/ucp_pm.php
+++ b/phpBB/includes/ucp/ucp_pm.php
@@ -62,7 +62,7 @@ class ucp_pm
$template->assign_var('S_PRIVMSGS', true);
// Folder directly specified?
- $folder_specified = request_var('folder', '');
+ $folder_specified = $request->variable('folder', '');
if (!in_array($folder_specified, array('inbox', 'outbox', 'sentbox')))
{
@@ -75,20 +75,23 @@ class ucp_pm
if (!$folder_specified)
{
- $mode = (!$mode) ? request_var('mode', 'view') : $mode;
+ $mode = (!$mode) ? $request->variable('mode', 'view') : $mode;
}
else
{
$mode = 'view';
}
- include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);
+ if (!function_exists('get_folder'))
+ {
+ include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);
+ }
switch ($mode)
{
// Compose message
case 'compose':
- $action = request_var('action', 'post');
+ $action = $request->variable('action', 'post');
$user_folders = get_folder($user->data['user_id']);
@@ -104,7 +107,10 @@ class ucp_pm
break;
}
- include($phpbb_root_path . 'includes/ucp/ucp_pm_compose.' . $phpEx);
+ if (!function_exists('compose_pm'))
+ {
+ include($phpbb_root_path . 'includes/ucp/ucp_pm_compose.' . $phpEx);
+ }
compose_pm($id, $mode, $action, $user_folders);
$tpl_file = 'posting_body';
@@ -114,7 +120,10 @@ class ucp_pm
set_user_message_limit();
get_folder($user->data['user_id']);
- include($phpbb_root_path . 'includes/ucp/ucp_pm_options.' . $phpEx);
+ if (!function_exists('message_options'))
+ {
+ include($phpbb_root_path . 'includes/ucp/ucp_pm_options.' . $phpEx);
+ }
message_options($id, $mode, $global_privmsgs_rules, $global_rule_conditions);
$tpl_file = 'ucp_pm_options';
@@ -125,8 +134,10 @@ class ucp_pm
get_folder($user->data['user_id']);
$this->p_name = 'pm';
- // Call another module... please do not try this at home... Hoochie Coochie Man
- include($phpbb_root_path . 'includes/ucp/ucp_main.' . $phpEx);
+ if (!class_exists('ucp_main'))
+ {
+ include($phpbb_root_path . 'includes/ucp/ucp_main.' . $phpEx);
+ }
$module = new ucp_main($this);
$module->u_action = $this->u_action;
@@ -151,12 +162,12 @@ class ucp_pm
}
else
{
- $folder_id = request_var('f', PRIVMSGS_NO_BOX);
- $action = request_var('action', 'view_folder');
+ $folder_id = $request->variable('f', PRIVMSGS_NO_BOX);
+ $action = $request->variable('action', 'view_folder');
}
- $msg_id = request_var('p', 0);
- $view = request_var('view', '');
+ $msg_id = $request->variable('p', 0);
+ $view = $request->variable('view', '');
// View message if specified
if ($msg_id)
@@ -166,20 +177,29 @@ class ucp_pm
if (!$auth->acl_get('u_readpm'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_READ_MESSAGE');
}
+ if ($view == 'print' && (!$config['print_pm'] || !$auth->acl_get('u_pm_printpm')))
+ {
+ send_status_line(403, 'Forbidden');
+ trigger_error('NO_AUTH_PRINT_MESSAGE');
+ }
+
// Do not allow hold messages to be seen
if ($folder_id == PRIVMSGS_HOLD_BOX)
{
trigger_error('NO_AUTH_READ_HOLD_MESSAGE');
}
+ add_form_key('ucp_pm_view');
+
// First Handle Mark actions and moving messages
$submit_mark = (isset($_POST['submit_mark'])) ? true : false;
$move_pm = (isset($_POST['move_pm'])) ? true : false;
- $mark_option = request_var('mark_option', '');
- $dest_folder = request_var('dest_folder', PRIVMSGS_NO_BOX);
+ $mark_option = $request->variable('mark_option', '');
+ $dest_folder = $request->variable('dest_folder', PRIVMSGS_NO_BOX);
// Is moving PM triggered through mark options?
if (!in_array($mark_option, array('mark_important', 'delete_marked')) && $submit_mark)
@@ -189,11 +209,16 @@ class ucp_pm
$submit_mark = false;
}
+ if (($move_pm || $submit_mark) && !check_form_key('ucp_pm_view'))
+ {
+ trigger_error('FORM_INVALID');
+ }
+
// Move PM
if ($move_pm)
{
- $move_msg_ids = (isset($_POST['marked_msg_id'])) ? request_var('marked_msg_id', array(0)) : array();
- $cur_folder_id = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
+ $move_msg_ids = (isset($_POST['marked_msg_id'])) ? $request->variable('marked_msg_id', array(0)) : array();
+ $cur_folder_id = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX);
if (move_pm($user->data['user_id'], $user->data['message_limit'], $move_msg_ids, $dest_folder, $cur_folder_id))
{
@@ -201,7 +226,7 @@ class ucp_pm
if ($action == 'view_message')
{
$msg_id = 0;
- $folder_id = request_var('cur_folder_id', PRIVMSGS_NO_BOX);
+ $folder_id = $request->variable('cur_folder_id', PRIVMSGS_NO_BOX);
$action = 'view_folder';
}
}
@@ -215,7 +240,7 @@ class ucp_pm
// If new messages arrived, place them into the appropriate folder
$num_not_moved = $num_removed = 0;
- $release = request_var('release', 0);
+ $release = $request->variable('release', 0);
if ($user->data['user_new_privmsg'] && ($action == 'view_folder' || $action == 'view_message'))
{
@@ -368,7 +393,10 @@ class ucp_pm
if ($action == 'view_folder')
{
- include($phpbb_root_path . 'includes/ucp/ucp_pm_viewfolder.' . $phpEx);
+ if (!function_exists('view_folder'))
+ {
+ include($phpbb_root_path . 'includes/ucp/ucp_pm_viewfolder.' . $phpEx);
+ }
view_folder($id, $mode, $folder_id, $folder);
$tpl_file = 'ucp_pm_viewfolder';
@@ -386,7 +414,10 @@ class ucp_pm
trigger_error('NO_MESSAGE');
}
- include($phpbb_root_path . 'includes/ucp/ucp_pm_viewmessage.' . $phpEx);
+ if (!function_exists('view_message'))
+ {
+ include($phpbb_root_path . 'includes/ucp/ucp_pm_viewmessage.' . $phpEx);
+ }
view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row);
$tpl_file = ($view == 'print') ? 'ucp_pm_viewmessage_print' : 'ucp_pm_viewmessage';
diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php
index 4906eec1bb..87a8c91fd2 100644
--- a/phpBB/includes/ucp/ucp_pm_compose.php
+++ b/phpBB/includes/ucp/ucp_pm_compose.php
@@ -26,16 +26,27 @@ if (!defined('IN_PHPBB'))
function compose_pm($id, $mode, $action, $user_folders = array())
{
global $template, $db, $auth, $user, $cache;
- global $phpbb_root_path, $phpEx, $config;
+ global $phpbb_root_path, $phpEx, $config, $language;
global $request, $phpbb_dispatcher, $phpbb_container;
// Damn php and globals - i know, this is horrible
// Needed for handle_message_list_actions()
global $refresh, $submit, $preview;
- include($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
- include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
+ if (!function_exists('generate_smilies'))
+ {
+ include($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
+ }
+
+ if (!function_exists('display_custom_bbcodes'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
+
+ if (!class_exists('parse_message'))
+ {
+ include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
+ }
if (!$action)
{
@@ -44,14 +55,13 @@ function compose_pm($id, $mode, $action, $user_folders = array())
add_form_key('ucp_pm_compose');
// Grab only parameters needed here
- $to_user_id = request_var('u', 0);
- $to_group_id = request_var('g', 0);
- $msg_id = request_var('p', 0);
- $draft_id = request_var('d', 0);
- $lastclick = request_var('lastclick', 0);
+ $to_user_id = $request->variable('u', 0);
+ $to_group_id = $request->variable('g', 0);
+ $msg_id = $request->variable('p', 0);
+ $draft_id = $request->variable('d', 0);
// Reply to all triggered (quote/reply)
- $reply_to_all = request_var('reply_to_all', 0);
+ $reply_to_all = $request->variable('reply_to_all', 0);
$address_list = $request->variable('address_list', array('' => array(0 => '')));
@@ -76,8 +86,11 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$error = array();
$current_time = time();
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
+
// Was cancel pressed? If so then redirect to the appropriate page
- if ($cancel || ($current_time - $lastclick < 2 && $submit))
+ if ($cancel)
{
if ($msg_id)
{
@@ -122,7 +135,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
// Add groups to PM box
if ($config['allow_mass_pm'] && $auth->acl_get('u_masspm_group'))
{
- $sql = 'SELECT g.group_id, g.group_name, g.group_type
+ $sql = 'SELECT g.group_id, g.group_name, g.group_type, g.group_colour
FROM ' . GROUPS_TABLE . ' g';
if (!$auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel'))
@@ -145,7 +158,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$group_options = '';
while ($row = $db->sql_fetchrow($result))
{
- $group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '">' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>';
+ $group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '"' . ($row['group_colour'] ? ' style="color: #' . $row['group_colour'] . '"' : '') . '>' . $group_helper->get_name($row['group_name']) . '</option>';
}
$db->sql_freeresult($result);
}
@@ -168,6 +181,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
case 'post':
if (!$auth->acl_get('u_sendpm'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_SEND_MESSAGE');
}
break;
@@ -183,6 +197,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
if (!$auth->acl_get('u_sendpm'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_SEND_MESSAGE');
}
@@ -223,6 +238,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
case 'delete':
if (!$auth->acl_get('u_pm_delete'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_DELETE_MESSAGE');
}
@@ -248,11 +264,13 @@ function compose_pm($id, $mode, $action, $user_folders = array())
if ($action == 'forward' && (!$config['forward_pm'] || !$auth->acl_get('u_pm_forward')))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_FORWARD_MESSAGE');
}
if ($action == 'edit' && !$auth->acl_get('u_pm_edit'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_EDIT_MESSAGE');
}
@@ -263,8 +281,6 @@ function compose_pm($id, $mode, $action, $user_folders = array())
*
* @event core.ucp_pm_compose_compose_pm_basic_info_query_before
* @var string sql String with the query to be executed
- * @var array forum_list List of forums that contain the posts
- * @var int visibility_const Integer with one of the possible ITEM_* constant values
* @var int msg_id topic_id in the page request
* @var int to_user_id The id of whom the message is to
* @var int to_group_id The id of the group whom the message is to
@@ -273,14 +289,11 @@ function compose_pm($id, $mode, $action, $user_folders = array())
* @var string action One of: post, reply, quote, forward, quotepost, edit, delete, smilies
* @var bool delete Whether the user is deleting the PM
* @var int reply_to_all Value of reply_to_all request variable.
- * @var string limit_time_sql String with the SQL code to limit the time interval of the post (Note: May be empty string)
- * @var string sort_order_sql String with the ORDER BY SQL code used in this query
* @since 3.1.0-RC5
+ * @changed 3.2.0-a1 Removed undefined variables
*/
$vars = array(
'sql',
- 'forum_list',
- 'visibility_const',
'msg_id',
'to_user_id',
'to_group_id',
@@ -289,8 +302,6 @@ function compose_pm($id, $mode, $action, $user_folders = array())
'action',
'delete',
'reply_to_all',
- 'limit_time_sql',
- 'sort_order_sql',
);
extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_compose_pm_basic_info_query_before', compact($vars)));
@@ -325,6 +336,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
{
if (($post['forum_id'] && !$auth->acl_get('f_read', $post['forum_id'])) || (!$post['forum_id'] && !$auth->acl_getf_global('f_read')))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
@@ -335,8 +347,6 @@ function compose_pm($id, $mode, $action, $user_folders = array())
* @var string sql The original SQL used in the query
* @var array post Associative array with the data of the quoted post
* @var array msg_id The post_id that was searched to get the message for quoting
- * @var int visibility_const Visibility of the quoted post (one of the possible ITEM_* constant values)
- * @var int topic_id Topic ID of the quoted post
* @var int to_user_id Users the message is sent to
* @var int to_group_id Groups the message is sent to
* @var bool submit Whether the user is sending the PM or not
@@ -345,13 +355,12 @@ function compose_pm($id, $mode, $action, $user_folders = array())
* @var bool delete If deleting message
* @var int reply_to_all Value of reply_to_all request variable.
* @since 3.1.0-RC5
+ * @changed 3.2.0-a1 Removed undefined variables
*/
$vars = array(
'sql',
'post',
'msg_id',
- 'visibility_const',
- 'topic_id',
'to_user_id',
'to_group_id',
'submit',
@@ -407,7 +416,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$quote_username = (isset($post['quote_username'])) ? $post['quote_username'] : '';
$icon_id = (isset($post['icon_id'])) ? $post['icon_id'] : 0;
- if (($action == 'reply' || $action == 'quote' || $action == 'quotepost') && !sizeof($address_list) && !$refresh && !$submit && !$preview)
+ if (($action == 'reply' || $action == 'quote' || $action == 'quotepost') && !count($address_list) && !$refresh && !$submit && !$preview)
{
// Add the original author as the recipient if quoting a post or only replying and not having checked "reply to all"
if ($action == 'quotepost' || !$reply_to_all)
@@ -429,7 +438,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
}
}
- else if ($action == 'edit' && !sizeof($address_list) && !$refresh && !$submit && !$preview)
+ else if ($action == 'edit' && !count($address_list) && !$refresh && !$submit && !$preview)
{
// Rebuild TO and BCC Header
$address_list = rebuild_header(array('to' => $post['to_address'], 'bcc' => $post['bcc_address']));
@@ -474,6 +483,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
if (($to_group_id || isset($address_list['g'])) && (!$config['allow_mass_pm'] || !$auth->acl_get('u_masspm_group')))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_GROUP_MESSAGE');
}
@@ -495,8 +505,9 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$icon_id = 0;
}
- $message_parser = new parse_message();
+ /* @var $plupload \phpbb\plupload\plupload */
$plupload = $phpbb_container->get('plupload');
+ $message_parser = new parse_message();
$message_parser->set_plupload($plupload);
$message_parser->message = ($action == 'reply') ? '' : $message_text;
@@ -509,7 +520,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
if ($action == 'delete')
{
// Folder id has been determined by the SQL Statement
- // $folder_id = request_var('f', PRIVMSGS_NO_BOX);
+ // $folder_id = $request->variable('f', PRIVMSGS_NO_BOX);
// Do we need to confirm ?
if (confirm_box(true))
@@ -540,15 +551,9 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
// Get maximum number of allowed recipients
- $sql = 'SELECT MAX(g.group_max_recipients) as max_recipients
- FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
- WHERE ug.user_id = ' . $user->data['user_id'] . '
- AND ug.user_pending = 0
- AND ug.group_id = g.group_id';
- $result = $db->sql_query($sql);
- $max_recipients = (int) $db->sql_fetchfield('max_recipients');
- $db->sql_freeresult($result);
+ $max_recipients = phpbb_get_max_setting_from_group($db, $user->data['user_id'], 'max_recipients');
+ // If it is 0, there is no limit set and we use the maximum value within the config.
$max_recipients = (!$max_recipients) ? $config['pm_max_recipients'] : $max_recipients;
// If this is a quote/reply "to all"... we may increase the max_recpients to the number of original recipients
@@ -566,7 +571,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
unset($list[$user->data['user_id']]);
}
- $max_recipients = ($max_recipients < sizeof($list)) ? sizeof($list) : $max_recipients;
+ $max_recipients = ($max_recipients < count($list)) ? count($list) : $max_recipients;
unset($list);
}
@@ -589,7 +594,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
// Check for too many recipients
- if (!empty($address_list['u']) && $max_recipients && sizeof($address_list['u']) > $max_recipients)
+ if (!empty($address_list['u']) && $max_recipients && count($address_list['u']) > $max_recipients)
{
$address_list = get_recipients($address_list, $max_recipients);
$error[] = $user->lang('TOO_MANY_RECIPIENTS', $max_recipients);
@@ -621,7 +626,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$enable_urls = true;
}
- $enable_magic_url = $drafts = false;
+ $drafts = false;
// User own some drafts?
if ($auth->acl_get('u_savedrafts') && $action != 'delete')
@@ -656,21 +661,24 @@ function compose_pm($id, $mode, $action, $user_folders = array())
// Save Draft
if ($save && $auth->acl_get('u_savedrafts'))
{
- $subject = utf8_normalize_nfc(request_var('subject', '', true));
+ $subject = $request->variable('subject', '', true);
$subject = (!$subject && $action != 'post') ? $user->lang['NEW_MESSAGE'] : $subject;
- $message = utf8_normalize_nfc(request_var('message', '', true));
+ $message = $request->variable('message', '', true);
if ($subject && $message)
{
if (confirm_box(true))
{
+ $message_parser->message = $message;
+ $message_parser->parse($bbcode_status, $url_status, $smilies_status, $img_status, $flash_status, true, $url_status);
+
$sql = 'INSERT INTO ' . DRAFTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => $user->data['user_id'],
'topic_id' => 0,
'forum_id' => 0,
'save_time' => $current_time,
'draft_subject' => $subject,
- 'draft_message' => $message
+ 'draft_message' => $message_parser->message,
)
);
$db->sql_query($sql);
@@ -752,10 +760,10 @@ function compose_pm($id, $mode, $action, $user_folders = array())
{
$error[] = $user->lang['FORM_INVALID'];
}
- $subject = utf8_normalize_nfc(request_var('subject', '', true));
- $message_parser->message = utf8_normalize_nfc(request_var('message', '', true));
+ $subject = $request->variable('subject', '', true);
+ $message_parser->message = $request->variable('message', '', true);
- $icon_id = request_var('icon', 0);
+ $icon_id = $request->variable('icon', 0);
$enable_bbcode = (!$bbcode_status || isset($_POST['disable_bbcode'])) ? false : true;
$enable_smilies = (!$smilies_status || isset($_POST['disable_smilies'])) ? false : true;
@@ -790,20 +798,13 @@ function compose_pm($id, $mode, $action, $user_folders = array())
);
extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_modify_parse_before', compact($vars)));
- if ($submit)
- {
- $status_switch = (($enable_bbcode+1) << 8) + (($enable_smilies+1) << 4) + (($enable_urls+1) << 2) + (($enable_sig+1) << 1);
- $status_switch = ($status_switch != $check_value);
- }
- else
+ // Parse Attachments - before checksum is calculated
+ if ($message_parser->check_attachment_form_token($language, $request, 'ucp_pm_compose'))
{
- $status_switch = 1;
+ $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true);
}
- // Parse Attachments - before checksum is calculated
- $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true);
-
- if (sizeof($message_parser->warn_msg) && !($remove_u || $remove_g || $add_to || $add_bcc))
+ if (count($message_parser->warn_msg) && !($remove_u || $remove_g || $add_to || $add_bcc))
{
$error[] = implode('<br />', $message_parser->warn_msg);
$message_parser->warn_msg = array();
@@ -813,7 +814,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$message_parser->parse($enable_bbcode, ($config['allow_post_links']) ? $enable_urls : false, $enable_smilies, $img_status, $flash_status, true, $config['allow_post_links']);
// On a refresh we do not care about message parsing errors
- if (sizeof($message_parser->warn_msg) && !$refresh)
+ if (count($message_parser->warn_msg) && !$refresh)
{
$error[] = implode('<br />', $message_parser->warn_msg);
}
@@ -840,14 +841,14 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$error[] = $user->lang['EMPTY_MESSAGE_SUBJECT'];
}
- if (!sizeof($address_list))
+ if (!count($address_list))
{
$error[] = $user->lang['NO_RECIPIENT'];
}
}
// Store message, sync counters
- if (!sizeof($error) && $submit)
+ if (!count($error) && $submit)
{
$pm_data = array(
'msg_id' => (int) $msg_id,
@@ -904,7 +905,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
// Preview
- if (!sizeof($error) && $preview)
+ if (!count($error) && $preview)
{
$preview_message = $message_parser->format_display($enable_bbcode, $enable_urls, $enable_smilies, false);
@@ -915,13 +916,8 @@ function compose_pm($id, $mode, $action, $user_folders = array())
// Signature
if ($enable_sig && $config['allow_sig'] && $preview_signature)
{
- $parse_sig = new parse_message($preview_signature);
- $parse_sig->bbcode_uid = $preview_signature_uid;
- $parse_sig->bbcode_bitfield = $preview_signature_bitfield;
-
- $parse_sig->format_display($config['allow_sig_bbcode'], $config['allow_sig_links'], $config['allow_sig_smilies']);
- $preview_signature = $parse_sig->message;
- unset($parse_sig);
+ $bbcode_flags = ($enable_bbcode ? OPTION_FLAG_BBCODE : 0) + ($enable_smilies ? OPTION_FLAG_SMILIES : 0) + ($enable_urls ? OPTION_FLAG_LINKS : 0);
+ $preview_signature = generate_text_for_display($preview_signature, $preview_signature_uid, $preview_signature_bitfield, $bbcode_flags);
}
else
{
@@ -929,7 +925,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
// Attachment Preview
- if (sizeof($message_parser->attachment_data))
+ if (count($message_parser->attachment_data))
{
$template->assign_var('S_HAS_ATTACHMENTS', true);
@@ -949,7 +945,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$preview_subject = censor_text($subject);
- if (!sizeof($error))
+ if (!count($error))
{
$template->assign_vars(array(
'PREVIEW_SUBJECT' => $preview_subject,
@@ -963,7 +959,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
// Decode text for message display
- $bbcode_uid = (($action == 'quote' || $action == 'forward') && !$preview && !$refresh && (!sizeof($error) || (sizeof($error) && !$submit))) ? $bbcode_uid : $message_parser->bbcode_uid;
+ $bbcode_uid = (($action == 'quote' || $action == 'forward') && !$preview && !$refresh && (!count($error) || (count($error) && !$submit))) ? $bbcode_uid : $message_parser->bbcode_uid;
$message_parser->decode_message($bbcode_uid);
@@ -971,10 +967,19 @@ function compose_pm($id, $mode, $action, $user_folders = array())
{
if ($action == 'quotepost')
{
- $post_id = request_var('p', 0);
+ $post_id = $request->variable('p', 0);
if ($config['allow_post_links'])
{
- $message_link = "[url=" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id}]{$user->lang['SUBJECT']}{$user->lang['COLON']} {$message_subject}[/url]\n\n";
+ $message_link = generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id}";
+ $message_link_subject = "{$user->lang['SUBJECT']}{$user->lang['COLON']} {$message_subject}";
+ if ($bbcode_status)
+ {
+ $message_link = "[url=" . $message_link . "]" . $message_link_subject . "[/url]\n\n";
+ }
+ else
+ {
+ $message_link = $message_link . " - " . $message_link_subject . "\n\n";
+ }
}
else
{
@@ -985,12 +990,39 @@ function compose_pm($id, $mode, $action, $user_folders = array())
{
$message_link = '';
}
- $message_parser->message = $message_link . '[quote=&quot;' . $quote_username . '&quot;]' . censor_text(trim($message_parser->message)) . "[/quote]\n";
+ $quote_attributes = array(
+ 'author' => $quote_username,
+ 'time' => $post['message_time'],
+ 'user_id' => $post['author_id'],
+ );
+ if ($action === 'quotepost')
+ {
+ $quote_attributes['post_id'] = $post['msg_id'];
+ }
+ if ($action === 'quote')
+ {
+ $quote_attributes['msg_id'] = $post['msg_id'];
+ }
+ /** @var \phpbb\language\language $language */
+ $language = $phpbb_container->get('language');
+ /** @var \phpbb\textformatter\utils_interface $text_formatter_utils */
+ $text_formatter_utils = $phpbb_container->get('text_formatter.utils');
+ phpbb_format_quote($language, $message_parser, $text_formatter_utils, $bbcode_status, $quote_attributes, $message_link);
}
if (($action == 'reply' || $action == 'quote' || $action == 'quotepost') && !$preview && !$refresh)
{
$message_subject = ((!preg_match('/^Re:/', $message_subject)) ? 'Re: ' : '') . censor_text($message_subject);
+
+ /**
+ * This event allows you to modify the PM subject of the PM being quoted
+ *
+ * @event core.pm_modify_message_subject
+ * @var string message_subject String with the PM subject already censored.
+ * @since 3.2.8-RC1
+ */
+ $vars = array('message_subject');
+ extract($phpbb_dispatcher->trigger_event('core.pm_modify_message_subject', compact($vars)));
}
if ($action == 'forward' && !$preview && !$refresh && !$submit)
@@ -1013,7 +1045,11 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$forward_text[] = sprintf($user->lang['FWD_FROM'], $quote_username_text);
$forward_text[] = sprintf($user->lang['FWD_TO'], implode($user->lang['COMMA_SEPARATOR'], $fwd_to_field['to']));
- $message_parser->message = implode("\n", $forward_text) . "\n\n[quote=&quot;{$quote_username}&quot;]\n" . censor_text(trim($message_parser->message)) . "\n[/quote]";
+ $quote_text = $phpbb_container->get('text_formatter.utils')->generate_quote(
+ censor_text($message_parser->message),
+ array('author' => $quote_username)
+ );
+ $message_parser->message = implode("\n", $forward_text) . "\n\n" . $quote_text;
$message_subject = ((!preg_match('/^Fwd:/', $message_subject)) ? 'Fwd: ' : '') . censor_text($message_subject);
}
@@ -1038,7 +1074,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
// Build address list for display
// array('u' => array($author_id => 'to'));
- if (sizeof($address_list))
+ if (count($address_list))
{
// Get Usernames and Group Names
$result = array();
@@ -1086,7 +1122,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
{
if ($type == 'g')
{
- $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name'];
+ $row['name'] = $group_helper->get_name($row['name']);
}
${$type}[$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']);
@@ -1096,7 +1132,6 @@ function compose_pm($id, $mode, $action, $user_folders = array())
}
// Now Build the address list
- $plain_address_field = '';
foreach ($address_list as $type => $adr_ary)
{
foreach ($adr_ary as $id => $field)
@@ -1178,28 +1213,30 @@ function compose_pm($id, $mode, $action, $user_folders = array())
break;
}
- $s_hidden_fields = '<input type="hidden" name="lastclick" value="' . $current_time . '" />';
- $s_hidden_fields .= (isset($check_value)) ? '<input type="hidden" name="status_switch" value="' . $check_value . '" />' : '';
+ $s_hidden_fields = (isset($check_value)) ? '<input type="hidden" name="status_switch" value="' . $check_value . '" />' : '';
$s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '<input type="hidden" name="draft_loaded" value="' . ((isset($_REQUEST['draft_loaded'])) ? $request->variable('draft_loaded', 0) : $draft_id) . '" />' : '';
$form_enctype = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !$config['allow_pm_attach'] || !$auth->acl_get('u_pm_attach')) ? '' : ' enctype="multipart/form-data"';
+ /** @var \phpbb\controller\helper $controller_helper */
+ $controller_helper = $phpbb_container->get('controller.helper');
+
// Start assigning vars for main posting page ...
- $template->assign_vars(array(
+ $template_ary = array(
'L_POST_A' => $page_title,
'L_ICON' => $user->lang['PM_ICON'],
'L_MESSAGE_BODY_EXPLAIN' => $user->lang('MESSAGE_BODY_EXPLAIN', (int) $config['max_post_chars']),
'SUBJECT' => (isset($message_subject)) ? $message_subject : '',
'MESSAGE' => $message_text,
- 'BBCODE_STATUS' => ($bbcode_status) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'),
+ 'BBCODE_STATUS' => $user->lang(($bbcode_status ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '<a href="' . $controller_helper->route('phpbb_help_bbcode_controller') . '">', '</a>'),
'IMG_STATUS' => ($img_status) ? $user->lang['IMAGES_ARE_ON'] : $user->lang['IMAGES_ARE_OFF'],
'FLASH_STATUS' => ($flash_status) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'],
'SMILIES_STATUS' => ($smilies_status) ? $user->lang['SMILIES_ARE_ON'] : $user->lang['SMILIES_ARE_OFF'],
'URL_STATUS' => ($url_status) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'],
'MAX_FONT_SIZE' => (int) $config['max_post_font_size'],
'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['PM']),
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'MAX_RECIPIENTS' => ($config['allow_mass_pm'] && ($auth->acl_get('u_masspm') || $auth->acl_get('u_masspm_group'))) ? $max_recipients : 0,
'S_COMPOSE_PM' => true,
@@ -1230,7 +1267,19 @@ function compose_pm($id, $mode, $action, $user_folders = array())
'S_CLOSE_PROGRESS_WINDOW' => isset($_POST['add_file']),
'U_PROGRESS_BAR' => append_sid("{$phpbb_root_path}posting.$phpEx", 'f=0&amp;mode=popup'),
'UA_PROGRESS_BAR' => addslashes(append_sid("{$phpbb_root_path}posting.$phpEx", 'f=0&amp;mode=popup')),
- ));
+ );
+
+ /**
+ * Modify the default template vars
+ *
+ * @event core.ucp_pm_compose_template
+ * @var array template_ary Template variables
+ * @since 3.2.6-RC1
+ */
+ $vars = array('template_ary');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_pm_compose_template', compact($vars)));
+
+ $template->assign_vars($template_ary);
// Build custom bbcodes array
display_custom_bbcodes();
@@ -1263,7 +1312,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove_g, $add_to, $add_bcc)
{
global $auth, $db, $user;
- global $request;
+ global $request, $phpbb_dispatcher;
// Delete User [TO/BCC]
if ($remove_u && $request->variable('remove_u', array(0 => '')))
@@ -1288,20 +1337,20 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove
}
// Add Selected Groups
- $group_list = request_var('group_list', array(0));
+ $group_list = $request->variable('group_list', array(0));
// Build usernames to add
- $usernames = request_var('username', '', true);
+ $usernames = $request->variable('username', '', true);
$usernames = (empty($usernames)) ? array() : array($usernames);
- $username_list = request_var('username_list', '', true);
+ $username_list = $request->variable('username_list', '', true);
if ($username_list)
{
$usernames = array_merge($usernames, explode("\n", $username_list));
}
// If add to or add bcc not pressed, users could still have usernames listed they want to add...
- if (!$add_to && !$add_bcc && (sizeof($group_list) || sizeof($usernames)))
+ if (!$add_to && !$add_bcc && (count($group_list) || count($usernames)))
{
$add_to = true;
@@ -1311,7 +1360,7 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove
$submit = false;
// Preview is only true if there was also a message entered
- if (request_var('message', ''))
+ if ($request->variable('message', ''))
{
$preview = true;
}
@@ -1322,7 +1371,7 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove
{
$type = ($add_to) ? 'to' : 'bcc';
- if (sizeof($group_list))
+ if (count($group_list))
{
foreach ($group_list as $group_id)
{
@@ -1334,13 +1383,13 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove
$user_id_ary = array();
// Reveal the correct user_ids
- if (sizeof($usernames))
+ if (count($usernames))
{
$user_id_ary = array();
user_get_id_name($user_id_ary, $usernames, array(USER_NORMAL, USER_FOUNDER, USER_INACTIVE));
// If there are users not existing, we will at least print a notice...
- if (!sizeof($user_id_ary))
+ if (!count($user_id_ary))
{
$error[] = $user->lang['PM_NO_USERS'];
}
@@ -1409,7 +1458,7 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove
$error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION'];
}
- if (!sizeof(array_keys($address_list['u'])))
+ if (!count(array_keys($address_list['u'])))
{
return;
}
@@ -1440,10 +1489,25 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove
$error[] = $user->lang['PM_USERS_REMOVED_NO_PERMISSION'];
}
}
+
+ /**
+ * Event for additional message list actions
+ *
+ * @event core.message_list_actions
+ * @var array address_list The assoc array with the recipient user/group ids
+ * @var array error The array containing error data
+ * @var bool remove_u The variable for removing a user
+ * @var bool remove_g The variable for removing a group
+ * @var bool add_to The variable for adding a user to the [TO] field
+ * @var bool add_bcc The variable for adding a user to the [BCC] field
+ * @since 3.2.4-RC1
+ */
+ $vars = array('address_list', 'error', 'remove_u', 'remove_g', 'add_to', 'add_bcc');
+ extract($phpbb_dispatcher->trigger_event('core.message_list_actions', compact($vars)));
}
/**
-* Build the hidden field for the recipients. Needed, as the variable is not read via request_var.
+* Build the hidden field for the recipients. Needed, as the variable is not read via $request->variable().
*/
function build_address_field($address_list)
{
@@ -1467,7 +1531,7 @@ function num_recipients($address_list)
foreach ($address_list as $field => $adr_ary)
{
- $num_recipients += sizeof($adr_ary);
+ $num_recipients += count($adr_ary);
}
return $num_recipients;
diff --git a/phpBB/includes/ucp/ucp_pm_options.php b/phpBB/includes/ucp/ucp_pm_options.php
index d1fc9d2c62..3861962516 100644
--- a/phpBB/includes/ucp/ucp_pm_options.php
+++ b/phpBB/includes/ucp/ucp_pm_options.php
@@ -24,7 +24,7 @@ if (!defined('IN_PHPBB'))
*/
function message_options($id, $mode, $global_privmsgs_rules, $global_rule_conditions)
{
- global $phpbb_root_path, $phpEx, $user, $template, $auth, $config, $db;
+ global $phpbb_root_path, $phpEx, $user, $template, $config, $db, $request;
$redirect_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&amp;mode=options");
@@ -37,7 +37,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
trigger_error('FORM_INVALID');
}
- $full_action = request_var('full_action', 0);
+ $full_action = $request->variable('full_action', 0);
$set_folder_id = 0;
switch ($full_action)
@@ -47,7 +47,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
break;
case 2:
- $set_folder_id = request_var('full_move_to', PRIVMSGS_INBOX);
+ $set_folder_id = $request->variable('full_move_to', PRIVMSGS_INBOX);
break;
case 3:
@@ -79,8 +79,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
{
if (check_form_key('ucp_pm_options'))
{
- $folder_name = utf8_normalize_nfc(request_var('foldername', '', true));
- $msg = '';
+ $folder_name = $request->variable('foldername', '', true);
if ($folder_name)
{
@@ -135,8 +134,8 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
{
if (check_form_key('ucp_pm_options'))
{
- $new_folder_name = utf8_normalize_nfc(request_var('new_folder_name', '', true));
- $rename_folder_id= request_var('rename_folder_id', 0);
+ $new_folder_name = $request->variable('new_folder_name', '', true);
+ $rename_folder_id= $request->variable('rename_folder_id', 0);
if (!$new_folder_name)
{
@@ -178,11 +177,11 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
// Remove Folder
if (isset($_POST['remove_folder']))
{
- $remove_folder_id = request_var('remove_folder_id', 0);
+ $remove_folder_id = $request->variable('remove_folder_id', 0);
// Default to "move all messages to inbox"
- $remove_action = request_var('remove_action', 1);
- $move_to = request_var('move_to', PRIVMSGS_INBOX);
+ $remove_action = $request->variable('remove_action', 1);
+ $move_to = $request->variable('move_to', PRIVMSGS_INBOX);
// Move to same folder?
if ($remove_action == 1 && $remove_folder_id == $move_to)
@@ -291,13 +290,13 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
{
if (check_form_key('ucp_pm_options'))
{
- $check_option = request_var('check_option', 0);
- $rule_option = request_var('rule_option', 0);
- $cond_option = request_var('cond_option', '');
- $action_option = explode('|', request_var('action_option', ''));
- $rule_string = ($cond_option != 'none') ? utf8_normalize_nfc(request_var('rule_string', '', true)) : '';
- $rule_user_id = ($cond_option != 'none') ? request_var('rule_user_id', 0) : 0;
- $rule_group_id = ($cond_option != 'none') ? request_var('rule_group_id', 0) : 0;
+ $check_option = $request->variable('check_option', 0);
+ $rule_option = $request->variable('rule_option', 0);
+ $cond_option = $request->variable('cond_option', '');
+ $action_option = explode('|', $request->variable('action_option', ''));
+ $rule_string = ($cond_option != 'none') ? $request->variable('rule_string', '', true) : '';
+ $rule_user_id = ($cond_option != 'none') ? $request->variable('rule_user_id', 0) : 0;
+ $rule_group_id = ($cond_option != 'none') ? $request->variable('rule_group_id', 0) : 0;
$action = (int) $action_option[0];
$folder_id = (int) $action_option[1];
@@ -371,7 +370,7 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
// Remove Rule
if (isset($_POST['delete_rule']) && !isset($_POST['cancel']))
{
- $delete_id = array_keys(request_var('delete_rule', array(0 => 0)));
+ $delete_id = array_keys($request->variable('delete_rule', array(0 => 0)));
$delete_id = (!empty($delete_id[0])) ? $delete_id[0] : 0;
if (!$delete_id)
@@ -507,20 +506,22 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit
$rule_lang = $action_lang = $check_lang = array();
// Build all three language arrays
- preg_replace('#^((RULE|ACTION|CHECK)_([A-Z0-9_]+))$#e', "\${strtolower('\\2') . '_lang'}[constant('\\1')] = \$user->lang['PM_\\2']['\\3']", array_keys(get_defined_constants()));
+ preg_replace_callback('#^((RULE|ACTION|CHECK)_([A-Z0-9_]+))$#', function ($match) use(&$rule_lang, &$action_lang, &$check_lang, $user) {
+ ${strtolower($match[2]) . '_lang'}[constant($match[1])] = $user->lang['PM_' . $match[2]][$match[3]];
+ }, array_keys(get_defined_constants()));
/*
Rule Ordering:
-> CHECK_* -> RULE_* [IN $global_privmsgs_rules:CHECK_*] -> [IF $rule_conditions[RULE_*] [|text|bool|user|group|own_group]] -> ACTION_*
*/
- $check_option = request_var('check_option', 0);
- $rule_option = request_var('rule_option', 0);
- $cond_option = request_var('cond_option', '');
- $action_option = request_var('action_option', '');
- $back = (isset($_REQUEST['back'])) ? request_var('back', array('' => 0)) : array();
+ $check_option = $request->variable('check_option', 0);
+ $rule_option = $request->variable('rule_option', 0);
+ $cond_option = $request->variable('cond_option', '');
+ $action_option = $request->variable('action_option', '');
+ $back = (isset($_REQUEST['back'])) ? $request->variable('back', array('' => 0)) : array();
- if (sizeof($back))
+ if (count($back))
{
if ($action_option)
{
@@ -609,7 +610,7 @@ function define_check_option($hardcoded, $check_option, $check_lang)
*/
function define_action_option($hardcoded, $action_option, $action_lang, $folder)
{
- global $db, $template, $user;
+ global $template;
$l_action = $s_action_options = '';
if ($hardcoded)
@@ -698,7 +699,10 @@ function define_rule_option($hardcoded, $rule_option, $rule_lang, $check_ary)
*/
function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule_conditions)
{
- global $db, $template, $auth, $user;
+ global $db, $template, $auth, $user, $request, $phpbb_container;
+
+ /** @var \phpbb\group\helper $group_helper */
+ $group_helper = $phpbb_container->get('group_helper');
$template->assign_vars(array(
'S_COND_DEFINED' => true,
@@ -717,12 +721,11 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule
// Define Condition
$condition = $global_rule_conditions[$rule_option];
- $current_value = '';
switch ($condition)
{
case 'text':
- $rule_string = utf8_normalize_nfc(request_var('rule_string', '', true));
+ $rule_string = $request->variable('rule_string', '', true);
$template->assign_vars(array(
'S_TEXT_CONDITION' => true,
@@ -735,8 +738,8 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule
break;
case 'user':
- $rule_user_id = request_var('rule_user_id', 0);
- $rule_string = utf8_normalize_nfc(request_var('rule_string', '', true));
+ $rule_user_id = $request->variable('rule_user_id', 0);
+ $rule_string = $request->variable('rule_string', '', true);
if ($rule_string && !$rule_user_id)
{
@@ -778,8 +781,8 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule
break;
case 'group':
- $rule_group_id = request_var('rule_group_id', 0);
- $rule_string = utf8_normalize_nfc(request_var('rule_string', '', true));
+ $rule_group_id = $request->variable('rule_group_id', 0);
+ $rule_string = $request->variable('rule_string', '', true);
$sql = 'SELECT g.group_id, g.group_name, g.group_type
FROM ' . GROUPS_TABLE . ' g ';
@@ -810,13 +813,13 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule
{
if ($rule_group_id && ($row['group_id'] == $rule_group_id))
{
- $rule_string = (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']);
+ $rule_string = $group_helper->get_name($row['group_name']);
}
$s_class = ($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '';
$s_selected = ($row['group_id'] == $rule_group_id) ? ' selected="selected"' : '';
- $s_group_options .= '<option value="' . $row['group_id'] . '"' . $s_class . $s_selected . '>' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>';
+ $s_group_options .= '<option value="' . $row['group_id'] . '"' . $s_class . $s_selected . '>' . $group_helper->get_name($row['group_name']) . '</option>';
}
$db->sql_freeresult($result);
diff --git a/phpBB/includes/ucp/ucp_pm_viewfolder.php b/phpBB/includes/ucp/ucp_pm_viewfolder.php
index 3364206680..ce40a2507d 100644
--- a/phpBB/includes/ucp/ucp_pm_viewfolder.php
+++ b/phpBB/includes/ucp/ucp_pm_viewfolder.php
@@ -25,13 +25,15 @@ if (!defined('IN_PHPBB'))
*/
function view_folder($id, $mode, $folder_id, $folder)
{
- global $user, $template, $auth, $db, $cache;
+ global $user, $template, $auth, $db, $cache, $request;
global $phpbb_root_path, $config, $phpEx;
$submit_export = (isset($_POST['submit_export'])) ? true : false;
$folder_info = get_pm_from($folder_id, $folder, $user->data['user_id']);
+ add_form_key('ucp_pm_view_folder');
+
if (!$submit_export)
{
$user->add_lang('viewforum');
@@ -39,10 +41,7 @@ function view_folder($id, $mode, $folder_id, $folder)
// Grab icons
$icons = $cache->obtain_icons();
- $color_rows = array('marked', 'replied');
-
- // only show the friend/foe color rows if the module is enabled
- $zebra_enabled = false;
+ $color_rows = array('message_reported', 'marked', 'replied');
$_module = new p_master();
$_module->list_modules('ucp');
@@ -117,7 +116,7 @@ function view_folder($id, $mode, $folder_id, $folder)
);
// Okay, lets dump out the page ...
- if (sizeof($folder_info['pm_list']))
+ if (count($folder_info['pm_list']))
{
$address_list = array();
@@ -141,9 +140,9 @@ function view_folder($id, $mode, $folder_id, $folder)
$row_indicator = '';
foreach ($color_rows as $var)
{
- if (($var != 'friend' && $var != 'foe' && $row['pm_' . $var])
+ if (($var !== 'friend' && $var !== 'foe' && $row[($var === 'message_reported') ? $var : "pm_{$var}"])
||
- (($var == 'friend' || $var == 'foe') && isset(${$var}[$row['author_id']]) && ${$var}[$row['author_id']]))
+ (($var === 'friend' || $var === 'foe') && isset(${$var}[$row['author_id']]) && ${$var}[$row['author_id']]))
{
$row_indicator = $var;
break;
@@ -196,9 +195,14 @@ function view_folder($id, $mode, $folder_id, $folder)
}
else
{
- $export_type = request_var('export_option', '');
- $enclosure = request_var('enclosure', '');
- $delimiter = request_var('delimiter', '');
+ $export_type = $request->variable('export_option', '');
+ $enclosure = $request->variable('enclosure', '');
+ $delimiter = $request->variable('delimiter', '');
+
+ if (!check_form_key('ucp_pm_view_folder'))
+ {
+ trigger_error('FORM_INVALID');
+ }
if ($export_type == 'CSV' && ($delimiter === '' || $enclosure === ''))
{
@@ -239,7 +243,7 @@ function view_folder($id, $mode, $folder_id, $folder)
$_types = array('u', 'g');
foreach ($_types as $ug_type)
{
- if (isset($address_temp[$message_id][$ug_type]) && sizeof($address_temp[$message_id][$ug_type]))
+ if (isset($address_temp[$message_id][$ug_type]) && count($address_temp[$message_id][$ug_type]))
{
if (!isset($address[$message_id][$ug_type]))
{
@@ -272,8 +276,8 @@ function view_folder($id, $mode, $folder_id, $folder)
// There is the chance that all recipients of the message got deleted. To avoid creating
// exports without recipients, we add a bogus "undisclosed recipient".
- if (!(isset($address[$message_id]['g']) && sizeof($address[$message_id]['g'])) &&
- !(isset($address[$message_id]['u']) && sizeof($address[$message_id]['u'])))
+ if (!(isset($address[$message_id]['g']) && count($address[$message_id]['g'])) &&
+ !(isset($address[$message_id]['u']) && count($address[$message_id]['u'])))
{
$address[$message_id]['u'] = array();
$address[$message_id]['u']['to'] = array();
@@ -397,15 +401,16 @@ function view_folder($id, $mode, $folder_id, $folder)
*/
function get_pm_from($folder_id, $folder, $user_id)
{
- global $user, $db, $template, $config, $auth, $phpbb_container, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $user, $db, $template, $config, $auth, $phpbb_container, $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher;
- $start = request_var('start', 0);
+ $start = $request->variable('start', 0);
// Additional vars later, pm ordering is mostly different from post ordering. :/
- $sort_days = request_var('st', 0);
- $sort_key = request_var('sk', 't');
- $sort_dir = request_var('sd', 'd');
+ $sort_days = $request->variable('st', 0);
+ $sort_key = $request->variable('sk', 't');
+ $sort_dir = $request->variable('sd', 'd');
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// PM ordering options
diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php
index d7b9b32dbf..7c0091ef47 100644
--- a/phpBB/includes/ucp/ucp_pm_viewmessage.php
+++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php
@@ -24,7 +24,7 @@ if (!defined('IN_PHPBB'))
*/
function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
{
- global $user, $template, $auth, $db, $cache, $phpbb_container;
+ global $user, $template, $auth, $db, $phpbb_container;
global $phpbb_root_path, $request, $phpEx, $config, $phpbb_dispatcher;
$user->add_lang(array('viewtopic', 'memberlist'));
@@ -32,7 +32,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
$msg_id = (int) $msg_id;
$folder_id = (int) $folder_id;
$author_id = (int) $message_row['author_id'];
- $view = request_var('view', '');
+ $view = $request->variable('view', '');
// Not able to view message, it was deleted by the sender
if ($message_row['pm_deleted'])
@@ -41,6 +41,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
$message = $user->lang['NO_AUTH_READ_REMOVED_MESSAGE'];
$message .= '<br /><br />' . sprintf($user->lang['RETURN_FOLDER'], '<a href="' . $meta_info . '">', '</a>');
+ send_status_line(403, 'Forbidden');
trigger_error($message);
}
@@ -50,12 +51,10 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
trigger_error('NO_AUTH_READ_HOLD_MESSAGE');
}
- // Grab icons
- $icons = $cache->obtain_icons();
-
// Load the custom profile fields
if ($config['load_cpf_pm'])
{
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$profile_fields = $cp->grab_profile_fields_data($author_id);
@@ -114,7 +113,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
$db->sql_freeresult($result);
// No attachments exist, but message table thinks they do so go ahead and reset attach flags
- if (!sizeof($attachments))
+ if (!count($attachments))
{
$sql = 'UPDATE ' . PRIVMSGS_TABLE . "
SET message_attachment = 0
@@ -135,7 +134,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
parse_attachments(false, $message, $attachments, $update_count);
// Update the attachment download counts
- if (sizeof($update_count))
+ if (count($update_count))
{
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
SET download_count = download_count + 1
@@ -231,7 +230,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
'U_DELETE' => ($auth->acl_get('u_pm_delete')) ? "$url&amp;mode=compose&amp;action=delete&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] : '',
'U_EMAIL' => $user_info['email'],
- 'U_REPORT' => ($config['allow_pm_report']) ? append_sid("{$phpbb_root_path}report.$phpEx", "pm=" . $message_row['msg_id']) : '',
+ 'U_REPORT' => ($config['allow_pm_report']) ? $phpbb_container->get('controller.helper')->route('phpbb_report_pm_controller', array('id' => $message_row['msg_id'])) : '',
'U_QUOTE' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&amp;mode=compose&amp;action=quote&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] : '',
'U_EDIT' => (($message_row['message_time'] > time() - ($config['pm_edit_time'] * 60) || !$config['pm_edit_time']) && $folder_id == PRIVMSGS_OUTBOX && $auth->acl_get('u_pm_edit')) ? "$url&amp;mode=compose&amp;action=edit&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] : '',
'U_POST_REPLY_PM' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&amp;mode=compose&amp;action=reply&amp;f=$folder_id&amp;p=" . $message_row['msg_id'] : '',
@@ -241,7 +240,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
'U_PM_ACTION' => $url . '&amp;mode=compose&amp;f=' . $folder_id . '&amp;p=' . $message_row['msg_id'],
- 'S_HAS_ATTACHMENTS' => (sizeof($attachments)) ? true : false,
+ 'S_HAS_ATTACHMENTS' => (count($attachments)) ? true : false,
'S_DISPLAY_NOTICE' => $display_notice && $message_row['message_attachment'],
'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false,
'S_SPECIAL_FOLDER' => in_array($folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)),
@@ -268,6 +267,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
* @var array user_info User data of the sender
* @since 3.1.0-a1
* @changed 3.1.6-RC1 Added user_info into event
+ * @changed 3.2.2-RC1 Deprecated
+ * @deprecated 4.0.0 Event name is misspelled and is replaced with new event with correct name
*/
$vars = array(
'id',
@@ -282,6 +283,37 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
);
extract($phpbb_dispatcher->trigger_event('core.ucp_pm_view_messsage', compact($vars)));
+ /**
+ * Modify pm and sender data before it is assigned to the template
+ *
+ * @event core.ucp_pm_view_message
+ * @var mixed id Active module category (can be int or string)
+ * @var string mode Active module
+ * @var int folder_id ID of the folder the message is in
+ * @var int msg_id ID of the private message
+ * @var array folder Array with data of user's message folders
+ * @var array message_row Array with message data
+ * @var array cp_row Array with senders custom profile field data
+ * @var array msg_data Template array with message data
+ * @var array user_info User data of the sender
+ * @var array attachments Attachments data
+ * @since 3.2.2-RC1
+ * @changed 3.2.5-RC1 Added attachments
+ */
+ $vars = array(
+ 'id',
+ 'mode',
+ 'folder_id',
+ 'msg_id',
+ 'folder',
+ 'message_row',
+ 'cp_row',
+ 'msg_data',
+ 'user_info',
+ 'attachments',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.ucp_pm_view_message', compact($vars)));
+
$template->assign_vars($msg_data);
$contact_fields = array(
@@ -331,7 +363,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
}
// Display not already displayed Attachments for this post, we already parsed them. ;)
- if (isset($attachments) && sizeof($attachments))
+ if (isset($attachments) && count($attachments))
{
foreach ($attachments as $attachment)
{
@@ -356,7 +388,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
*/
function get_user_information($user_id, $user_row)
{
- global $db, $auth, $user, $cache;
+ global $db, $auth, $user;
global $phpbb_root_path, $phpEx, $config;
if (!$user_id)
diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php
index e63e9b4c08..7785aeb07b 100644
--- a/phpBB/includes/ucp/ucp_prefs.php
+++ b/phpBB/includes/ucp/ucp_prefs.php
@@ -29,7 +29,7 @@ class ucp_prefs
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
+ global $config, $db, $user, $auth, $template, $phpbb_dispatcher, $request;
$submit = (isset($_POST['submit'])) ? true : false;
$error = $data = array();
@@ -40,16 +40,16 @@ class ucp_prefs
case 'personal':
add_form_key('ucp_prefs_personal');
$data = array(
- 'notifymethod' => request_var('notifymethod', $user->data['user_notify_type']),
- 'dateformat' => request_var('dateformat', $user->data['user_dateformat'], true),
- 'lang' => basename(request_var('lang', $user->data['user_lang'])),
- 'user_style' => request_var('user_style', (int) $user->data['user_style']),
- 'tz' => request_var('tz', $user->data['user_timezone']),
-
- 'viewemail' => request_var('viewemail', (bool) $user->data['user_allow_viewemail']),
- 'massemail' => request_var('massemail', (bool) $user->data['user_allow_massemail']),
- 'hideonline' => request_var('hideonline', (bool) !$user->data['user_allow_viewonline']),
- 'allowpm' => request_var('allowpm', (bool) $user->data['user_allow_pm']),
+ 'notifymethod' => $request->variable('notifymethod', $user->data['user_notify_type']),
+ 'dateformat' => $request->variable('dateformat', $user->data['user_dateformat'], true),
+ 'lang' => basename($request->variable('lang', $user->data['user_lang'])),
+ 'user_style' => $request->variable('user_style', (int) $user->data['user_style']),
+ 'tz' => $request->variable('tz', $user->data['user_timezone']),
+
+ 'viewemail' => $request->variable('viewemail', (bool) $user->data['user_allow_viewemail']),
+ 'massemail' => $request->variable('massemail', (bool) $user->data['user_allow_massemail']),
+ 'hideonline' => $request->variable('hideonline', (bool) !$user->data['user_allow_viewonline']),
+ 'allowpm' => $request->variable('allowpm', (bool) $user->data['user_allow_pm']),
);
if ($data['notifymethod'] == NOTIFY_IM && (!$config['jab_enable'] || !$user->data['user_jabber'] || !@extension_loaded('xml')))
@@ -96,7 +96,7 @@ class ucp_prefs
$error[] = 'FORM_INVALID';
}
- if (!sizeof($error))
+ if (!count($error))
{
$sql_ary = array(
'user_allow_pm' => $data['allowpm'],
@@ -188,7 +188,7 @@ class ucp_prefs
$db->sql_freeresult($result);
$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'S_NOTIFY_EMAIL' => ($data['notifymethod'] == NOTIFY_EMAIL) ? true : false,
'S_NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false,
@@ -221,20 +221,20 @@ class ucp_prefs
add_form_key('ucp_prefs_view');
$data = array(
- 'topic_sk' => request_var('topic_sk', (!empty($user->data['user_topic_sortby_type'])) ? $user->data['user_topic_sortby_type'] : 't'),
- 'topic_sd' => request_var('topic_sd', (!empty($user->data['user_topic_sortby_dir'])) ? $user->data['user_topic_sortby_dir'] : 'd'),
- 'topic_st' => request_var('topic_st', (!empty($user->data['user_topic_show_days'])) ? (int) $user->data['user_topic_show_days'] : 0),
-
- 'post_sk' => request_var('post_sk', (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't'),
- 'post_sd' => request_var('post_sd', (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a'),
- 'post_st' => request_var('post_st', (!empty($user->data['user_post_show_days'])) ? (int) $user->data['user_post_show_days'] : 0),
-
- 'images' => request_var('images', (bool) $user->optionget('viewimg')),
- 'flash' => request_var('flash', (bool) $user->optionget('viewflash')),
- 'smilies' => request_var('smilies', (bool) $user->optionget('viewsmilies')),
- 'sigs' => request_var('sigs', (bool) $user->optionget('viewsigs')),
- 'avatars' => request_var('avatars', (bool) $user->optionget('viewavatars')),
- 'wordcensor' => request_var('wordcensor', (bool) $user->optionget('viewcensors')),
+ 'topic_sk' => $request->variable('topic_sk', (!empty($user->data['user_topic_sortby_type'])) ? $user->data['user_topic_sortby_type'] : 't'),
+ 'topic_sd' => $request->variable('topic_sd', (!empty($user->data['user_topic_sortby_dir'])) ? $user->data['user_topic_sortby_dir'] : 'd'),
+ 'topic_st' => $request->variable('topic_st', (!empty($user->data['user_topic_show_days'])) ? (int) $user->data['user_topic_show_days'] : 0),
+
+ 'post_sk' => $request->variable('post_sk', (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't'),
+ 'post_sd' => $request->variable('post_sd', (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a'),
+ 'post_st' => $request->variable('post_st', (!empty($user->data['user_post_show_days'])) ? (int) $user->data['user_post_show_days'] : 0),
+
+ 'images' => $request->variable('images', (bool) $user->optionget('viewimg')),
+ 'flash' => $request->variable('flash', (bool) $user->optionget('viewflash')),
+ 'smilies' => $request->variable('smilies', (bool) $user->optionget('viewsmilies')),
+ 'sigs' => $request->variable('sigs', (bool) $user->optionget('viewsigs')),
+ 'avatars' => $request->variable('avatars', (bool) $user->optionget('viewavatars')),
+ 'wordcensor' => $request->variable('wordcensor', (bool) $user->optionget('viewcensors')),
);
/**
@@ -277,7 +277,7 @@ class ucp_prefs
$error[] = 'FORM_INVALID';
}
- if (!sizeof($error))
+ if (!count($error))
{
$user->optionset('viewimg', $data['images']);
$user->optionset('viewflash', $data['flash']);
@@ -412,7 +412,7 @@ class ucp_prefs
extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_view_after', compact($vars)));
$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'S_IMAGES' => $data['images'],
'S_FLASH' => $data['flash'],
@@ -436,10 +436,10 @@ class ucp_prefs
case 'post':
$data = array(
- 'bbcode' => request_var('bbcode', $user->optionget('bbcode')),
- 'smilies' => request_var('smilies', $user->optionget('smilies')),
- 'sig' => request_var('sig', $user->optionget('attachsig')),
- 'notify' => request_var('notify', (bool) $user->data['user_notify']),
+ 'bbcode' => $request->variable('bbcode', $user->optionget('bbcode')),
+ 'smilies' => $request->variable('smilies', $user->optionget('smilies')),
+ 'sig' => $request->variable('sig', $user->optionget('attachsig')),
+ 'notify' => $request->variable('notify', (bool) $user->data['user_notify']),
);
add_form_key('ucp_prefs_post');
diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php
index 4a3d8133b3..36ab3d0463 100644
--- a/phpBB/includes/ucp/ucp_profile.php
+++ b/phpBB/includes/ucp/ucp_profile.php
@@ -31,14 +31,12 @@ class ucp_profile
function main($id, $mode)
{
- global $cache, $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
- global $request, $phpbb_container, $phpbb_dispatcher;
+ global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
+ global $request, $phpbb_container, $phpbb_log, $phpbb_dispatcher;
$user->add_lang('posting');
- $preview = $request->variable('preview', false, false, \phpbb\request\request_interface::POST);
$submit = $request->variable('submit', false, false, \phpbb\request\request_interface::POST);
- $delete = $request->variable('delete', false, false, \phpbb\request\request_interface::POST);
$error = $data = array();
$s_hidden_fields = '';
@@ -47,8 +45,8 @@ class ucp_profile
case 'reg_details':
$data = array(
- 'username' => utf8_normalize_nfc(request_var('username', $user->data['username'], true)),
- 'email' => strtolower(request_var('email', $user->data['user_email'])),
+ 'username' => $request->variable('username', $user->data['username'], true),
+ 'email' => strtolower($request->variable('email', $user->data['user_email'])),
'new_password' => $request->variable('new_password', '', true),
'cur_password' => $request->variable('cur_password', '', true),
'password_confirm' => $request->variable('password_confirm', '', true),
@@ -96,10 +94,11 @@ class ucp_profile
}
// Instantiate passwords manager
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
// Only check the new password against the previous password if there have been no errors
- if (!sizeof($error) && $auth->acl_get('u_chgpasswd') && $data['new_password'] && $passwords_manager->check($data['new_password'], $user->data['user_password']))
+ if (!count($error) && $auth->acl_get('u_chgpasswd') && $data['new_password'] && $passwords_manager->check($data['new_password'], $user->data['user_password']))
{
$error[] = 'SAME_PASSWORD_ERROR';
}
@@ -126,7 +125,7 @@ class ucp_profile
$vars = array('data', 'submit', 'error');
extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_validate', compact($vars)));
- if (!sizeof($error))
+ if (!count($error))
{
$sql_ary = array(
'username' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? $data['username'] : $user->data['username'],
@@ -134,23 +133,36 @@ class ucp_profile
'user_email' => ($auth->acl_get('u_chgemail')) ? $data['email'] : $user->data['user_email'],
'user_email_hash' => ($auth->acl_get('u_chgemail')) ? phpbb_email_hash($data['email']) : $user->data['user_email_hash'],
'user_password' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? $passwords_manager->hash($data['new_password']) : $user->data['user_password'],
- 'user_passchg' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? time() : 0,
);
if ($auth->acl_get('u_chgname') && $config['allow_namechange'] && $data['username'] != $user->data['username'])
{
- add_log('user', $user->data['user_id'], 'LOG_USER_UPDATE_NAME', $user->data['username'], $data['username']);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_UPDATE_NAME', false, array(
+ 'reportee_id' => $user->data['user_id'],
+ $user->data['username'],
+ $data['username']
+ ));
}
if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && !$passwords_manager->check($data['new_password'], $user->data['user_password']))
{
+ $sql_ary['user_passchg'] = time();
+
$user->reset_login_keys();
- add_log('user', $user->data['user_id'], 'LOG_USER_NEW_PASSWORD', $data['username']);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_NEW_PASSWORD', false, array(
+ 'reportee_id' => $user->data['user_id'],
+ $user->data['username']
+ ));
}
if ($auth->acl_get('u_chgemail') && $data['email'] != $user->data['user_email'])
{
- add_log('user', $user->data['user_id'], 'LOG_USER_UPDATE_EMAIL', $data['username'], $user->data['user_email'], $data['email']);
+ $phpbb_log->add('user', $user->data['user_id'], $user->ip, 'LOG_USER_UPDATE_EMAIL', false, array(
+ 'reportee_id' => $user->data['user_id'],
+ $user->data['username'],
+ $user->data['user_email'],
+ $data['email']
+ ));
}
$message = 'PROFILE_UPDATED';
@@ -209,7 +221,7 @@ class ucp_profile
$vars = array('data', 'sql_ary');
extract($phpbb_dispatcher->trigger_event('core.ucp_profile_reg_details_sql_ary', compact($vars)));
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
@@ -246,7 +258,7 @@ class ucp_profile
}
$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'USERNAME' => $data['username'],
'EMAIL' => $data['email'],
@@ -268,15 +280,17 @@ class ucp_profile
// Do not display profile information panel if not authed to do so
if (!$auth->acl_get('u_chgprofileinfo'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_PROFILEINFO');
}
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$cp_data = $cp_error = array();
$data = array(
- 'jabber' => utf8_normalize_nfc(request_var('jabber', $user->data['user_jabber'], true)),
+ 'jabber' => $request->variable('jabber', $user->data['user_jabber'], true),
);
if ($config['allow_birthdays'])
@@ -288,9 +302,9 @@ class ucp_profile
list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user->data['user_birthday']);
}
- $data['bday_day'] = request_var('bday_day', $data['bday_day']);
- $data['bday_month'] = request_var('bday_month', $data['bday_month']);
- $data['bday_year'] = request_var('bday_year', $data['bday_year']);
+ $data['bday_day'] = $request->variable('bday_day', $data['bday_day']);
+ $data['bday_month'] = $request->variable('bday_month', $data['bday_month']);
+ $data['bday_year'] = $request->variable('bday_year', $data['bday_year']);
$data['user_birthday'] = sprintf('%2d-%2d-%4d', $data['bday_day'], $data['bday_month'], $data['bday_year']);
}
@@ -330,7 +344,7 @@ class ucp_profile
// validate custom profile fields
$cp->submit_cp_field('profile', $user->get_iso_lang_id(), $cp_data, $cp_error);
- if (sizeof($cp_error))
+ if (count($cp_error))
{
$error = array_merge($error, $cp_error);
}
@@ -352,7 +366,7 @@ class ucp_profile
$vars = array('data', 'submit', 'error');
extract($phpbb_dispatcher->trigger_event('core.ucp_profile_validate_profile_info', compact($vars)));
- if (!sizeof($error))
+ if (!count($error))
{
$data['notify'] = $user->data['user_notify_type'];
@@ -417,7 +431,6 @@ class ucp_profile
$selected = ($i == $data['bday_month']) ? ' selected="selected"' : '';
$s_birthday_month_options .= "<option value=\"$i\"$selected>$i</option>";
}
- $s_birthday_year_options = '';
$now = getdate();
$s_birthday_year_options = '<option value="0"' . ((!$data['bday_year']) ? ' selected="selected"' : '') . '>--</option>';
@@ -437,7 +450,7 @@ class ucp_profile
}
$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'S_JABBER_ENABLED' => $config['jab_enable'],
'JABBER' => $data['jabber'],
));
@@ -453,128 +466,151 @@ class ucp_profile
if (!$auth->acl_get('u_sig'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_AUTH_SIGNATURE');
}
- include($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ if (!function_exists('generate_smilies'))
+ {
+ include($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
+ }
+
+ if (!function_exists('display_custom_bbcodes'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
+
+ $preview = $request->is_set_post('preview');
- $enable_bbcode = ($config['allow_sig_bbcode']) ? (bool) $user->optionget('sig_bbcode') : false;
- $enable_smilies = ($config['allow_sig_smilies']) ? (bool) $user->optionget('sig_smilies') : false;
- $enable_urls = ($config['allow_sig_links']) ? (bool) $user->optionget('sig_links') : false;
+ $enable_bbcode = ($config['allow_sig_bbcode']) ? $user->optionget('sig_bbcode') : false;
+ $enable_smilies = ($config['allow_sig_smilies']) ? $user->optionget('sig_smilies') : false;
+ $enable_urls = ($config['allow_sig_links']) ? $user->optionget('sig_links') : false;
- $signature = utf8_normalize_nfc(request_var('signature', (string) $user->data['user_sig'], true));
+ $bbcode_flags = ($enable_bbcode ? OPTION_FLAG_BBCODE : 0) + ($enable_smilies ? OPTION_FLAG_SMILIES : 0) + ($enable_urls ? OPTION_FLAG_LINKS : 0);
- add_form_key('ucp_sig');
+ $decoded_message = generate_text_for_edit($user->data['user_sig'], $user->data['user_sig_bbcode_uid'], $bbcode_flags);
+ $signature = $request->variable('signature', $decoded_message['text'], true);
+ $signature_preview = '';
if ($submit || $preview)
{
- include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
+ $enable_bbcode = ($config['allow_sig_bbcode']) ? !$request->variable('disable_bbcode', false) : false;
+ $enable_smilies = ($config['allow_sig_smilies']) ? !$request->variable('disable_smilies', false) : false;
+ $enable_urls = ($config['allow_sig_links']) ? !$request->variable('disable_magic_url', false) : false;
+
+ if (!check_form_key('ucp_sig'))
+ {
+ $error[] = 'FORM_INVALID';
+ }
+ }
- $enable_bbcode = ($config['allow_sig_bbcode']) ? ((request_var('disable_bbcode', false)) ? false : true) : false;
- $enable_smilies = ($config['allow_sig_smilies']) ? ((request_var('disable_smilies', false)) ? false : true) : false;
- $enable_urls = ($config['allow_sig_links']) ? ((request_var('disable_magic_url', false)) ? false : true) : false;
+ /**
+ * Modify user signature on editing profile in UCP
+ *
+ * @event core.ucp_profile_modify_signature
+ * @var bool enable_bbcode Whether or not bbcode is enabled
+ * @var bool enable_smilies Whether or not smilies are enabled
+ * @var bool enable_urls Whether or not urls are enabled
+ * @var string signature Users signature text
+ * @var array error Any error strings
+ * @var bool submit Whether or not the form has been sumitted
+ * @var bool preview Whether or not the signature is being previewed
+ * @since 3.1.10-RC1
+ * @changed 3.2.0-RC2 Removed message parser
+ */
+ $vars = array(
+ 'enable_bbcode',
+ 'enable_smilies',
+ 'enable_urls',
+ 'signature',
+ 'error',
+ 'submit',
+ 'preview',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_signature', compact($vars)));
+
+ $bbcode_uid = $bbcode_bitfield = $bbcode_flags = '';
+ $warn_msg = generate_text_for_storage(
+ $signature,
+ $bbcode_uid,
+ $bbcode_bitfield,
+ $bbcode_flags,
+ $enable_bbcode,
+ $enable_urls,
+ $enable_smilies,
+ $config['allow_sig_img'],
+ $config['allow_sig_flash'],
+ true,
+ $config['allow_sig_links'],
+ 'sig'
+ );
+
+ if (count($warn_msg))
+ {
+ $error += $warn_msg;
+ }
- if (!sizeof($error))
+ if (!$submit)
+ {
+ // Parse it for displaying
+ $signature_preview = generate_text_for_display($signature, $bbcode_uid, $bbcode_bitfield, $bbcode_flags);
+ }
+ else
+ {
+ if (!count($error))
{
- $message_parser = new parse_message($signature);
+ $user->optionset('sig_bbcode', $enable_bbcode);
+ $user->optionset('sig_smilies', $enable_smilies);
+ $user->optionset('sig_links', $enable_urls);
+
+ $sql_ary = array(
+ 'user_sig' => $signature,
+ 'user_options' => $user->data['user_options'],
+ 'user_sig_bbcode_uid' => $bbcode_uid,
+ 'user_sig_bbcode_bitfield' => $bbcode_bitfield
+ );
/**
- * Modify user signature on editing profile in UCP
+ * Modify user registration data before submitting it to the database
*
- * @event core.ucp_profile_modify_signature
- * @var bool enable_bbcode Whether or not bbcode is enabled
- * @var bool enable_smilies Whether or not smilies are enabled
- * @var bool enable_urls Whether or not urls are enabled
- * @var string signature Users signature text
- * @var object message_parser The message parser object
- * @var array error Any error strings
- * @var bool submit Whether or not the form has been sumitted
- * @var bool preview Whether or not the signature is being previewed
+ * @event core.ucp_profile_modify_signature_sql_ary
+ * @var array sql_ary Array with user signature data to submit to the database
* @since 3.1.10-RC1
*/
- $vars = array(
- 'enable_bbcode',
- 'enable_smilies',
- 'enable_urls',
- 'signature',
- 'message_parser',
- 'error',
- 'submit',
- 'preview',
- );
- extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_signature', compact($vars)));
+ $vars = array('sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_signature_sql_ary', compact($vars)));
- // Allowing Quote BBCode
- $message_parser->parse($enable_bbcode, $enable_urls, $enable_smilies, $config['allow_sig_img'], $config['allow_sig_flash'], true, $config['allow_sig_links'], true, 'sig');
-
- if (sizeof($message_parser->warn_msg))
- {
- $error[] = implode('<br />', $message_parser->warn_msg);
- }
-
- if (!check_form_key('ucp_sig'))
- {
- $error[] = 'FORM_INVALID';
- }
-
- if (!sizeof($error) && $submit)
- {
- $user->optionset('sig_bbcode', $enable_bbcode);
- $user->optionset('sig_smilies', $enable_smilies);
- $user->optionset('sig_links', $enable_urls);
-
- $sql_ary = array(
- 'user_sig' => (string) $message_parser->message,
- 'user_options' => $user->data['user_options'],
- 'user_sig_bbcode_uid' => (string) $message_parser->bbcode_uid,
- 'user_sig_bbcode_bitfield' => $message_parser->bbcode_bitfield
- );
-
- /**
- * Modify user registration data before submitting it to the database
- *
- * @event core.ucp_profile_modify_signature_sql_ary
- * @var array sql_ary Array with user signature data to submit to the database
- * @since 3.1.10-RC1
- */
- $vars = array('sql_ary');
- extract($phpbb_dispatcher->trigger_event('core.ucp_profile_modify_signature_sql_ary', compact($vars)));
-
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
- WHERE user_id = ' . $user->data['user_id'];
- $db->sql_query($sql);
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
+ WHERE user_id = ' . $user->data['user_id'];
+ $db->sql_query($sql);
- $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
- trigger_error($message);
- }
+ $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ trigger_error($message);
}
-
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $error);
}
- $signature_preview = '';
- if ($preview)
+ // Replace "error" strings with their real, localised form
+ $error = array_map(array($user, 'lang'), $error);
+
+ if ($request->is_set_post('preview'))
{
- // Now parse it for displaying
- $signature_preview = $message_parser->format_display($enable_bbcode, $enable_urls, $enable_smilies, false);
- unset($message_parser);
+ $decoded_message = generate_text_for_edit($signature, $bbcode_uid, $bbcode_flags);
}
- decode_message($signature, $user->data['user_sig_bbcode_uid']);
+ /** @var \phpbb\controller\helper $controller_helper */
+ $controller_helper = $phpbb_container->get('controller.helper');
$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
- 'SIGNATURE' => $signature,
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
+ 'SIGNATURE' => $decoded_message['text'],
'SIGNATURE_PREVIEW' => $signature_preview,
'S_BBCODE_CHECKED' => (!$enable_bbcode) ? ' checked="checked"' : '',
'S_SMILIES_CHECKED' => (!$enable_smilies) ? ' checked="checked"' : '',
'S_MAGIC_URL_CHECKED' => (!$enable_urls) ? ' checked="checked"' : '',
- 'BBCODE_STATUS' => ($config['allow_sig_bbcode']) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'),
+ 'BBCODE_STATUS' => $user->lang(($config['allow_sig_bbcode'] ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '<a href="' . $controller_helper->route('phpbb_help_bbcode_controller') . '">', '</a>'),
'SMILIES_STATUS' => ($config['allow_sig_smilies']) ? $user->lang['SMILIES_ARE_ON'] : $user->lang['SMILIES_ARE_OFF'],
'IMG_STATUS' => ($config['allow_sig_img']) ? $user->lang['IMAGES_ARE_ON'] : $user->lang['IMAGES_ARE_OFF'],
'FLASH_STATUS' => ($config['allow_sig_flash']) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'],
@@ -590,6 +626,8 @@ class ucp_profile
'S_LINKS_ALLOWED' => ($config['allow_sig_links']) ? true : false)
);
+ add_form_key('ucp_sig');
+
// Build custom bbcodes array
display_custom_bbcodes();
@@ -606,6 +644,7 @@ class ucp_profile
if ($config['allow_avatar'] && $auth->acl_get('u_chgavatar'))
{
+ /* @var $phpbb_avatar_manager \phpbb\avatar\manager */
$phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
$avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
@@ -722,7 +761,7 @@ class ucp_profile
$avatar = phpbb_get_user_avatar($user->data, 'USER_AVATAR', true);
$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'AVATAR' => $avatar,
'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
@@ -740,14 +779,14 @@ class ucp_profile
if ($submit)
{
- $keys = request_var('keys', array(''));
+ $keys = $request->variable('keys', array(''));
if (!check_form_key('ucp_autologin_keys'))
{
$error[] = 'FORM_INVALID';
}
- if (!sizeof($error))
+ if (!count($error))
{
if (!empty($keys))
{
@@ -794,7 +833,7 @@ class ucp_profile
}
$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'L_TITLE' => $user->lang['UCP_PROFILE_' . strtoupper($mode)],
diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php
index 52ed410b04..03ac63b12b 100644
--- a/phpBB/includes/ucp/ucp_register.php
+++ b/phpBB/includes/ucp/ucp_register.php
@@ -29,7 +29,7 @@ class ucp_register
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
+ global $config, $db, $user, $template, $phpbb_root_path, $phpEx;
global $request, $phpbb_container, $phpbb_dispatcher;
//
@@ -39,11 +39,22 @@ class ucp_register
trigger_error('UCP_REGISTER_DISABLE');
}
- $coppa = $request->is_set('coppa') ? (int) $request->variable('coppa', false) : false;
+ $coppa = $request->is_set('coppa_yes') ? 1 : ($request->is_set('coppa_no') ? 0 : false);
+ $coppa = $request->is_set('coppa') ? $request->variable('coppa', 0) : $coppa;
$agreed = $request->variable('agreed', false);
$submit = $request->is_set_post('submit');
- $change_lang = request_var('change_lang', '');
- $user_lang = request_var('lang', $user->lang_name);
+ $change_lang = $request->variable('change_lang', '');
+ $user_lang = $request->variable('lang', $user->lang_name);
+
+ if ($agreed && !check_form_key('ucp_register'))
+ {
+ $agreed = false;
+ }
+
+ if ($coppa !== false && !check_form_key('ucp_register'))
+ {
+ $coppa = false;
+ }
/**
* Add UCP register data before they are assigned to the template or submitted
@@ -67,14 +78,7 @@ class ucp_register
);
extract($phpbb_dispatcher->trigger_event('core.ucp_register_requests_after', compact($vars)));
- if ($agreed)
- {
- add_form_key('ucp_register');
- }
- else
- {
- add_form_key('ucp_register_terms');
- }
+ add_form_key('ucp_register');
if ($change_lang || $user_lang != $config['default_lang'])
{
@@ -99,6 +103,7 @@ class ucp_register
}
}
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$error = $cp_data = $cp_error = array();
@@ -110,6 +115,7 @@ class ucp_register
if (!empty($login_link_data))
{
// Confirm that we have all necessary data
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$auth_provider = $provider_collection->get_provider($request->variable('auth_provider', ''));
@@ -135,10 +141,10 @@ class ucp_register
{
// We do not include the password
$s_hidden_fields = array_merge($s_hidden_fields, array(
- 'username' => utf8_normalize_nfc(request_var('username', '', true)),
- 'email' => strtolower(request_var('email', '')),
+ 'username' => $request->variable('username', '', true),
+ 'email' => strtolower($request->variable('email', '')),
'lang' => $user->lang_name,
- 'tz' => request_var('tz', $config['board_timezone']),
+ 'tz' => $request->variable('tz', $config['board_timezone']),
));
}
@@ -164,13 +170,10 @@ class ucp_register
->format($user->lang['DATE_FORMAT'], true);
unset($now);
- $template->assign_vars(array(
- 'S_LANG_OPTIONS' => (sizeof($lang_row) > 1) ? language_select($user_lang) : '',
- 'L_COPPA_NO' => sprintf($user->lang['UCP_COPPA_BEFORE'], $coppa_birthday),
- 'L_COPPA_YES' => sprintf($user->lang['UCP_COPPA_ON_AFTER'], $coppa_birthday),
-
- 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&amp;coppa=0'),
- 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&amp;coppa=1'),
+ $template_vars = array(
+ 'S_LANG_OPTIONS' => (count($lang_row) > 1) ? language_select($user_lang) : '',
+ 'L_COPPA_NO' => $user->lang('UCP_COPPA_BEFORE', $coppa_birthday),
+ 'L_COPPA_YES' => $user->lang('UCP_COPPA_ON_AFTER', $coppa_birthday),
'S_SHOW_COPPA' => true,
'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields),
@@ -178,12 +181,12 @@ class ucp_register
'COOKIE_NAME' => $config['cookie_name'],
'COOKIE_PATH' => $config['cookie_path'],
- ));
+ );
}
else
{
- $template->assign_vars(array(
- 'S_LANG_OPTIONS' => (sizeof($lang_row) > 1) ? language_select($user_lang) : '',
+ $template_vars = array(
+ 'S_LANG_OPTIONS' => (count($lang_row) > 1) ? language_select($user_lang) : '',
'L_TERMS_OF_USE' => sprintf($user->lang['TERMS_OF_USE_CONTENT'], $config['sitename'], generate_board_url()),
'S_SHOW_COPPA' => false,
@@ -193,11 +196,32 @@ class ucp_register
'COOKIE_NAME' => $config['cookie_name'],
'COOKIE_PATH' => $config['cookie_path'],
- )
);
}
+
+ $tpl_name = 'ucp_agreement';
+
+ /**
+ * Allows to modify the agreements.
+ *
+ * @event core.ucp_register_agreement_modify_template_data
+ * @var string tpl_name Template file
+ * @var array template_vars Array with data about to be assigned to the template
+ * @var array s_hidden_fields Array with hidden form elements
+ * @var array lang_row Array with available languages, read only
+ * @since 3.2.2-RC1
+ */
+ $vars = array('tpl_name', 'template_vars', 's_hidden_fields', 'lang_row');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_register_agreement_modify_template_data', compact($vars)));
+
unset($lang_row);
+ $template_vars = array_merge($template_vars, array(
+ 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields),
+ ));
+
+ $template->assign_vars($template_vars);
+
/**
* Allows to modify the agreements.
*
@@ -205,10 +229,11 @@ class ucp_register
*
* @event core.ucp_register_agreement
* @since 3.1.6-RC1
+ * @deprecated 3.2.2-RC1 Replaced by core.ucp_register_agreement_modify_template_data and to be removed in 3.3.0-RC1
*/
$phpbb_dispatcher->dispatch('core.ucp_register_agreement');
- $this->tpl_name = 'ucp_agreement';
+ $this->tpl_name = $tpl_name;
return;
}
@@ -222,12 +247,12 @@ class ucp_register
$timezone = $config['board_timezone'];
$data = array(
- 'username' => utf8_normalize_nfc(request_var('username', '', true)),
+ 'username' => $request->variable('username', '', true),
'new_password' => $request->variable('new_password', '', true),
'password_confirm' => $request->variable('password_confirm', '', true),
- 'email' => strtolower(request_var('email', '')),
- 'lang' => basename(request_var('lang', $user->lang_name)),
- 'tz' => request_var('tz', $timezone),
+ 'email' => strtolower($request->variable('email', '')),
+ 'lang' => basename($request->variable('lang', $user->lang_name)),
+ 'tz' => $request->variable('tz', $timezone),
);
/**
* Add UCP register data before they are assigned to the template or submitted
@@ -295,7 +320,7 @@ class ucp_register
// validate custom profile fields
$cp->submit_cp_field('register', $user->get_iso_lang_id(), $cp_data, $error);
- if (!sizeof($error))
+ if (!count($error))
{
if ($data['new_password'] != $data['password_confirm'])
{
@@ -316,7 +341,7 @@ class ucp_register
$vars = array('submit', 'data', 'cp_data', 'error');
extract($phpbb_dispatcher->trigger_event('core.ucp_register_data_after', compact($vars)));
- if (!sizeof($error))
+ if (!count($error))
{
$server_url = generate_board_url();
@@ -356,6 +381,7 @@ class ucp_register
}
// Instantiate passwords manager
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $phpbb_container->get('passwords.manager');
$user_row = array(
@@ -456,11 +482,38 @@ class ucp_register
);
}
+ /**
+ * Modify messenger data before welcome mail is sent
+ *
+ * @event core.ucp_register_welcome_email_before
+ * @var array user_row Array with user registration data
+ * @var array cp_data Array with custom profile fields data
+ * @var array data Array with current ucp registration data
+ * @var string message Message to be displayed to the user after registration
+ * @var string server_url Server URL
+ * @var int user_id New user ID
+ * @var string user_actkey User activation key
+ * @var messenger messenger phpBB Messenger
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'user_row',
+ 'cp_data',
+ 'data',
+ 'message',
+ 'server_url',
+ 'user_id',
+ 'user_actkey',
+ 'messenger',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.ucp_register_welcome_email_before', compact($vars)));
+
$messenger->send(NOTIFY_EMAIL);
}
if ($config['require_activation'] == USER_ACTIVATION_ADMIN)
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
$phpbb_notifications->add_notifications('notification.type.admin_activate_user', array(
'user_id' => $user_id,
@@ -482,6 +535,30 @@ class ucp_register
}
}
+ /**
+ * Perform additional actions after user registration
+ *
+ * @event core.ucp_register_register_after
+ * @var array user_row Array with user registration data
+ * @var array cp_data Array with custom profile fields data
+ * @var array data Array with current ucp registration data
+ * @var string message Message to be displayed to the user after registration
+ * @var string server_url Server URL
+ * @var int user_id New user ID
+ * @var string user_actkey User activation key
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'user_row',
+ 'cp_data',
+ 'data',
+ 'message',
+ 'server_url',
+ 'user_id',
+ 'user_actkey',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.ucp_register_register_after', compact($vars)));
+
$message = $message . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
trigger_error($message);
}
@@ -501,8 +578,6 @@ class ucp_register
{
$s_hidden_fields = array_merge($s_hidden_fields, $captcha->get_hidden_fields());
}
- $s_hidden_fields = build_hidden_fields($s_hidden_fields);
- $confirm_image = '';
// Visual Confirmation - Show images
if ($config['enable_confirm'])
@@ -525,9 +600,10 @@ class ucp_register
break;
}
- $timezone_selects = phpbb_timezone_select($template, $user, $data['tz'], true);
- $template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ // Assign template vars for timezone select
+ phpbb_timezone_select($template, $user, $data['tz'], true);
+
+ $template_vars = array(
'USERNAME' => $data['username'],
'PASSWORD' => $data['new_password'],
'PASSWORD_CONFIRM' => $data['password_confirm'],
@@ -542,13 +618,41 @@ class ucp_register
'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false,
'S_REGISTRATION' => true,
'S_COPPA' => $coppa,
- 'S_HIDDEN_FIELDS' => $s_hidden_fields,
'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'),
'COOKIE_NAME' => $config['cookie_name'],
'COOKIE_PATH' => $config['cookie_path'],
+ );
+
+ $tpl_name = 'ucp_register';
+
+ /**
+ * Modify template data on the registration page
+ *
+ * @event core.ucp_register_modify_template_data
+ * @var array template_vars Array with template data
+ * @var array data Array with user data, read only
+ * @var array error Array with errors
+ * @var array s_hidden_fields Array with hidden field elements
+ * @var string tpl_name Template name
+ * @since 3.2.2-RC1
+ */
+ $vars = array(
+ 'template_vars',
+ 'data',
+ 'error',
+ 's_hidden_fields',
+ 'tpl_name',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.ucp_register_modify_template_data', compact($vars)));
+
+ $template_vars = array_merge($template_vars, array(
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
+ 'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields),
));
+ $template->assign_vars($template_vars);
+
//
$user->profile_fields = array();
@@ -556,8 +660,7 @@ class ucp_register
$cp->generate_profile_fields('register', $user->get_iso_lang_id());
//
- $this->tpl_name = 'ucp_register';
- $this->page_title = 'UCP_REGISTRATION';
+ $this->tpl_name = $tpl_name;
}
/**
diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php
index 497bf6a2c4..e50428bfea 100644
--- a/phpBB/includes/ucp/ucp_remind.php
+++ b/phpBB/includes/ucp/ucp_remind.php
@@ -29,16 +29,16 @@ class ucp_remind
function main($id, $mode)
{
- global $config, $phpbb_root_path, $phpEx;
- global $db, $user, $auth, $template, $phpbb_container, $phpbb_dispatcher;
+ global $config, $phpbb_root_path, $phpEx, $request;
+ global $db, $user, $template, $phpbb_container, $phpbb_dispatcher;
if (!$config['allow_password_reset'])
{
trigger_error($user->lang('UCP_PASSWORD_RESET_DISABLED', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'));
}
- $username = request_var('username', '', true);
- $email = strtolower(request_var('email', ''));
+ $username = $request->variable('username', '', true);
+ $email = strtolower($request->variable('email', ''));
$submit = (isset($_POST['submit'])) ? true : false;
add_form_key('ucp_remind');
@@ -50,11 +50,16 @@ class ucp_remind
trigger_error('FORM_INVALID');
}
+ if (empty($email))
+ {
+ trigger_error('NO_EMAIL_USER');
+ }
+
$sql_array = array(
'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type, user_lang, user_inactive_reason',
'FROM' => array(USERS_TABLE => 'u'),
- 'WHERE' => "user_email_hash = '" . $db->sql_escape(phpbb_email_hash($email)) . "'
- AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"
+ 'WHERE' => "user_email_hash = '" . $db->sql_escape(phpbb_email_hash($email)) . "'" .
+ (!empty($username) ? " AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'" : ''),
);
/**
@@ -74,80 +79,87 @@ class ucp_remind
extract($phpbb_dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars)));
$sql = $db->sql_build_query('SELECT', $sql_array);
- $result = $db->sql_query($sql);
- $user_row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
+ $result = $db->sql_query_limit($sql, 2); // don't waste resources on more rows than we need
+ $rowset = $db->sql_fetchrowset($result);
- if (!$user_row)
+ if (count($rowset) > 1)
{
- trigger_error('NO_EMAIL_USER');
- }
+ $db->sql_freeresult($result);
- if ($user_row['user_type'] == USER_IGNORE)
- {
- trigger_error('NO_USER');
+ $template->assign_vars(array(
+ 'USERNAME_REQUIRED' => true,
+ 'EMAIL' => $email,
+ ));
}
-
- if ($user_row['user_type'] == USER_INACTIVE)
+ else
{
- if ($user_row['user_inactive_reason'] == INACTIVE_MANUAL)
+ $message = $user->lang['PASSWORD_UPDATED_IF_EXISTED'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
+
+ if (empty($rowset))
{
- trigger_error('ACCOUNT_DEACTIVATED');
+ trigger_error($message);
}
- else
+
+ $user_row = $rowset[0];
+ $db->sql_freeresult($result);
+
+ if (!$user_row)
{
- trigger_error('ACCOUNT_NOT_ACTIVATED');
+ trigger_error($message);
}
- }
- // Check users permissions
- $auth2 = new \phpbb\auth\auth();
- $auth2->acl($user_row);
+ if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE)
+ {
+ trigger_error($message);
+ }
- if (!$auth2->acl_get('u_chgpasswd'))
- {
- trigger_error('NO_AUTH_PASSWORD_REMINDER');
- }
+ // Check users permissions
+ $auth2 = new \phpbb\auth\auth();
+ $auth2->acl($user_row);
- $server_url = generate_board_url();
+ if (!$auth2->acl_get('u_chgpasswd'))
+ {
+ trigger_error($message);
+ }
- // Make password at least 8 characters long, make it longer if admin wants to.
- // gen_rand_string() however has a limit of 12 or 13.
- $user_password = gen_rand_string_friendly(max(8, mt_rand((int) $config['min_pass_chars'], (int) $config['max_pass_chars'])));
+ $server_url = generate_board_url();
- // For the activation key a random length between 6 and 10 will do.
- $user_actkey = gen_rand_string(mt_rand(6, 10));
+ // Make password at least 8 characters long, make it longer if admin wants to.
+ // gen_rand_string() however has a limit of 12 or 13.
+ $user_password = gen_rand_string_friendly(max(8, mt_rand((int) $config['min_pass_chars'], (int) $config['max_pass_chars'])));
- // Instantiate passwords manager
- $passwords_manager = $phpbb_container->get('passwords.manager');
+ // For the activation key a random length between 6 and 10 will do.
+ $user_actkey = gen_rand_string(mt_rand(6, 10));
- $sql = 'UPDATE ' . USERS_TABLE . "
- SET user_newpasswd = '" . $db->sql_escape($passwords_manager->hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "'
- WHERE user_id = " . $user_row['user_id'];
- $db->sql_query($sql);
+ // Instantiate passwords manager
+ /* @var $manager \phpbb\passwords\manager */
+ $passwords_manager = $phpbb_container->get('passwords.manager');
- include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
+ $sql = 'UPDATE ' . USERS_TABLE . "
+ SET user_newpasswd = '" . $db->sql_escape($passwords_manager->hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "'
+ WHERE user_id = " . $user_row['user_id'];
+ $db->sql_query($sql);
- $messenger = new messenger(false);
+ include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $messenger->template('user_activate_passwd', $user_row['user_lang']);
+ $messenger = new messenger(false);
- $messenger->set_addresses($user_row);
+ $messenger->template('user_activate_passwd', $user_row['user_lang']);
- $messenger->anti_abuse_headers($config, $user);
+ $messenger->set_addresses($user_row);
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($user_row['username']),
- 'PASSWORD' => htmlspecialchars_decode($user_password),
- 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey")
- );
+ $messenger->anti_abuse_headers($config, $user);
- $messenger->send($user_row['user_notify_type']);
+ $messenger->assign_vars(array(
+ 'USERNAME' => htmlspecialchars_decode($user_row['username']),
+ 'PASSWORD' => htmlspecialchars_decode($user_password),
+ 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey")
+ );
- meta_refresh(3, append_sid("{$phpbb_root_path}index.$phpEx"));
+ $messenger->send($user_row['user_notify_type']);
- $message = $user->lang['PASSWORD_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
- trigger_error($message);
+ trigger_error($message);
+ }
}
$template->assign_vars(array(
diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php
index 9fe8850000..44c54100cd 100644
--- a/phpBB/includes/ucp/ucp_resend.php
+++ b/phpBB/includes/ucp/ucp_resend.php
@@ -30,10 +30,10 @@ class ucp_resend
function main($id, $mode)
{
global $config, $phpbb_root_path, $phpEx;
- global $db, $user, $auth, $template;
+ global $db, $user, $auth, $template, $request;
- $username = request_var('username', '', true);
- $email = strtolower(request_var('email', ''));
+ $username = $request->variable('username', '', true);
+ $email = strtolower($request->variable('email', ''));
$submit = (isset($_POST['submit'])) ? true : false;
add_form_key('ucp_resend');
diff --git a/phpBB/includes/ucp/ucp_zebra.php b/phpBB/includes/ucp/ucp_zebra.php
index dbf8cf31c1..b4c561fc76 100644
--- a/phpBB/includes/ucp/ucp_zebra.php
+++ b/phpBB/includes/ucp/ucp_zebra.php
@@ -25,7 +25,7 @@ class ucp_zebra
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher;
+ global $db, $user, $auth, $template, $phpbb_root_path, $phpEx, $request, $phpbb_dispatcher;
$submit = (isset($_POST['submit']) || isset($_GET['add']) || isset($_GET['remove'])) ? true : false;
$s_hidden_fields = '';
@@ -44,10 +44,10 @@ class ucp_zebra
foreach ($var_ary as $var => $default)
{
- $data[$var] = request_var($var, $default, true);
+ $data[$var] = $request->variable($var, $default, true);
}
- if (!empty($data['add']) || sizeof($data['usernames']))
+ if (!empty($data['add']) || count($data['usernames']))
{
if (confirm_box(true))
{
@@ -105,35 +105,35 @@ class ucp_zebra
$db->sql_freeresult($result);
// remove friends from the username array
- $n = sizeof($data['add']);
+ $n = count($data['add']);
$data['add'] = array_diff($data['add'], $friends);
- if (sizeof($data['add']) < $n && $mode == 'foes')
+ if (count($data['add']) < $n && $mode == 'foes')
{
$error[] = $user->lang['NOT_ADDED_FOES_FRIENDS'];
}
// remove foes from the username array
- $n = sizeof($data['add']);
+ $n = count($data['add']);
$data['add'] = array_diff($data['add'], $foes);
- if (sizeof($data['add']) < $n && $mode == 'friends')
+ if (count($data['add']) < $n && $mode == 'friends')
{
$error[] = $user->lang['NOT_ADDED_FRIENDS_FOES'];
}
// remove the user himself from the username array
- $n = sizeof($data['add']);
+ $n = count($data['add']);
$data['add'] = array_diff($data['add'], array(utf8_clean_string($user->data['username'])));
- if (sizeof($data['add']) < $n)
+ if (count($data['add']) < $n)
{
$error[] = $user->lang['NOT_ADDED_' . $l_mode . '_SELF'];
}
unset($friends, $foes, $n);
- if (sizeof($data['add']))
+ if (count($data['add']))
{
$sql = 'SELECT user_id, user_type
FROM ' . USERS_TABLE . '
@@ -159,7 +159,7 @@ class ucp_zebra
}
$db->sql_freeresult($result);
- if (sizeof($user_id_ary))
+ if (count($user_id_ary))
{
// Remove users from foe list if they are admins or moderators
if ($mode == 'foes')
@@ -175,7 +175,7 @@ class ucp_zebra
$perms = array_unique($perms);
- if (sizeof($perms))
+ if (count($perms))
{
$error[] = $user->lang['NOT_ADDED_FOES_MOD_ADMIN'];
}
@@ -185,7 +185,7 @@ class ucp_zebra
unset($perms);
}
- if (sizeof($user_id_ary))
+ if (count($user_id_ary))
{
$sql_mode = ($mode == 'friends') ? 'friend' : 'foe';
@@ -218,7 +218,7 @@ class ucp_zebra
}
unset($user_id_ary);
}
- else if (!sizeof($error))
+ else if (!count($error))
{
$error[] = $user->lang['USER_NOT_FOUND_OR_INACTIVE'];
}
@@ -244,7 +244,7 @@ class ucp_zebra
else if ($updated)
{
meta_refresh(3, $this->u_action);
- $message = $user->lang[$l_mode . '_UPDATED'] . '<br />' . implode('<br />', $error) . ((sizeof($error)) ? '<br />' : '') . '<br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ $message = $user->lang[$l_mode . '_UPDATED'] . '<br />' . implode('<br />', $error) . ((count($error)) ? '<br />' : '') . '<br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
trigger_error($message);
}
else
diff --git a/phpBB/includes/utf/data/utf_canonical_comp.php b/phpBB/includes/utf/data/utf_canonical_comp.php
deleted file mode 100644
index 2de3149ee8..0000000000
--- a/phpBB/includes/utf/data/utf_canonical_comp.php
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-$GLOBALS['utf_canonical_comp']=array('AÌ€'=>'À','AÌ'=>'Ã','AÌ‚'=>'Â','Ã'=>'Ã','Ä'=>'Ä','AÌŠ'=>'Ã…','Ç'=>'Ç','EÌ€'=>'È','EÌ'=>'É','EÌ‚'=>'Ê','Ë'=>'Ë','IÌ€'=>'ÃŒ','IÌ'=>'Ã','IÌ‚'=>'ÃŽ','Ï'=>'Ã','Ñ'=>'Ñ','OÌ€'=>'Ã’','OÌ'=>'Ó','OÌ‚'=>'Ô','Õ'=>'Õ','Ö'=>'Ö','UÌ€'=>'Ù','UÌ'=>'Ú','UÌ‚'=>'Û','Ü'=>'Ãœ','YÌ'=>'Ã','aÌ€'=>'à','aÌ'=>'á','aÌ‚'=>'â','ã'=>'ã','ä'=>'ä','aÌŠ'=>'Ã¥','ç'=>'ç','eÌ€'=>'è','eÌ'=>'é','eÌ‚'=>'ê','ë'=>'ë','iÌ€'=>'ì','iÌ'=>'í','iÌ‚'=>'î','ï'=>'ï','ñ'=>'ñ','oÌ€'=>'ò','oÌ'=>'ó','oÌ‚'=>'ô','õ'=>'õ','ö'=>'ö','uÌ€'=>'ù','uÌ'=>'ú','uÌ‚'=>'û','ü'=>'ü','yÌ'=>'ý','ÿ'=>'ÿ','AÌ„'=>'Ä€','aÌ„'=>'Ä','Ă'=>'Ä‚','ă'=>'ă','Ą'=>'Ä„','ą'=>'Ä…','CÌ'=>'Ć','cÌ'=>'ć','CÌ‚'=>'Ĉ','cÌ‚'=>'ĉ','Ċ'=>'ÄŠ','ċ'=>'Ä‹','CÌŒ'=>'ÄŒ','cÌŒ'=>'Ä','DÌŒ'=>'ÄŽ','dÌŒ'=>'Ä','EÌ„'=>'Ä’','eÌ„'=>'Ä“','Ĕ'=>'Ä”','ĕ'=>'Ä•','Ė'=>'Ä–','ė'=>'Ä—','Ę'=>'Ę','ę'=>'Ä™','EÌŒ'=>'Äš','eÌŒ'=>'Ä›','GÌ‚'=>'Äœ','gÌ‚'=>'Ä','Ğ'=>'Äž','ğ'=>'ÄŸ','Ġ'=>'Ä ','ġ'=>'Ä¡','Ģ'=>'Ä¢','ģ'=>'Ä£','HÌ‚'=>'Ĥ','hÌ‚'=>'Ä¥','Ĩ'=>'Ĩ','ĩ'=>'Ä©','IÌ„'=>'Ī','iÌ„'=>'Ä«','Ĭ'=>'Ĭ','ĭ'=>'Ä­','Į'=>'Ä®','į'=>'į','İ'=>'Ä°','JÌ‚'=>'Ä´','jÌ‚'=>'ĵ','Ķ'=>'Ķ','ķ'=>'Ä·','LÌ'=>'Ĺ','lÌ'=>'ĺ','Ļ'=>'Ä»','ļ'=>'ļ','LÌŒ'=>'Ľ','lÌŒ'=>'ľ','NÌ'=>'Ń','nÌ'=>'Å„','Ņ'=>'Å…','ņ'=>'ņ','NÌŒ'=>'Ň','nÌŒ'=>'ň','OÌ„'=>'ÅŒ','oÌ„'=>'Å','Ŏ'=>'ÅŽ','ŏ'=>'Å','OÌ‹'=>'Å','oÌ‹'=>'Å‘','RÌ'=>'Å”','rÌ'=>'Å•','Ŗ'=>'Å–','ŗ'=>'Å—','RÌŒ'=>'Ř','rÌŒ'=>'Å™','SÌ'=>'Åš','sÌ'=>'Å›','SÌ‚'=>'Åœ','sÌ‚'=>'Å','Ş'=>'Åž','ş'=>'ÅŸ','SÌŒ'=>'Å ','sÌŒ'=>'Å¡','Ţ'=>'Å¢','ţ'=>'Å£','TÌŒ'=>'Ť','tÌŒ'=>'Å¥','Ũ'=>'Ũ','ũ'=>'Å©','UÌ„'=>'Ū','uÌ„'=>'Å«','Ŭ'=>'Ŭ','ŭ'=>'Å­','UÌŠ'=>'Å®','uÌŠ'=>'ů','UÌ‹'=>'Å°','uÌ‹'=>'ű','Ų'=>'Ų','ų'=>'ų','WÌ‚'=>'Å´','wÌ‚'=>'ŵ','YÌ‚'=>'Ŷ','yÌ‚'=>'Å·','Ÿ'=>'Ÿ','ZÌ'=>'Ź','zÌ'=>'ź','Ż'=>'Å»','ż'=>'ż','ZÌŒ'=>'Ž','zÌŒ'=>'ž','OÌ›'=>'Æ ','oÌ›'=>'Æ¡','UÌ›'=>'Ư','uÌ›'=>'Æ°','AÌŒ'=>'Ç','aÌŒ'=>'ÇŽ','IÌŒ'=>'Ç','iÌŒ'=>'Ç','OÌŒ'=>'Ç‘','oÌŒ'=>'Ç’','UÌŒ'=>'Ç“','uÌŒ'=>'Ç”','Ǖ'=>'Ç•','ǖ'=>'Ç–','ÃœÌ'=>'Ç—','üÌ'=>'ǘ','Ǚ'=>'Ç™','ǚ'=>'Çš','Ǜ'=>'Ç›','ǜ'=>'Çœ','Ǟ'=>'Çž','ǟ'=>'ÇŸ','Ǡ'=>'Ç ','ǡ'=>'Ç¡','Ǣ'=>'Ç¢','ǣ'=>'Ç£','GÌŒ'=>'Ǧ','gÌŒ'=>'ǧ','KÌŒ'=>'Ǩ','kÌŒ'=>'Ç©','Ǫ'=>'Ǫ','ǫ'=>'Ç«','Ǭ'=>'Ǭ','Ç«Ì„'=>'Ç­','Æ·ÌŒ'=>'Ç®','Ê’ÌŒ'=>'ǯ','jÌŒ'=>'Ç°','GÌ'=>'Ç´','gÌ'=>'ǵ','NÌ€'=>'Ǹ','nÌ€'=>'ǹ','Ã…Ì'=>'Ǻ','Ã¥Ì'=>'Ç»','ÆÌ'=>'Ǽ','æÌ'=>'ǽ','ØÌ'=>'Ǿ','øÌ'=>'Ç¿','AÌ'=>'È€','aÌ'=>'È','AÌ‘'=>'È‚','aÌ‘'=>'ȃ','EÌ'=>'È„','eÌ'=>'È…','EÌ‘'=>'Ȇ','eÌ‘'=>'ȇ','IÌ'=>'Ȉ','iÌ'=>'ȉ','IÌ‘'=>'ÈŠ','iÌ‘'=>'È‹','OÌ'=>'ÈŒ','oÌ'=>'È','OÌ‘'=>'ÈŽ','oÌ‘'=>'È','RÌ'=>'È','rÌ'=>'È‘','RÌ‘'=>'È’','rÌ‘'=>'È“','UÌ'=>'È”','uÌ'=>'È•','UÌ‘'=>'È–','uÌ‘'=>'È—','Ș'=>'Ș','ș'=>'È™','Ț'=>'Èš','ț'=>'È›','HÌŒ'=>'Èž','hÌŒ'=>'ÈŸ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','ȩ'=>'È©','Ȫ'=>'Ȫ','ȫ'=>'È«','Ȭ'=>'Ȭ','ȭ'=>'È­','Ȯ'=>'È®','ȯ'=>'ȯ','Ȱ'=>'È°','ȱ'=>'ȱ','YÌ„'=>'Ȳ','yÌ„'=>'ȳ','̈Ì'=>'Í„','¨Ì'=>'Î…','ΑÌ'=>'Ά','ΕÌ'=>'Έ','ΗÌ'=>'Ή','ΙÌ'=>'Ί','ΟÌ'=>'ÎŒ','Î¥Ì'=>'ÎŽ','ΩÌ'=>'Î','ÏŠÌ'=>'Î','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','αÌ'=>'ά','εÌ'=>'έ','ηÌ'=>'ή','ιÌ'=>'ί','Ï‹Ì'=>'ΰ','ϊ'=>'ÏŠ','ϋ'=>'Ï‹','οÌ'=>'ÏŒ','Ï…Ì'=>'Ï','ωÌ'=>'ÏŽ','Ï’Ì'=>'Ï“','ϔ'=>'Ï”','Ѐ'=>'Ѐ','Ё'=>'Ð','ГÌ'=>'Ѓ','Ї'=>'Ї','КÌ'=>'ÐŒ','Ѝ'=>'Ð','Ў'=>'ÐŽ','Й'=>'Й','й'=>'й','ѐ'=>'Ñ','ё'=>'Ñ‘','гÌ'=>'Ñ“','ї'=>'Ñ—','кÌ'=>'Ñœ','ѝ'=>'Ñ','ў'=>'Ñž','Ñ´Ì'=>'Ѷ','ѵÌ'=>'Ñ·','Ӂ'=>'Ó','ӂ'=>'Ó‚','Ð̆'=>'Ó','ӑ'=>'Ó‘','Ð̈'=>'Ó’','ӓ'=>'Ó“','Ӗ'=>'Ó–','ӗ'=>'Ó—','Ӛ'=>'Óš','ӛ'=>'Ó›','Ӝ'=>'Óœ','ӝ'=>'Ó','Ӟ'=>'Óž','ӟ'=>'ÓŸ','Ӣ'=>'Ó¢','ӣ'=>'Ó£','Ӥ'=>'Ó¤','ӥ'=>'Ó¥','Ӧ'=>'Ó¦','ӧ'=>'Ó§','Ӫ'=>'Óª','ӫ'=>'Ó«','Ӭ'=>'Ó¬','Ñ̈'=>'Ó­','Ӯ'=>'Ó®','ӯ'=>'Ó¯','Ӱ'=>'Ó°','ӱ'=>'Ó±','Ӳ'=>'Ó²','ӳ'=>'Ó³','Ӵ'=>'Ó´','ӵ'=>'Óµ','Ӹ'=>'Ó¸','ӹ'=>'Ó¹','آ'=>'Ø¢','أ'=>'Ø£','ÙˆÙ”'=>'ؤ','إ'=>'Ø¥','ÙŠÙ”'=>'ئ','Û•Ù”'=>'Û€','ÛÙ”'=>'Û‚','Û’Ù”'=>'Û“','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','ো'=>'ো','ৌ'=>'ৌ','ୈ'=>'à­ˆ','ୋ'=>'à­‹','ୌ'=>'à­Œ','ஔ'=>'à®”','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','ೀ'=>'à³€','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','ේ'=>'à·š','à·™à·'=>'à·œ','ෝ'=>'à·','ෞ'=>'à·ž','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ཱྀ'=>'à¾','ဦ'=>'ဦ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','á¬á¬µ'=>'ᬎ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','ᭀ'=>'á­€','ᭁ'=>'á­','ᭃ'=>'á­ƒ','AÌ¥'=>'Ḁ','aÌ¥'=>'á¸','Ḃ'=>'Ḃ','ḃ'=>'ḃ','BÌ£'=>'Ḅ','bÌ£'=>'ḅ','Ḇ'=>'Ḇ','ḇ'=>'ḇ','ÇÌ'=>'Ḉ','çÌ'=>'ḉ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','DÌ£'=>'Ḍ','dÌ£'=>'á¸','Ḏ'=>'Ḏ','ḏ'=>'á¸','Ḑ'=>'á¸','ḑ'=>'ḑ','DÌ­'=>'Ḓ','dÌ­'=>'ḓ','Ä’Ì€'=>'Ḕ','Ä“Ì€'=>'ḕ','Ä’Ì'=>'Ḗ','Ä“Ì'=>'ḗ','EÌ­'=>'Ḙ','eÌ­'=>'ḙ','EÌ°'=>'Ḛ','eÌ°'=>'ḛ','Ḝ'=>'Ḝ','ḝ'=>'á¸','Ḟ'=>'Ḟ','ḟ'=>'ḟ','GÌ„'=>'Ḡ','gÌ„'=>'ḡ','Ḣ'=>'Ḣ','ḣ'=>'ḣ','HÌ£'=>'Ḥ','hÌ£'=>'ḥ','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','HÌ®'=>'Ḫ','hÌ®'=>'ḫ','IÌ°'=>'Ḭ','iÌ°'=>'ḭ','ÃÌ'=>'Ḯ','ïÌ'=>'ḯ','KÌ'=>'Ḱ','kÌ'=>'ḱ','KÌ£'=>'Ḳ','kÌ£'=>'ḳ','Ḵ'=>'Ḵ','ḵ'=>'ḵ','LÌ£'=>'Ḷ','lÌ£'=>'ḷ','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','LÌ­'=>'Ḽ','lÌ­'=>'ḽ','MÌ'=>'Ḿ','mÌ'=>'ḿ','Ṁ'=>'á¹€','ṁ'=>'á¹','MÌ£'=>'Ṃ','mÌ£'=>'ṃ','Ṅ'=>'Ṅ','ṅ'=>'á¹…','NÌ£'=>'Ṇ','nÌ£'=>'ṇ','Ṉ'=>'Ṉ','ṉ'=>'ṉ','NÌ­'=>'Ṋ','nÌ­'=>'ṋ','ÕÌ'=>'Ṍ','õÌ'=>'á¹','Ṏ'=>'Ṏ','ṏ'=>'á¹','Ṑ'=>'á¹','ÅÌ€'=>'ṑ','ÅŒÌ'=>'á¹’','ÅÌ'=>'ṓ','PÌ'=>'á¹”','pÌ'=>'ṕ','Ṗ'=>'á¹–','ṗ'=>'á¹—','Ṙ'=>'Ṙ','ṙ'=>'á¹™','RÌ£'=>'Ṛ','rÌ£'=>'á¹›','Ṝ'=>'Ṝ','ṝ'=>'á¹','Ṟ'=>'Ṟ','ṟ'=>'ṟ','Ṡ'=>'á¹ ','ṡ'=>'ṡ','SÌ£'=>'á¹¢','sÌ£'=>'á¹£','Ṥ'=>'Ṥ','ṥ'=>'á¹¥','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','TÌ£'=>'Ṭ','tÌ£'=>'á¹­','Ṯ'=>'á¹®','ṯ'=>'ṯ','TÌ­'=>'á¹°','tÌ­'=>'á¹±','Ṳ'=>'á¹²','ṳ'=>'á¹³','UÌ°'=>'á¹´','uÌ°'=>'á¹µ','UÌ­'=>'Ṷ','uÌ­'=>'á¹·','ŨÌ'=>'Ṹ','Å©Ì'=>'á¹¹','Ṻ'=>'Ṻ','ṻ'=>'á¹»','Ṽ'=>'á¹¼','ṽ'=>'á¹½','VÌ£'=>'á¹¾','vÌ£'=>'ṿ','WÌ€'=>'Ẁ','wÌ€'=>'áº','WÌ'=>'Ẃ','wÌ'=>'ẃ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','WÌ£'=>'Ẉ','wÌ£'=>'ẉ','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','ẍ'=>'áº','Ẏ'=>'Ẏ','ẏ'=>'áº','ZÌ‚'=>'áº','zÌ‚'=>'ẑ','ZÌ£'=>'Ẓ','zÌ£'=>'ẓ','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','wÌŠ'=>'ẘ','yÌŠ'=>'ẙ','ẛ'=>'ẛ','AÌ£'=>'Ạ','aÌ£'=>'ạ','Ả'=>'Ả','ả'=>'ả','ÂÌ'=>'Ấ','âÌ'=>'ấ','Ầ'=>'Ầ','ầ'=>'ầ','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ä‚Ì'=>'Ắ','ăÌ'=>'ắ','Ä‚Ì€'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','EÌ£'=>'Ẹ','eÌ£'=>'ẹ','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','ÊÌ'=>'Ế','êÌ'=>'ế','Ề'=>'Ề','ề'=>'á»','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','ễ'=>'á»…','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','IÌ£'=>'Ị','iÌ£'=>'ị','OÌ£'=>'Ọ','oÌ£'=>'á»','Ỏ'=>'Ỏ','ỏ'=>'á»','ÔÌ'=>'á»','ôÌ'=>'ố','Ồ'=>'á»’','ồ'=>'ồ','Ổ'=>'á»”','ổ'=>'ổ','Ỗ'=>'á»–','ỗ'=>'á»—','Ộ'=>'Ộ','á»Ì‚'=>'á»™','Æ Ì'=>'Ớ','Æ¡Ì'=>'á»›','Ờ'=>'Ờ','Æ¡Ì€'=>'á»','Ở'=>'Ở','ở'=>'ở','Ỡ'=>'á» ','ỡ'=>'ỡ','Ợ'=>'Ợ','Æ¡Ì£'=>'ợ','UÌ£'=>'Ụ','uÌ£'=>'ụ','Ủ'=>'Ủ','ủ'=>'ủ','ƯÌ'=>'Ứ','Æ°Ì'=>'ứ','Ừ'=>'Ừ','Æ°Ì€'=>'ừ','Ử'=>'Ử','ử'=>'á»­','Ữ'=>'á»®','ữ'=>'ữ','Ự'=>'á»°','Æ°Ì£'=>'á»±','YÌ€'=>'Ỳ','yÌ€'=>'ỳ','YÌ£'=>'á»´','yÌ£'=>'ỵ','Ỷ'=>'Ỷ','ỷ'=>'á»·','Ỹ'=>'Ỹ','ỹ'=>'ỹ','ἀ'=>'á¼€','ἁ'=>'á¼','ἂ'=>'ἂ','á¼Ì€'=>'ἃ','á¼€Ì'=>'ἄ','á¼Ì'=>'á¼…','ἆ'=>'ἆ','á¼Í‚'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','ἈÌ'=>'Ἄ','ἉÌ'=>'á¼','Ἆ'=>'Ἆ','Ἇ'=>'á¼','ἐ'=>'á¼','ἑ'=>'ἑ','á¼Ì€'=>'á¼’','ἓ'=>'ἓ','á¼Ì'=>'á¼”','ἑÌ'=>'ἕ','Ἐ'=>'Ἐ','Ἑ'=>'á¼™','Ἒ'=>'Ἒ','Ἓ'=>'á¼›','ἘÌ'=>'Ἔ','á¼™Ì'=>'á¼','ἠ'=>'á¼ ','ἡ'=>'ἡ','ἢ'=>'á¼¢','ἣ'=>'á¼£','á¼ Ì'=>'ἤ','ἡÌ'=>'á¼¥','á¼ Í‚'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','ἨÌ'=>'Ἤ','ἩÌ'=>'á¼­','Ἦ'=>'á¼®','Ἧ'=>'Ἧ','ἰ'=>'á¼°','ἱ'=>'á¼±','á¼°Ì€'=>'á¼²','ἳ'=>'á¼³','á¼°Ì'=>'á¼´','á¼±Ì'=>'á¼µ','á¼°Í‚'=>'ἶ','ἷ'=>'á¼·','Ἰ'=>'Ἰ','Ἱ'=>'á¼¹','Ἲ'=>'Ἲ','Ἳ'=>'á¼»','ἸÌ'=>'á¼¼','á¼¹Ì'=>'á¼½','Ἶ'=>'á¼¾','Ἷ'=>'Ἷ','ὀ'=>'á½€','ὁ'=>'á½','ὂ'=>'ὂ','á½Ì€'=>'ὃ','á½€Ì'=>'ὄ','á½Ì'=>'á½…','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','ὈÌ'=>'Ὄ','ὉÌ'=>'á½','Ï…Ì“'=>'á½','Ï…Ì”'=>'ὑ','á½Ì€'=>'á½’','ὓ'=>'ὓ','á½Ì'=>'á½”','ὑÌ'=>'ὕ','á½Í‚'=>'á½–','ὗ'=>'á½—','Ὑ'=>'á½™','Ὓ'=>'á½›','á½™Ì'=>'á½','Ὗ'=>'Ὗ','ὠ'=>'á½ ','ὡ'=>'ὡ','ὢ'=>'á½¢','ὣ'=>'á½£','á½ Ì'=>'ὤ','ὡÌ'=>'á½¥','á½ Í‚'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','ὨÌ'=>'Ὤ','ὩÌ'=>'á½­','Ὦ'=>'á½®','Ὧ'=>'Ὧ','ὰ'=>'á½°','ὲ'=>'á½²','ὴ'=>'á½´','ὶ'=>'ὶ','ὸ'=>'ὸ','Ï…Ì€'=>'ὺ','ὼ'=>'á½¼','ᾀ'=>'á¾€','á¼Í…'=>'á¾','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ᾄ','á¼…Í…'=>'á¾…','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ᾌ','á¼Í…'=>'á¾','ᾎ'=>'ᾎ','á¼Í…'=>'á¾','á¼ Í…'=>'á¾','ᾑ'=>'ᾑ','ᾒ'=>'á¾’','ᾓ'=>'ᾓ','ᾔ'=>'á¾”','ᾕ'=>'ᾕ','ᾖ'=>'á¾–','ᾗ'=>'á¾—','ᾘ'=>'ᾘ','ᾙ'=>'á¾™','ᾚ'=>'ᾚ','ᾛ'=>'á¾›','ᾜ'=>'ᾜ','á¼­Í…'=>'á¾','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','á½ Í…'=>'á¾ ','ᾡ'=>'ᾡ','ᾢ'=>'á¾¢','ᾣ'=>'á¾£','ᾤ'=>'ᾤ','ᾥ'=>'á¾¥','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ᾬ','á½­Í…'=>'á¾­','ᾮ'=>'á¾®','ᾯ'=>'ᾯ','ᾰ'=>'á¾°','ᾱ'=>'á¾±','á½°Í…'=>'á¾²','ᾳ'=>'á¾³','ᾴ'=>'á¾´','ᾶ'=>'ᾶ','ᾷ'=>'á¾·','Ᾰ'=>'Ᾰ','Ᾱ'=>'á¾¹','Ὰ'=>'Ὰ','ᾼ'=>'á¾¼','῁'=>'á¿','á½´Í…'=>'á¿‚','ῃ'=>'ῃ','ῄ'=>'á¿„','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Ὴ'=>'á¿Š','ῌ'=>'á¿Œ','῍'=>'á¿','᾿Ì'=>'á¿Ž','῏'=>'á¿','ῐ'=>'á¿','ῑ'=>'á¿‘','ÏŠÌ€'=>'á¿’','ῖ'=>'á¿–','ÏŠÍ‚'=>'á¿—','Ῐ'=>'Ῐ','Ῑ'=>'á¿™','Ὶ'=>'á¿š','῝'=>'á¿','῾Ì'=>'á¿ž','῟'=>'á¿Ÿ','ῠ'=>'á¿ ','Ï…Ì„'=>'á¿¡','Ï‹Ì€'=>'á¿¢','ÏÌ“'=>'ῤ','ÏÌ”'=>'á¿¥','Ï…Í‚'=>'ῦ','Ï‹Í‚'=>'ῧ','Ῠ'=>'Ῠ','Ῡ'=>'á¿©','Ὺ'=>'Ὺ','Ῥ'=>'Ῥ','῭'=>'á¿­','ῲ'=>'ῲ','ῳ'=>'ῳ','ÏŽÍ…'=>'á¿´','ῶ'=>'ῶ','ῷ'=>'á¿·','Ὸ'=>'Ὸ','Ὼ'=>'Ὼ','ῼ'=>'ῼ','â†Ì¸'=>'↚','↛'=>'↛','↮'=>'↮','â‡Ì¸'=>'â‡','⇎'=>'⇎','⇏'=>'â‡','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','≁'=>'â‰','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','â‰Ì¸'=>'≭','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','⊁'=>'âŠ','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','⋠'=>'â‹ ','⋡'=>'â‹¡','⋢'=>'â‹¢','⋣'=>'â‹£','⋪'=>'⋪','⋫'=>'â‹«','⋬'=>'⋬','⋭'=>'â‹­','ã‹ã‚™'=>'ãŒ','ãã‚™'=>'ãŽ','ãã‚™'=>'ã','ã‘ã‚™'=>'ã’','ã“ã‚™'=>'ã”','ã•ã‚™'=>'ã–','ã—ã‚™'=>'ã˜','ã™ã‚™'=>'ãš','ã›ã‚™'=>'ãœ','ãã‚™'=>'ãž','ãŸã‚™'=>'ã ','ã¡ã‚™'=>'ã¢','ã¤ã‚™'=>'ã¥','ã¦ã‚™'=>'ã§','ã¨ã‚™'=>'ã©','ã¯ã‚™'=>'ã°','ã¯ã‚š'=>'ã±','ã²ã‚™'=>'ã³','ã²ã‚š'=>'ã´','ãµã‚™'=>'ã¶','ãµã‚š'=>'ã·','ã¸ã‚™'=>'ã¹','ã¸ã‚š'=>'ãº','ã»ã‚™'=>'ã¼','ã»ã‚š'=>'ã½','ã†ã‚™'=>'ã‚”','ã‚ã‚™'=>'ã‚ž','ã‚«ã‚™'=>'ガ','ã‚­ã‚™'=>'ã‚®','グ'=>'ã‚°','ゲ'=>'ゲ','ゴ'=>'ã‚´','ザ'=>'ザ','ã‚·ã‚™'=>'ジ','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ã‚¿ã‚™'=>'ダ','ãƒã‚™'=>'ヂ','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','ãƒã‚™'=>'ãƒ','ãƒã‚š'=>'パ','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ポ'=>'ãƒ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ');
diff --git a/phpBB/includes/utf/data/utf_canonical_decomp.php b/phpBB/includes/utf/data/utf_canonical_decomp.php
deleted file mode 100644
index 9fb90803e2..0000000000
--- a/phpBB/includes/utf/data/utf_canonical_decomp.php
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-$GLOBALS['utf_canonical_decomp']=array('À'=>'AÌ€','Ã'=>'AÌ','Â'=>'AÌ‚','Ã'=>'Ã','Ä'=>'Ä','Ã…'=>'AÌŠ','Ç'=>'Ç','È'=>'EÌ€','É'=>'EÌ','Ê'=>'EÌ‚','Ë'=>'Ë','ÃŒ'=>'IÌ€','Ã'=>'IÌ','ÃŽ'=>'IÌ‚','Ã'=>'Ï','Ñ'=>'Ñ','Ã’'=>'OÌ€','Ó'=>'OÌ','Ô'=>'OÌ‚','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'UÌ€','Ú'=>'UÌ','Û'=>'UÌ‚','Ãœ'=>'Ü','Ã'=>'YÌ','à'=>'aÌ€','á'=>'aÌ','â'=>'aÌ‚','ã'=>'ã','ä'=>'ä','Ã¥'=>'aÌŠ','ç'=>'ç','è'=>'eÌ€','é'=>'eÌ','ê'=>'eÌ‚','ë'=>'ë','ì'=>'iÌ€','í'=>'iÌ','î'=>'iÌ‚','ï'=>'ï','ñ'=>'ñ','ò'=>'oÌ€','ó'=>'oÌ','ô'=>'oÌ‚','õ'=>'õ','ö'=>'ö','ù'=>'uÌ€','ú'=>'uÌ','û'=>'uÌ‚','ü'=>'ü','ý'=>'yÌ','ÿ'=>'ÿ','Ä€'=>'AÌ„','Ä'=>'aÌ„','Ä‚'=>'Ă','ă'=>'ă','Ä„'=>'Ą','Ä…'=>'ą','Ć'=>'CÌ','ć'=>'cÌ','Ĉ'=>'CÌ‚','ĉ'=>'cÌ‚','ÄŠ'=>'Ċ','Ä‹'=>'ċ','ÄŒ'=>'CÌŒ','Ä'=>'cÌŒ','ÄŽ'=>'DÌŒ','Ä'=>'dÌŒ','Ä’'=>'EÌ„','Ä“'=>'eÌ„','Ä”'=>'Ĕ','Ä•'=>'ĕ','Ä–'=>'Ė','Ä—'=>'ė','Ę'=>'Ę','Ä™'=>'ę','Äš'=>'EÌŒ','Ä›'=>'eÌŒ','Äœ'=>'GÌ‚','Ä'=>'gÌ‚','Äž'=>'Ğ','ÄŸ'=>'ğ','Ä '=>'Ġ','Ä¡'=>'ġ','Ä¢'=>'Ģ','Ä£'=>'ģ','Ĥ'=>'HÌ‚','Ä¥'=>'hÌ‚','Ĩ'=>'Ĩ','Ä©'=>'ĩ','Ī'=>'IÌ„','Ä«'=>'iÌ„','Ĭ'=>'Ĭ','Ä­'=>'ĭ','Ä®'=>'Į','į'=>'į','Ä°'=>'İ','Ä´'=>'JÌ‚','ĵ'=>'jÌ‚','Ķ'=>'Ķ','Ä·'=>'ķ','Ĺ'=>'LÌ','ĺ'=>'lÌ','Ä»'=>'Ļ','ļ'=>'ļ','Ľ'=>'LÌŒ','ľ'=>'lÌŒ','Ń'=>'NÌ','Å„'=>'nÌ','Å…'=>'Ņ','ņ'=>'ņ','Ň'=>'NÌŒ','ň'=>'nÌŒ','ÅŒ'=>'OÌ„','Å'=>'oÌ„','ÅŽ'=>'Ŏ','Å'=>'ŏ','Å'=>'OÌ‹','Å‘'=>'oÌ‹','Å”'=>'RÌ','Å•'=>'rÌ','Å–'=>'Ŗ','Å—'=>'ŗ','Ř'=>'RÌŒ','Å™'=>'rÌŒ','Åš'=>'SÌ','Å›'=>'sÌ','Åœ'=>'SÌ‚','Å'=>'sÌ‚','Åž'=>'Ş','ÅŸ'=>'ş','Å '=>'SÌŒ','Å¡'=>'sÌŒ','Å¢'=>'Ţ','Å£'=>'ţ','Ť'=>'TÌŒ','Å¥'=>'tÌŒ','Ũ'=>'Ũ','Å©'=>'ũ','Ū'=>'UÌ„','Å«'=>'uÌ„','Ŭ'=>'Ŭ','Å­'=>'ŭ','Å®'=>'UÌŠ','ů'=>'uÌŠ','Å°'=>'UÌ‹','ű'=>'uÌ‹','Ų'=>'Ų','ų'=>'ų','Å´'=>'WÌ‚','ŵ'=>'wÌ‚','Ŷ'=>'YÌ‚','Å·'=>'yÌ‚','Ÿ'=>'Ÿ','Ź'=>'ZÌ','ź'=>'zÌ','Å»'=>'Ż','ż'=>'ż','Ž'=>'ZÌŒ','ž'=>'zÌŒ','Æ '=>'OÌ›','Æ¡'=>'oÌ›','Ư'=>'UÌ›','Æ°'=>'uÌ›','Ç'=>'AÌŒ','ÇŽ'=>'aÌŒ','Ç'=>'IÌŒ','Ç'=>'iÌŒ','Ç‘'=>'OÌŒ','Ç’'=>'oÌŒ','Ç“'=>'UÌŒ','Ç”'=>'uÌŒ','Ç•'=>'Ǖ','Ç–'=>'ǖ','Ç—'=>'ÜÌ','ǘ'=>'üÌ','Ç™'=>'Ǚ','Çš'=>'ǚ','Ç›'=>'Ǜ','Çœ'=>'ǜ','Çž'=>'Ǟ','ÇŸ'=>'ǟ','Ç '=>'Ǡ','Ç¡'=>'ǡ','Ç¢'=>'Ǣ','Ç£'=>'ǣ','Ǧ'=>'GÌŒ','ǧ'=>'gÌŒ','Ǩ'=>'KÌŒ','Ç©'=>'kÌŒ','Ǫ'=>'Ǫ','Ç«'=>'ǫ','Ǭ'=>'Ǭ','Ç­'=>'ǭ','Ç®'=>'Æ·ÌŒ','ǯ'=>'Ê’ÌŒ','Ç°'=>'jÌŒ','Ç´'=>'GÌ','ǵ'=>'gÌ','Ǹ'=>'NÌ€','ǹ'=>'nÌ€','Ǻ'=>'AÌŠÌ','Ç»'=>'aÌŠÌ','Ǽ'=>'ÆÌ','ǽ'=>'æÌ','Ǿ'=>'ØÌ','Ç¿'=>'øÌ','È€'=>'AÌ','È'=>'aÌ','È‚'=>'AÌ‘','ȃ'=>'aÌ‘','È„'=>'EÌ','È…'=>'eÌ','Ȇ'=>'EÌ‘','ȇ'=>'eÌ‘','Ȉ'=>'IÌ','ȉ'=>'iÌ','ÈŠ'=>'IÌ‘','È‹'=>'iÌ‘','ÈŒ'=>'OÌ','È'=>'oÌ','ÈŽ'=>'OÌ‘','È'=>'oÌ‘','È'=>'RÌ','È‘'=>'rÌ','È’'=>'RÌ‘','È“'=>'rÌ‘','È”'=>'UÌ','È•'=>'uÌ','È–'=>'UÌ‘','È—'=>'uÌ‘','Ș'=>'Ș','È™'=>'ș','Èš'=>'Ț','È›'=>'ț','Èž'=>'HÌŒ','ÈŸ'=>'hÌŒ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','È©'=>'ȩ','Ȫ'=>'Ȫ','È«'=>'ȫ','Ȭ'=>'Ȭ','È­'=>'ȭ','È®'=>'Ȯ','ȯ'=>'ȯ','È°'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'YÌ„','ȳ'=>'yÌ„','Í€'=>'Ì€','Í'=>'Ì','̓'=>'Ì“','Í„'=>'̈Ì','Í´'=>'ʹ',';'=>';','Î…'=>'¨Ì','Ά'=>'ΑÌ','·'=>'·','Έ'=>'ΕÌ','Ή'=>'ΗÌ','Ί'=>'ΙÌ','ÎŒ'=>'ΟÌ','ÎŽ'=>'Î¥Ì','Î'=>'ΩÌ','Î'=>'ϊÌ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'αÌ','έ'=>'εÌ','ή'=>'ηÌ','ί'=>'ιÌ','ΰ'=>'ϋÌ','ÏŠ'=>'ϊ','Ï‹'=>'ϋ','ÏŒ'=>'οÌ','Ï'=>'Ï…Ì','ÏŽ'=>'ωÌ','Ï“'=>'Ï’Ì','Ï”'=>'ϔ','Ѐ'=>'Ѐ','Ð'=>'Ё','Ѓ'=>'ГÌ','Ї'=>'Ї','ÐŒ'=>'КÌ','Ð'=>'Ѝ','ÐŽ'=>'Ў','Й'=>'Й','й'=>'й','Ñ'=>'ѐ','Ñ‘'=>'ё','Ñ“'=>'гÌ','Ñ—'=>'ї','Ñœ'=>'кÌ','Ñ'=>'ѝ','Ñž'=>'ў','Ѷ'=>'Ñ´Ì','Ñ·'=>'ѵÌ','Ó'=>'Ӂ','Ó‚'=>'ӂ','Ó'=>'Ð̆','Ó‘'=>'ӑ','Ó’'=>'Ð̈','Ó“'=>'ӓ','Ó–'=>'Ӗ','Ó—'=>'ӗ','Óš'=>'Ӛ','Ó›'=>'ӛ','Óœ'=>'Ӝ','Ó'=>'ӝ','Óž'=>'Ӟ','ÓŸ'=>'ӟ','Ó¢'=>'Ӣ','Ó£'=>'ӣ','Ó¤'=>'Ӥ','Ó¥'=>'ӥ','Ó¦'=>'Ӧ','Ó§'=>'ӧ','Óª'=>'Ӫ','Ó«'=>'ӫ','Ó¬'=>'Ӭ','Ó­'=>'Ñ̈','Ó®'=>'Ӯ','Ó¯'=>'ӯ','Ó°'=>'Ӱ','Ó±'=>'ӱ','Ó²'=>'Ӳ','Ó³'=>'ӳ','Ó´'=>'Ӵ','Óµ'=>'ӵ','Ó¸'=>'Ӹ','Ó¹'=>'ӹ','Ø¢'=>'آ','Ø£'=>'أ','ؤ'=>'ÙˆÙ”','Ø¥'=>'إ','ئ'=>'ÙŠÙ”','Û€'=>'Û•Ù”','Û‚'=>'ÛÙ”','Û“'=>'Û’Ù”','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','à¥'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ো'=>'ো','ৌ'=>'ৌ','ড়'=>'ড়','à§'=>'ঢ়','য়'=>'য়','ਲ਼'=>'ਲ਼','ਸ਼'=>'ਸ਼','à©™'=>'ਖ਼','à©š'=>'ਗ਼','à©›'=>'ਜ਼','à©ž'=>'ਫ਼','à­ˆ'=>'ୈ','à­‹'=>'ୋ','à­Œ'=>'ୌ','à­œ'=>'ଡ଼','à­'=>'ଢ଼','à®”'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','à³€'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','à·š'=>'ේ','à·œ'=>'à·™à·','à·'=>'à·™à·à·Š','à·ž'=>'ෞ','གྷ'=>'གྷ','à½'=>'ཌྷ','དྷ'=>'དྷ','བྷ'=>'བྷ','ཛྷ'=>'ཛྷ','ཀྵ'=>'ཀྵ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ླྀ'=>'ླྀ','à¾'=>'ཱྀ','ྒྷ'=>'ྒྷ','à¾'=>'ྜྷ','ྡྷ'=>'ྡྷ','ྦྷ'=>'ྦྷ','ྫྷ'=>'ྫྷ','ྐྵ'=>'à¾à¾µ','ဦ'=>'ဦ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'á¬á¬µ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','á­€'=>'ᭀ','á­'=>'ᭁ','á­ƒ'=>'ᭃ','Ḁ'=>'AÌ¥','á¸'=>'aÌ¥','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'BÌ£','ḅ'=>'bÌ£','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'ÇÌ','ḉ'=>'çÌ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'DÌ£','á¸'=>'dÌ£','Ḏ'=>'Ḏ','á¸'=>'ḏ','á¸'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'DÌ­','ḓ'=>'dÌ­','Ḕ'=>'EÌ„Ì€','ḕ'=>'eÌ„Ì€','Ḗ'=>'EÌ„Ì','ḗ'=>'eÌ„Ì','Ḙ'=>'EÌ­','ḙ'=>'eÌ­','Ḛ'=>'EÌ°','ḛ'=>'eÌ°','Ḝ'=>'Ḝ','á¸'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'GÌ„','ḡ'=>'gÌ„','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'HÌ£','ḥ'=>'hÌ£','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'HÌ®','ḫ'=>'hÌ®','Ḭ'=>'IÌ°','ḭ'=>'iÌ°','Ḯ'=>'ÏÌ','ḯ'=>'ïÌ','Ḱ'=>'KÌ','ḱ'=>'kÌ','Ḳ'=>'KÌ£','ḳ'=>'kÌ£','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'LÌ£','ḷ'=>'lÌ£','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'LÌ­','ḽ'=>'lÌ­','Ḿ'=>'MÌ','ḿ'=>'mÌ','á¹€'=>'Ṁ','á¹'=>'ṁ','Ṃ'=>'MÌ£','ṃ'=>'mÌ£','Ṅ'=>'Ṅ','á¹…'=>'ṅ','Ṇ'=>'NÌ£','ṇ'=>'nÌ£','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'NÌ­','ṋ'=>'nÌ­','Ṍ'=>'ÕÌ','á¹'=>'õÌ','Ṏ'=>'Ṏ','á¹'=>'ṏ','á¹'=>'OÌ„Ì€','ṑ'=>'oÌ„Ì€','á¹’'=>'OÌ„Ì','ṓ'=>'oÌ„Ì','á¹”'=>'PÌ','ṕ'=>'pÌ','á¹–'=>'Ṗ','á¹—'=>'ṗ','Ṙ'=>'Ṙ','á¹™'=>'ṙ','Ṛ'=>'RÌ£','á¹›'=>'rÌ£','Ṝ'=>'Ṝ','á¹'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','á¹ '=>'Ṡ','ṡ'=>'ṡ','á¹¢'=>'SÌ£','á¹£'=>'sÌ£','Ṥ'=>'SÌ̇','á¹¥'=>'sÌ̇','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'TÌ£','á¹­'=>'tÌ£','á¹®'=>'Ṯ','ṯ'=>'ṯ','á¹°'=>'TÌ­','á¹±'=>'tÌ­','á¹²'=>'Ṳ','á¹³'=>'ṳ','á¹´'=>'UÌ°','á¹µ'=>'uÌ°','Ṷ'=>'UÌ­','á¹·'=>'uÌ­','Ṹ'=>'ŨÌ','á¹¹'=>'ũÌ','Ṻ'=>'Ṻ','á¹»'=>'ṻ','á¹¼'=>'Ṽ','á¹½'=>'ṽ','á¹¾'=>'VÌ£','ṿ'=>'vÌ£','Ẁ'=>'WÌ€','áº'=>'wÌ€','Ẃ'=>'WÌ','ẃ'=>'wÌ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'WÌ£','ẉ'=>'wÌ£','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','áº'=>'ẍ','Ẏ'=>'Ẏ','áº'=>'ẏ','áº'=>'ZÌ‚','ẑ'=>'zÌ‚','Ẓ'=>'ZÌ£','ẓ'=>'zÌ£','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'wÌŠ','ẙ'=>'yÌŠ','ẛ'=>'ẛ','Ạ'=>'AÌ£','ạ'=>'aÌ£','Ả'=>'Ả','ả'=>'ả','Ấ'=>'AÌ‚Ì','ấ'=>'aÌ‚Ì','Ầ'=>'AÌ‚Ì€','ầ'=>'aÌ‚Ì€','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'ĂÌ','ắ'=>'ăÌ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'EÌ£','ẹ'=>'eÌ£','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'EÌ‚Ì','ế'=>'eÌ‚Ì','Ề'=>'EÌ‚Ì€','á»'=>'eÌ‚Ì€','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','á»…'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'IÌ£','ị'=>'iÌ£','Ọ'=>'OÌ£','á»'=>'oÌ£','Ỏ'=>'Ỏ','á»'=>'ỏ','á»'=>'OÌ‚Ì','ố'=>'oÌ‚Ì','á»’'=>'OÌ‚Ì€','ồ'=>'oÌ‚Ì€','á»”'=>'Ổ','ổ'=>'ổ','á»–'=>'Ỗ','á»—'=>'ỗ','Ộ'=>'Ộ','á»™'=>'ộ','Ớ'=>'OÌ›Ì','á»›'=>'oÌ›Ì','Ờ'=>'Ờ','á»'=>'ờ','Ở'=>'Ở','ở'=>'ở','á» '=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'UÌ£','ụ'=>'uÌ£','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'UÌ›Ì','ứ'=>'uÌ›Ì','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','á»­'=>'ử','á»®'=>'Ữ','ữ'=>'ữ','á»°'=>'Ự','á»±'=>'ự','Ỳ'=>'YÌ€','ỳ'=>'yÌ€','á»´'=>'YÌ£','ỵ'=>'yÌ£','Ỷ'=>'Ỷ','á»·'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','á¼€'=>'ἀ','á¼'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἀÌ','á¼…'=>'ἁÌ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'ἈÌ','á¼'=>'ἉÌ','Ἆ'=>'Ἆ','á¼'=>'Ἇ','á¼'=>'ἐ','ἑ'=>'ἑ','á¼’'=>'ἒ','ἓ'=>'ἓ','á¼”'=>'ἐÌ','ἕ'=>'ἑÌ','Ἐ'=>'Ἐ','á¼™'=>'Ἑ','Ἒ'=>'Ἒ','á¼›'=>'Ἓ','Ἔ'=>'ἘÌ','á¼'=>'ἙÌ','á¼ '=>'ἠ','ἡ'=>'ἡ','á¼¢'=>'ἢ','á¼£'=>'ἣ','ἤ'=>'ἠÌ','á¼¥'=>'ἡÌ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'ἨÌ','á¼­'=>'ἩÌ','á¼®'=>'Ἦ','Ἧ'=>'Ἧ','á¼°'=>'ἰ','á¼±'=>'ἱ','á¼²'=>'ἲ','á¼³'=>'ἳ','á¼´'=>'ἰÌ','á¼µ'=>'ἱÌ','ἶ'=>'ἶ','á¼·'=>'ἷ','Ἰ'=>'Ἰ','á¼¹'=>'Ἱ','Ἲ'=>'Ἲ','á¼»'=>'Ἳ','á¼¼'=>'ἸÌ','á¼½'=>'ἹÌ','á¼¾'=>'Ἶ','Ἷ'=>'Ἷ','á½€'=>'ὀ','á½'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὀÌ','á½…'=>'ὁÌ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'ὈÌ','á½'=>'ὉÌ','á½'=>'Ï…Ì“','ὑ'=>'Ï…Ì”','á½’'=>'Ï…Ì“Ì€','ὓ'=>'ὓ','á½”'=>'Ï…Ì“Ì','ὕ'=>'Ï…Ì”Ì','á½–'=>'Ï…Ì“Í‚','á½—'=>'ὗ','á½™'=>'Ὑ','á½›'=>'Ὓ','á½'=>'ὙÌ','Ὗ'=>'Ὗ','á½ '=>'ὠ','ὡ'=>'ὡ','á½¢'=>'ὢ','á½£'=>'ὣ','ὤ'=>'ὠÌ','á½¥'=>'ὡÌ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'ὨÌ','á½­'=>'ὩÌ','á½®'=>'Ὦ','Ὧ'=>'Ὧ','á½°'=>'ὰ','á½±'=>'αÌ','á½²'=>'ὲ','á½³'=>'εÌ','á½´'=>'ὴ','á½µ'=>'ηÌ','ὶ'=>'ὶ','á½·'=>'ιÌ','ὸ'=>'ὸ','á½¹'=>'οÌ','ὺ'=>'Ï…Ì€','á½»'=>'Ï…Ì','á½¼'=>'ὼ','á½½'=>'ωÌ','á¾€'=>'ᾀ','á¾'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ἀÌÍ…','á¾…'=>'ἁÌÍ…','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ἈÌÍ…','á¾'=>'ἉÌÍ…','ᾎ'=>'ᾎ','á¾'=>'ᾏ','á¾'=>'ᾐ','ᾑ'=>'ᾑ','á¾’'=>'ᾒ','ᾓ'=>'ᾓ','á¾”'=>'ἠÌÍ…','ᾕ'=>'ἡÌÍ…','á¾–'=>'ᾖ','á¾—'=>'ᾗ','ᾘ'=>'ᾘ','á¾™'=>'ᾙ','ᾚ'=>'ᾚ','á¾›'=>'ᾛ','ᾜ'=>'ἨÌÍ…','á¾'=>'ἩÌÍ…','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','á¾ '=>'ᾠ','ᾡ'=>'ᾡ','á¾¢'=>'ᾢ','á¾£'=>'ᾣ','ᾤ'=>'ὠÌÍ…','á¾¥'=>'ὡÌÍ…','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ὨÌÍ…','á¾­'=>'ὩÌÍ…','á¾®'=>'ᾮ','ᾯ'=>'ᾯ','á¾°'=>'ᾰ','á¾±'=>'ᾱ','á¾²'=>'ᾲ','á¾³'=>'ᾳ','á¾´'=>'αÌÍ…','ᾶ'=>'ᾶ','á¾·'=>'ᾷ','Ᾰ'=>'Ᾰ','á¾¹'=>'Ᾱ','Ὰ'=>'Ὰ','á¾»'=>'ΑÌ','á¾¼'=>'ᾼ','á¾¾'=>'ι','á¿'=>'῁','á¿‚'=>'ῂ','ῃ'=>'ῃ','á¿„'=>'ηÌÍ…','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Έ'=>'ΕÌ','á¿Š'=>'Ὴ','á¿‹'=>'ΗÌ','á¿Œ'=>'ῌ','á¿'=>'῍','á¿Ž'=>'᾿Ì','á¿'=>'῏','á¿'=>'ῐ','á¿‘'=>'ῑ','á¿’'=>'ῒ','á¿“'=>'ϊÌ','á¿–'=>'ῖ','á¿—'=>'ῗ','Ῐ'=>'Ῐ','á¿™'=>'Ῑ','á¿š'=>'Ὶ','á¿›'=>'ΙÌ','á¿'=>'῝','á¿ž'=>'῾Ì','á¿Ÿ'=>'῟','á¿ '=>'ῠ','á¿¡'=>'Ï…Ì„','á¿¢'=>'ῢ','á¿£'=>'ϋÌ','ῤ'=>'ÏÌ“','á¿¥'=>'ÏÌ”','ῦ'=>'Ï…Í‚','ῧ'=>'ῧ','Ῠ'=>'Ῠ','á¿©'=>'Ῡ','Ὺ'=>'Ὺ','á¿«'=>'Î¥Ì','Ῥ'=>'Ῥ','á¿­'=>'῭','á¿®'=>'¨Ì','`'=>'`','ῲ'=>'ῲ','ῳ'=>'ῳ','á¿´'=>'ωÌÍ…','ῶ'=>'ῶ','á¿·'=>'ῷ','Ὸ'=>'Ὸ','Ό'=>'ΟÌ','Ὼ'=>'Ὼ','á¿»'=>'ΩÌ','ῼ'=>'ῼ','´'=>'´',' '=>' ','â€'=>' ','Ω'=>'Ω','K'=>'K','â„«'=>'AÌŠ','↚'=>'â†Ì¸','↛'=>'↛','↮'=>'↮','â‡'=>'â‡Ì¸','⇎'=>'⇎','â‡'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','â‰'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'â‰Ì¸','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','âŠ'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','â‹ '=>'⋠','â‹¡'=>'⋡','â‹¢'=>'⋢','â‹£'=>'⋣','⋪'=>'⋪','â‹«'=>'⋫','⋬'=>'⋬','â‹­'=>'⋭','〈'=>'〈','〉'=>'〉','â«œ'=>'â«Ì¸','ãŒ'=>'ã‹ã‚™','ãŽ'=>'ãã‚™','ã'=>'ãã‚™','ã’'=>'ã‘ã‚™','ã”'=>'ã“ã‚™','ã–'=>'ã•ã‚™','ã˜'=>'ã—ã‚™','ãš'=>'ã™ã‚™','ãœ'=>'ã›ã‚™','ãž'=>'ãã‚™','ã '=>'ãŸã‚™','ã¢'=>'ã¡ã‚™','ã¥'=>'ã¤ã‚™','ã§'=>'ã¦ã‚™','ã©'=>'ã¨ã‚™','ã°'=>'ã¯ã‚™','ã±'=>'ã¯ã‚š','ã³'=>'ã²ã‚™','ã´'=>'ã²ã‚š','ã¶'=>'ãµã‚™','ã·'=>'ãµã‚š','ã¹'=>'ã¸ã‚™','ãº'=>'ã¸ã‚š','ã¼'=>'ã»ã‚™','ã½'=>'ã»ã‚š','ã‚”'=>'ã†ã‚™','ã‚ž'=>'ã‚ã‚™','ガ'=>'ã‚«ã‚™','ã‚®'=>'ã‚­ã‚™','ã‚°'=>'グ','ゲ'=>'ゲ','ã‚´'=>'ゴ','ザ'=>'ザ','ジ'=>'ã‚·ã‚™','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ã‚¿ã‚™','ヂ'=>'ãƒã‚™','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','ãƒ'=>'ãƒã‚™','パ'=>'ãƒã‚š','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ãƒ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ','豈'=>'豈','ï¤'=>'æ›´','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'å¥','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'å–‡','奈'=>'奈','ï¤'=>'懶','癩'=>'癩','ï¤'=>'ç¾…','ï¤'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'é‚','樂'=>'樂','洛'=>'æ´›','烙'=>'烙','珞'=>'çž','落'=>'è½','酪'=>'é…ª','駱'=>'駱','亂'=>'亂','卵'=>'åµ','ï¤'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'åµ','濫'=>'æ¿«','藍'=>'è—','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'è Ÿ','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'å‹ž','擄'=>'æ“„','櫓'=>'æ«“','爐'=>'çˆ','盧'=>'盧','老'=>'è€','蘆'=>'蘆','虜'=>'虜','路'=>'è·¯','露'=>'露','魯'=>'é­¯','鷺'=>'é·º','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'è‰','錄'=>'錄','鹿'=>'鹿','ï¥'=>'è«–','壟'=>'壟','弄'=>'弄','籠'=>'ç± ','聾'=>'è¾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'é›·','壘'=>'壘','屢'=>'å±¢','樓'=>'樓','ï¥'=>'æ·š','漏'=>'æ¼','ï¥'=>'ç´¯','ï¥'=>'縷','陋'=>'陋','勒'=>'å‹’','肋'=>'è‚‹','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'è±','陵'=>'陵','讀'=>'讀','拏'=>'æ‹','樂'=>'樂','ï¥'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'ç•°','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'ä¸','泌'=>'泌','數'=>'數','索'=>'ç´¢','參'=>'åƒ','塞'=>'å¡ž','省'=>'çœ','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'è¾°','沈'=>'沈','拾'=>'拾','若'=>'è‹¥','掠'=>'掠','略'=>'ç•¥','亮'=>'亮','兩'=>'å…©','凉'=>'凉','梁'=>'æ¢','糧'=>'糧','良'=>'良','諒'=>'è«’','量'=>'é‡','勵'=>'勵','呂'=>'å‘‚','ï¦'=>'女','廬'=>'廬','旅'=>'æ—…','濾'=>'濾','礪'=>'礪','閭'=>'é–­','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'æ­·','ï¦'=>'è½¢','年'=>'å¹´','ï¦'=>'æ†','ï¦'=>'戀','撚'=>'æ’š','漣'=>'æ¼£','煉'=>'ç…‰','璉'=>'ç’‰','秊'=>'秊','練'=>'ç·´','聯'=>'è¯','輦'=>'輦','蓮'=>'è“®','連'=>'連','鍊'=>'éŠ','列'=>'列','ï¦'=>'劣','咽'=>'å’½','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'æ»','殮'=>'æ®®','簾'=>'ç°¾','獵'=>'çµ','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'ç‘©','羚'=>'羚','聆'=>'è†','鈴'=>'鈴','零'=>'零','靈'=>'éˆ','領'=>'é ˜','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'å°¿','料'=>'æ–™','樂'=>'樂','燎'=>'燎','ï§'=>'療','蓼'=>'蓼','遼'=>'é¼','龍'=>'é¾','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'æ»','柳'=>'柳','流'=>'æµ','溜'=>'溜','琉'=>'ç‰','ï§'=>'ç•™','硫'=>'ç¡«','ï§'=>'ç´','ï§'=>'é¡ž','六'=>'å…­','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'å´™','淪'=>'æ·ª','輪'=>'輪','律'=>'律','慄'=>'æ…„','栗'=>'æ —','率'=>'率','隆'=>'隆','ï§'=>'利','吏'=>'å','履'=>'å±¥','易'=>'易','李'=>'æŽ','梨'=>'梨','泥'=>'æ³¥','理'=>'ç†','痢'=>'ç—¢','罹'=>'ç½¹','裏'=>'è£','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'å','燐'=>'ç‡','璘'=>'ç’˜','藺'=>'è—º','隣'=>'隣','鱗'=>'é±—','麟'=>'麟','林'=>'æž—','淋'=>'æ·‹','臨'=>'臨','立'=>'ç«‹','笠'=>'笠','粒'=>'ç²’','狀'=>'ç‹€','炙'=>'ç‚™','識'=>'è­˜','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','ï¨'=>'度','拓'=>'æ‹“','糖'=>'ç³–','宅'=>'å®…','洞'=>'æ´ž','暴'=>'æš´','輻'=>'è¼»','行'=>'è¡Œ','降'=>'é™','見'=>'見','廓'=>'廓','兀'=>'å…€','ï¨'=>'å—€','ï¨'=>'å¡š','晴'=>'æ™´','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'ç¦','靖'=>'é–','ï¨'=>'ç²¾','羽'=>'ç¾½','蘒'=>'蘒','諸'=>'諸','逸'=>'逸','都'=>'都','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'ä¾®','僧'=>'僧','免'=>'å…','勉'=>'勉','勤'=>'勤','卑'=>'å‘','喝'=>'å–','嘆'=>'嘆','器'=>'器','塀'=>'å¡€','墨'=>'墨','層'=>'層','屮'=>'å±®','悔'=>'æ‚”','慨'=>'æ…¨','憎'=>'憎','ï©€'=>'懲','ï©'=>'æ•','ï©‚'=>'æ—¢','暑'=>'æš‘','ï©„'=>'梅','ï©…'=>'æµ·','渚'=>'渚','漢'=>'æ¼¢','煮'=>'ç…®','爫'=>'爫','ï©Š'=>'ç¢','ï©‹'=>'碑','ï©Œ'=>'社','ï©'=>'祉','ï©Ž'=>'祈','ï©'=>'ç¥','ï©'=>'祖','ï©‘'=>'ç¥','ï©’'=>'ç¦','ï©“'=>'禎','ï©”'=>'ç©€','ï©•'=>'çª','ï©–'=>'節','ï©—'=>'ç·´','縉'=>'縉','ï©™'=>'ç¹','ï©š'=>'ç½²','ï©›'=>'者','ï©œ'=>'臭','ï©'=>'艹','ï©ž'=>'艹','ï©Ÿ'=>'è‘—','ï© '=>'è¤','ï©¡'=>'視','ï©¢'=>'è¬','ï©£'=>'謹','賓'=>'賓','ï©¥'=>'è´ˆ','辶'=>'辶','逸'=>'逸','難'=>'難','ï©©'=>'響','頻'=>'é »','ï©°'=>'並','况'=>'况','全'=>'å…¨','侀'=>'ä¾€','ï©´'=>'å……','冀'=>'冀','勇'=>'勇','ï©·'=>'勺','喝'=>'å–','啕'=>'å••','喙'=>'å–™','ï©»'=>'å—¢','塚'=>'å¡š','墳'=>'墳','奄'=>'奄','ï©¿'=>'奔','婢'=>'å©¢','ïª'=>'嬨','廒'=>'å»’','廙'=>'å»™','彩'=>'彩','徭'=>'å¾­','惘'=>'惘','慎'=>'æ…Ž','愈'=>'愈','憎'=>'憎','慠'=>'æ… ','懲'=>'懲','戴'=>'戴','ïª'=>'æ„','搜'=>'æœ','ïª'=>'æ‘’','ïª'=>'æ•–','晴'=>'æ™´','朗'=>'朗','望'=>'望','杖'=>'æ–','歹'=>'æ­¹','殺'=>'殺','流'=>'æµ','滛'=>'æ»›','滋'=>'滋','漢'=>'æ¼¢','瀞'=>'瀞','煮'=>'ç…®','ïª'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'ç”»','瘝'=>'ç˜','瘟'=>'瘟','益'=>'益','盛'=>'ç››','直'=>'ç›´','睊'=>'çŠ','着'=>'ç€','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'ç±»','絛'=>'çµ›','練'=>'ç·´','缾'=>'ç¼¾','者'=>'者','荒'=>'è’','華'=>'è¯','蝹'=>'è¹','襁'=>'è¥','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'è«‹','謁'=>'è¬','諾'=>'諾','諭'=>'è«­','謹'=>'謹','ï«€'=>'變','ï«'=>'è´ˆ','ï«‚'=>'輸','遲'=>'é²','ï«„'=>'醙','ï«…'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'é–','韛'=>'韛','ï«Š'=>'響','ï«‹'=>'é ‹','ï«Œ'=>'é »','ï«'=>'鬒','ï«Ž'=>'龜','ï«'=>'𢡊','ï«'=>'𢡄','ï«‘'=>'ð£•','ï«’'=>'ã®','ï«“'=>'䀘','ï«”'=>'䀹','ï«•'=>'𥉉','ï«–'=>'ð¥³','ï«—'=>'𧻓','齃'=>'齃','ï«™'=>'龎','ï¬'=>'×™Ö´','ײַ'=>'ײַ','שׁ'=>'ש×','שׂ'=>'שׂ','שּׁ'=>'שּ×','שּׂ'=>'שּׂ','אַ'=>'×Ö·','אָ'=>'×Ö¸','אּ'=>'×Ö¼','בּ'=>'בּ','גּ'=>'×’Ö¼','דּ'=>'דּ','הּ'=>'×”Ö¼','וּ'=>'וּ','זּ'=>'×–Ö¼','טּ'=>'טּ','יּ'=>'×™Ö¼','ךּ'=>'ךּ','כּ'=>'×›Ö¼','לּ'=>'לּ','מּ'=>'מּ','ï­€'=>'× Ö¼','ï­'=>'סּ','ï­ƒ'=>'×£Ö¼','ï­„'=>'פּ','ï­†'=>'צּ','ï­‡'=>'קּ','ï­ˆ'=>'רּ','ï­‰'=>'שּ','ï­Š'=>'תּ','ï­‹'=>'וֹ','ï­Œ'=>'בֿ','ï­'=>'×›Ö¿','ï­Ž'=>'פֿ','ð…ž'=>'ð…—ð…¥','ð…Ÿ'=>'ð…˜ð…¥','ð… '=>'ð…˜ð…¥ð…®','ð…¡'=>'ð…˜ð…¥ð…¯','ð…¢'=>'ð…˜ð…¥ð…°','ð…£'=>'ð…˜ð…¥ð…±','ð…¤'=>'ð…˜ð…¥ð…²','ð†»'=>'ð†¹ð…¥','ð†¼'=>'ð†ºð…¥','ð†½'=>'ð†¹ð…¥ð…®','ð†¾'=>'ð†ºð…¥ð…®','ð†¿'=>'ð†¹ð…¥ð…¯','ð‡€'=>'ð†ºð…¥ð…¯','丽'=>'丽','ð¯ '=>'丸','乁'=>'ä¹','𠄢'=>'ð „¢','你'=>'ä½ ','侮'=>'ä¾®','侻'=>'ä¾»','倂'=>'倂','偺'=>'åº','備'=>'å‚™','僧'=>'僧','像'=>'åƒ','㒞'=>'ã’ž','ð¯ '=>'𠘺','免'=>'å…','ð¯ '=>'å…”','ð¯ '=>'å…¤','具'=>'å…·','𠔜'=>'𠔜','㒹'=>'ã’¹','內'=>'å…§','再'=>'å†','𠕋'=>'ð •‹','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','ð¯ '=>'凵','刃'=>'刃','㓟'=>'ã“Ÿ','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'å‰','卑'=>'å‘','博'=>'åš','即'=>'å³','卽'=>'å½','卿'=>'å¿','卿'=>'å¿','卿'=>'å¿','𠨬'=>'𠨬','灰'=>'ç°','及'=>'åŠ','叟'=>'åŸ','𠭣'=>'ð ­£','叫'=>'å«','叱'=>'å±','吆'=>'å†','咞'=>'å’ž','吸'=>'å¸','呈'=>'呈','周'=>'周','咢'=>'å’¢','ð¯¡'=>'哶','唐'=>'å”','啓'=>'å•“','啣'=>'å•£','善'=>'å–„','善'=>'å–„','喙'=>'å–™','喫'=>'å–«','喳'=>'å–³','嗂'=>'å—‚','圖'=>'圖','嘆'=>'嘆','ð¯¡'=>'圗','噑'=>'噑','ð¯¡'=>'å™´','ð¯¡'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'å ','型'=>'åž‹','堲'=>'å ²','報'=>'å ±','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','ð¯¡'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'ã›®','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'å°†','当'=>'当','尢'=>'å°¢','㞁'=>'ãž','屠'=>'å± ','屮'=>'å±®','峀'=>'å³€','岍'=>'å²','𡷤'=>'ð¡·¤','嵃'=>'嵃','𡷦'=>'ð¡·¦','嵮'=>'åµ®','嵫'=>'嵫','嵼'=>'åµ¼','ð¯¢'=>'å·¡','巢'=>'å·¢','㠯'=>'ã ¯','巽'=>'å·½','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'ã¡¢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','ð¯¢'=>'庶','廊'=>'廊','ð¯¢'=>'𪎒','ð¯¢'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'èˆ','弢'=>'å¼¢','弢'=>'å¼¢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'å½¢','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','ð¯¢'=>'å¿','志'=>'å¿—','忹'=>'忹','悁'=>'æ‚','㤺'=>'㤺','㤜'=>'㤜','悔'=>'æ‚”','𢛔'=>'𢛔','惇'=>'惇','慈'=>'æ…ˆ','慌'=>'æ…Œ','慎'=>'æ…Ž','慌'=>'æ…Œ','慺'=>'æ…º','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'æˆ','戛'=>'戛','扝'=>'æ‰','抱'=>'抱','拔'=>'æ‹”','捐'=>'æ','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'æ¨','掃'=>'掃','揤'=>'æ¤','𢯱'=>'𢯱','搢'=>'æ¢','揅'=>'æ…','ð¯£'=>'掩','㨮'=>'㨮','摩'=>'æ‘©','摾'=>'摾','撝'=>'æ’','摷'=>'æ‘·','㩬'=>'㩬','敏'=>'æ•','敬'=>'敬','𣀊'=>'𣀊','旣'=>'æ—£','書'=>'書','ð¯£'=>'晉','㬙'=>'㬙','ð¯£'=>'æš‘','ð¯£'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'æšœ','肭'=>'è‚­','䏙'=>'ä™','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'æž','杓'=>'æ“','ð¯£'=>'ð£ƒ','㭉'=>'ã­‰','柺'=>'柺','枅'=>'æž…','桒'=>'æ¡’','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'æ Ÿ','椔'=>'椔','㮝'=>'ã®','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'æ«›','㰘'=>'ã°˜','次'=>'次','𣢧'=>'𣢧','歔'=>'æ­”','㱎'=>'㱎','歲'=>'æ­²','殟'=>'殟','殺'=>'殺','殻'=>'æ®»','𣪍'=>'ð£ª','𡴋'=>'ð¡´‹','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'æ³','汧'=>'汧','洖'=>'æ´–','派'=>'æ´¾','ð¯¤'=>'æµ·','流'=>'æµ','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'æ´´','港'=>'港','湮'=>'æ¹®','㴳'=>'ã´³','滋'=>'滋','滇'=>'滇','ð¯¤'=>'𣻑','淹'=>'æ·¹','ð¯¤'=>'æ½®','ð¯¤'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'çŠ','災'=>'ç½','灷'=>'ç·','炭'=>'ç‚­','𠔥'=>'𠔥','煅'=>'ç……','ð¯¤'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'ç‰','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'çº','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'ç‘œ','瑱'=>'瑱','璅'=>'ç’…','瓊'=>'ç“Š','㼛'=>'ã¼›','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'ç•°','𢆟'=>'𢆟','瘐'=>'ç˜','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'ð¥„','㿼'=>'㿼','䀈'=>'䀈','直'=>'ç›´','ð¯¥'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'çŠ','䀹'=>'䀹','瞋'=>'çž‹','䁆'=>'ä†','䂖'=>'ä‚–','ð¯¥'=>'ð¥','硎'=>'ç¡Ž','ð¯¥'=>'碌','ð¯¥'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'ç¦','秫'=>'秫','䄯'=>'䄯','穀'=>'ç©€','穊'=>'ç©Š','穏'=>'ç©','𥥼'=>'𥥼','ð¯¥'=>'𥪧','𥪧'=>'𥪧','竮'=>'ç«®','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'ç³’','䊠'=>'䊠','糨'=>'糨','糣'=>'ç³£','紀'=>'ç´€','𥾆'=>'𥾆','絣'=>'çµ£','䌁'=>'äŒ','緇'=>'ç·‡','縂'=>'縂','繅'=>'ç¹…','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'ä™','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'è ','𦖨'=>'𦖨','聰'=>'è°','𣍟'=>'ð£Ÿ','ð¯¦'=>'ä•','育'=>'育','脃'=>'脃','䐋'=>'ä‹','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'èˆ','舄'=>'舄','ð¯¦'=>'辞','䑫'=>'ä‘«','ð¯¦'=>'芑','ð¯¦'=>'芋','芝'=>'èŠ','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'è‹¥','茝'=>'èŒ','荣'=>'è£','莭'=>'莭','茣'=>'茣','ð¯¦'=>'莽','菧'=>'è§','著'=>'è‘—','荓'=>'è“','菊'=>'èŠ','菌'=>'èŒ','菜'=>'èœ','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'è”–','𧏊'=>'ð§Š','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'ä•','䕡'=>'ä•¡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'ä•«','虐'=>'è™','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'èš©','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'è¹','蜨'=>'蜨','蝫'=>'è«','螆'=>'螆','䗗'=>'ä——','蟡'=>'蟡','ð¯§'=>'è ','䗹'=>'ä—¹','衠'=>'è¡ ','衣'=>'è¡£','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'ã’»','𧢮'=>'𧢮','𧥦'=>'𧥦','ð¯§'=>'äš¾','䛇'=>'䛇','ð¯§'=>'誠','ð¯§'=>'è«­','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'è³','贛'=>'è´›','起'=>'èµ·','𧼯'=>'𧼯','𠠄'=>'ð  „','跋'=>'è·‹','趼'=>'趼','跰'=>'è·°','ð¯§'=>'𠣞','軔'=>'è»”','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'é‚”','郱'=>'郱','鄑'=>'é„‘','𨜮'=>'𨜮','鄛'=>'é„›','鈸'=>'鈸','鋗'=>'é‹—','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'é¹','鐕'=>'é•','𨯺'=>'𨯺','開'=>'é–‹','䦕'=>'䦕','閷'=>'é–·','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'ð©……','𩈚'=>'𩈚','䩮'=>'ä©®','䩶'=>'䩶','韠'=>'韠','𩐊'=>'ð©Š','䪲'=>'䪲','𩒖'=>'ð©’–','頋'=>'é ‹','頋'=>'é ‹','頩'=>'é ©','ð¯¨'=>'ð©–¶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'é±€','鳽'=>'é³½','ð¯¨'=>'䳎','䳭'=>'ä³­','ð¯¨'=>'鵧','ð¯¨'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'äµ–','黹'=>'黹','黾'=>'黾','鼅'=>'é¼…','鼏'=>'é¼','鼖'=>'é¼–','鼻'=>'é¼»','ð¯¨'=>'𪘀');
diff --git a/phpBB/includes/utf/data/utf_compatibility_decomp.php b/phpBB/includes/utf/data/utf_compatibility_decomp.php
deleted file mode 100644
index c62948e81a..0000000000
--- a/phpBB/includes/utf/data/utf_compatibility_decomp.php
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-$GLOBALS['utf_compatibility_decomp']=array(' '=>' ','¨'=>' ̈','ª'=>'a','¯'=>' Ì„','²'=>'2','³'=>'3','´'=>' Ì','µ'=>'μ','¸'=>' ̧','¹'=>'1','º'=>'o','¼'=>'1â„4','½'=>'1â„2','¾'=>'3â„4','À'=>'AÌ€','Ã'=>'AÌ','Â'=>'AÌ‚','Ã'=>'Ã','Ä'=>'Ä','Ã…'=>'AÌŠ','Ç'=>'Ç','È'=>'EÌ€','É'=>'EÌ','Ê'=>'EÌ‚','Ë'=>'Ë','ÃŒ'=>'IÌ€','Ã'=>'IÌ','ÃŽ'=>'IÌ‚','Ã'=>'Ï','Ñ'=>'Ñ','Ã’'=>'OÌ€','Ó'=>'OÌ','Ô'=>'OÌ‚','Õ'=>'Õ','Ö'=>'Ö','Ù'=>'UÌ€','Ú'=>'UÌ','Û'=>'UÌ‚','Ãœ'=>'Ü','Ã'=>'YÌ','à'=>'aÌ€','á'=>'aÌ','â'=>'aÌ‚','ã'=>'ã','ä'=>'ä','Ã¥'=>'aÌŠ','ç'=>'ç','è'=>'eÌ€','é'=>'eÌ','ê'=>'eÌ‚','ë'=>'ë','ì'=>'iÌ€','í'=>'iÌ','î'=>'iÌ‚','ï'=>'ï','ñ'=>'ñ','ò'=>'oÌ€','ó'=>'oÌ','ô'=>'oÌ‚','õ'=>'õ','ö'=>'ö','ù'=>'uÌ€','ú'=>'uÌ','û'=>'uÌ‚','ü'=>'ü','ý'=>'yÌ','ÿ'=>'ÿ','Ä€'=>'AÌ„','Ä'=>'aÌ„','Ä‚'=>'Ă','ă'=>'ă','Ä„'=>'Ą','Ä…'=>'ą','Ć'=>'CÌ','ć'=>'cÌ','Ĉ'=>'CÌ‚','ĉ'=>'cÌ‚','ÄŠ'=>'Ċ','Ä‹'=>'ċ','ÄŒ'=>'CÌŒ','Ä'=>'cÌŒ','ÄŽ'=>'DÌŒ','Ä'=>'dÌŒ','Ä’'=>'EÌ„','Ä“'=>'eÌ„','Ä”'=>'Ĕ','Ä•'=>'ĕ','Ä–'=>'Ė','Ä—'=>'ė','Ę'=>'Ę','Ä™'=>'ę','Äš'=>'EÌŒ','Ä›'=>'eÌŒ','Äœ'=>'GÌ‚','Ä'=>'gÌ‚','Äž'=>'Ğ','ÄŸ'=>'ğ','Ä '=>'Ġ','Ä¡'=>'ġ','Ä¢'=>'Ģ','Ä£'=>'ģ','Ĥ'=>'HÌ‚','Ä¥'=>'hÌ‚','Ĩ'=>'Ĩ','Ä©'=>'ĩ','Ī'=>'IÌ„','Ä«'=>'iÌ„','Ĭ'=>'Ĭ','Ä­'=>'ĭ','Ä®'=>'Į','į'=>'į','Ä°'=>'İ','IJ'=>'IJ','ij'=>'ij','Ä´'=>'JÌ‚','ĵ'=>'jÌ‚','Ķ'=>'Ķ','Ä·'=>'ķ','Ĺ'=>'LÌ','ĺ'=>'lÌ','Ä»'=>'Ļ','ļ'=>'ļ','Ľ'=>'LÌŒ','ľ'=>'lÌŒ','Ä¿'=>'L·','Å€'=>'l·','Ń'=>'NÌ','Å„'=>'nÌ','Å…'=>'Ņ','ņ'=>'ņ','Ň'=>'NÌŒ','ň'=>'nÌŒ','ʼn'=>'ʼn','ÅŒ'=>'OÌ„','Å'=>'oÌ„','ÅŽ'=>'Ŏ','Å'=>'ŏ','Å'=>'OÌ‹','Å‘'=>'oÌ‹','Å”'=>'RÌ','Å•'=>'rÌ','Å–'=>'Ŗ','Å—'=>'ŗ','Ř'=>'RÌŒ','Å™'=>'rÌŒ','Åš'=>'SÌ','Å›'=>'sÌ','Åœ'=>'SÌ‚','Å'=>'sÌ‚','Åž'=>'Ş','ÅŸ'=>'ş','Å '=>'SÌŒ','Å¡'=>'sÌŒ','Å¢'=>'Ţ','Å£'=>'ţ','Ť'=>'TÌŒ','Å¥'=>'tÌŒ','Ũ'=>'Ũ','Å©'=>'ũ','Ū'=>'UÌ„','Å«'=>'uÌ„','Ŭ'=>'Ŭ','Å­'=>'ŭ','Å®'=>'UÌŠ','ů'=>'uÌŠ','Å°'=>'UÌ‹','ű'=>'uÌ‹','Ų'=>'Ų','ų'=>'ų','Å´'=>'WÌ‚','ŵ'=>'wÌ‚','Ŷ'=>'YÌ‚','Å·'=>'yÌ‚','Ÿ'=>'Ÿ','Ź'=>'ZÌ','ź'=>'zÌ','Å»'=>'Ż','ż'=>'ż','Ž'=>'ZÌŒ','ž'=>'zÌŒ','Å¿'=>'s','Æ '=>'OÌ›','Æ¡'=>'oÌ›','Ư'=>'UÌ›','Æ°'=>'uÌ›','Ç„'=>'DZÌŒ','Ç…'=>'DzÌŒ','dž'=>'dzÌŒ','LJ'=>'LJ','Lj'=>'Lj','lj'=>'lj','ÇŠ'=>'NJ','Ç‹'=>'Nj','ÇŒ'=>'nj','Ç'=>'AÌŒ','ÇŽ'=>'aÌŒ','Ç'=>'IÌŒ','Ç'=>'iÌŒ','Ç‘'=>'OÌŒ','Ç’'=>'oÌŒ','Ç“'=>'UÌŒ','Ç”'=>'uÌŒ','Ç•'=>'Ǖ','Ç–'=>'ǖ','Ç—'=>'ÜÌ','ǘ'=>'üÌ','Ç™'=>'Ǚ','Çš'=>'ǚ','Ç›'=>'Ǜ','Çœ'=>'ǜ','Çž'=>'Ǟ','ÇŸ'=>'ǟ','Ç '=>'Ǡ','Ç¡'=>'ǡ','Ç¢'=>'Ǣ','Ç£'=>'ǣ','Ǧ'=>'GÌŒ','ǧ'=>'gÌŒ','Ǩ'=>'KÌŒ','Ç©'=>'kÌŒ','Ǫ'=>'Ǫ','Ç«'=>'ǫ','Ǭ'=>'Ǭ','Ç­'=>'ǭ','Ç®'=>'Æ·ÌŒ','ǯ'=>'Ê’ÌŒ','Ç°'=>'jÌŒ','DZ'=>'DZ','Dz'=>'Dz','dz'=>'dz','Ç´'=>'GÌ','ǵ'=>'gÌ','Ǹ'=>'NÌ€','ǹ'=>'nÌ€','Ǻ'=>'AÌŠÌ','Ç»'=>'aÌŠÌ','Ǽ'=>'ÆÌ','ǽ'=>'æÌ','Ǿ'=>'ØÌ','Ç¿'=>'øÌ','È€'=>'AÌ','È'=>'aÌ','È‚'=>'AÌ‘','ȃ'=>'aÌ‘','È„'=>'EÌ','È…'=>'eÌ','Ȇ'=>'EÌ‘','ȇ'=>'eÌ‘','Ȉ'=>'IÌ','ȉ'=>'iÌ','ÈŠ'=>'IÌ‘','È‹'=>'iÌ‘','ÈŒ'=>'OÌ','È'=>'oÌ','ÈŽ'=>'OÌ‘','È'=>'oÌ‘','È'=>'RÌ','È‘'=>'rÌ','È’'=>'RÌ‘','È“'=>'rÌ‘','È”'=>'UÌ','È•'=>'uÌ','È–'=>'UÌ‘','È—'=>'uÌ‘','Ș'=>'Ș','È™'=>'ș','Èš'=>'Ț','È›'=>'ț','Èž'=>'HÌŒ','ÈŸ'=>'hÌŒ','Ȧ'=>'Ȧ','ȧ'=>'ȧ','Ȩ'=>'Ȩ','È©'=>'ȩ','Ȫ'=>'Ȫ','È«'=>'ȫ','Ȭ'=>'Ȭ','È­'=>'ȭ','È®'=>'Ȯ','ȯ'=>'ȯ','È°'=>'Ȱ','ȱ'=>'ȱ','Ȳ'=>'YÌ„','ȳ'=>'yÌ„','Ê°'=>'h','ʱ'=>'ɦ','ʲ'=>'j','ʳ'=>'r','Ê´'=>'ɹ','ʵ'=>'É»','ʶ'=>'Ê','Ê·'=>'w','ʸ'=>'y','˘'=>' ̆','Ë™'=>' ̇','Ëš'=>' ÌŠ','Ë›'=>' ̨','Ëœ'=>' ̃','Ë'=>' Ì‹','Ë '=>'É£','Ë¡'=>'l','Ë¢'=>'s','Ë£'=>'x','ˤ'=>'Ê•','Í€'=>'Ì€','Í'=>'Ì','̓'=>'Ì“','Í„'=>'̈Ì','Í´'=>'ʹ','ͺ'=>' Í…',';'=>';','΄'=>' Ì','Î…'=>' ̈Ì','Ά'=>'ΑÌ','·'=>'·','Έ'=>'ΕÌ','Ή'=>'ΗÌ','Ί'=>'ΙÌ','ÎŒ'=>'ΟÌ','ÎŽ'=>'Î¥Ì','Î'=>'ΩÌ','Î'=>'ϊÌ','Ϊ'=>'Ϊ','Ϋ'=>'Ϋ','ά'=>'αÌ','έ'=>'εÌ','ή'=>'ηÌ','ί'=>'ιÌ','ΰ'=>'ϋÌ','ÏŠ'=>'ϊ','Ï‹'=>'ϋ','ÏŒ'=>'οÌ','Ï'=>'Ï…Ì','ÏŽ'=>'ωÌ','Ï'=>'β','Ï‘'=>'θ','Ï’'=>'Î¥','Ï“'=>'Î¥Ì','Ï”'=>'Ϋ','Ï•'=>'φ','Ï–'=>'Ï€','Ï°'=>'κ','ϱ'=>'Ï','ϲ'=>'Ï‚','Ï´'=>'Θ','ϵ'=>'ε','Ϲ'=>'Σ','Ѐ'=>'Ѐ','Ð'=>'Ё','Ѓ'=>'ГÌ','Ї'=>'Ї','ÐŒ'=>'КÌ','Ð'=>'Ѝ','ÐŽ'=>'Ў','Й'=>'Й','й'=>'й','Ñ'=>'ѐ','Ñ‘'=>'ё','Ñ“'=>'гÌ','Ñ—'=>'ї','Ñœ'=>'кÌ','Ñ'=>'ѝ','Ñž'=>'ў','Ѷ'=>'Ñ´Ì','Ñ·'=>'ѵÌ','Ó'=>'Ӂ','Ó‚'=>'ӂ','Ó'=>'Ð̆','Ó‘'=>'ӑ','Ó’'=>'Ð̈','Ó“'=>'ӓ','Ó–'=>'Ӗ','Ó—'=>'ӗ','Óš'=>'Ӛ','Ó›'=>'ӛ','Óœ'=>'Ӝ','Ó'=>'ӝ','Óž'=>'Ӟ','ÓŸ'=>'ӟ','Ó¢'=>'Ӣ','Ó£'=>'ӣ','Ó¤'=>'Ӥ','Ó¥'=>'ӥ','Ó¦'=>'Ӧ','Ó§'=>'ӧ','Óª'=>'Ӫ','Ó«'=>'ӫ','Ó¬'=>'Ӭ','Ó­'=>'Ñ̈','Ó®'=>'Ӯ','Ó¯'=>'ӯ','Ó°'=>'Ӱ','Ó±'=>'ӱ','Ó²'=>'Ӳ','Ó³'=>'ӳ','Ó´'=>'Ӵ','Óµ'=>'ӵ','Ó¸'=>'Ӹ','Ó¹'=>'ӹ','Ö‡'=>'Õ¥Ö‚','Ø¢'=>'آ','Ø£'=>'أ','ؤ'=>'ÙˆÙ”','Ø¥'=>'إ','ئ'=>'ÙŠÙ”','Ùµ'=>'اٴ','Ù¶'=>'وٴ','Ù·'=>'Û‡Ù´','Ù¸'=>'يٴ','Û€'=>'Û•Ù”','Û‚'=>'ÛÙ”','Û“'=>'Û’Ù”','ऩ'=>'ऩ','ऱ'=>'ऱ','ऴ'=>'ऴ','क़'=>'क़','ख़'=>'ख़','ग़'=>'ग़','ज़'=>'ज़','ड़'=>'ड़','à¥'=>'ढ़','फ़'=>'फ़','य़'=>'य़','ো'=>'ো','ৌ'=>'ৌ','ড়'=>'ড়','à§'=>'ঢ়','য়'=>'য়','ਲ਼'=>'ਲ਼','ਸ਼'=>'ਸ਼','à©™'=>'ਖ਼','à©š'=>'ਗ਼','à©›'=>'ਜ਼','à©ž'=>'ਫ਼','à­ˆ'=>'ୈ','à­‹'=>'ୋ','à­Œ'=>'ୌ','à­œ'=>'ଡ଼','à­'=>'ଢ଼','à®”'=>'ஔ','ொ'=>'ொ','ோ'=>'ோ','ௌ'=>'ௌ','ై'=>'ై','à³€'=>'ೀ','ೇ'=>'ೇ','ೈ'=>'ೈ','ೊ'=>'ೊ','ೋ'=>'ೋ','ൊ'=>'ൊ','ോ'=>'ോ','ൌ'=>'ൌ','à·š'=>'ේ','à·œ'=>'à·™à·','à·'=>'à·™à·à·Š','à·ž'=>'ෞ','ำ'=>'à¹à¸²','ຳ'=>'à»àº²','ໜ'=>'ຫນ','à»'=>'ຫມ','༌'=>'་','གྷ'=>'གྷ','à½'=>'ཌྷ','དྷ'=>'དྷ','བྷ'=>'བྷ','ཛྷ'=>'ཛྷ','ཀྵ'=>'ཀྵ','ཱི'=>'ཱི','ཱུ'=>'ཱུ','ྲྀ'=>'ྲྀ','ཷ'=>'ྲཱྀ','ླྀ'=>'ླྀ','ཹ'=>'ླཱྀ','à¾'=>'ཱྀ','ྒྷ'=>'ྒྷ','à¾'=>'ྜྷ','ྡྷ'=>'ྡྷ','ྦྷ'=>'ྦྷ','ྫྷ'=>'ྫྷ','ྐྵ'=>'à¾à¾µ','ဦ'=>'ဦ','ჼ'=>'ნ','ᬆ'=>'ᬆ','ᬈ'=>'ᬈ','ᬊ'=>'ᬊ','ᬌ'=>'ᬌ','ᬎ'=>'á¬á¬µ','ᬒ'=>'ᬒ','ᬻ'=>'ᬻ','ᬽ'=>'ᬽ','á­€'=>'ᭀ','á­'=>'ᭁ','á­ƒ'=>'ᭃ','á´¬'=>'A','á´­'=>'Æ','á´®'=>'B','á´°'=>'D','á´±'=>'E','á´²'=>'ÆŽ','á´³'=>'G','á´´'=>'H','á´µ'=>'I','á´¶'=>'J','á´·'=>'K','á´¸'=>'L','á´¹'=>'M','á´º'=>'N','á´¼'=>'O','á´½'=>'È¢','á´¾'=>'P','á´¿'=>'R','áµ€'=>'T','áµ'=>'U','ᵂ'=>'W','ᵃ'=>'a','ᵄ'=>'É','áµ…'=>'É‘','ᵆ'=>'á´‚','ᵇ'=>'b','ᵈ'=>'d','ᵉ'=>'e','ᵊ'=>'É™','ᵋ'=>'É›','ᵌ'=>'Éœ','áµ'=>'g','áµ'=>'k','áµ'=>'m','ᵑ'=>'Å‹','áµ’'=>'o','ᵓ'=>'É”','áµ”'=>'á´–','ᵕ'=>'á´—','áµ–'=>'p','áµ—'=>'t','ᵘ'=>'u','áµ™'=>'á´','ᵚ'=>'ɯ','áµ›'=>'v','ᵜ'=>'á´¥','áµ'=>'β','ᵞ'=>'γ','ᵟ'=>'δ','áµ '=>'φ','ᵡ'=>'χ','áµ¢'=>'i','áµ£'=>'r','ᵤ'=>'u','áµ¥'=>'v','ᵦ'=>'β','ᵧ'=>'γ','ᵨ'=>'Ï','ᵩ'=>'φ','ᵪ'=>'χ','ᵸ'=>'н','ᶛ'=>'É’','ᶜ'=>'c','á¶'=>'É•','ᶞ'=>'ð','ᶟ'=>'Éœ','ᶠ'=>'f','ᶡ'=>'ÉŸ','ᶢ'=>'É¡','ᶣ'=>'É¥','ᶤ'=>'ɨ','ᶥ'=>'É©','ᶦ'=>'ɪ','ᶧ'=>'áµ»','ᶨ'=>'Ê','ᶩ'=>'É­','ᶪ'=>'ᶅ','ᶫ'=>'ÊŸ','ᶬ'=>'ɱ','ᶭ'=>'É°','ᶮ'=>'ɲ','ᶯ'=>'ɳ','ᶰ'=>'É´','ᶱ'=>'ɵ','ᶲ'=>'ɸ','ᶳ'=>'Ê‚','ᶴ'=>'ʃ','ᶵ'=>'Æ«','ᶶ'=>'ʉ','ᶷ'=>'ÊŠ','ᶸ'=>'á´œ','ᶹ'=>'Ê‹','ᶺ'=>'ÊŒ','ᶻ'=>'z','ᶼ'=>'Ê','ᶽ'=>'Ê‘','ᶾ'=>'Ê’','ᶿ'=>'θ','Ḁ'=>'AÌ¥','á¸'=>'aÌ¥','Ḃ'=>'Ḃ','ḃ'=>'ḃ','Ḅ'=>'BÌ£','ḅ'=>'bÌ£','Ḇ'=>'Ḇ','ḇ'=>'ḇ','Ḉ'=>'ÇÌ','ḉ'=>'çÌ','Ḋ'=>'Ḋ','ḋ'=>'ḋ','Ḍ'=>'DÌ£','á¸'=>'dÌ£','Ḏ'=>'Ḏ','á¸'=>'ḏ','á¸'=>'Ḑ','ḑ'=>'ḑ','Ḓ'=>'DÌ­','ḓ'=>'dÌ­','Ḕ'=>'EÌ„Ì€','ḕ'=>'eÌ„Ì€','Ḗ'=>'EÌ„Ì','ḗ'=>'eÌ„Ì','Ḙ'=>'EÌ­','ḙ'=>'eÌ­','Ḛ'=>'EÌ°','ḛ'=>'eÌ°','Ḝ'=>'Ḝ','á¸'=>'ḝ','Ḟ'=>'Ḟ','ḟ'=>'ḟ','Ḡ'=>'GÌ„','ḡ'=>'gÌ„','Ḣ'=>'Ḣ','ḣ'=>'ḣ','Ḥ'=>'HÌ£','ḥ'=>'hÌ£','Ḧ'=>'Ḧ','ḧ'=>'ḧ','Ḩ'=>'Ḩ','ḩ'=>'ḩ','Ḫ'=>'HÌ®','ḫ'=>'hÌ®','Ḭ'=>'IÌ°','ḭ'=>'iÌ°','Ḯ'=>'ÏÌ','ḯ'=>'ïÌ','Ḱ'=>'KÌ','ḱ'=>'kÌ','Ḳ'=>'KÌ£','ḳ'=>'kÌ£','Ḵ'=>'Ḵ','ḵ'=>'ḵ','Ḷ'=>'LÌ£','ḷ'=>'lÌ£','Ḹ'=>'Ḹ','ḹ'=>'ḹ','Ḻ'=>'Ḻ','ḻ'=>'ḻ','Ḽ'=>'LÌ­','ḽ'=>'lÌ­','Ḿ'=>'MÌ','ḿ'=>'mÌ','á¹€'=>'Ṁ','á¹'=>'ṁ','Ṃ'=>'MÌ£','ṃ'=>'mÌ£','Ṅ'=>'Ṅ','á¹…'=>'ṅ','Ṇ'=>'NÌ£','ṇ'=>'nÌ£','Ṉ'=>'Ṉ','ṉ'=>'ṉ','Ṋ'=>'NÌ­','ṋ'=>'nÌ­','Ṍ'=>'ÕÌ','á¹'=>'õÌ','Ṏ'=>'Ṏ','á¹'=>'ṏ','á¹'=>'OÌ„Ì€','ṑ'=>'oÌ„Ì€','á¹’'=>'OÌ„Ì','ṓ'=>'oÌ„Ì','á¹”'=>'PÌ','ṕ'=>'pÌ','á¹–'=>'Ṗ','á¹—'=>'ṗ','Ṙ'=>'Ṙ','á¹™'=>'ṙ','Ṛ'=>'RÌ£','á¹›'=>'rÌ£','Ṝ'=>'Ṝ','á¹'=>'ṝ','Ṟ'=>'Ṟ','ṟ'=>'ṟ','á¹ '=>'Ṡ','ṡ'=>'ṡ','á¹¢'=>'SÌ£','á¹£'=>'sÌ£','Ṥ'=>'SÌ̇','á¹¥'=>'sÌ̇','Ṧ'=>'Ṧ','ṧ'=>'ṧ','Ṩ'=>'Ṩ','ṩ'=>'ṩ','Ṫ'=>'Ṫ','ṫ'=>'ṫ','Ṭ'=>'TÌ£','á¹­'=>'tÌ£','á¹®'=>'Ṯ','ṯ'=>'ṯ','á¹°'=>'TÌ­','á¹±'=>'tÌ­','á¹²'=>'Ṳ','á¹³'=>'ṳ','á¹´'=>'UÌ°','á¹µ'=>'uÌ°','Ṷ'=>'UÌ­','á¹·'=>'uÌ­','Ṹ'=>'ŨÌ','á¹¹'=>'ũÌ','Ṻ'=>'Ṻ','á¹»'=>'ṻ','á¹¼'=>'Ṽ','á¹½'=>'ṽ','á¹¾'=>'VÌ£','ṿ'=>'vÌ£','Ẁ'=>'WÌ€','áº'=>'wÌ€','Ẃ'=>'WÌ','ẃ'=>'wÌ','Ẅ'=>'Ẅ','ẅ'=>'ẅ','Ẇ'=>'Ẇ','ẇ'=>'ẇ','Ẉ'=>'WÌ£','ẉ'=>'wÌ£','Ẋ'=>'Ẋ','ẋ'=>'ẋ','Ẍ'=>'Ẍ','áº'=>'ẍ','Ẏ'=>'Ẏ','áº'=>'ẏ','áº'=>'ZÌ‚','ẑ'=>'zÌ‚','Ẓ'=>'ZÌ£','ẓ'=>'zÌ£','Ẕ'=>'Ẕ','ẕ'=>'ẕ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'wÌŠ','ẙ'=>'yÌŠ','ẚ'=>'aʾ','ẛ'=>'ṡ','Ạ'=>'AÌ£','ạ'=>'aÌ£','Ả'=>'Ả','ả'=>'ả','Ấ'=>'AÌ‚Ì','ấ'=>'aÌ‚Ì','Ầ'=>'AÌ‚Ì€','ầ'=>'aÌ‚Ì€','Ẩ'=>'Ẩ','ẩ'=>'ẩ','Ẫ'=>'Ẫ','ẫ'=>'ẫ','Ậ'=>'Ậ','ậ'=>'ậ','Ắ'=>'ĂÌ','ắ'=>'ăÌ','Ằ'=>'Ằ','ằ'=>'ằ','Ẳ'=>'Ẳ','ẳ'=>'ẳ','Ẵ'=>'Ẵ','ẵ'=>'ẵ','Ặ'=>'Ặ','ặ'=>'ặ','Ẹ'=>'EÌ£','ẹ'=>'eÌ£','Ẻ'=>'Ẻ','ẻ'=>'ẻ','Ẽ'=>'Ẽ','ẽ'=>'ẽ','Ế'=>'EÌ‚Ì','ế'=>'eÌ‚Ì','Ề'=>'EÌ‚Ì€','á»'=>'eÌ‚Ì€','Ể'=>'Ể','ể'=>'ể','Ễ'=>'Ễ','á»…'=>'ễ','Ệ'=>'Ệ','ệ'=>'ệ','Ỉ'=>'Ỉ','ỉ'=>'ỉ','Ị'=>'IÌ£','ị'=>'iÌ£','Ọ'=>'OÌ£','á»'=>'oÌ£','Ỏ'=>'Ỏ','á»'=>'ỏ','á»'=>'OÌ‚Ì','ố'=>'oÌ‚Ì','á»’'=>'OÌ‚Ì€','ồ'=>'oÌ‚Ì€','á»”'=>'Ổ','ổ'=>'ổ','á»–'=>'Ỗ','á»—'=>'ỗ','Ộ'=>'Ộ','á»™'=>'ộ','Ớ'=>'OÌ›Ì','á»›'=>'oÌ›Ì','Ờ'=>'Ờ','á»'=>'ờ','Ở'=>'Ở','ở'=>'ở','á» '=>'Ỡ','ỡ'=>'ỡ','Ợ'=>'Ợ','ợ'=>'ợ','Ụ'=>'UÌ£','ụ'=>'uÌ£','Ủ'=>'Ủ','ủ'=>'ủ','Ứ'=>'UÌ›Ì','ứ'=>'uÌ›Ì','Ừ'=>'Ừ','ừ'=>'ừ','Ử'=>'Ử','á»­'=>'ử','á»®'=>'Ữ','ữ'=>'ữ','á»°'=>'Ự','á»±'=>'ự','Ỳ'=>'YÌ€','ỳ'=>'yÌ€','á»´'=>'YÌ£','ỵ'=>'yÌ£','Ỷ'=>'Ỷ','á»·'=>'ỷ','Ỹ'=>'Ỹ','ỹ'=>'ỹ','á¼€'=>'ἀ','á¼'=>'ἁ','ἂ'=>'ἂ','ἃ'=>'ἃ','ἄ'=>'ἀÌ','á¼…'=>'ἁÌ','ἆ'=>'ἆ','ἇ'=>'ἇ','Ἀ'=>'Ἀ','Ἁ'=>'Ἁ','Ἂ'=>'Ἂ','Ἃ'=>'Ἃ','Ἄ'=>'ἈÌ','á¼'=>'ἉÌ','Ἆ'=>'Ἆ','á¼'=>'Ἇ','á¼'=>'ἐ','ἑ'=>'ἑ','á¼’'=>'ἒ','ἓ'=>'ἓ','á¼”'=>'ἐÌ','ἕ'=>'ἑÌ','Ἐ'=>'Ἐ','á¼™'=>'Ἑ','Ἒ'=>'Ἒ','á¼›'=>'Ἓ','Ἔ'=>'ἘÌ','á¼'=>'ἙÌ','á¼ '=>'ἠ','ἡ'=>'ἡ','á¼¢'=>'ἢ','á¼£'=>'ἣ','ἤ'=>'ἠÌ','á¼¥'=>'ἡÌ','ἦ'=>'ἦ','ἧ'=>'ἧ','Ἠ'=>'Ἠ','Ἡ'=>'Ἡ','Ἢ'=>'Ἢ','Ἣ'=>'Ἣ','Ἤ'=>'ἨÌ','á¼­'=>'ἩÌ','á¼®'=>'Ἦ','Ἧ'=>'Ἧ','á¼°'=>'ἰ','á¼±'=>'ἱ','á¼²'=>'ἲ','á¼³'=>'ἳ','á¼´'=>'ἰÌ','á¼µ'=>'ἱÌ','ἶ'=>'ἶ','á¼·'=>'ἷ','Ἰ'=>'Ἰ','á¼¹'=>'Ἱ','Ἲ'=>'Ἲ','á¼»'=>'Ἳ','á¼¼'=>'ἸÌ','á¼½'=>'ἹÌ','á¼¾'=>'Ἶ','Ἷ'=>'Ἷ','á½€'=>'ὀ','á½'=>'ὁ','ὂ'=>'ὂ','ὃ'=>'ὃ','ὄ'=>'ὀÌ','á½…'=>'ὁÌ','Ὀ'=>'Ὀ','Ὁ'=>'Ὁ','Ὂ'=>'Ὂ','Ὃ'=>'Ὃ','Ὄ'=>'ὈÌ','á½'=>'ὉÌ','á½'=>'Ï…Ì“','ὑ'=>'Ï…Ì”','á½’'=>'Ï…Ì“Ì€','ὓ'=>'ὓ','á½”'=>'Ï…Ì“Ì','ὕ'=>'Ï…Ì”Ì','á½–'=>'Ï…Ì“Í‚','á½—'=>'ὗ','á½™'=>'Ὑ','á½›'=>'Ὓ','á½'=>'ὙÌ','Ὗ'=>'Ὗ','á½ '=>'ὠ','ὡ'=>'ὡ','á½¢'=>'ὢ','á½£'=>'ὣ','ὤ'=>'ὠÌ','á½¥'=>'ὡÌ','ὦ'=>'ὦ','ὧ'=>'ὧ','Ὠ'=>'Ὠ','Ὡ'=>'Ὡ','Ὢ'=>'Ὢ','Ὣ'=>'Ὣ','Ὤ'=>'ὨÌ','á½­'=>'ὩÌ','á½®'=>'Ὦ','Ὧ'=>'Ὧ','á½°'=>'ὰ','á½±'=>'αÌ','á½²'=>'ὲ','á½³'=>'εÌ','á½´'=>'ὴ','á½µ'=>'ηÌ','ὶ'=>'ὶ','á½·'=>'ιÌ','ὸ'=>'ὸ','á½¹'=>'οÌ','ὺ'=>'Ï…Ì€','á½»'=>'Ï…Ì','á½¼'=>'ὼ','á½½'=>'ωÌ','á¾€'=>'ᾀ','á¾'=>'ᾁ','ᾂ'=>'ᾂ','ᾃ'=>'ᾃ','ᾄ'=>'ἀÌÍ…','á¾…'=>'ἁÌÍ…','ᾆ'=>'ᾆ','ᾇ'=>'ᾇ','ᾈ'=>'ᾈ','ᾉ'=>'ᾉ','ᾊ'=>'ᾊ','ᾋ'=>'ᾋ','ᾌ'=>'ἈÌÍ…','á¾'=>'ἉÌÍ…','ᾎ'=>'ᾎ','á¾'=>'ᾏ','á¾'=>'ᾐ','ᾑ'=>'ᾑ','á¾’'=>'ᾒ','ᾓ'=>'ᾓ','á¾”'=>'ἠÌÍ…','ᾕ'=>'ἡÌÍ…','á¾–'=>'ᾖ','á¾—'=>'ᾗ','ᾘ'=>'ᾘ','á¾™'=>'ᾙ','ᾚ'=>'ᾚ','á¾›'=>'ᾛ','ᾜ'=>'ἨÌÍ…','á¾'=>'ἩÌÍ…','ᾞ'=>'ᾞ','ᾟ'=>'ᾟ','á¾ '=>'ᾠ','ᾡ'=>'ᾡ','á¾¢'=>'ᾢ','á¾£'=>'ᾣ','ᾤ'=>'ὠÌÍ…','á¾¥'=>'ὡÌÍ…','ᾦ'=>'ᾦ','ᾧ'=>'ᾧ','ᾨ'=>'ᾨ','ᾩ'=>'ᾩ','ᾪ'=>'ᾪ','ᾫ'=>'ᾫ','ᾬ'=>'ὨÌÍ…','á¾­'=>'ὩÌÍ…','á¾®'=>'ᾮ','ᾯ'=>'ᾯ','á¾°'=>'ᾰ','á¾±'=>'ᾱ','á¾²'=>'ᾲ','á¾³'=>'ᾳ','á¾´'=>'αÌÍ…','ᾶ'=>'ᾶ','á¾·'=>'ᾷ','Ᾰ'=>'Ᾰ','á¾¹'=>'Ᾱ','Ὰ'=>'Ὰ','á¾»'=>'ΑÌ','á¾¼'=>'ᾼ','á¾½'=>' Ì“','á¾¾'=>'ι','᾿'=>' Ì“','á¿€'=>' Í‚','á¿'=>' ̈͂','á¿‚'=>'ῂ','ῃ'=>'ῃ','á¿„'=>'ηÌÍ…','ῆ'=>'ῆ','ῇ'=>'ῇ','Ὲ'=>'Ὲ','Έ'=>'ΕÌ','á¿Š'=>'Ὴ','á¿‹'=>'ΗÌ','á¿Œ'=>'ῌ','á¿'=>' Ì“Ì€','á¿Ž'=>' Ì“Ì','á¿'=>' Ì“Í‚','á¿'=>'ῐ','á¿‘'=>'ῑ','á¿’'=>'ῒ','á¿“'=>'ϊÌ','á¿–'=>'ῖ','á¿—'=>'ῗ','Ῐ'=>'Ῐ','á¿™'=>'Ῑ','á¿š'=>'Ὶ','á¿›'=>'ΙÌ','á¿'=>' ̔̀','á¿ž'=>' Ì”Ì','á¿Ÿ'=>' ̔͂','á¿ '=>'ῠ','á¿¡'=>'Ï…Ì„','á¿¢'=>'ῢ','á¿£'=>'ϋÌ','ῤ'=>'ÏÌ“','á¿¥'=>'ÏÌ”','ῦ'=>'Ï…Í‚','ῧ'=>'ῧ','Ῠ'=>'Ῠ','á¿©'=>'Ῡ','Ὺ'=>'Ὺ','á¿«'=>'Î¥Ì','Ῥ'=>'Ῥ','á¿­'=>' ̈̀','á¿®'=>' ̈Ì','`'=>'`','ῲ'=>'ῲ','ῳ'=>'ῳ','á¿´'=>'ωÌÍ…','ῶ'=>'ῶ','á¿·'=>'ῷ','Ὸ'=>'Ὸ','Ό'=>'ΟÌ','Ὼ'=>'Ὼ','á¿»'=>'ΩÌ','ῼ'=>'ῼ','´'=>' Ì','῾'=>' Ì”',' '=>' ','â€'=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ',' '=>' ','‑'=>'â€','‗'=>' ̳','․'=>'.','‥'=>'..','…'=>'...',' '=>' ','″'=>'′′','‴'=>'′′′','‶'=>'‵‵','‷'=>'‵‵‵','‼'=>'!!','‾'=>' Ì…','â‡'=>'??','âˆ'=>'?!','â‰'=>'!?','â—'=>'′′′′','âŸ'=>' ','â°'=>'0','â±'=>'i','â´'=>'4','âµ'=>'5','â¶'=>'6','â·'=>'7','â¸'=>'8','â¹'=>'9','âº'=>'+','â»'=>'−','â¼'=>'=','â½'=>'(','â¾'=>')','â¿'=>'n','â‚€'=>'0','â‚'=>'1','â‚‚'=>'2','₃'=>'3','â‚„'=>'4','â‚…'=>'5','₆'=>'6','₇'=>'7','₈'=>'8','₉'=>'9','â‚Š'=>'+','â‚‹'=>'−','â‚Œ'=>'=','â‚'=>'(','â‚Ž'=>')','â‚'=>'a','â‚‘'=>'e','â‚’'=>'o','â‚“'=>'x','â‚”'=>'É™','₨'=>'Rs','â„€'=>'a/c','â„'=>'a/s','â„‚'=>'C','℃'=>'°C','â„…'=>'c/o','℆'=>'c/u','ℇ'=>'Æ','℉'=>'°F','â„Š'=>'g','â„‹'=>'H','â„Œ'=>'H','â„'=>'H','â„Ž'=>'h','â„'=>'ħ','â„'=>'I','â„‘'=>'I','â„’'=>'L','â„“'=>'l','â„•'=>'N','â„–'=>'No','â„™'=>'P','â„š'=>'Q','â„›'=>'R','â„œ'=>'R','â„'=>'R','â„ '=>'SM','â„¡'=>'TEL','â„¢'=>'TM','ℤ'=>'Z','Ω'=>'Ω','ℨ'=>'Z','K'=>'K','â„«'=>'AÌŠ','ℬ'=>'B','â„­'=>'C','ℯ'=>'e','â„°'=>'E','ℱ'=>'F','ℳ'=>'M','â„´'=>'o','ℵ'=>'×','ℶ'=>'ב','â„·'=>'×’','ℸ'=>'ד','ℹ'=>'i','â„»'=>'FAX','ℼ'=>'Ï€','ℽ'=>'γ','ℾ'=>'Γ','â„¿'=>'Π','â…€'=>'∑','â……'=>'D','â…†'=>'d','â…‡'=>'e','â…ˆ'=>'i','â…‰'=>'j','â…“'=>'1â„3','â…”'=>'2â„3','â…•'=>'1â„5','â…–'=>'2â„5','â…—'=>'3â„5','â…˜'=>'4â„5','â…™'=>'1â„6','â…š'=>'5â„6','â…›'=>'1â„8','â…œ'=>'3â„8','â…'=>'5â„8','â…ž'=>'7â„8','â…Ÿ'=>'1â„','â… '=>'I','â…¡'=>'II','â…¢'=>'III','â…£'=>'IV','â…¤'=>'V','â…¥'=>'VI','â…¦'=>'VII','â…§'=>'VIII','â…¨'=>'IX','â…©'=>'X','â…ª'=>'XI','â…«'=>'XII','â…¬'=>'L','â…­'=>'C','â…®'=>'D','â…¯'=>'M','â…°'=>'i','â…±'=>'ii','â…²'=>'iii','â…³'=>'iv','â…´'=>'v','â…µ'=>'vi','â…¶'=>'vii','â…·'=>'viii','â…¸'=>'ix','â…¹'=>'x','â…º'=>'xi','â…»'=>'xii','â…¼'=>'l','â…½'=>'c','â…¾'=>'d','â…¿'=>'m','↚'=>'â†Ì¸','↛'=>'↛','↮'=>'↮','â‡'=>'â‡Ì¸','⇎'=>'⇎','â‡'=>'⇏','∄'=>'∄','∉'=>'∉','∌'=>'∌','∤'=>'∤','∦'=>'∦','∬'=>'∫∫','∭'=>'∫∫∫','∯'=>'∮∮','∰'=>'∮∮∮','â‰'=>'≁','≄'=>'≄','≇'=>'≇','≉'=>'≉','≠'=>'≠','≢'=>'≢','≭'=>'â‰Ì¸','≮'=>'≮','≯'=>'≯','≰'=>'≰','≱'=>'≱','≴'=>'≴','≵'=>'≵','≸'=>'≸','≹'=>'≹','⊀'=>'⊀','âŠ'=>'⊁','⊄'=>'⊄','⊅'=>'⊅','⊈'=>'⊈','⊉'=>'⊉','⊬'=>'⊬','⊭'=>'⊭','⊮'=>'⊮','⊯'=>'⊯','â‹ '=>'⋠','â‹¡'=>'⋡','â‹¢'=>'⋢','â‹£'=>'⋣','⋪'=>'⋪','â‹«'=>'⋫','⋬'=>'⋬','â‹­'=>'⋭','〈'=>'〈','〉'=>'〉','â‘ '=>'1','â‘¡'=>'2','â‘¢'=>'3','â‘£'=>'4','⑤'=>'5','â‘¥'=>'6','⑦'=>'7','⑧'=>'8','⑨'=>'9','â‘©'=>'10','⑪'=>'11','â‘«'=>'12','⑬'=>'13','â‘­'=>'14','â‘®'=>'15','⑯'=>'16','â‘°'=>'17','⑱'=>'18','⑲'=>'19','⑳'=>'20','â‘´'=>'(1)','⑵'=>'(2)','⑶'=>'(3)','â‘·'=>'(4)','⑸'=>'(5)','⑹'=>'(6)','⑺'=>'(7)','â‘»'=>'(8)','⑼'=>'(9)','⑽'=>'(10)','⑾'=>'(11)','â‘¿'=>'(12)','â’€'=>'(13)','â’'=>'(14)','â’‚'=>'(15)','â’ƒ'=>'(16)','â’„'=>'(17)','â’…'=>'(18)','â’†'=>'(19)','â’‡'=>'(20)','â’ˆ'=>'1.','â’‰'=>'2.','â’Š'=>'3.','â’‹'=>'4.','â’Œ'=>'5.','â’'=>'6.','â’Ž'=>'7.','â’'=>'8.','â’'=>'9.','â’‘'=>'10.','â’’'=>'11.','â’“'=>'12.','â’”'=>'13.','â’•'=>'14.','â’–'=>'15.','â’—'=>'16.','â’˜'=>'17.','â’™'=>'18.','â’š'=>'19.','â’›'=>'20.','â’œ'=>'(a)','â’'=>'(b)','â’ž'=>'(c)','â’Ÿ'=>'(d)','â’ '=>'(e)','â’¡'=>'(f)','â’¢'=>'(g)','â’£'=>'(h)','â’¤'=>'(i)','â’¥'=>'(j)','â’¦'=>'(k)','â’§'=>'(l)','â’¨'=>'(m)','â’©'=>'(n)','â’ª'=>'(o)','â’«'=>'(p)','â’¬'=>'(q)','â’­'=>'(r)','â’®'=>'(s)','â’¯'=>'(t)','â’°'=>'(u)','â’±'=>'(v)','â’²'=>'(w)','â’³'=>'(x)','â’´'=>'(y)','â’µ'=>'(z)','â’¶'=>'A','â’·'=>'B','â’¸'=>'C','â’¹'=>'D','â’º'=>'E','â’»'=>'F','â’¼'=>'G','â’½'=>'H','â’¾'=>'I','â’¿'=>'J','â“€'=>'K','â“'=>'L','â“‚'=>'M','Ⓝ'=>'N','â“„'=>'O','â“…'=>'P','Ⓠ'=>'Q','Ⓡ'=>'R','Ⓢ'=>'S','Ⓣ'=>'T','â“Š'=>'U','â“‹'=>'V','â“Œ'=>'W','â“'=>'X','â“Ž'=>'Y','â“'=>'Z','â“'=>'a','â“‘'=>'b','â“’'=>'c','â““'=>'d','â“”'=>'e','â“•'=>'f','â“–'=>'g','â“—'=>'h','ⓘ'=>'i','â“™'=>'j','â“š'=>'k','â“›'=>'l','â“œ'=>'m','â“'=>'n','â“ž'=>'o','â“Ÿ'=>'p','â“ '=>'q','â“¡'=>'r','â“¢'=>'s','â“£'=>'t','ⓤ'=>'u','â“¥'=>'v','ⓦ'=>'w','ⓧ'=>'x','ⓨ'=>'y','â“©'=>'z','⓪'=>'0','⨌'=>'∫∫∫∫','â©´'=>'::=','⩵'=>'==','⩶'=>'===','â«œ'=>'â«Ì¸','ⵯ'=>'ⵡ','⺟'=>'æ¯','⻳'=>'龟','â¼€'=>'一','â¼'=>'丨','⼂'=>'丶','⼃'=>'丿','⼄'=>'ä¹™','â¼…'=>'亅','⼆'=>'二','⼇'=>'亠','⼈'=>'人','⼉'=>'å„¿','⼊'=>'å…¥','⼋'=>'å…«','⼌'=>'冂','â¼'=>'冖','⼎'=>'冫','â¼'=>'几','â¼'=>'凵','⼑'=>'刀','â¼’'=>'力','⼓'=>'勹','â¼”'=>'匕','⼕'=>'匚','â¼–'=>'匸','â¼—'=>'å','⼘'=>'åœ','â¼™'=>'å©','⼚'=>'厂','â¼›'=>'厶','⼜'=>'åˆ','â¼'=>'å£','⼞'=>'å›—','⼟'=>'土','â¼ '=>'士','⼡'=>'夂','â¼¢'=>'夊','â¼£'=>'夕','⼤'=>'大','â¼¥'=>'女','⼦'=>'å­','⼧'=>'宀','⼨'=>'寸','⼩'=>'å°','⼪'=>'å°¢','⼫'=>'å°¸','⼬'=>'å±®','â¼­'=>'å±±','â¼®'=>'å·›','⼯'=>'å·¥','â¼°'=>'å·±','â¼±'=>'å·¾','â¼²'=>'å¹²','â¼³'=>'幺','â¼´'=>'广','â¼µ'=>'å»´','⼶'=>'廾','â¼·'=>'弋','⼸'=>'弓','â¼¹'=>'å½','⼺'=>'彡','â¼»'=>'å½³','â¼¼'=>'心','â¼½'=>'戈','â¼¾'=>'戶','⼿'=>'手','â½€'=>'支','â½'=>'æ”´','⽂'=>'æ–‡','⽃'=>'æ–—','⽄'=>'æ–¤','â½…'=>'æ–¹','⽆'=>'æ— ','⽇'=>'æ—¥','⽈'=>'æ›°','⽉'=>'月','⽊'=>'木','⽋'=>'欠','⽌'=>'æ­¢','â½'=>'æ­¹','⽎'=>'殳','â½'=>'毋','â½'=>'比','⽑'=>'毛','â½’'=>'æ°','⽓'=>'æ°”','â½”'=>'æ°´','⽕'=>'ç«','â½–'=>'爪','â½—'=>'父','⽘'=>'爻','â½™'=>'爿','⽚'=>'片','â½›'=>'牙','⽜'=>'牛','â½'=>'犬','⽞'=>'玄','⽟'=>'玉','â½ '=>'ç“œ','⽡'=>'瓦','â½¢'=>'甘','â½£'=>'生','⽤'=>'用','â½¥'=>'ç”°','⽦'=>'ç–‹','⽧'=>'ç–’','⽨'=>'癶','⽩'=>'白','⽪'=>'çš®','⽫'=>'çš¿','⽬'=>'ç›®','â½­'=>'矛','â½®'=>'矢','⽯'=>'石','â½°'=>'示','â½±'=>'禸','â½²'=>'禾','â½³'=>'ç©´','â½´'=>'ç«‹','â½µ'=>'竹','⽶'=>'ç±³','â½·'=>'糸','⽸'=>'缶','â½¹'=>'网','⽺'=>'羊','â½»'=>'ç¾½','â½¼'=>'è€','â½½'=>'而','â½¾'=>'耒','⽿'=>'耳','â¾€'=>'è¿','â¾'=>'肉','⾂'=>'臣','⾃'=>'自','⾄'=>'至','â¾…'=>'臼','⾆'=>'舌','⾇'=>'舛','⾈'=>'舟','⾉'=>'艮','⾊'=>'色','⾋'=>'艸','⾌'=>'è™','â¾'=>'虫','⾎'=>'è¡€','â¾'=>'è¡Œ','â¾'=>'è¡£','⾑'=>'襾','â¾’'=>'見','⾓'=>'角','â¾”'=>'言','⾕'=>'è°·','â¾–'=>'豆','â¾—'=>'豕','⾘'=>'豸','â¾™'=>'è²','⾚'=>'赤','â¾›'=>'èµ°','⾜'=>'足','â¾'=>'身','⾞'=>'車','⾟'=>'è¾›','â¾ '=>'è¾°','⾡'=>'è¾µ','â¾¢'=>'é‚‘','â¾£'=>'é…‰','⾤'=>'釆','â¾¥'=>'里','⾦'=>'金','⾧'=>'é•·','⾨'=>'é–€','⾩'=>'阜','⾪'=>'隶','⾫'=>'éš¹','⾬'=>'雨','â¾­'=>'é‘','â¾®'=>'éž','⾯'=>'é¢','â¾°'=>'é©','â¾±'=>'韋','â¾²'=>'韭','â¾³'=>'音','â¾´'=>'é ','â¾µ'=>'風','⾶'=>'飛','â¾·'=>'食','⾸'=>'首','â¾¹'=>'香','⾺'=>'馬','â¾»'=>'骨','â¾¼'=>'高','â¾½'=>'é«Ÿ','â¾¾'=>'鬥','⾿'=>'鬯','â¿€'=>'鬲','â¿'=>'鬼','â¿‚'=>'é­š','⿃'=>'é³¥','â¿„'=>'é¹µ','â¿…'=>'鹿','⿆'=>'麥','⿇'=>'麻','⿈'=>'黃','⿉'=>'é»','â¿Š'=>'黑','â¿‹'=>'黹','â¿Œ'=>'黽','â¿'=>'鼎','â¿Ž'=>'鼓','â¿'=>'é¼ ','â¿'=>'é¼»','â¿‘'=>'齊','â¿’'=>'é½’','â¿“'=>'é¾','â¿”'=>'龜','â¿•'=>'é¾ ',' '=>' ','〶'=>'〒','〸'=>'å','〹'=>'å„','〺'=>'å…','ãŒ'=>'ã‹ã‚™','ãŽ'=>'ãã‚™','ã'=>'ãã‚™','ã’'=>'ã‘ã‚™','ã”'=>'ã“ã‚™','ã–'=>'ã•ã‚™','ã˜'=>'ã—ã‚™','ãš'=>'ã™ã‚™','ãœ'=>'ã›ã‚™','ãž'=>'ãã‚™','ã '=>'ãŸã‚™','ã¢'=>'ã¡ã‚™','ã¥'=>'ã¤ã‚™','ã§'=>'ã¦ã‚™','ã©'=>'ã¨ã‚™','ã°'=>'ã¯ã‚™','ã±'=>'ã¯ã‚š','ã³'=>'ã²ã‚™','ã´'=>'ã²ã‚š','ã¶'=>'ãµã‚™','ã·'=>'ãµã‚š','ã¹'=>'ã¸ã‚™','ãº'=>'ã¸ã‚š','ã¼'=>'ã»ã‚™','ã½'=>'ã»ã‚š','ã‚”'=>'ã†ã‚™','ã‚›'=>' ã‚™','ã‚œ'=>' ã‚š','ã‚ž'=>'ã‚ã‚™','ã‚Ÿ'=>'より','ガ'=>'ã‚«ã‚™','ã‚®'=>'ã‚­ã‚™','ã‚°'=>'グ','ゲ'=>'ゲ','ã‚´'=>'ゴ','ザ'=>'ザ','ジ'=>'ã‚·ã‚™','ズ'=>'ズ','ゼ'=>'ゼ','ゾ'=>'ゾ','ダ'=>'ã‚¿ã‚™','ヂ'=>'ãƒã‚™','ヅ'=>'ヅ','デ'=>'デ','ド'=>'ド','ãƒ'=>'ãƒã‚™','パ'=>'ãƒã‚š','ビ'=>'ビ','ピ'=>'ピ','ブ'=>'ブ','プ'=>'プ','ベ'=>'ベ','ペ'=>'ペ','ボ'=>'ボ','ãƒ'=>'ポ','ヴ'=>'ヴ','ヷ'=>'ヷ','ヸ'=>'ヸ','ヹ'=>'ヹ','ヺ'=>'ヺ','ヾ'=>'ヾ','ヿ'=>'コト','ㄱ'=>'á„€','ㄲ'=>'á„','ㄳ'=>'ᆪ','ã„´'=>'á„‚','ㄵ'=>'ᆬ','ㄶ'=>'ᆭ','ã„·'=>'ᄃ','ㄸ'=>'á„„','ㄹ'=>'á„…','ㄺ'=>'ᆰ','ã„»'=>'ᆱ','ㄼ'=>'ᆲ','ㄽ'=>'ᆳ','ㄾ'=>'ᆴ','ã„¿'=>'ᆵ','ã…€'=>'á„š','ã…'=>'ᄆ','ã…‚'=>'ᄇ','ã…ƒ'=>'ᄈ','ã…„'=>'á„¡','ã……'=>'ᄉ','ã…†'=>'á„Š','ã…‡'=>'á„‹','ã…ˆ'=>'á„Œ','ã…‰'=>'á„','ã…Š'=>'á„Ž','ã…‹'=>'á„','ã…Œ'=>'á„','ã…'=>'á„‘','ã…Ž'=>'á„’','ã…'=>'á…¡','ã…'=>'á…¢','ã…‘'=>'á…£','ã…’'=>'á…¤','ã…“'=>'á…¥','ã…”'=>'á…¦','ã…•'=>'á…§','ã…–'=>'á…¨','ã…—'=>'á…©','ã…˜'=>'á…ª','ã…™'=>'á…«','ã…š'=>'á…¬','ã…›'=>'á…­','ã…œ'=>'á…®','ã…'=>'á…¯','ã…ž'=>'á…°','ã…Ÿ'=>'á…±','ã… '=>'á…²','ã…¡'=>'á…³','ã…¢'=>'á…´','ã…£'=>'á…µ','ã…¤'=>'á… ','ã…¥'=>'á„”','ã…¦'=>'á„•','ã…§'=>'ᇇ','ã…¨'=>'ᇈ','ã…©'=>'ᇌ','ã…ª'=>'ᇎ','ã…«'=>'ᇓ','ã…¬'=>'ᇗ','ã…­'=>'ᇙ','ã…®'=>'á„œ','ã…¯'=>'á‡','ã…°'=>'ᇟ','ã…±'=>'á„','ã…²'=>'á„ž','ã…³'=>'á„ ','ã…´'=>'á„¢','ã…µ'=>'á„£','ã…¶'=>'ᄧ','ã…·'=>'á„©','ã…¸'=>'á„«','ã…¹'=>'ᄬ','ã…º'=>'á„­','ã…»'=>'á„®','ã…¼'=>'ᄯ','ã…½'=>'ᄲ','ã…¾'=>'ᄶ','ã…¿'=>'á…€','ㆀ'=>'á…‡','ã†'=>'á…Œ','ㆂ'=>'ᇱ','ㆃ'=>'ᇲ','ㆄ'=>'á…—','ㆅ'=>'á…˜','ㆆ'=>'á…™','ㆇ'=>'ᆄ','ㆈ'=>'ᆅ','ㆉ'=>'ᆈ','ㆊ'=>'ᆑ','ㆋ'=>'ᆒ','ㆌ'=>'ᆔ','ã†'=>'ᆞ','ㆎ'=>'ᆡ','㆒'=>'一','㆓'=>'二','㆔'=>'三','㆕'=>'å››','㆖'=>'上','㆗'=>'中','㆘'=>'下','㆙'=>'甲','㆚'=>'ä¹™','㆛'=>'丙','㆜'=>'ä¸','ã†'=>'天','㆞'=>'地','㆟'=>'人','㈀'=>'(á„€)','ãˆ'=>'(á„‚)','㈂'=>'(ᄃ)','㈃'=>'(á„…)','㈄'=>'(ᄆ)','㈅'=>'(ᄇ)','㈆'=>'(ᄉ)','㈇'=>'(á„‹)','㈈'=>'(á„Œ)','㈉'=>'(á„Ž)','㈊'=>'(á„)','㈋'=>'(á„)','㈌'=>'(á„‘)','ãˆ'=>'(á„’)','㈎'=>'(가)','ãˆ'=>'(á„‚á…¡)','ãˆ'=>'(다)','㈑'=>'(á„…á…¡)','㈒'=>'(마)','㈓'=>'(바)','㈔'=>'(사)','㈕'=>'(á„‹á…¡)','㈖'=>'(자)','㈗'=>'(á„Žá…¡)','㈘'=>'(á„á…¡)','㈙'=>'(á„á…¡)','㈚'=>'(á„‘á…¡)','㈛'=>'(á„’á…¡)','㈜'=>'(주)','ãˆ'=>'(오전)','㈞'=>'(á„‹á…©á„’á…®)','㈠'=>'(一)','㈡'=>'(二)','㈢'=>'(三)','㈣'=>'(å››)','㈤'=>'(五)','㈥'=>'(å…­)','㈦'=>'(七)','㈧'=>'(å…«)','㈨'=>'(ä¹)','㈩'=>'(å)','㈪'=>'(月)','㈫'=>'(ç«)','㈬'=>'(æ°´)','㈭'=>'(木)','㈮'=>'(金)','㈯'=>'(土)','㈰'=>'(æ—¥)','㈱'=>'(æ ª)','㈲'=>'(有)','㈳'=>'(社)','㈴'=>'(å)','㈵'=>'(特)','㈶'=>'(財)','㈷'=>'(ç¥)','㈸'=>'(労)','㈹'=>'(代)','㈺'=>'(呼)','㈻'=>'(å­¦)','㈼'=>'(監)','㈽'=>'(ä¼)','㈾'=>'(資)','㈿'=>'(å”)','㉀'=>'(祭)','ã‰'=>'(休)','㉂'=>'(自)','㉃'=>'(至)','ã‰'=>'PTE','㉑'=>'21','㉒'=>'22','㉓'=>'23','㉔'=>'24','㉕'=>'25','㉖'=>'26','㉗'=>'27','㉘'=>'28','㉙'=>'29','㉚'=>'30','㉛'=>'31','㉜'=>'32','ã‰'=>'33','㉞'=>'34','㉟'=>'35','㉠'=>'á„€','㉡'=>'á„‚','㉢'=>'ᄃ','㉣'=>'á„…','㉤'=>'ᄆ','㉥'=>'ᄇ','㉦'=>'ᄉ','㉧'=>'á„‹','㉨'=>'á„Œ','㉩'=>'á„Ž','㉪'=>'á„','㉫'=>'á„','㉬'=>'á„‘','㉭'=>'á„’','㉮'=>'가','㉯'=>'á„‚á…¡','㉰'=>'다','㉱'=>'á„…á…¡','㉲'=>'마','㉳'=>'바','㉴'=>'사','㉵'=>'á„‹á…¡','㉶'=>'자','㉷'=>'á„Žá…¡','㉸'=>'á„á…¡','㉹'=>'á„á…¡','㉺'=>'á„‘á…¡','㉻'=>'á„’á…¡','㉼'=>'참고','㉽'=>'주의','㉾'=>'á„‹á…®','㊀'=>'一','ãŠ'=>'二','㊂'=>'三','㊃'=>'å››','㊄'=>'五','㊅'=>'å…­','㊆'=>'七','㊇'=>'å…«','㊈'=>'ä¹','㊉'=>'å','㊊'=>'月','㊋'=>'ç«','㊌'=>'æ°´','ãŠ'=>'木','㊎'=>'金','ãŠ'=>'土','ãŠ'=>'æ—¥','㊑'=>'æ ª','㊒'=>'有','㊓'=>'社','㊔'=>'å','㊕'=>'特','㊖'=>'財','㊗'=>'ç¥','㊘'=>'労','㊙'=>'秘','㊚'=>'ç”·','㊛'=>'女','㊜'=>'é©','ãŠ'=>'優','㊞'=>'å°','㊟'=>'注','㊠'=>'é …','㊡'=>'休','㊢'=>'写','㊣'=>'æ­£','㊤'=>'上','㊥'=>'中','㊦'=>'下','㊧'=>'å·¦','㊨'=>'å³','㊩'=>'医','㊪'=>'å®—','㊫'=>'å­¦','㊬'=>'監','㊭'=>'ä¼','㊮'=>'資','㊯'=>'å”','㊰'=>'夜','㊱'=>'36','㊲'=>'37','㊳'=>'38','㊴'=>'39','㊵'=>'40','㊶'=>'41','㊷'=>'42','㊸'=>'43','㊹'=>'44','㊺'=>'45','㊻'=>'46','㊼'=>'47','㊽'=>'48','㊾'=>'49','㊿'=>'50','ã‹€'=>'1月','ã‹'=>'2月','ã‹‚'=>'3月','㋃'=>'4月','ã‹„'=>'5月','ã‹…'=>'6月','㋆'=>'7月','㋇'=>'8月','㋈'=>'9月','㋉'=>'10月','ã‹Š'=>'11月','ã‹‹'=>'12月','ã‹Œ'=>'Hg','ã‹'=>'erg','ã‹Ž'=>'eV','ã‹'=>'LTD','ã‹'=>'ã‚¢','ã‹‘'=>'イ','ã‹’'=>'ウ','ã‹“'=>'エ','ã‹”'=>'オ','ã‹•'=>'ã‚«','ã‹–'=>'ã‚­','ã‹—'=>'ク','㋘'=>'ケ','ã‹™'=>'コ','ã‹š'=>'サ','ã‹›'=>'ã‚·','ã‹œ'=>'ス','ã‹'=>'ã‚»','ã‹ž'=>'ソ','ã‹Ÿ'=>'ã‚¿','ã‹ '=>'ãƒ','ã‹¡'=>'ツ','ã‹¢'=>'テ','ã‹£'=>'ト','㋤'=>'ナ','ã‹¥'=>'ニ','㋦'=>'ヌ','㋧'=>'ãƒ','㋨'=>'ノ','ã‹©'=>'ãƒ','㋪'=>'ヒ','ã‹«'=>'フ','㋬'=>'ヘ','ã‹­'=>'ホ','ã‹®'=>'マ','㋯'=>'ミ','ã‹°'=>'ム','㋱'=>'メ','㋲'=>'モ','㋳'=>'ヤ','ã‹´'=>'ユ','㋵'=>'ヨ','㋶'=>'ラ','ã‹·'=>'リ','㋸'=>'ル','㋹'=>'レ','㋺'=>'ロ','ã‹»'=>'ワ','㋼'=>'ヰ','㋽'=>'ヱ','㋾'=>'ヲ','㌀'=>'ã‚¢ãƒã‚šãƒ¼ãƒˆ','ãŒ'=>'アルファ','㌂'=>'アンペア','㌃'=>'アール','㌄'=>'イニング','㌅'=>'インãƒ','㌆'=>'ウォン','㌇'=>'エスクード','㌈'=>'エーカー','㌉'=>'オンス','㌊'=>'オーム','㌋'=>'カイリ','㌌'=>'カラット','ãŒ'=>'カロリー','㌎'=>'ガロン','ãŒ'=>'ガンマ','ãŒ'=>'ギガ','㌑'=>'ギニー','㌒'=>'キュリー','㌓'=>'ギルダー','㌔'=>'キロ','㌕'=>'キログラム','㌖'=>'キロメートル','㌗'=>'キロワット','㌘'=>'グラム','㌙'=>'グラムトン','㌚'=>'クルゼイロ','㌛'=>'クローãƒ','㌜'=>'ケース','ãŒ'=>'コルナ','㌞'=>'コーポ','㌟'=>'サイクル','㌠'=>'サンãƒãƒ¼ãƒ ','㌡'=>'シリング','㌢'=>'センãƒ','㌣'=>'セント','㌤'=>'ダース','㌥'=>'デシ','㌦'=>'ドル','㌧'=>'トン','㌨'=>'ナノ','㌩'=>'ノット','㌪'=>'ãƒã‚¤ãƒ„','㌫'=>'ãƒã‚šãƒ¼ã‚»ãƒ³ãƒˆ','㌬'=>'ãƒã‚šãƒ¼ãƒ„','㌭'=>'ãƒã‚™ãƒ¼ãƒ¬ãƒ«','㌮'=>'ピアストル','㌯'=>'ピクル','㌰'=>'ピコ','㌱'=>'ビル','㌲'=>'ファラッド','㌳'=>'フィート','㌴'=>'ブッシェル','㌵'=>'フラン','㌶'=>'ヘクタール','㌷'=>'ペソ','㌸'=>'ペニヒ','㌹'=>'ヘルツ','㌺'=>'ペンス','㌻'=>'ページ','㌼'=>'ベータ','㌽'=>'ポイント','㌾'=>'ボルト','㌿'=>'ホン','ã€'=>'ポンド','ã'=>'ホール','ã‚'=>'ホーン','ãƒ'=>'マイクロ','ã„'=>'マイル','ã…'=>'マッãƒ','ã†'=>'マルク','ã‡'=>'マンション','ãˆ'=>'ミクロン','ã‰'=>'ミリ','ãŠ'=>'ミリãƒã‚™ãƒ¼ãƒ«','ã‹'=>'メガ','ãŒ'=>'メガトン','ã'=>'メートル','ãŽ'=>'ヤード','ã'=>'ヤール','ã'=>'ユアン','ã‘'=>'リットル','ã’'=>'リラ','ã“'=>'ルピー','ã”'=>'ルーブル','ã•'=>'レム','ã–'=>'レントゲン','ã—'=>'ワット','ã˜'=>'0点','ã™'=>'1点','ãš'=>'2点','ã›'=>'3点','ãœ'=>'4点','ã'=>'5点','ãž'=>'6点','ãŸ'=>'7点','ã '=>'8点','ã¡'=>'9点','ã¢'=>'10点','ã£'=>'11点','ã¤'=>'12点','ã¥'=>'13点','ã¦'=>'14点','ã§'=>'15点','ã¨'=>'16点','ã©'=>'17点','ãª'=>'18点','ã«'=>'19点','ã¬'=>'20点','ã­'=>'21点','ã®'=>'22点','ã¯'=>'23点','ã°'=>'24点','ã±'=>'hPa','ã²'=>'da','ã³'=>'AU','ã´'=>'bar','ãµ'=>'oV','ã¶'=>'pc','ã·'=>'dm','ã¸'=>'dm2','ã¹'=>'dm3','ãº'=>'IU','ã»'=>'å¹³æˆ','ã¼'=>'昭和','ã½'=>'大正','ã¾'=>'明治','ã¿'=>'æ ªå¼ä¼šç¤¾','㎀'=>'pA','ãŽ'=>'nA','㎂'=>'μA','㎃'=>'mA','㎄'=>'kA','㎅'=>'KB','㎆'=>'MB','㎇'=>'GB','㎈'=>'cal','㎉'=>'kcal','㎊'=>'pF','㎋'=>'nF','㎌'=>'μF','ãŽ'=>'μg','㎎'=>'mg','ãŽ'=>'kg','ãŽ'=>'Hz','㎑'=>'kHz','㎒'=>'MHz','㎓'=>'GHz','㎔'=>'THz','㎕'=>'μl','㎖'=>'ml','㎗'=>'dl','㎘'=>'kl','㎙'=>'fm','㎚'=>'nm','㎛'=>'μm','㎜'=>'mm','ãŽ'=>'cm','㎞'=>'km','㎟'=>'mm2','㎠'=>'cm2','㎡'=>'m2','㎢'=>'km2','㎣'=>'mm3','㎤'=>'cm3','㎥'=>'m3','㎦'=>'km3','㎧'=>'m∕s','㎨'=>'m∕s2','㎩'=>'Pa','㎪'=>'kPa','㎫'=>'MPa','㎬'=>'GPa','㎭'=>'rad','㎮'=>'rad∕s','㎯'=>'rad∕s2','㎰'=>'ps','㎱'=>'ns','㎲'=>'μs','㎳'=>'ms','㎴'=>'pV','㎵'=>'nV','㎶'=>'μV','㎷'=>'mV','㎸'=>'kV','㎹'=>'MV','㎺'=>'pW','㎻'=>'nW','㎼'=>'μW','㎽'=>'mW','㎾'=>'kW','㎿'=>'MW','ã€'=>'kΩ','ã'=>'MΩ','ã‚'=>'a.m.','ãƒ'=>'Bq','ã„'=>'cc','ã…'=>'cd','ã†'=>'C∕kg','ã‡'=>'Co.','ãˆ'=>'dB','ã‰'=>'Gy','ãŠ'=>'ha','ã‹'=>'HP','ãŒ'=>'in','ã'=>'KK','ãŽ'=>'KM','ã'=>'kt','ã'=>'lm','ã‘'=>'ln','ã’'=>'log','ã“'=>'lx','ã”'=>'mb','ã•'=>'mil','ã–'=>'mol','ã—'=>'PH','ã˜'=>'p.m.','ã™'=>'PPM','ãš'=>'PR','ã›'=>'sr','ãœ'=>'Sv','ã'=>'Wb','ãž'=>'V∕m','ãŸ'=>'A∕m','ã '=>'1æ—¥','ã¡'=>'2æ—¥','ã¢'=>'3æ—¥','ã£'=>'4æ—¥','ã¤'=>'5æ—¥','ã¥'=>'6æ—¥','ã¦'=>'7æ—¥','ã§'=>'8æ—¥','ã¨'=>'9æ—¥','ã©'=>'10æ—¥','ãª'=>'11æ—¥','ã«'=>'12æ—¥','ã¬'=>'13æ—¥','ã­'=>'14æ—¥','ã®'=>'15æ—¥','ã¯'=>'16æ—¥','ã°'=>'17æ—¥','ã±'=>'18æ—¥','ã²'=>'19æ—¥','ã³'=>'20æ—¥','ã´'=>'21æ—¥','ãµ'=>'22æ—¥','ã¶'=>'23æ—¥','ã·'=>'24æ—¥','ã¸'=>'25æ—¥','ã¹'=>'26æ—¥','ãº'=>'27æ—¥','ã»'=>'28æ—¥','ã¼'=>'29æ—¥','ã½'=>'30æ—¥','ã¾'=>'31æ—¥','ã¿'=>'gal','豈'=>'豈','ï¤'=>'æ›´','車'=>'車','賈'=>'賈','滑'=>'滑','串'=>'串','句'=>'å¥','龜'=>'龜','龜'=>'龜','契'=>'契','金'=>'金','喇'=>'å–‡','奈'=>'奈','ï¤'=>'懶','癩'=>'癩','ï¤'=>'ç¾…','ï¤'=>'蘿','螺'=>'螺','裸'=>'裸','邏'=>'é‚','樂'=>'樂','洛'=>'æ´›','烙'=>'烙','珞'=>'çž','落'=>'è½','酪'=>'é…ª','駱'=>'駱','亂'=>'亂','卵'=>'åµ','ï¤'=>'欄','爛'=>'爛','蘭'=>'蘭','鸞'=>'鸞','嵐'=>'åµ','濫'=>'æ¿«','藍'=>'è—','襤'=>'襤','拉'=>'拉','臘'=>'臘','蠟'=>'è Ÿ','廊'=>'廊','朗'=>'朗','浪'=>'浪','狼'=>'狼','郎'=>'郎','來'=>'來','冷'=>'冷','勞'=>'å‹ž','擄'=>'æ“„','櫓'=>'æ«“','爐'=>'çˆ','盧'=>'盧','老'=>'è€','蘆'=>'蘆','虜'=>'虜','路'=>'è·¯','露'=>'露','魯'=>'é­¯','鷺'=>'é·º','碌'=>'碌','祿'=>'祿','綠'=>'綠','菉'=>'è‰','錄'=>'錄','鹿'=>'鹿','ï¥'=>'è«–','壟'=>'壟','弄'=>'弄','籠'=>'ç± ','聾'=>'è¾','牢'=>'牢','磊'=>'磊','賂'=>'賂','雷'=>'é›·','壘'=>'壘','屢'=>'å±¢','樓'=>'樓','ï¥'=>'æ·š','漏'=>'æ¼','ï¥'=>'ç´¯','ï¥'=>'縷','陋'=>'陋','勒'=>'å‹’','肋'=>'è‚‹','凜'=>'凜','凌'=>'凌','稜'=>'稜','綾'=>'綾','菱'=>'è±','陵'=>'陵','讀'=>'讀','拏'=>'æ‹','樂'=>'樂','ï¥'=>'諾','丹'=>'丹','寧'=>'寧','怒'=>'怒','率'=>'率','異'=>'ç•°','北'=>'北','磻'=>'磻','便'=>'便','復'=>'復','不'=>'ä¸','泌'=>'泌','數'=>'數','索'=>'ç´¢','參'=>'åƒ','塞'=>'å¡ž','省'=>'çœ','葉'=>'葉','說'=>'說','殺'=>'殺','辰'=>'è¾°','沈'=>'沈','拾'=>'拾','若'=>'è‹¥','掠'=>'掠','略'=>'ç•¥','亮'=>'亮','兩'=>'å…©','凉'=>'凉','梁'=>'æ¢','糧'=>'糧','良'=>'良','諒'=>'è«’','量'=>'é‡','勵'=>'勵','呂'=>'å‘‚','ï¦'=>'女','廬'=>'廬','旅'=>'æ—…','濾'=>'濾','礪'=>'礪','閭'=>'é–­','驪'=>'驪','麗'=>'麗','黎'=>'黎','力'=>'力','曆'=>'曆','歷'=>'æ­·','ï¦'=>'è½¢','年'=>'å¹´','ï¦'=>'æ†','ï¦'=>'戀','撚'=>'æ’š','漣'=>'æ¼£','煉'=>'ç…‰','璉'=>'ç’‰','秊'=>'秊','練'=>'ç·´','聯'=>'è¯','輦'=>'輦','蓮'=>'è“®','連'=>'連','鍊'=>'éŠ','列'=>'列','ï¦'=>'劣','咽'=>'å’½','烈'=>'烈','裂'=>'裂','說'=>'說','廉'=>'廉','念'=>'念','捻'=>'æ»','殮'=>'æ®®','簾'=>'ç°¾','獵'=>'çµ','令'=>'令','囹'=>'囹','寧'=>'寧','嶺'=>'嶺','怜'=>'怜','玲'=>'玲','瑩'=>'ç‘©','羚'=>'羚','聆'=>'è†','鈴'=>'鈴','零'=>'零','靈'=>'éˆ','領'=>'é ˜','例'=>'例','禮'=>'禮','醴'=>'醴','隸'=>'隸','惡'=>'惡','了'=>'了','僚'=>'僚','寮'=>'寮','尿'=>'å°¿','料'=>'æ–™','樂'=>'樂','燎'=>'燎','ï§'=>'療','蓼'=>'蓼','遼'=>'é¼','龍'=>'é¾','暈'=>'暈','阮'=>'阮','劉'=>'劉','杻'=>'æ»','柳'=>'柳','流'=>'æµ','溜'=>'溜','琉'=>'ç‰','ï§'=>'ç•™','硫'=>'ç¡«','ï§'=>'ç´','ï§'=>'é¡ž','六'=>'å…­','戮'=>'戮','陸'=>'陸','倫'=>'倫','崙'=>'å´™','淪'=>'æ·ª','輪'=>'輪','律'=>'律','慄'=>'æ…„','栗'=>'æ —','率'=>'率','隆'=>'隆','ï§'=>'利','吏'=>'å','履'=>'å±¥','易'=>'易','李'=>'æŽ','梨'=>'梨','泥'=>'æ³¥','理'=>'ç†','痢'=>'ç—¢','罹'=>'ç½¹','裏'=>'è£','裡'=>'裡','里'=>'里','離'=>'離','匿'=>'匿','溺'=>'溺','吝'=>'å','燐'=>'ç‡','璘'=>'ç’˜','藺'=>'è—º','隣'=>'隣','鱗'=>'é±—','麟'=>'麟','林'=>'æž—','淋'=>'æ·‹','臨'=>'臨','立'=>'ç«‹','笠'=>'笠','粒'=>'ç²’','狀'=>'ç‹€','炙'=>'ç‚™','識'=>'è­˜','什'=>'什','茶'=>'茶','刺'=>'刺','切'=>'切','ï¨'=>'度','拓'=>'æ‹“','糖'=>'ç³–','宅'=>'å®…','洞'=>'æ´ž','暴'=>'æš´','輻'=>'è¼»','行'=>'è¡Œ','降'=>'é™','見'=>'見','廓'=>'廓','兀'=>'å…€','ï¨'=>'å—€','ï¨'=>'å¡š','晴'=>'æ™´','凞'=>'凞','猪'=>'猪','益'=>'益','礼'=>'礼','神'=>'神','祥'=>'祥','福'=>'ç¦','靖'=>'é–','ï¨'=>'ç²¾','羽'=>'ç¾½','蘒'=>'蘒','諸'=>'諸','逸'=>'逸','都'=>'都','飯'=>'飯','飼'=>'飼','館'=>'館','鶴'=>'鶴','侮'=>'ä¾®','僧'=>'僧','免'=>'å…','勉'=>'勉','勤'=>'勤','卑'=>'å‘','喝'=>'å–','嘆'=>'嘆','器'=>'器','塀'=>'å¡€','墨'=>'墨','層'=>'層','屮'=>'å±®','悔'=>'æ‚”','慨'=>'æ…¨','憎'=>'憎','ï©€'=>'懲','ï©'=>'æ•','ï©‚'=>'æ—¢','暑'=>'æš‘','ï©„'=>'梅','ï©…'=>'æµ·','渚'=>'渚','漢'=>'æ¼¢','煮'=>'ç…®','爫'=>'爫','ï©Š'=>'ç¢','ï©‹'=>'碑','ï©Œ'=>'社','ï©'=>'祉','ï©Ž'=>'祈','ï©'=>'ç¥','ï©'=>'祖','ï©‘'=>'ç¥','ï©’'=>'ç¦','ï©“'=>'禎','ï©”'=>'ç©€','ï©•'=>'çª','ï©–'=>'節','ï©—'=>'ç·´','縉'=>'縉','ï©™'=>'ç¹','ï©š'=>'ç½²','ï©›'=>'者','ï©œ'=>'臭','ï©'=>'艹','ï©ž'=>'艹','ï©Ÿ'=>'è‘—','ï© '=>'è¤','ï©¡'=>'視','ï©¢'=>'è¬','ï©£'=>'謹','賓'=>'賓','ï©¥'=>'è´ˆ','辶'=>'辶','逸'=>'逸','難'=>'難','ï©©'=>'響','頻'=>'é »','ï©°'=>'並','况'=>'况','全'=>'å…¨','侀'=>'ä¾€','ï©´'=>'å……','冀'=>'冀','勇'=>'勇','ï©·'=>'勺','喝'=>'å–','啕'=>'å••','喙'=>'å–™','ï©»'=>'å—¢','塚'=>'å¡š','墳'=>'墳','奄'=>'奄','ï©¿'=>'奔','婢'=>'å©¢','ïª'=>'嬨','廒'=>'å»’','廙'=>'å»™','彩'=>'彩','徭'=>'å¾­','惘'=>'惘','慎'=>'æ…Ž','愈'=>'愈','憎'=>'憎','慠'=>'æ… ','懲'=>'懲','戴'=>'戴','ïª'=>'æ„','搜'=>'æœ','ïª'=>'æ‘’','ïª'=>'æ•–','晴'=>'æ™´','朗'=>'朗','望'=>'望','杖'=>'æ–','歹'=>'æ­¹','殺'=>'殺','流'=>'æµ','滛'=>'æ»›','滋'=>'滋','漢'=>'æ¼¢','瀞'=>'瀞','煮'=>'ç…®','ïª'=>'瞧','爵'=>'爵','犯'=>'犯','猪'=>'猪','瑱'=>'瑱','甆'=>'甆','画'=>'ç”»','瘝'=>'ç˜','瘟'=>'瘟','益'=>'益','盛'=>'ç››','直'=>'ç›´','睊'=>'çŠ','着'=>'ç€','磌'=>'磌','窱'=>'窱','節'=>'節','类'=>'ç±»','絛'=>'çµ›','練'=>'ç·´','缾'=>'ç¼¾','者'=>'者','荒'=>'è’','華'=>'è¯','蝹'=>'è¹','襁'=>'è¥','覆'=>'覆','視'=>'視','調'=>'調','諸'=>'諸','請'=>'è«‹','謁'=>'è¬','諾'=>'諾','諭'=>'è«­','謹'=>'謹','ï«€'=>'變','ï«'=>'è´ˆ','ï«‚'=>'輸','遲'=>'é²','ï«„'=>'醙','ï«…'=>'鉶','陼'=>'陼','難'=>'難','靖'=>'é–','韛'=>'韛','ï«Š'=>'響','ï«‹'=>'é ‹','ï«Œ'=>'é »','ï«'=>'鬒','ï«Ž'=>'龜','ï«'=>'𢡊','ï«'=>'𢡄','ï«‘'=>'ð£•','ï«’'=>'ã®','ï«“'=>'䀘','ï«”'=>'䀹','ï«•'=>'𥉉','ï«–'=>'ð¥³','ï«—'=>'𧻓','齃'=>'齃','ï«™'=>'龎','ff'=>'ff','ï¬'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'st','st'=>'st','ﬓ'=>'Õ´Õ¶','ﬔ'=>'Õ´Õ¥','ﬕ'=>'Õ´Õ«','ﬖ'=>'Õ¾Õ¶','ﬗ'=>'Õ´Õ­','ï¬'=>'×™Ö´','ײַ'=>'ײַ','ﬠ'=>'×¢','ﬡ'=>'×','ﬢ'=>'ד','ﬣ'=>'×”','ﬤ'=>'×›','ﬥ'=>'ל','ﬦ'=>'×','ﬧ'=>'ר','ﬨ'=>'ת','﬩'=>'+','שׁ'=>'ש×','שׂ'=>'שׂ','שּׁ'=>'שּ×','שּׂ'=>'שּׂ','אַ'=>'×Ö·','אָ'=>'×Ö¸','אּ'=>'×Ö¼','בּ'=>'בּ','גּ'=>'×’Ö¼','דּ'=>'דּ','הּ'=>'×”Ö¼','וּ'=>'וּ','זּ'=>'×–Ö¼','טּ'=>'טּ','יּ'=>'×™Ö¼','ךּ'=>'ךּ','כּ'=>'×›Ö¼','לּ'=>'לּ','מּ'=>'מּ','ï­€'=>'× Ö¼','ï­'=>'סּ','ï­ƒ'=>'×£Ö¼','ï­„'=>'פּ','ï­†'=>'צּ','ï­‡'=>'קּ','ï­ˆ'=>'רּ','ï­‰'=>'שּ','ï­Š'=>'תּ','ï­‹'=>'וֹ','ï­Œ'=>'בֿ','ï­'=>'×›Ö¿','ï­Ž'=>'פֿ','ï­'=>'×ל','ï­'=>'Ù±','ï­‘'=>'Ù±','ï­’'=>'Ù»','ï­“'=>'Ù»','ï­”'=>'Ù»','ï­•'=>'Ù»','ï­–'=>'Ù¾','ï­—'=>'Ù¾','ï­˜'=>'Ù¾','ï­™'=>'Ù¾','ï­š'=>'Ú€','ï­›'=>'Ú€','ï­œ'=>'Ú€','ï­'=>'Ú€','ï­ž'=>'Ùº','ï­Ÿ'=>'Ùº','ï­ '=>'Ùº','ï­¡'=>'Ùº','ï­¢'=>'Ù¿','ï­£'=>'Ù¿','ï­¤'=>'Ù¿','ï­¥'=>'Ù¿','ï­¦'=>'Ù¹','ï­§'=>'Ù¹','ï­¨'=>'Ù¹','ï­©'=>'Ù¹','ï­ª'=>'Ú¤','ï­«'=>'Ú¤','ï­¬'=>'Ú¤','ï­­'=>'Ú¤','ï­®'=>'Ú¦','ï­¯'=>'Ú¦','ï­°'=>'Ú¦','ï­±'=>'Ú¦','ï­²'=>'Ú„','ï­³'=>'Ú„','ï­´'=>'Ú„','ï­µ'=>'Ú„','ï­¶'=>'Úƒ','ï­·'=>'Úƒ','ï­¸'=>'Úƒ','ï­¹'=>'Úƒ','ï­º'=>'Ú†','ï­»'=>'Ú†','ï­¼'=>'Ú†','ï­½'=>'Ú†','ï­¾'=>'Ú‡','ï­¿'=>'Ú‡','ﮀ'=>'Ú‡','ï®'=>'Ú‡','ﮂ'=>'Ú','ﮃ'=>'Ú','ﮄ'=>'ÚŒ','ï®…'=>'ÚŒ','ﮆ'=>'ÚŽ','ﮇ'=>'ÚŽ','ﮈ'=>'Úˆ','ﮉ'=>'Úˆ','ﮊ'=>'Ú˜','ﮋ'=>'Ú˜','ﮌ'=>'Ú‘','ï®'=>'Ú‘','ﮎ'=>'Ú©','ï®'=>'Ú©','ï®'=>'Ú©','ﮑ'=>'Ú©','ï®’'=>'Ú¯','ﮓ'=>'Ú¯','ï®”'=>'Ú¯','ﮕ'=>'Ú¯','ï®–'=>'Ú³','ï®—'=>'Ú³','ﮘ'=>'Ú³','ï®™'=>'Ú³','ﮚ'=>'Ú±','ï®›'=>'Ú±','ﮜ'=>'Ú±','ï®'=>'Ú±','ﮞ'=>'Úº','ﮟ'=>'Úº','ï® '=>'Ú»','ﮡ'=>'Ú»','ﮢ'=>'Ú»','ﮣ'=>'Ú»','ﮤ'=>'Û•Ù”','ﮥ'=>'Û•Ù”','ﮦ'=>'Û','ﮧ'=>'Û','ﮨ'=>'Û','ﮩ'=>'Û','ﮪ'=>'Ú¾','ﮫ'=>'Ú¾','ﮬ'=>'Ú¾','ï®­'=>'Ú¾','ï®®'=>'Û’','ﮯ'=>'Û’','ï®°'=>'Û’Ù”','ï®±'=>'Û’Ù”','ﯓ'=>'Ú­','ﯔ'=>'Ú­','ﯕ'=>'Ú­','ﯖ'=>'Ú­','ﯗ'=>'Û‡','ﯘ'=>'Û‡','ﯙ'=>'Û†','ﯚ'=>'Û†','ﯛ'=>'Ûˆ','ﯜ'=>'Ûˆ','ï¯'=>'Û‡Ù´','ﯞ'=>'Û‹','ﯟ'=>'Û‹','ﯠ'=>'Û…','ﯡ'=>'Û…','ﯢ'=>'Û‰','ﯣ'=>'Û‰','ﯤ'=>'Û','ﯥ'=>'Û','ﯦ'=>'Û','ﯧ'=>'Û','ﯨ'=>'Ù‰','ﯩ'=>'Ù‰','ﯪ'=>'ئا','ﯫ'=>'ئا','ﯬ'=>'ÙŠÙ”Û•','ﯭ'=>'ÙŠÙ”Û•','ﯮ'=>'ÙŠÙ”Ùˆ','ﯯ'=>'ÙŠÙ”Ùˆ','ﯰ'=>'ÙŠÙ”Û‡','ﯱ'=>'ÙŠÙ”Û‡','ﯲ'=>'ÙŠÙ”Û†','ﯳ'=>'ÙŠÙ”Û†','ﯴ'=>'ÙŠÙ”Ûˆ','ﯵ'=>'ÙŠÙ”Ûˆ','ﯶ'=>'ÙŠÙ”Û','ﯷ'=>'ÙŠÙ”Û','ﯸ'=>'ÙŠÙ”Û','ﯹ'=>'ÙŠÙ”Ù‰','ﯺ'=>'ÙŠÙ”Ù‰','ﯻ'=>'ÙŠÙ”Ù‰','ﯼ'=>'ÛŒ','ﯽ'=>'ÛŒ','ﯾ'=>'ÛŒ','ﯿ'=>'ÛŒ','ï°€'=>'ئج','ï°'=>'ئح','ï°‚'=>'ÙŠÙ”Ù…','ï°ƒ'=>'ÙŠÙ”Ù‰','ï°„'=>'ÙŠÙ”ÙŠ','ï°…'=>'بج','ï°†'=>'بح','ï°‡'=>'بخ','ï°ˆ'=>'بم','ï°‰'=>'بى','ï°Š'=>'بي','ï°‹'=>'تج','ï°Œ'=>'تح','ï°'=>'تخ','ï°Ž'=>'تم','ï°'=>'تى','ï°'=>'تي','ï°‘'=>'ثج','ï°’'=>'ثم','ï°“'=>'ثى','ï°”'=>'ثي','ï°•'=>'جح','ï°–'=>'جم','ï°—'=>'حج','ï°˜'=>'حم','ï°™'=>'خج','ï°š'=>'خح','ï°›'=>'خم','ï°œ'=>'سج','ï°'=>'سح','ï°ž'=>'سخ','ï°Ÿ'=>'سم','ï° '=>'صح','ï°¡'=>'صم','ï°¢'=>'ضج','ï°£'=>'ضح','ï°¤'=>'ضخ','ï°¥'=>'ضم','ï°¦'=>'طح','ï°§'=>'طم','ï°¨'=>'ظم','ï°©'=>'عج','ï°ª'=>'عم','ï°«'=>'غج','ï°¬'=>'غم','ï°­'=>'Ùج','ï°®'=>'ÙØ­','ï°¯'=>'ÙØ®','ï°°'=>'ÙÙ…','ï°±'=>'ÙÙ‰','ï°²'=>'ÙÙŠ','ï°³'=>'قح','ï°´'=>'قم','ï°µ'=>'قى','ï°¶'=>'قي','ï°·'=>'كا','ï°¸'=>'كج','ï°¹'=>'كح','ï°º'=>'كخ','ï°»'=>'كل','ï°¼'=>'كم','ï°½'=>'كى','ï°¾'=>'كي','ï°¿'=>'لج','ï±€'=>'لح','ï±'=>'لخ','ﱂ'=>'لم','ﱃ'=>'لى','ﱄ'=>'لي','ï±…'=>'مج','ﱆ'=>'مح','ﱇ'=>'مخ','ﱈ'=>'مم','ﱉ'=>'مى','ﱊ'=>'مي','ﱋ'=>'نج','ﱌ'=>'نح','ï±'=>'نخ','ﱎ'=>'نم','ï±'=>'نى','ï±'=>'ني','ﱑ'=>'هج','ï±’'=>'هم','ﱓ'=>'هى','ï±”'=>'هي','ﱕ'=>'يج','ï±–'=>'يح','ï±—'=>'يخ','ﱘ'=>'يم','ï±™'=>'يى','ﱚ'=>'يي','ï±›'=>'ذٰ','ﱜ'=>'رٰ','ï±'=>'ىٰ','ﱞ'=>' ٌّ','ﱟ'=>' ÙÙ‘','ï± '=>' ÙŽÙ‘','ﱡ'=>' ÙÙ‘','ï±¢'=>' ÙÙ‘','ï±£'=>' ّٰ','ﱤ'=>'ئر','ï±¥'=>'ئز','ﱦ'=>'ÙŠÙ”Ù…','ﱧ'=>'ÙŠÙ”Ù†','ﱨ'=>'ÙŠÙ”Ù‰','ﱩ'=>'ÙŠÙ”ÙŠ','ﱪ'=>'بر','ﱫ'=>'بز','ﱬ'=>'بم','ï±­'=>'بن','ï±®'=>'بى','ﱯ'=>'بي','ï±°'=>'تر','ï±±'=>'تز','ï±²'=>'تم','ï±³'=>'تن','ï±´'=>'تى','ï±µ'=>'تي','ﱶ'=>'ثر','ï±·'=>'ثز','ﱸ'=>'ثم','ï±¹'=>'ثن','ﱺ'=>'ثى','ï±»'=>'ثي','ï±¼'=>'ÙÙ‰','ï±½'=>'ÙÙŠ','ï±¾'=>'قى','ﱿ'=>'قي','ï²€'=>'كا','ï²'=>'كل','ﲂ'=>'كم','ﲃ'=>'كى','ﲄ'=>'كي','ï²…'=>'لم','ﲆ'=>'لى','ﲇ'=>'لي','ﲈ'=>'ما','ﲉ'=>'مم','ﲊ'=>'نر','ﲋ'=>'نز','ﲌ'=>'نم','ï²'=>'نن','ﲎ'=>'نى','ï²'=>'ني','ï²'=>'ىٰ','ﲑ'=>'ير','ï²’'=>'يز','ﲓ'=>'يم','ï²”'=>'ين','ﲕ'=>'يى','ï²–'=>'يي','ï²—'=>'ئج','ﲘ'=>'ئح','ï²™'=>'ئخ','ﲚ'=>'ÙŠÙ”Ù…','ï²›'=>'ÙŠÙ”Ù‡','ﲜ'=>'بج','ï²'=>'بح','ﲞ'=>'بخ','ﲟ'=>'بم','ï² '=>'به','ﲡ'=>'تج','ï²¢'=>'تح','ï²£'=>'تخ','ﲤ'=>'تم','ï²¥'=>'ته','ﲦ'=>'ثم','ﲧ'=>'جح','ﲨ'=>'جم','ﲩ'=>'حج','ﲪ'=>'حم','ﲫ'=>'خج','ﲬ'=>'خم','ï²­'=>'سج','ï²®'=>'سح','ﲯ'=>'سخ','ï²°'=>'سم','ï²±'=>'صح','ï²²'=>'صخ','ï²³'=>'صم','ï²´'=>'ضج','ï²µ'=>'ضح','ﲶ'=>'ضخ','ï²·'=>'ضم','ﲸ'=>'طح','ï²¹'=>'ظم','ﲺ'=>'عج','ï²»'=>'عم','ï²¼'=>'غج','ï²½'=>'غم','ï²¾'=>'Ùج','ﲿ'=>'ÙØ­','ï³€'=>'ÙØ®','ï³'=>'ÙÙ…','ﳂ'=>'قح','ﳃ'=>'قم','ﳄ'=>'كج','ï³…'=>'كح','ﳆ'=>'كخ','ﳇ'=>'كل','ﳈ'=>'كم','ﳉ'=>'لج','ﳊ'=>'لح','ﳋ'=>'لخ','ﳌ'=>'لم','ï³'=>'له','ﳎ'=>'مج','ï³'=>'مح','ï³'=>'مخ','ﳑ'=>'مم','ï³’'=>'نج','ﳓ'=>'نح','ï³”'=>'نخ','ﳕ'=>'نم','ï³–'=>'نه','ï³—'=>'هج','ﳘ'=>'هم','ï³™'=>'هٰ','ﳚ'=>'يج','ï³›'=>'يح','ﳜ'=>'يخ','ï³'=>'يم','ﳞ'=>'يه','ﳟ'=>'ÙŠÙ”Ù…','ï³ '=>'ÙŠÙ”Ù‡','ﳡ'=>'بم','ï³¢'=>'به','ï³£'=>'تم','ﳤ'=>'ته','ï³¥'=>'ثم','ﳦ'=>'ثه','ﳧ'=>'سم','ﳨ'=>'سه','ﳩ'=>'شم','ﳪ'=>'شه','ﳫ'=>'كل','ﳬ'=>'كم','ï³­'=>'لم','ï³®'=>'نم','ﳯ'=>'نه','ï³°'=>'يم','ï³±'=>'يه','ï³²'=>'Ù€ÙŽÙ‘','ï³³'=>'Ù€ÙÙ‘','ï³´'=>'Ù€ÙÙ‘','ï³µ'=>'طى','ﳶ'=>'طي','ï³·'=>'عى','ﳸ'=>'عي','ï³¹'=>'غى','ﳺ'=>'غي','ï³»'=>'سى','ï³¼'=>'سي','ï³½'=>'شى','ï³¾'=>'شي','ﳿ'=>'حى','ï´€'=>'حي','ï´'=>'جى','ï´‚'=>'جي','ï´ƒ'=>'خى','ï´„'=>'خي','ï´…'=>'صى','ï´†'=>'صي','ï´‡'=>'ضى','ï´ˆ'=>'ضي','ï´‰'=>'شج','ï´Š'=>'شح','ï´‹'=>'شخ','ï´Œ'=>'شم','ï´'=>'شر','ï´Ž'=>'سر','ï´'=>'صر','ï´'=>'ضر','ï´‘'=>'طى','ï´’'=>'طي','ï´“'=>'عى','ï´”'=>'عي','ï´•'=>'غى','ï´–'=>'غي','ï´—'=>'سى','ï´˜'=>'سي','ï´™'=>'شى','ï´š'=>'شي','ï´›'=>'حى','ï´œ'=>'حي','ï´'=>'جى','ï´ž'=>'جي','ï´Ÿ'=>'خى','ï´ '=>'خي','ï´¡'=>'صى','ï´¢'=>'صي','ï´£'=>'ضى','ï´¤'=>'ضي','ï´¥'=>'شج','ï´¦'=>'شح','ï´§'=>'شخ','ï´¨'=>'شم','ï´©'=>'شر','ï´ª'=>'سر','ï´«'=>'صر','ï´¬'=>'ضر','ï´­'=>'شج','ï´®'=>'شح','ï´¯'=>'شخ','ï´°'=>'شم','ï´±'=>'سه','ï´²'=>'شه','ï´³'=>'طم','ï´´'=>'سج','ï´µ'=>'سح','ï´¶'=>'سخ','ï´·'=>'شج','ï´¸'=>'شح','ï´¹'=>'شخ','ï´º'=>'طم','ï´»'=>'ظم','ï´¼'=>'اً','ï´½'=>'اً','ïµ'=>'تجم','ﵑ'=>'تحج','ïµ’'=>'تحج','ﵓ'=>'تحم','ïµ”'=>'تخم','ﵕ'=>'تمج','ïµ–'=>'تمح','ïµ—'=>'تمخ','ﵘ'=>'جمح','ïµ™'=>'جمح','ﵚ'=>'حمي','ïµ›'=>'حمى','ﵜ'=>'سحج','ïµ'=>'سجح','ﵞ'=>'سجى','ﵟ'=>'سمح','ïµ '=>'سمح','ﵡ'=>'سمج','ïµ¢'=>'سمم','ïµ£'=>'سمم','ﵤ'=>'صحح','ïµ¥'=>'صحح','ﵦ'=>'صمم','ﵧ'=>'شحم','ﵨ'=>'شحم','ﵩ'=>'شجي','ﵪ'=>'شمخ','ﵫ'=>'شمخ','ﵬ'=>'شمم','ïµ­'=>'شمم','ïµ®'=>'ضحى','ﵯ'=>'ضخم','ïµ°'=>'ضخم','ïµ±'=>'طمح','ïµ²'=>'طمح','ïµ³'=>'طمم','ïµ´'=>'طمي','ïµµ'=>'عجم','ﵶ'=>'عمم','ïµ·'=>'عمم','ﵸ'=>'عمى','ïµ¹'=>'غمم','ﵺ'=>'غمي','ïµ»'=>'غمى','ïµ¼'=>'Ùخم','ïµ½'=>'Ùخم','ïµ¾'=>'قمح','ﵿ'=>'قمم','ﶀ'=>'لحم','ï¶'=>'لحي','ﶂ'=>'لحى','ﶃ'=>'لجج','ﶄ'=>'لجج','ﶅ'=>'لخم','ﶆ'=>'لخم','ﶇ'=>'لمح','ﶈ'=>'لمح','ﶉ'=>'محج','ﶊ'=>'محم','ﶋ'=>'محي','ﶌ'=>'مجح','ï¶'=>'مجم','ﶎ'=>'مخج','ï¶'=>'مخم','ﶒ'=>'مجخ','ﶓ'=>'همج','ﶔ'=>'همم','ﶕ'=>'نحم','ﶖ'=>'نحى','ﶗ'=>'نجم','ﶘ'=>'نجم','ﶙ'=>'نجى','ﶚ'=>'نمي','ﶛ'=>'نمى','ﶜ'=>'يمم','ï¶'=>'يمم','ﶞ'=>'بخي','ﶟ'=>'تجي','ﶠ'=>'تجى','ﶡ'=>'تخي','ﶢ'=>'تخى','ﶣ'=>'تمي','ﶤ'=>'تمى','ﶥ'=>'جمي','ﶦ'=>'جحى','ﶧ'=>'جمى','ﶨ'=>'سخى','ﶩ'=>'صحي','ﶪ'=>'شحي','ﶫ'=>'ضحي','ﶬ'=>'لجي','ﶭ'=>'لمي','ﶮ'=>'يحي','ﶯ'=>'يجي','ﶰ'=>'يمي','ﶱ'=>'ممي','ﶲ'=>'قمي','ﶳ'=>'نحي','ﶴ'=>'قمح','ﶵ'=>'لحم','ﶶ'=>'عمي','ﶷ'=>'كمي','ﶸ'=>'نجح','ﶹ'=>'مخي','ﶺ'=>'لجم','ﶻ'=>'كمم','ﶼ'=>'لجم','ﶽ'=>'نجح','ﶾ'=>'جحي','ﶿ'=>'حجي','ï·€'=>'مجي','ï·'=>'Ùمي','ï·‚'=>'بحي','ï·ƒ'=>'كمم','ï·„'=>'عجم','ï·…'=>'صمم','ï·†'=>'سخي','ï·‡'=>'نجي','ï·°'=>'صلے','ï·±'=>'قلے','ï·²'=>'الله','ï·³'=>'اكبر','ï·´'=>'محمد','ï·µ'=>'صلعم','ï·¶'=>'رسول','ï··'=>'عليه','ï·¸'=>'وسلم','ï·¹'=>'صلى','ï·º'=>'صلى الله عليه وسلم','ï·»'=>'جل جلاله','ï·¼'=>'ریال','ï¸'=>',','︑'=>'ã€','︒'=>'。','︓'=>':','︔'=>';','︕'=>'!','︖'=>'?','︗'=>'〖','︘'=>'〗','︙'=>'...','︰'=>'..','︱'=>'—','︲'=>'–','︳'=>'_','︴'=>'_','︵'=>'(','︶'=>')','︷'=>'{','︸'=>'}','︹'=>'〔','︺'=>'〕','︻'=>'ã€','︼'=>'】','︽'=>'《','︾'=>'》','︿'=>'〈','ï¹€'=>'〉','ï¹'=>'「','﹂'=>'ã€','﹃'=>'『','﹄'=>'ã€','﹇'=>'[','﹈'=>']','﹉'=>' Ì…','﹊'=>' Ì…','﹋'=>' Ì…','﹌'=>' Ì…','ï¹'=>'_','﹎'=>'_','ï¹'=>'_','ï¹'=>',','﹑'=>'ã€','ï¹’'=>'.','ï¹”'=>';','﹕'=>':','ï¹–'=>'?','ï¹—'=>'!','﹘'=>'—','ï¹™'=>'(','﹚'=>')','ï¹›'=>'{','﹜'=>'}','ï¹'=>'〔','﹞'=>'〕','﹟'=>'#','ï¹ '=>'&','﹡'=>'*','ï¹¢'=>'+','ï¹£'=>'-','﹤'=>'<','ï¹¥'=>'>','﹦'=>'=','﹨'=>'\\','﹩'=>'$','﹪'=>'%','﹫'=>'@','ï¹°'=>' Ù‹','ï¹±'=>'ـً','ï¹²'=>' ÙŒ','ï¹´'=>' Ù','ﹶ'=>' ÙŽ','ï¹·'=>'Ù€ÙŽ','ﹸ'=>' Ù','ï¹¹'=>'Ù€Ù','ﹺ'=>' Ù','ï¹»'=>'Ù€Ù','ï¹¼'=>' Ù‘','ï¹½'=>'ـّ','ï¹¾'=>' Ù’','ﹿ'=>'ـْ','ﺀ'=>'Ø¡','ïº'=>'آ','ﺂ'=>'آ','ﺃ'=>'أ','ﺄ'=>'أ','ﺅ'=>'ÙˆÙ”','ﺆ'=>'ÙˆÙ”','ﺇ'=>'إ','ﺈ'=>'إ','ﺉ'=>'ÙŠÙ”','ﺊ'=>'ÙŠÙ”','ﺋ'=>'ÙŠÙ”','ﺌ'=>'ÙŠÙ”','ïº'=>'ا','ﺎ'=>'ا','ïº'=>'ب','ïº'=>'ب','ﺑ'=>'ب','ﺒ'=>'ب','ﺓ'=>'Ø©','ﺔ'=>'Ø©','ﺕ'=>'ت','ﺖ'=>'ت','ﺗ'=>'ت','ﺘ'=>'ت','ﺙ'=>'Ø«','ﺚ'=>'Ø«','ﺛ'=>'Ø«','ﺜ'=>'Ø«','ïº'=>'ج','ﺞ'=>'ج','ﺟ'=>'ج','ﺠ'=>'ج','ﺡ'=>'Ø­','ﺢ'=>'Ø­','ﺣ'=>'Ø­','ﺤ'=>'Ø­','ﺥ'=>'Ø®','ﺦ'=>'Ø®','ﺧ'=>'Ø®','ﺨ'=>'Ø®','ﺩ'=>'د','ﺪ'=>'د','ﺫ'=>'Ø°','ﺬ'=>'Ø°','ﺭ'=>'ر','ﺮ'=>'ر','ﺯ'=>'ز','ﺰ'=>'ز','ﺱ'=>'س','ﺲ'=>'س','ﺳ'=>'س','ﺴ'=>'س','ﺵ'=>'Ø´','ﺶ'=>'Ø´','ﺷ'=>'Ø´','ﺸ'=>'Ø´','ﺹ'=>'ص','ﺺ'=>'ص','ﺻ'=>'ص','ﺼ'=>'ص','ﺽ'=>'ض','ﺾ'=>'ض','ﺿ'=>'ض','ﻀ'=>'ض','ï»'=>'Ø·','ﻂ'=>'Ø·','ﻃ'=>'Ø·','ﻄ'=>'Ø·','ï»…'=>'ظ','ﻆ'=>'ظ','ﻇ'=>'ظ','ﻈ'=>'ظ','ﻉ'=>'ع','ﻊ'=>'ع','ﻋ'=>'ع','ﻌ'=>'ع','ï»'=>'غ','ﻎ'=>'غ','ï»'=>'غ','ï»'=>'غ','ﻑ'=>'Ù','ï»’'=>'Ù','ﻓ'=>'Ù','ï»”'=>'Ù','ﻕ'=>'Ù‚','ï»–'=>'Ù‚','ï»—'=>'Ù‚','ﻘ'=>'Ù‚','ï»™'=>'Ùƒ','ﻚ'=>'Ùƒ','ï»›'=>'Ùƒ','ﻜ'=>'Ùƒ','ï»'=>'Ù„','ﻞ'=>'Ù„','ﻟ'=>'Ù„','ï» '=>'Ù„','ﻡ'=>'Ù…','ﻢ'=>'Ù…','ﻣ'=>'Ù…','ﻤ'=>'Ù…','ﻥ'=>'Ù†','ﻦ'=>'Ù†','ﻧ'=>'Ù†','ﻨ'=>'Ù†','ﻩ'=>'Ù‡','ﻪ'=>'Ù‡','ﻫ'=>'Ù‡','ﻬ'=>'Ù‡','ï»­'=>'Ùˆ','ï»®'=>'Ùˆ','ﻯ'=>'Ù‰','ï»°'=>'Ù‰','ï»±'=>'ÙŠ','ﻲ'=>'ÙŠ','ﻳ'=>'ÙŠ','ï»´'=>'ÙŠ','ﻵ'=>'لآ','ﻶ'=>'لآ','ï»·'=>'لأ','ﻸ'=>'لأ','ﻹ'=>'لإ','ﻺ'=>'لإ','ï»»'=>'لا','ﻼ'=>'لا','ï¼'=>'!','"'=>'"','#'=>'#','$'=>'$','ï¼…'=>'%','&'=>'&','''=>'\'','('=>'(',')'=>')','*'=>'*','+'=>'+',','=>',','ï¼'=>'-','.'=>'.','ï¼'=>'/','ï¼'=>'0','1'=>'1','ï¼’'=>'2','3'=>'3','ï¼”'=>'4','5'=>'5','ï¼–'=>'6','ï¼—'=>'7','8'=>'8','ï¼™'=>'9',':'=>':','ï¼›'=>';','<'=>'<','ï¼'=>'=','>'=>'>','?'=>'?','ï¼ '=>'@','A'=>'A','ï¼¢'=>'B','ï¼£'=>'C','D'=>'D','ï¼¥'=>'E','F'=>'F','G'=>'G','H'=>'H','I'=>'I','J'=>'J','K'=>'K','L'=>'L','ï¼­'=>'M','ï¼®'=>'N','O'=>'O','ï¼°'=>'P','ï¼±'=>'Q','ï¼²'=>'R','ï¼³'=>'S','ï¼´'=>'T','ï¼µ'=>'U','V'=>'V','ï¼·'=>'W','X'=>'X','ï¼¹'=>'Y','Z'=>'Z','ï¼»'=>'[','ï¼¼'=>'\\','ï¼½'=>']','ï¼¾'=>'^','_'=>'_','ï½€'=>'`','ï½'=>'a','b'=>'b','c'=>'c','d'=>'d','ï½…'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j','k'=>'k','l'=>'l','ï½'=>'m','n'=>'n','ï½'=>'o','ï½'=>'p','q'=>'q','ï½’'=>'r','s'=>'s','ï½”'=>'t','u'=>'u','ï½–'=>'v','ï½—'=>'w','x'=>'x','ï½™'=>'y','z'=>'z','ï½›'=>'{','|'=>'|','ï½'=>'}','~'=>'~','⦅'=>'⦅','ï½ '=>'⦆','。'=>'。','ï½¢'=>'「','ï½£'=>'ã€','、'=>'ã€','ï½¥'=>'・','ヲ'=>'ヲ','ァ'=>'ã‚¡','ィ'=>'ã‚£','ゥ'=>'ã‚¥','ェ'=>'ェ','ォ'=>'ã‚©','ャ'=>'ャ','ï½­'=>'ュ','ï½®'=>'ョ','ッ'=>'ッ','ï½°'=>'ー','ï½±'=>'ã‚¢','ï½²'=>'イ','ï½³'=>'ウ','ï½´'=>'エ','ï½µ'=>'オ','カ'=>'ã‚«','ï½·'=>'ã‚­','ク'=>'ク','ï½¹'=>'ケ','コ'=>'コ','ï½»'=>'サ','ï½¼'=>'ã‚·','ï½½'=>'ス','ï½¾'=>'ã‚»','ソ'=>'ソ','ï¾€'=>'ã‚¿','ï¾'=>'ãƒ','ツ'=>'ツ','テ'=>'テ','ト'=>'ト','ï¾…'=>'ナ','ニ'=>'ニ','ヌ'=>'ヌ','ネ'=>'ãƒ','ノ'=>'ノ','ハ'=>'ãƒ','ヒ'=>'ヒ','フ'=>'フ','ï¾'=>'ヘ','ホ'=>'ホ','ï¾'=>'マ','ï¾'=>'ミ','ム'=>'ム','ï¾’'=>'メ','モ'=>'モ','ï¾”'=>'ヤ','ユ'=>'ユ','ï¾–'=>'ヨ','ï¾—'=>'ラ','リ'=>'リ','ï¾™'=>'ル','レ'=>'レ','ï¾›'=>'ロ','ワ'=>'ワ','ï¾'=>'ン','゙'=>'ã‚™','゚'=>'ã‚š','ï¾ '=>'á… ','ᄀ'=>'á„€','ï¾¢'=>'á„','ï¾£'=>'ᆪ','ᄂ'=>'á„‚','ï¾¥'=>'ᆬ','ᆭ'=>'ᆭ','ᄃ'=>'ᄃ','ᄄ'=>'á„„','ᄅ'=>'á„…','ᆰ'=>'ᆰ','ᆱ'=>'ᆱ','ᆲ'=>'ᆲ','ï¾­'=>'ᆳ','ï¾®'=>'ᆴ','ᆵ'=>'ᆵ','ï¾°'=>'á„š','ï¾±'=>'ᄆ','ï¾²'=>'ᄇ','ï¾³'=>'ᄈ','ï¾´'=>'á„¡','ï¾µ'=>'ᄉ','ᄊ'=>'á„Š','ï¾·'=>'á„‹','ᄌ'=>'á„Œ','ï¾¹'=>'á„','ᄎ'=>'á„Ž','ï¾»'=>'á„','ï¾¼'=>'á„','ï¾½'=>'á„‘','ï¾¾'=>'á„’','ï¿‚'=>'á…¡','ᅢ'=>'á…¢','ï¿„'=>'á…£','ï¿…'=>'á…¤','ᅥ'=>'á…¥','ᅦ'=>'á…¦','ï¿Š'=>'á…§','ï¿‹'=>'á…¨','ï¿Œ'=>'á…©','ï¿'=>'á…ª','ï¿Ž'=>'á…«','ï¿'=>'á…¬','ï¿’'=>'á…­','ï¿“'=>'á…®','ï¿”'=>'á…¯','ï¿•'=>'á…°','ï¿–'=>'á…±','ï¿—'=>'á…²','ï¿š'=>'á…³','ï¿›'=>'á…´','ï¿œ'=>'á…µ','ï¿ '=>'¢','ï¿¡'=>'£','ï¿¢'=>'¬','ï¿£'=>' Ì„','¦'=>'¦','ï¿¥'=>'Â¥','₩'=>'â‚©','│'=>'│','ï¿©'=>'â†','↑'=>'↑','ï¿«'=>'→','↓'=>'↓','ï¿­'=>'â– ','ï¿®'=>'â—‹','ð…ž'=>'ð…—ð…¥','ð…Ÿ'=>'ð…˜ð…¥','ð… '=>'ð…˜ð…¥ð…®','ð…¡'=>'ð…˜ð…¥ð…¯','ð…¢'=>'ð…˜ð…¥ð…°','ð…£'=>'ð…˜ð…¥ð…±','ð…¤'=>'ð…˜ð…¥ð…²','ð†»'=>'ð†¹ð…¥','ð†¼'=>'ð†ºð…¥','ð†½'=>'ð†¹ð…¥ð…®','ð†¾'=>'ð†ºð…¥ð…®','ð†¿'=>'ð†¹ð…¥ð…¯','ð‡€'=>'ð†ºð…¥ð…¯','ð€'=>'A','ð'=>'B','ð‚'=>'C','ðƒ'=>'D','ð„'=>'E','ð…'=>'F','ð†'=>'G','ð‡'=>'H','ðˆ'=>'I','ð‰'=>'J','ðŠ'=>'K','ð‹'=>'L','ðŒ'=>'M','ð'=>'N','ðŽ'=>'O','ð'=>'P','ð'=>'Q','ð‘'=>'R','ð’'=>'S','ð“'=>'T','ð”'=>'U','ð•'=>'V','ð–'=>'W','ð—'=>'X','ð˜'=>'Y','ð™'=>'Z','ðš'=>'a','ð›'=>'b','ðœ'=>'c','ð'=>'d','ðž'=>'e','ðŸ'=>'f','ð '=>'g','ð¡'=>'h','ð¢'=>'i','ð£'=>'j','ð¤'=>'k','ð¥'=>'l','ð¦'=>'m','ð§'=>'n','ð¨'=>'o','ð©'=>'p','ðª'=>'q','ð«'=>'r','ð¬'=>'s','ð­'=>'t','ð®'=>'u','ð¯'=>'v','ð°'=>'w','ð±'=>'x','ð²'=>'y','ð³'=>'z','ð´'=>'A','ðµ'=>'B','ð¶'=>'C','ð·'=>'D','ð¸'=>'E','ð¹'=>'F','ðº'=>'G','ð»'=>'H','ð¼'=>'I','ð½'=>'J','ð¾'=>'K','ð¿'=>'L','ð‘€'=>'M','ð‘'=>'N','ð‘‚'=>'O','ð‘ƒ'=>'P','ð‘„'=>'Q','ð‘…'=>'R','ð‘†'=>'S','ð‘‡'=>'T','ð‘ˆ'=>'U','ð‘‰'=>'V','ð‘Š'=>'W','ð‘‹'=>'X','ð‘Œ'=>'Y','ð‘'=>'Z','ð‘Ž'=>'a','ð‘'=>'b','ð‘'=>'c','ð‘‘'=>'d','ð‘’'=>'e','ð‘“'=>'f','ð‘”'=>'g','ð‘–'=>'i','ð‘—'=>'j','ð‘˜'=>'k','ð‘™'=>'l','ð‘š'=>'m','ð‘›'=>'n','ð‘œ'=>'o','ð‘'=>'p','ð‘ž'=>'q','ð‘Ÿ'=>'r','ð‘ '=>'s','ð‘¡'=>'t','ð‘¢'=>'u','ð‘£'=>'v','ð‘¤'=>'w','ð‘¥'=>'x','ð‘¦'=>'y','ð‘§'=>'z','ð‘¨'=>'A','ð‘©'=>'B','ð‘ª'=>'C','ð‘«'=>'D','ð‘¬'=>'E','ð‘­'=>'F','ð‘®'=>'G','ð‘¯'=>'H','ð‘°'=>'I','ð‘±'=>'J','ð‘²'=>'K','ð‘³'=>'L','ð‘´'=>'M','ð‘µ'=>'N','ð‘¶'=>'O','ð‘·'=>'P','ð‘¸'=>'Q','ð‘¹'=>'R','ð‘º'=>'S','ð‘»'=>'T','ð‘¼'=>'U','ð‘½'=>'V','ð‘¾'=>'W','ð‘¿'=>'X','ð’€'=>'Y','ð’'=>'Z','ð’‚'=>'a','ð’ƒ'=>'b','ð’„'=>'c','ð’…'=>'d','ð’†'=>'e','ð’‡'=>'f','ð’ˆ'=>'g','ð’‰'=>'h','ð’Š'=>'i','ð’‹'=>'j','ð’Œ'=>'k','ð’'=>'l','ð’Ž'=>'m','ð’'=>'n','ð’'=>'o','ð’‘'=>'p','ð’’'=>'q','ð’“'=>'r','ð’”'=>'s','ð’•'=>'t','ð’–'=>'u','ð’—'=>'v','ð’˜'=>'w','ð’™'=>'x','ð’š'=>'y','ð’›'=>'z','ð’œ'=>'A','ð’ž'=>'C','ð’Ÿ'=>'D','ð’¢'=>'G','ð’¥'=>'J','ð’¦'=>'K','ð’©'=>'N','ð’ª'=>'O','ð’«'=>'P','ð’¬'=>'Q','ð’®'=>'S','ð’¯'=>'T','ð’°'=>'U','ð’±'=>'V','ð’²'=>'W','ð’³'=>'X','ð’´'=>'Y','ð’µ'=>'Z','ð’¶'=>'a','ð’·'=>'b','ð’¸'=>'c','ð’¹'=>'d','ð’»'=>'f','ð’½'=>'h','ð’¾'=>'i','ð’¿'=>'j','ð“€'=>'k','ð“'=>'l','ð“‚'=>'m','ð“ƒ'=>'n','ð“…'=>'p','ð“†'=>'q','ð“‡'=>'r','ð“ˆ'=>'s','ð“‰'=>'t','ð“Š'=>'u','ð“‹'=>'v','ð“Œ'=>'w','ð“'=>'x','ð“Ž'=>'y','ð“'=>'z','ð“'=>'A','ð“‘'=>'B','ð“’'=>'C','ð““'=>'D','ð“”'=>'E','ð“•'=>'F','ð“–'=>'G','ð“—'=>'H','ð“˜'=>'I','ð“™'=>'J','ð“š'=>'K','ð“›'=>'L','ð“œ'=>'M','ð“'=>'N','ð“ž'=>'O','ð“Ÿ'=>'P','ð“ '=>'Q','ð“¡'=>'R','ð“¢'=>'S','ð“£'=>'T','ð“¤'=>'U','ð“¥'=>'V','ð“¦'=>'W','ð“§'=>'X','ð“¨'=>'Y','ð“©'=>'Z','ð“ª'=>'a','ð“«'=>'b','ð“¬'=>'c','ð“­'=>'d','ð“®'=>'e','ð“¯'=>'f','ð“°'=>'g','ð“±'=>'h','ð“²'=>'i','ð“³'=>'j','ð“´'=>'k','ð“µ'=>'l','ð“¶'=>'m','ð“·'=>'n','ð“¸'=>'o','ð“¹'=>'p','ð“º'=>'q','ð“»'=>'r','ð“¼'=>'s','ð“½'=>'t','ð“¾'=>'u','ð“¿'=>'v','ð”€'=>'w','ð”'=>'x','ð”‚'=>'y','ð”ƒ'=>'z','ð”„'=>'A','ð”…'=>'B','ð”‡'=>'D','ð”ˆ'=>'E','ð”‰'=>'F','ð”Š'=>'G','ð”'=>'J','ð”Ž'=>'K','ð”'=>'L','ð”'=>'M','ð”‘'=>'N','ð”’'=>'O','ð”“'=>'P','ð””'=>'Q','ð”–'=>'S','ð”—'=>'T','ð”˜'=>'U','ð”™'=>'V','ð”š'=>'W','ð”›'=>'X','ð”œ'=>'Y','ð”ž'=>'a','ð”Ÿ'=>'b','ð” '=>'c','ð”¡'=>'d','ð”¢'=>'e','ð”£'=>'f','ð”¤'=>'g','ð”¥'=>'h','ð”¦'=>'i','ð”§'=>'j','ð”¨'=>'k','ð”©'=>'l','ð”ª'=>'m','ð”«'=>'n','ð”¬'=>'o','ð”­'=>'p','ð”®'=>'q','ð”¯'=>'r','ð”°'=>'s','ð”±'=>'t','ð”²'=>'u','ð”³'=>'v','ð”´'=>'w','ð”µ'=>'x','ð”¶'=>'y','ð”·'=>'z','ð”¸'=>'A','ð”¹'=>'B','ð”»'=>'D','ð”¼'=>'E','ð”½'=>'F','ð”¾'=>'G','ð•€'=>'I','ð•'=>'J','ð•‚'=>'K','ð•ƒ'=>'L','ð•„'=>'M','ð•†'=>'O','ð•Š'=>'S','ð•‹'=>'T','ð•Œ'=>'U','ð•'=>'V','ð•Ž'=>'W','ð•'=>'X','ð•'=>'Y','ð•’'=>'a','ð•“'=>'b','ð•”'=>'c','ð••'=>'d','ð•–'=>'e','ð•—'=>'f','ð•˜'=>'g','ð•™'=>'h','ð•š'=>'i','ð•›'=>'j','ð•œ'=>'k','ð•'=>'l','ð•ž'=>'m','ð•Ÿ'=>'n','ð• '=>'o','ð•¡'=>'p','ð•¢'=>'q','ð•£'=>'r','ð•¤'=>'s','ð•¥'=>'t','ð•¦'=>'u','ð•§'=>'v','ð•¨'=>'w','ð•©'=>'x','ð•ª'=>'y','ð•«'=>'z','ð•¬'=>'A','ð•­'=>'B','ð•®'=>'C','ð•¯'=>'D','ð•°'=>'E','ð•±'=>'F','ð•²'=>'G','ð•³'=>'H','ð•´'=>'I','ð•µ'=>'J','ð•¶'=>'K','ð•·'=>'L','ð•¸'=>'M','ð•¹'=>'N','ð•º'=>'O','ð•»'=>'P','ð•¼'=>'Q','ð•½'=>'R','ð•¾'=>'S','ð•¿'=>'T','ð–€'=>'U','ð–'=>'V','ð–‚'=>'W','ð–ƒ'=>'X','ð–„'=>'Y','ð–…'=>'Z','ð–†'=>'a','ð–‡'=>'b','ð–ˆ'=>'c','ð–‰'=>'d','ð–Š'=>'e','ð–‹'=>'f','ð–Œ'=>'g','ð–'=>'h','ð–Ž'=>'i','ð–'=>'j','ð–'=>'k','ð–‘'=>'l','ð–’'=>'m','ð–“'=>'n','ð–”'=>'o','ð–•'=>'p','ð––'=>'q','ð–—'=>'r','ð–˜'=>'s','ð–™'=>'t','ð–š'=>'u','ð–›'=>'v','ð–œ'=>'w','ð–'=>'x','ð–ž'=>'y','ð–Ÿ'=>'z','ð– '=>'A','ð–¡'=>'B','ð–¢'=>'C','ð–£'=>'D','ð–¤'=>'E','ð–¥'=>'F','ð–¦'=>'G','ð–§'=>'H','ð–¨'=>'I','ð–©'=>'J','ð–ª'=>'K','ð–«'=>'L','ð–¬'=>'M','ð–­'=>'N','ð–®'=>'O','ð–¯'=>'P','ð–°'=>'Q','ð–±'=>'R','ð–²'=>'S','ð–³'=>'T','ð–´'=>'U','ð–µ'=>'V','ð–¶'=>'W','ð–·'=>'X','ð–¸'=>'Y','ð–¹'=>'Z','ð–º'=>'a','ð–»'=>'b','ð–¼'=>'c','ð–½'=>'d','ð–¾'=>'e','ð–¿'=>'f','ð—€'=>'g','ð—'=>'h','ð—‚'=>'i','ð—ƒ'=>'j','ð—„'=>'k','ð—…'=>'l','ð—†'=>'m','ð—‡'=>'n','ð—ˆ'=>'o','ð—‰'=>'p','ð—Š'=>'q','ð—‹'=>'r','ð—Œ'=>'s','ð—'=>'t','ð—Ž'=>'u','ð—'=>'v','ð—'=>'w','ð—‘'=>'x','ð—’'=>'y','ð—“'=>'z','ð—”'=>'A','ð—•'=>'B','ð—–'=>'C','ð——'=>'D','ð—˜'=>'E','ð—™'=>'F','ð—š'=>'G','ð—›'=>'H','ð—œ'=>'I','ð—'=>'J','ð—ž'=>'K','ð—Ÿ'=>'L','ð— '=>'M','ð—¡'=>'N','ð—¢'=>'O','ð—£'=>'P','ð—¤'=>'Q','ð—¥'=>'R','ð—¦'=>'S','ð—§'=>'T','ð—¨'=>'U','ð—©'=>'V','ð—ª'=>'W','ð—«'=>'X','ð—¬'=>'Y','ð—­'=>'Z','ð—®'=>'a','ð—¯'=>'b','ð—°'=>'c','ð—±'=>'d','ð—²'=>'e','ð—³'=>'f','ð—´'=>'g','ð—µ'=>'h','ð—¶'=>'i','ð—·'=>'j','ð—¸'=>'k','ð—¹'=>'l','ð—º'=>'m','ð—»'=>'n','ð—¼'=>'o','ð—½'=>'p','ð—¾'=>'q','ð—¿'=>'r','ð˜€'=>'s','ð˜'=>'t','ð˜‚'=>'u','ð˜ƒ'=>'v','ð˜„'=>'w','ð˜…'=>'x','ð˜†'=>'y','ð˜‡'=>'z','ð˜ˆ'=>'A','ð˜‰'=>'B','ð˜Š'=>'C','ð˜‹'=>'D','ð˜Œ'=>'E','ð˜'=>'F','ð˜Ž'=>'G','ð˜'=>'H','ð˜'=>'I','ð˜‘'=>'J','ð˜’'=>'K','ð˜“'=>'L','ð˜”'=>'M','ð˜•'=>'N','ð˜–'=>'O','ð˜—'=>'P','ð˜˜'=>'Q','ð˜™'=>'R','ð˜š'=>'S','ð˜›'=>'T','ð˜œ'=>'U','ð˜'=>'V','ð˜ž'=>'W','ð˜Ÿ'=>'X','ð˜ '=>'Y','ð˜¡'=>'Z','ð˜¢'=>'a','ð˜£'=>'b','ð˜¤'=>'c','ð˜¥'=>'d','ð˜¦'=>'e','ð˜§'=>'f','ð˜¨'=>'g','ð˜©'=>'h','ð˜ª'=>'i','ð˜«'=>'j','ð˜¬'=>'k','ð˜­'=>'l','ð˜®'=>'m','ð˜¯'=>'n','ð˜°'=>'o','ð˜±'=>'p','ð˜²'=>'q','ð˜³'=>'r','ð˜´'=>'s','ð˜µ'=>'t','ð˜¶'=>'u','ð˜·'=>'v','ð˜¸'=>'w','ð˜¹'=>'x','ð˜º'=>'y','ð˜»'=>'z','ð˜¼'=>'A','ð˜½'=>'B','ð˜¾'=>'C','ð˜¿'=>'D','ð™€'=>'E','ð™'=>'F','ð™‚'=>'G','ð™ƒ'=>'H','ð™„'=>'I','ð™…'=>'J','ð™†'=>'K','ð™‡'=>'L','ð™ˆ'=>'M','ð™‰'=>'N','ð™Š'=>'O','ð™‹'=>'P','ð™Œ'=>'Q','ð™'=>'R','ð™Ž'=>'S','ð™'=>'T','ð™'=>'U','ð™‘'=>'V','ð™’'=>'W','ð™“'=>'X','ð™”'=>'Y','ð™•'=>'Z','ð™–'=>'a','ð™—'=>'b','ð™˜'=>'c','ð™™'=>'d','ð™š'=>'e','ð™›'=>'f','ð™œ'=>'g','ð™'=>'h','ð™ž'=>'i','ð™Ÿ'=>'j','ð™ '=>'k','ð™¡'=>'l','ð™¢'=>'m','ð™£'=>'n','ð™¤'=>'o','ð™¥'=>'p','ð™¦'=>'q','ð™§'=>'r','ð™¨'=>'s','ð™©'=>'t','ð™ª'=>'u','ð™«'=>'v','ð™¬'=>'w','ð™­'=>'x','ð™®'=>'y','ð™¯'=>'z','ð™°'=>'A','ð™±'=>'B','ð™²'=>'C','ð™³'=>'D','ð™´'=>'E','ð™µ'=>'F','ð™¶'=>'G','ð™·'=>'H','ð™¸'=>'I','ð™¹'=>'J','ð™º'=>'K','ð™»'=>'L','ð™¼'=>'M','ð™½'=>'N','ð™¾'=>'O','ð™¿'=>'P','ðš€'=>'Q','ðš'=>'R','ðš‚'=>'S','ðšƒ'=>'T','ðš„'=>'U','ðš…'=>'V','ðš†'=>'W','ðš‡'=>'X','ðšˆ'=>'Y','ðš‰'=>'Z','ðšŠ'=>'a','ðš‹'=>'b','ðšŒ'=>'c','ðš'=>'d','ðšŽ'=>'e','ðš'=>'f','ðš'=>'g','ðš‘'=>'h','ðš’'=>'i','ðš“'=>'j','ðš”'=>'k','ðš•'=>'l','ðš–'=>'m','ðš—'=>'n','ðš˜'=>'o','ðš™'=>'p','ðšš'=>'q','ðš›'=>'r','ðšœ'=>'s','ðš'=>'t','ðšž'=>'u','ðšŸ'=>'v','ðš '=>'w','ðš¡'=>'x','ðš¢'=>'y','ðš£'=>'z','ðš¤'=>'ı','ðš¥'=>'È·','ðš¨'=>'Α','ðš©'=>'Î’','ðšª'=>'Γ','ðš«'=>'Δ','ðš¬'=>'Ε','ðš­'=>'Ζ','ðš®'=>'Η','ðš¯'=>'Θ','ðš°'=>'Ι','ðš±'=>'Κ','ðš²'=>'Λ','ðš³'=>'Îœ','ðš´'=>'Î','ðšµ'=>'Ξ','ðš¶'=>'Ο','ðš·'=>'Π','ðš¸'=>'Ρ','ðš¹'=>'Θ','ðšº'=>'Σ','ðš»'=>'Τ','ðš¼'=>'Î¥','ðš½'=>'Φ','ðš¾'=>'Χ','ðš¿'=>'Ψ','ð›€'=>'Ω','ð›'=>'∇','ð›‚'=>'α','ð›ƒ'=>'β','ð›„'=>'γ','ð›…'=>'δ','ð›†'=>'ε','ð›‡'=>'ζ','ð›ˆ'=>'η','ð›‰'=>'θ','ð›Š'=>'ι','ð›‹'=>'κ','ð›Œ'=>'λ','ð›'=>'μ','ð›Ž'=>'ν','ð›'=>'ξ','ð›'=>'ο','ð›‘'=>'Ï€','ð›’'=>'Ï','ð›“'=>'Ï‚','ð›”'=>'σ','ð›•'=>'Ï„','ð›–'=>'Ï…','ð›—'=>'φ','ð›˜'=>'χ','ð›™'=>'ψ','ð›š'=>'ω','ð››'=>'∂','ð›œ'=>'ε','ð›'=>'θ','ð›ž'=>'κ','ð›Ÿ'=>'φ','ð› '=>'Ï','ð›¡'=>'Ï€','ð›¢'=>'Α','ð›£'=>'Î’','ð›¤'=>'Γ','ð›¥'=>'Δ','ð›¦'=>'Ε','ð›§'=>'Ζ','ð›¨'=>'Η','ð›©'=>'Θ','ð›ª'=>'Ι','ð›«'=>'Κ','ð›¬'=>'Λ','ð›­'=>'Îœ','ð›®'=>'Î','ð›¯'=>'Ξ','ð›°'=>'Ο','ð›±'=>'Π','ð›²'=>'Ρ','ð›³'=>'Θ','ð›´'=>'Σ','ð›µ'=>'Τ','ð›¶'=>'Î¥','ð›·'=>'Φ','ð›¸'=>'Χ','ð›¹'=>'Ψ','ð›º'=>'Ω','ð›»'=>'∇','ð›¼'=>'α','ð›½'=>'β','ð›¾'=>'γ','ð›¿'=>'δ','ðœ€'=>'ε','ðœ'=>'ζ','ðœ‚'=>'η','ðœƒ'=>'θ','ðœ„'=>'ι','ðœ…'=>'κ','ðœ†'=>'λ','ðœ‡'=>'μ','ðœˆ'=>'ν','ðœ‰'=>'ξ','ðœŠ'=>'ο','ðœ‹'=>'Ï€','ðœŒ'=>'Ï','ðœ'=>'Ï‚','ðœŽ'=>'σ','ðœ'=>'Ï„','ðœ'=>'Ï…','ðœ‘'=>'φ','ðœ’'=>'χ','ðœ“'=>'ψ','ðœ”'=>'ω','ðœ•'=>'∂','ðœ–'=>'ε','ðœ—'=>'θ','ðœ˜'=>'κ','ðœ™'=>'φ','ðœš'=>'Ï','ðœ›'=>'Ï€','ðœœ'=>'Α','ðœ'=>'Î’','ðœž'=>'Γ','ðœŸ'=>'Δ','ðœ '=>'Ε','ðœ¡'=>'Ζ','ðœ¢'=>'Η','ðœ£'=>'Θ','ðœ¤'=>'Ι','ðœ¥'=>'Κ','ðœ¦'=>'Λ','ðœ§'=>'Îœ','ðœ¨'=>'Î','ðœ©'=>'Ξ','ðœª'=>'Ο','ðœ«'=>'Π','ðœ¬'=>'Ρ','ðœ­'=>'Θ','ðœ®'=>'Σ','ðœ¯'=>'Τ','ðœ°'=>'Î¥','ðœ±'=>'Φ','ðœ²'=>'Χ','ðœ³'=>'Ψ','ðœ´'=>'Ω','ðœµ'=>'∇','ðœ¶'=>'α','ðœ·'=>'β','ðœ¸'=>'γ','ðœ¹'=>'δ','ðœº'=>'ε','ðœ»'=>'ζ','ðœ¼'=>'η','ðœ½'=>'θ','ðœ¾'=>'ι','ðœ¿'=>'κ','ð€'=>'λ','ð'=>'μ','ð‚'=>'ν','ðƒ'=>'ξ','ð„'=>'ο','ð…'=>'Ï€','ð†'=>'Ï','ð‡'=>'Ï‚','ðˆ'=>'σ','ð‰'=>'Ï„','ðŠ'=>'Ï…','ð‹'=>'φ','ðŒ'=>'χ','ð'=>'ψ','ðŽ'=>'ω','ð'=>'∂','ð'=>'ε','ð‘'=>'θ','ð’'=>'κ','ð“'=>'φ','ð”'=>'Ï','ð•'=>'Ï€','ð–'=>'Α','ð—'=>'Î’','ð˜'=>'Γ','ð™'=>'Δ','ðš'=>'Ε','ð›'=>'Ζ','ðœ'=>'Η','ð'=>'Θ','ðž'=>'Ι','ðŸ'=>'Κ','ð '=>'Λ','ð¡'=>'Îœ','ð¢'=>'Î','ð£'=>'Ξ','ð¤'=>'Ο','ð¥'=>'Π','ð¦'=>'Ρ','ð§'=>'Θ','ð¨'=>'Σ','ð©'=>'Τ','ðª'=>'Î¥','ð«'=>'Φ','ð¬'=>'Χ','ð­'=>'Ψ','ð®'=>'Ω','ð¯'=>'∇','ð°'=>'α','ð±'=>'β','ð²'=>'γ','ð³'=>'δ','ð´'=>'ε','ðµ'=>'ζ','ð¶'=>'η','ð·'=>'θ','ð¸'=>'ι','ð¹'=>'κ','ðº'=>'λ','ð»'=>'μ','ð¼'=>'ν','ð½'=>'ξ','ð¾'=>'ο','ð¿'=>'Ï€','ðž€'=>'Ï','ðž'=>'Ï‚','ðž‚'=>'σ','ðžƒ'=>'Ï„','ðž„'=>'Ï…','ðž…'=>'φ','ðž†'=>'χ','ðž‡'=>'ψ','ðžˆ'=>'ω','ðž‰'=>'∂','ðžŠ'=>'ε','ðž‹'=>'θ','ðžŒ'=>'κ','ðž'=>'φ','ðžŽ'=>'Ï','ðž'=>'Ï€','ðž'=>'Α','ðž‘'=>'Î’','ðž’'=>'Γ','ðž“'=>'Δ','ðž”'=>'Ε','ðž•'=>'Ζ','ðž–'=>'Η','ðž—'=>'Θ','ðž˜'=>'Ι','ðž™'=>'Κ','ðžš'=>'Λ','ðž›'=>'Îœ','ðžœ'=>'Î','ðž'=>'Ξ','ðžž'=>'Ο','ðžŸ'=>'Π','ðž '=>'Ρ','ðž¡'=>'Θ','ðž¢'=>'Σ','ðž£'=>'Τ','ðž¤'=>'Î¥','ðž¥'=>'Φ','ðž¦'=>'Χ','ðž§'=>'Ψ','ðž¨'=>'Ω','ðž©'=>'∇','ðžª'=>'α','ðž«'=>'β','ðž¬'=>'γ','ðž­'=>'δ','ðž®'=>'ε','ðž¯'=>'ζ','ðž°'=>'η','ðž±'=>'θ','ðž²'=>'ι','ðž³'=>'κ','ðž´'=>'λ','ðžµ'=>'μ','ðž¶'=>'ν','ðž·'=>'ξ','ðž¸'=>'ο','ðž¹'=>'Ï€','ðžº'=>'Ï','ðž»'=>'Ï‚','ðž¼'=>'σ','ðž½'=>'Ï„','ðž¾'=>'Ï…','ðž¿'=>'φ','ðŸ€'=>'χ','ðŸ'=>'ψ','ðŸ‚'=>'ω','ðŸƒ'=>'∂','ðŸ„'=>'ε','ðŸ…'=>'θ','ðŸ†'=>'κ','ðŸ‡'=>'φ','ðŸˆ'=>'Ï','ðŸ‰'=>'Ï€','ðŸŠ'=>'Ïœ','ðŸ‹'=>'Ï','ðŸŽ'=>'0','ðŸ'=>'1','ðŸ'=>'2','ðŸ‘'=>'3','ðŸ’'=>'4','ðŸ“'=>'5','ðŸ”'=>'6','ðŸ•'=>'7','ðŸ–'=>'8','ðŸ—'=>'9','ðŸ˜'=>'0','ðŸ™'=>'1','ðŸš'=>'2','ðŸ›'=>'3','ðŸœ'=>'4','ðŸ'=>'5','ðŸž'=>'6','ðŸŸ'=>'7','ðŸ '=>'8','ðŸ¡'=>'9','ðŸ¢'=>'0','ðŸ£'=>'1','ðŸ¤'=>'2','ðŸ¥'=>'3','ðŸ¦'=>'4','ðŸ§'=>'5','ðŸ¨'=>'6','ðŸ©'=>'7','ðŸª'=>'8','ðŸ«'=>'9','ðŸ¬'=>'0','ðŸ­'=>'1','ðŸ®'=>'2','ðŸ¯'=>'3','ðŸ°'=>'4','ðŸ±'=>'5','ðŸ²'=>'6','ðŸ³'=>'7','ðŸ´'=>'8','ðŸµ'=>'9','ðŸ¶'=>'0','ðŸ·'=>'1','ðŸ¸'=>'2','ðŸ¹'=>'3','ðŸº'=>'4','ðŸ»'=>'5','ðŸ¼'=>'6','ðŸ½'=>'7','ðŸ¾'=>'8','ðŸ¿'=>'9','丽'=>'丽','ð¯ '=>'丸','乁'=>'ä¹','𠄢'=>'ð „¢','你'=>'ä½ ','侮'=>'ä¾®','侻'=>'ä¾»','倂'=>'倂','偺'=>'åº','備'=>'å‚™','僧'=>'僧','像'=>'åƒ','㒞'=>'ã’ž','ð¯ '=>'𠘺','免'=>'å…','ð¯ '=>'å…”','ð¯ '=>'å…¤','具'=>'å…·','𠔜'=>'𠔜','㒹'=>'ã’¹','內'=>'å…§','再'=>'å†','𠕋'=>'ð •‹','冗'=>'冗','冤'=>'冤','仌'=>'仌','冬'=>'冬','况'=>'况','𩇟'=>'𩇟','ð¯ '=>'凵','刃'=>'刃','㓟'=>'ã“Ÿ','刻'=>'刻','剆'=>'剆','割'=>'割','剷'=>'剷','㔕'=>'㔕','勇'=>'勇','勉'=>'勉','勤'=>'勤','勺'=>'勺','包'=>'包','匆'=>'匆','北'=>'北','卉'=>'å‰','卑'=>'å‘','博'=>'åš','即'=>'å³','卽'=>'å½','卿'=>'å¿','卿'=>'å¿','卿'=>'å¿','𠨬'=>'𠨬','灰'=>'ç°','及'=>'åŠ','叟'=>'åŸ','𠭣'=>'ð ­£','叫'=>'å«','叱'=>'å±','吆'=>'å†','咞'=>'å’ž','吸'=>'å¸','呈'=>'呈','周'=>'周','咢'=>'å’¢','ð¯¡'=>'哶','唐'=>'å”','啓'=>'å•“','啣'=>'å•£','善'=>'å–„','善'=>'å–„','喙'=>'å–™','喫'=>'å–«','喳'=>'å–³','嗂'=>'å—‚','圖'=>'圖','嘆'=>'嘆','ð¯¡'=>'圗','噑'=>'噑','ð¯¡'=>'å™´','ð¯¡'=>'切','壮'=>'壮','城'=>'城','埴'=>'埴','堍'=>'å ','型'=>'åž‹','堲'=>'å ²','報'=>'å ±','墬'=>'墬','𡓤'=>'𡓤','売'=>'売','壷'=>'壷','夆'=>'夆','ð¯¡'=>'多','夢'=>'夢','奢'=>'奢','𡚨'=>'𡚨','𡛪'=>'𡛪','姬'=>'姬','娛'=>'娛','娧'=>'娧','姘'=>'姘','婦'=>'婦','㛮'=>'ã›®','㛼'=>'㛼','嬈'=>'嬈','嬾'=>'嬾','嬾'=>'嬾','𡧈'=>'𡧈','寃'=>'寃','寘'=>'寘','寧'=>'寧','寳'=>'寳','𡬘'=>'𡬘','寿'=>'寿','将'=>'å°†','当'=>'当','尢'=>'å°¢','㞁'=>'ãž','屠'=>'å± ','屮'=>'å±®','峀'=>'å³€','岍'=>'å²','𡷤'=>'ð¡·¤','嵃'=>'嵃','𡷦'=>'ð¡·¦','嵮'=>'åµ®','嵫'=>'嵫','嵼'=>'åµ¼','ð¯¢'=>'å·¡','巢'=>'å·¢','㠯'=>'ã ¯','巽'=>'å·½','帨'=>'帨','帽'=>'帽','幩'=>'幩','㡢'=>'ã¡¢','𢆃'=>'𢆃','㡼'=>'㡼','庰'=>'庰','庳'=>'庳','ð¯¢'=>'庶','廊'=>'廊','ð¯¢'=>'𪎒','ð¯¢'=>'廾','𢌱'=>'𢌱','𢌱'=>'𢌱','舁'=>'èˆ','弢'=>'å¼¢','弢'=>'å¼¢','㣇'=>'㣇','𣊸'=>'𣊸','𦇚'=>'𦇚','形'=>'å½¢','彫'=>'彫','㣣'=>'㣣','徚'=>'徚','ð¯¢'=>'å¿','志'=>'å¿—','忹'=>'忹','悁'=>'æ‚','㤺'=>'㤺','㤜'=>'㤜','悔'=>'æ‚”','𢛔'=>'𢛔','惇'=>'惇','慈'=>'æ…ˆ','慌'=>'æ…Œ','慎'=>'æ…Ž','慌'=>'æ…Œ','慺'=>'æ…º','憎'=>'憎','憲'=>'憲','憤'=>'憤','憯'=>'憯','懞'=>'懞','懲'=>'懲','懶'=>'懶','成'=>'æˆ','戛'=>'戛','扝'=>'æ‰','抱'=>'抱','拔'=>'æ‹”','捐'=>'æ','𢬌'=>'𢬌','挽'=>'挽','拼'=>'拼','捨'=>'æ¨','掃'=>'掃','揤'=>'æ¤','𢯱'=>'𢯱','搢'=>'æ¢','揅'=>'æ…','ð¯£'=>'掩','㨮'=>'㨮','摩'=>'æ‘©','摾'=>'摾','撝'=>'æ’','摷'=>'æ‘·','㩬'=>'㩬','敏'=>'æ•','敬'=>'敬','𣀊'=>'𣀊','旣'=>'æ—£','書'=>'書','ð¯£'=>'晉','㬙'=>'㬙','ð¯£'=>'æš‘','ð¯£'=>'㬈','㫤'=>'㫤','冒'=>'冒','冕'=>'冕','最'=>'最','暜'=>'æšœ','肭'=>'è‚­','䏙'=>'ä™','朗'=>'朗','望'=>'望','朡'=>'朡','杞'=>'æž','杓'=>'æ“','ð¯£'=>'ð£ƒ','㭉'=>'ã­‰','柺'=>'柺','枅'=>'æž…','桒'=>'æ¡’','梅'=>'梅','𣑭'=>'𣑭','梎'=>'梎','栟'=>'æ Ÿ','椔'=>'椔','㮝'=>'ã®','楂'=>'楂','榣'=>'榣','槪'=>'槪','檨'=>'檨','𣚣'=>'𣚣','櫛'=>'æ«›','㰘'=>'ã°˜','次'=>'次','𣢧'=>'𣢧','歔'=>'æ­”','㱎'=>'㱎','歲'=>'æ­²','殟'=>'殟','殺'=>'殺','殻'=>'æ®»','𣪍'=>'ð£ª','𡴋'=>'ð¡´‹','𣫺'=>'𣫺','汎'=>'汎','𣲼'=>'𣲼','沿'=>'沿','泍'=>'æ³','汧'=>'汧','洖'=>'æ´–','派'=>'æ´¾','ð¯¤'=>'æµ·','流'=>'æµ','浩'=>'浩','浸'=>'浸','涅'=>'涅','𣴞'=>'𣴞','洴'=>'æ´´','港'=>'港','湮'=>'æ¹®','㴳'=>'ã´³','滋'=>'滋','滇'=>'滇','ð¯¤'=>'𣻑','淹'=>'æ·¹','ð¯¤'=>'æ½®','ð¯¤'=>'𣽞','𣾎'=>'𣾎','濆'=>'濆','瀹'=>'瀹','瀞'=>'瀞','瀛'=>'瀛','㶖'=>'㶖','灊'=>'çŠ','災'=>'ç½','灷'=>'ç·','炭'=>'ç‚­','𠔥'=>'𠔥','煅'=>'ç……','ð¯¤'=>'𤉣','熜'=>'熜','𤎫'=>'𤎫','爨'=>'爨','爵'=>'爵','牐'=>'ç‰','𤘈'=>'𤘈','犀'=>'犀','犕'=>'犕','𤜵'=>'𤜵','𤠔'=>'𤠔','獺'=>'çº','王'=>'王','㺬'=>'㺬','玥'=>'玥','㺸'=>'㺸','㺸'=>'㺸','瑇'=>'瑇','瑜'=>'ç‘œ','瑱'=>'瑱','璅'=>'ç’…','瓊'=>'ç“Š','㼛'=>'ã¼›','甤'=>'甤','𤰶'=>'𤰶','甾'=>'甾','𤲒'=>'𤲒','異'=>'ç•°','𢆟'=>'𢆟','瘐'=>'ç˜','𤾡'=>'𤾡','𤾸'=>'𤾸','𥁄'=>'ð¥„','㿼'=>'㿼','䀈'=>'䀈','直'=>'ç›´','ð¯¥'=>'𥃳','𥃲'=>'𥃲','𥄙'=>'𥄙','𥄳'=>'𥄳','眞'=>'眞','真'=>'真','真'=>'真','睊'=>'çŠ','䀹'=>'䀹','瞋'=>'çž‹','䁆'=>'ä†','䂖'=>'ä‚–','ð¯¥'=>'ð¥','硎'=>'ç¡Ž','ð¯¥'=>'碌','ð¯¥'=>'磌','䃣'=>'䃣','𥘦'=>'𥘦','祖'=>'祖','𥚚'=>'𥚚','𥛅'=>'𥛅','福'=>'ç¦','秫'=>'秫','䄯'=>'䄯','穀'=>'ç©€','穊'=>'ç©Š','穏'=>'ç©','𥥼'=>'𥥼','ð¯¥'=>'𥪧','𥪧'=>'𥪧','竮'=>'ç«®','䈂'=>'䈂','𥮫'=>'𥮫','篆'=>'篆','築'=>'築','䈧'=>'䈧','𥲀'=>'𥲀','糒'=>'ç³’','䊠'=>'䊠','糨'=>'糨','糣'=>'ç³£','紀'=>'ç´€','𥾆'=>'𥾆','絣'=>'çµ£','䌁'=>'äŒ','緇'=>'ç·‡','縂'=>'縂','繅'=>'ç¹…','䌴'=>'䌴','𦈨'=>'𦈨','𦉇'=>'𦉇','䍙'=>'ä™','𦋙'=>'𦋙','罺'=>'罺','𦌾'=>'𦌾','羕'=>'羕','翺'=>'翺','者'=>'者','𦓚'=>'𦓚','𦔣'=>'𦔣','聠'=>'è ','𦖨'=>'𦖨','聰'=>'è°','𣍟'=>'ð£Ÿ','ð¯¦'=>'ä•','育'=>'育','脃'=>'脃','䐋'=>'ä‹','脾'=>'脾','媵'=>'媵','𦞧'=>'𦞧','𦞵'=>'𦞵','𣎓'=>'𣎓','𣎜'=>'𣎜','舁'=>'èˆ','舄'=>'舄','ð¯¦'=>'辞','䑫'=>'ä‘«','ð¯¦'=>'芑','ð¯¦'=>'芋','芝'=>'èŠ','劳'=>'劳','花'=>'花','芳'=>'芳','芽'=>'芽','苦'=>'苦','𦬼'=>'𦬼','若'=>'è‹¥','茝'=>'èŒ','荣'=>'è£','莭'=>'莭','茣'=>'茣','ð¯¦'=>'莽','菧'=>'è§','著'=>'è‘—','荓'=>'è“','菊'=>'èŠ','菌'=>'èŒ','菜'=>'èœ','𦰶'=>'𦰶','𦵫'=>'𦵫','𦳕'=>'𦳕','䔫'=>'䔫','蓱'=>'蓱','蓳'=>'蓳','蔖'=>'è”–','𧏊'=>'ð§Š','蕤'=>'蕤','𦼬'=>'𦼬','䕝'=>'ä•','䕡'=>'ä•¡','𦾱'=>'𦾱','𧃒'=>'𧃒','䕫'=>'ä•«','虐'=>'è™','虜'=>'虜','虧'=>'虧','虩'=>'虩','蚩'=>'èš©','蚈'=>'蚈','蜎'=>'蜎','蛢'=>'蛢','蝹'=>'è¹','蜨'=>'蜨','蝫'=>'è«','螆'=>'螆','䗗'=>'ä——','蟡'=>'蟡','ð¯§'=>'è ','䗹'=>'ä—¹','衠'=>'è¡ ','衣'=>'è¡£','𧙧'=>'𧙧','裗'=>'裗','裞'=>'裞','䘵'=>'䘵','裺'=>'裺','㒻'=>'ã’»','𧢮'=>'𧢮','𧥦'=>'𧥦','ð¯§'=>'äš¾','䛇'=>'䛇','ð¯§'=>'誠','ð¯§'=>'è«­','變'=>'變','豕'=>'豕','𧲨'=>'𧲨','貫'=>'貫','賁'=>'è³','贛'=>'è´›','起'=>'èµ·','𧼯'=>'𧼯','𠠄'=>'ð  „','跋'=>'è·‹','趼'=>'趼','跰'=>'è·°','ð¯§'=>'𠣞','軔'=>'è»”','輸'=>'輸','𨗒'=>'𨗒','𨗭'=>'𨗭','邔'=>'é‚”','郱'=>'郱','鄑'=>'é„‘','𨜮'=>'𨜮','鄛'=>'é„›','鈸'=>'鈸','鋗'=>'é‹—','鋘'=>'鋘','鉼'=>'鉼','鏹'=>'é¹','鐕'=>'é•','𨯺'=>'𨯺','開'=>'é–‹','䦕'=>'䦕','閷'=>'é–·','𨵷'=>'𨵷','䧦'=>'䧦','雃'=>'雃','嶲'=>'嶲','霣'=>'霣','𩅅'=>'ð©……','𩈚'=>'𩈚','䩮'=>'ä©®','䩶'=>'䩶','韠'=>'韠','𩐊'=>'ð©Š','䪲'=>'䪲','𩒖'=>'ð©’–','頋'=>'é ‹','頋'=>'é ‹','頩'=>'é ©','ð¯¨'=>'ð©–¶','飢'=>'飢','䬳'=>'䬳','餩'=>'餩','馧'=>'馧','駂'=>'駂','駾'=>'駾','䯎'=>'䯎','𩬰'=>'𩬰','鬒'=>'鬒','鱀'=>'é±€','鳽'=>'é³½','ð¯¨'=>'䳎','䳭'=>'ä³­','ð¯¨'=>'鵧','ð¯¨'=>'𪃎','䳸'=>'䳸','𪄅'=>'𪄅','𪈎'=>'𪈎','𪊑'=>'𪊑','麻'=>'麻','䵖'=>'äµ–','黹'=>'黹','黾'=>'黾','鼅'=>'é¼…','鼏'=>'é¼','鼖'=>'é¼–','鼻'=>'é¼»','ð¯¨'=>'𪘀');
diff --git a/phpBB/includes/utf/data/utf_nfc_qc.php b/phpBB/includes/utf/data/utf_nfc_qc.php
deleted file mode 100644
index ff56357ea6..0000000000
--- a/phpBB/includes/utf/data/utf_nfc_qc.php
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-$GLOBALS['utf_nfc_qc']=array('Í€'=>1,'Í'=>1,'̓'=>1,'Í„'=>1,'Í´'=>1,';'=>1,'·'=>1,'क़'=>1,'ख़'=>1,'ग़'=>1,'ज़'=>1,'ड़'=>1,'à¥'=>1,'फ़'=>1,'य़'=>1,'ড়'=>1,'à§'=>1,'য়'=>1,'ਲ਼'=>1,'ਸ਼'=>1,'à©™'=>1,'à©š'=>1,'à©›'=>1,'à©ž'=>1,'à­œ'=>1,'à­'=>1,'གྷ'=>1,'à½'=>1,'དྷ'=>1,'བྷ'=>1,'ཛྷ'=>1,'ཀྵ'=>1,'ཱི'=>1,'ཱུ'=>1,'ྲྀ'=>1,'ླྀ'=>1,'à¾'=>1,'ྒྷ'=>1,'à¾'=>1,'ྡྷ'=>1,'ྦྷ'=>1,'ྫྷ'=>1,'ྐྵ'=>1,'á½±'=>1,'á½³'=>1,'á½µ'=>1,'á½·'=>1,'á½¹'=>1,'á½»'=>1,'á½½'=>1,'á¾»'=>1,'á¾¾'=>1,'Έ'=>1,'á¿‹'=>1,'á¿“'=>1,'á¿›'=>1,'á¿£'=>1,'á¿«'=>1,'á¿®'=>1,'`'=>1,'Ό'=>1,'á¿»'=>1,'´'=>1,' '=>1,'â€'=>1,'Ω'=>1,'K'=>1,'â„«'=>1,'〈'=>1,'〉'=>1,'â«œ'=>1,'豈'=>1,'ï¤'=>1,'車'=>1,'賈'=>1,'滑'=>1,'串'=>1,'句'=>1,'龜'=>1,'龜'=>1,'契'=>1,'金'=>1,'喇'=>1,'奈'=>1,'ï¤'=>1,'癩'=>1,'ï¤'=>1,'ï¤'=>1,'螺'=>1,'裸'=>1,'邏'=>1,'樂'=>1,'洛'=>1,'烙'=>1,'珞'=>1,'落'=>1,'酪'=>1,'駱'=>1,'亂'=>1,'卵'=>1,'ï¤'=>1,'爛'=>1,'蘭'=>1,'鸞'=>1,'嵐'=>1,'濫'=>1,'藍'=>1,'襤'=>1,'拉'=>1,'臘'=>1,'蠟'=>1,'廊'=>1,'朗'=>1,'浪'=>1,'狼'=>1,'郎'=>1,'來'=>1,'冷'=>1,'勞'=>1,'擄'=>1,'櫓'=>1,'爐'=>1,'盧'=>1,'老'=>1,'蘆'=>1,'虜'=>1,'路'=>1,'露'=>1,'魯'=>1,'鷺'=>1,'碌'=>1,'祿'=>1,'綠'=>1,'菉'=>1,'錄'=>1,'鹿'=>1,'ï¥'=>1,'壟'=>1,'弄'=>1,'籠'=>1,'聾'=>1,'牢'=>1,'磊'=>1,'賂'=>1,'雷'=>1,'壘'=>1,'屢'=>1,'樓'=>1,'ï¥'=>1,'漏'=>1,'ï¥'=>1,'ï¥'=>1,'陋'=>1,'勒'=>1,'肋'=>1,'凜'=>1,'凌'=>1,'稜'=>1,'綾'=>1,'菱'=>1,'陵'=>1,'讀'=>1,'拏'=>1,'樂'=>1,'ï¥'=>1,'丹'=>1,'寧'=>1,'怒'=>1,'率'=>1,'異'=>1,'北'=>1,'磻'=>1,'便'=>1,'復'=>1,'不'=>1,'泌'=>1,'數'=>1,'索'=>1,'參'=>1,'塞'=>1,'省'=>1,'葉'=>1,'說'=>1,'殺'=>1,'辰'=>1,'沈'=>1,'拾'=>1,'若'=>1,'掠'=>1,'略'=>1,'亮'=>1,'兩'=>1,'凉'=>1,'梁'=>1,'糧'=>1,'良'=>1,'諒'=>1,'量'=>1,'勵'=>1,'呂'=>1,'ï¦'=>1,'廬'=>1,'旅'=>1,'濾'=>1,'礪'=>1,'閭'=>1,'驪'=>1,'麗'=>1,'黎'=>1,'力'=>1,'曆'=>1,'歷'=>1,'ï¦'=>1,'年'=>1,'ï¦'=>1,'ï¦'=>1,'撚'=>1,'漣'=>1,'煉'=>1,'璉'=>1,'秊'=>1,'練'=>1,'聯'=>1,'輦'=>1,'蓮'=>1,'連'=>1,'鍊'=>1,'列'=>1,'ï¦'=>1,'咽'=>1,'烈'=>1,'裂'=>1,'說'=>1,'廉'=>1,'念'=>1,'捻'=>1,'殮'=>1,'簾'=>1,'獵'=>1,'令'=>1,'囹'=>1,'寧'=>1,'嶺'=>1,'怜'=>1,'玲'=>1,'瑩'=>1,'羚'=>1,'聆'=>1,'鈴'=>1,'零'=>1,'靈'=>1,'領'=>1,'例'=>1,'禮'=>1,'醴'=>1,'隸'=>1,'惡'=>1,'了'=>1,'僚'=>1,'寮'=>1,'尿'=>1,'料'=>1,'樂'=>1,'燎'=>1,'ï§'=>1,'蓼'=>1,'遼'=>1,'龍'=>1,'暈'=>1,'阮'=>1,'劉'=>1,'杻'=>1,'柳'=>1,'流'=>1,'溜'=>1,'琉'=>1,'ï§'=>1,'硫'=>1,'ï§'=>1,'ï§'=>1,'六'=>1,'戮'=>1,'陸'=>1,'倫'=>1,'崙'=>1,'淪'=>1,'輪'=>1,'律'=>1,'慄'=>1,'栗'=>1,'率'=>1,'隆'=>1,'ï§'=>1,'吏'=>1,'履'=>1,'易'=>1,'李'=>1,'梨'=>1,'泥'=>1,'理'=>1,'痢'=>1,'罹'=>1,'裏'=>1,'裡'=>1,'里'=>1,'離'=>1,'匿'=>1,'溺'=>1,'吝'=>1,'燐'=>1,'璘'=>1,'藺'=>1,'隣'=>1,'鱗'=>1,'麟'=>1,'林'=>1,'淋'=>1,'臨'=>1,'立'=>1,'笠'=>1,'粒'=>1,'狀'=>1,'炙'=>1,'識'=>1,'什'=>1,'茶'=>1,'刺'=>1,'切'=>1,'ï¨'=>1,'拓'=>1,'糖'=>1,'宅'=>1,'洞'=>1,'暴'=>1,'輻'=>1,'行'=>1,'降'=>1,'見'=>1,'廓'=>1,'兀'=>1,'ï¨'=>1,'ï¨'=>1,'晴'=>1,'凞'=>1,'猪'=>1,'益'=>1,'礼'=>1,'神'=>1,'祥'=>1,'福'=>1,'靖'=>1,'ï¨'=>1,'羽'=>1,'蘒'=>1,'諸'=>1,'逸'=>1,'都'=>1,'飯'=>1,'飼'=>1,'館'=>1,'鶴'=>1,'侮'=>1,'僧'=>1,'免'=>1,'勉'=>1,'勤'=>1,'卑'=>1,'喝'=>1,'嘆'=>1,'器'=>1,'塀'=>1,'墨'=>1,'層'=>1,'屮'=>1,'悔'=>1,'慨'=>1,'憎'=>1,'ï©€'=>1,'ï©'=>1,'ï©‚'=>1,'暑'=>1,'ï©„'=>1,'ï©…'=>1,'渚'=>1,'漢'=>1,'煮'=>1,'爫'=>1,'ï©Š'=>1,'ï©‹'=>1,'ï©Œ'=>1,'ï©'=>1,'ï©Ž'=>1,'ï©'=>1,'ï©'=>1,'ï©‘'=>1,'ï©’'=>1,'ï©“'=>1,'ï©”'=>1,'ï©•'=>1,'ï©–'=>1,'ï©—'=>1,'縉'=>1,'ï©™'=>1,'ï©š'=>1,'ï©›'=>1,'ï©œ'=>1,'ï©'=>1,'ï©ž'=>1,'ï©Ÿ'=>1,'ï© '=>1,'ï©¡'=>1,'ï©¢'=>1,'ï©£'=>1,'賓'=>1,'ï©¥'=>1,'辶'=>1,'逸'=>1,'難'=>1,'ï©©'=>1,'頻'=>1,'ï©°'=>1,'况'=>1,'全'=>1,'侀'=>1,'ï©´'=>1,'冀'=>1,'勇'=>1,'ï©·'=>1,'喝'=>1,'啕'=>1,'喙'=>1,'ï©»'=>1,'塚'=>1,'墳'=>1,'奄'=>1,'ï©¿'=>1,'婢'=>1,'ïª'=>1,'廒'=>1,'廙'=>1,'彩'=>1,'徭'=>1,'惘'=>1,'慎'=>1,'愈'=>1,'憎'=>1,'慠'=>1,'懲'=>1,'戴'=>1,'ïª'=>1,'搜'=>1,'ïª'=>1,'ïª'=>1,'晴'=>1,'朗'=>1,'望'=>1,'杖'=>1,'歹'=>1,'殺'=>1,'流'=>1,'滛'=>1,'滋'=>1,'漢'=>1,'瀞'=>1,'煮'=>1,'ïª'=>1,'爵'=>1,'犯'=>1,'猪'=>1,'瑱'=>1,'甆'=>1,'画'=>1,'瘝'=>1,'瘟'=>1,'益'=>1,'盛'=>1,'直'=>1,'睊'=>1,'着'=>1,'磌'=>1,'窱'=>1,'節'=>1,'类'=>1,'絛'=>1,'練'=>1,'缾'=>1,'者'=>1,'荒'=>1,'華'=>1,'蝹'=>1,'襁'=>1,'覆'=>1,'視'=>1,'調'=>1,'諸'=>1,'請'=>1,'謁'=>1,'諾'=>1,'諭'=>1,'謹'=>1,'ï«€'=>1,'ï«'=>1,'ï«‚'=>1,'遲'=>1,'ï«„'=>1,'ï«…'=>1,'陼'=>1,'難'=>1,'靖'=>1,'韛'=>1,'ï«Š'=>1,'ï«‹'=>1,'ï«Œ'=>1,'ï«'=>1,'ï«Ž'=>1,'ï«'=>1,'ï«'=>1,'ï«‘'=>1,'ï«’'=>1,'ï«“'=>1,'ï«”'=>1,'ï«•'=>1,'ï«–'=>1,'ï«—'=>1,'齃'=>1,'ï«™'=>1,'ï¬'=>1,'ײַ'=>1,'שׁ'=>1,'שׂ'=>1,'שּׁ'=>1,'שּׂ'=>1,'אַ'=>1,'אָ'=>1,'אּ'=>1,'בּ'=>1,'גּ'=>1,'דּ'=>1,'הּ'=>1,'וּ'=>1,'זּ'=>1,'טּ'=>1,'יּ'=>1,'ךּ'=>1,'כּ'=>1,'לּ'=>1,'מּ'=>1,'ï­€'=>1,'ï­'=>1,'ï­ƒ'=>1,'ï­„'=>1,'ï­†'=>1,'ï­‡'=>1,'ï­ˆ'=>1,'ï­‰'=>1,'ï­Š'=>1,'ï­‹'=>1,'ï­Œ'=>1,'ï­'=>1,'ï­Ž'=>1,'ð…ž'=>1,'ð…Ÿ'=>1,'ð… '=>1,'ð…¡'=>1,'ð…¢'=>1,'ð…£'=>1,'ð…¤'=>1,'ð†»'=>1,'ð†¼'=>1,'ð†½'=>1,'ð†¾'=>1,'ð†¿'=>1,'ð‡€'=>1,'丽'=>1,'ð¯ '=>1,'乁'=>1,'𠄢'=>1,'你'=>1,'侮'=>1,'侻'=>1,'倂'=>1,'偺'=>1,'備'=>1,'僧'=>1,'像'=>1,'㒞'=>1,'ð¯ '=>1,'免'=>1,'ð¯ '=>1,'ð¯ '=>1,'具'=>1,'𠔜'=>1,'㒹'=>1,'內'=>1,'再'=>1,'𠕋'=>1,'冗'=>1,'冤'=>1,'仌'=>1,'冬'=>1,'况'=>1,'𩇟'=>1,'ð¯ '=>1,'刃'=>1,'㓟'=>1,'刻'=>1,'剆'=>1,'割'=>1,'剷'=>1,'㔕'=>1,'勇'=>1,'勉'=>1,'勤'=>1,'勺'=>1,'包'=>1,'匆'=>1,'北'=>1,'卉'=>1,'卑'=>1,'博'=>1,'即'=>1,'卽'=>1,'卿'=>1,'卿'=>1,'卿'=>1,'𠨬'=>1,'灰'=>1,'及'=>1,'叟'=>1,'𠭣'=>1,'叫'=>1,'叱'=>1,'吆'=>1,'咞'=>1,'吸'=>1,'呈'=>1,'周'=>1,'咢'=>1,'ð¯¡'=>1,'唐'=>1,'啓'=>1,'啣'=>1,'善'=>1,'善'=>1,'喙'=>1,'喫'=>1,'喳'=>1,'嗂'=>1,'圖'=>1,'嘆'=>1,'ð¯¡'=>1,'噑'=>1,'ð¯¡'=>1,'ð¯¡'=>1,'壮'=>1,'城'=>1,'埴'=>1,'堍'=>1,'型'=>1,'堲'=>1,'報'=>1,'墬'=>1,'𡓤'=>1,'売'=>1,'壷'=>1,'夆'=>1,'ð¯¡'=>1,'夢'=>1,'奢'=>1,'𡚨'=>1,'𡛪'=>1,'姬'=>1,'娛'=>1,'娧'=>1,'姘'=>1,'婦'=>1,'㛮'=>1,'㛼'=>1,'嬈'=>1,'嬾'=>1,'嬾'=>1,'𡧈'=>1,'寃'=>1,'寘'=>1,'寧'=>1,'寳'=>1,'𡬘'=>1,'寿'=>1,'将'=>1,'当'=>1,'尢'=>1,'㞁'=>1,'屠'=>1,'屮'=>1,'峀'=>1,'岍'=>1,'𡷤'=>1,'嵃'=>1,'𡷦'=>1,'嵮'=>1,'嵫'=>1,'嵼'=>1,'ð¯¢'=>1,'巢'=>1,'㠯'=>1,'巽'=>1,'帨'=>1,'帽'=>1,'幩'=>1,'㡢'=>1,'𢆃'=>1,'㡼'=>1,'庰'=>1,'庳'=>1,'ð¯¢'=>1,'廊'=>1,'ð¯¢'=>1,'ð¯¢'=>1,'𢌱'=>1,'𢌱'=>1,'舁'=>1,'弢'=>1,'弢'=>1,'㣇'=>1,'𣊸'=>1,'𦇚'=>1,'形'=>1,'彫'=>1,'㣣'=>1,'徚'=>1,'ð¯¢'=>1,'志'=>1,'忹'=>1,'悁'=>1,'㤺'=>1,'㤜'=>1,'悔'=>1,'𢛔'=>1,'惇'=>1,'慈'=>1,'慌'=>1,'慎'=>1,'慌'=>1,'慺'=>1,'憎'=>1,'憲'=>1,'憤'=>1,'憯'=>1,'懞'=>1,'懲'=>1,'懶'=>1,'成'=>1,'戛'=>1,'扝'=>1,'抱'=>1,'拔'=>1,'捐'=>1,'𢬌'=>1,'挽'=>1,'拼'=>1,'捨'=>1,'掃'=>1,'揤'=>1,'𢯱'=>1,'搢'=>1,'揅'=>1,'ð¯£'=>1,'㨮'=>1,'摩'=>1,'摾'=>1,'撝'=>1,'摷'=>1,'㩬'=>1,'敏'=>1,'敬'=>1,'𣀊'=>1,'旣'=>1,'書'=>1,'ð¯£'=>1,'㬙'=>1,'ð¯£'=>1,'ð¯£'=>1,'㫤'=>1,'冒'=>1,'冕'=>1,'最'=>1,'暜'=>1,'肭'=>1,'䏙'=>1,'朗'=>1,'望'=>1,'朡'=>1,'杞'=>1,'杓'=>1,'ð¯£'=>1,'㭉'=>1,'柺'=>1,'枅'=>1,'桒'=>1,'梅'=>1,'𣑭'=>1,'梎'=>1,'栟'=>1,'椔'=>1,'㮝'=>1,'楂'=>1,'榣'=>1,'槪'=>1,'檨'=>1,'𣚣'=>1,'櫛'=>1,'㰘'=>1,'次'=>1,'𣢧'=>1,'歔'=>1,'㱎'=>1,'歲'=>1,'殟'=>1,'殺'=>1,'殻'=>1,'𣪍'=>1,'𡴋'=>1,'𣫺'=>1,'汎'=>1,'𣲼'=>1,'沿'=>1,'泍'=>1,'汧'=>1,'洖'=>1,'派'=>1,'ð¯¤'=>1,'流'=>1,'浩'=>1,'浸'=>1,'涅'=>1,'𣴞'=>1,'洴'=>1,'港'=>1,'湮'=>1,'㴳'=>1,'滋'=>1,'滇'=>1,'ð¯¤'=>1,'淹'=>1,'ð¯¤'=>1,'ð¯¤'=>1,'𣾎'=>1,'濆'=>1,'瀹'=>1,'瀞'=>1,'瀛'=>1,'㶖'=>1,'灊'=>1,'災'=>1,'灷'=>1,'炭'=>1,'𠔥'=>1,'煅'=>1,'ð¯¤'=>1,'熜'=>1,'𤎫'=>1,'爨'=>1,'爵'=>1,'牐'=>1,'𤘈'=>1,'犀'=>1,'犕'=>1,'𤜵'=>1,'𤠔'=>1,'獺'=>1,'王'=>1,'㺬'=>1,'玥'=>1,'㺸'=>1,'㺸'=>1,'瑇'=>1,'瑜'=>1,'瑱'=>1,'璅'=>1,'瓊'=>1,'㼛'=>1,'甤'=>1,'𤰶'=>1,'甾'=>1,'𤲒'=>1,'異'=>1,'𢆟'=>1,'瘐'=>1,'𤾡'=>1,'𤾸'=>1,'𥁄'=>1,'㿼'=>1,'䀈'=>1,'直'=>1,'ð¯¥'=>1,'𥃲'=>1,'𥄙'=>1,'𥄳'=>1,'眞'=>1,'真'=>1,'真'=>1,'睊'=>1,'䀹'=>1,'瞋'=>1,'䁆'=>1,'䂖'=>1,'ð¯¥'=>1,'硎'=>1,'ð¯¥'=>1,'ð¯¥'=>1,'䃣'=>1,'𥘦'=>1,'祖'=>1,'𥚚'=>1,'𥛅'=>1,'福'=>1,'秫'=>1,'䄯'=>1,'穀'=>1,'穊'=>1,'穏'=>1,'𥥼'=>1,'ð¯¥'=>1,'𥪧'=>1,'竮'=>1,'䈂'=>1,'𥮫'=>1,'篆'=>1,'築'=>1,'䈧'=>1,'𥲀'=>1,'糒'=>1,'䊠'=>1,'糨'=>1,'糣'=>1,'紀'=>1,'𥾆'=>1,'絣'=>1,'䌁'=>1,'緇'=>1,'縂'=>1,'繅'=>1,'䌴'=>1,'𦈨'=>1,'𦉇'=>1,'䍙'=>1,'𦋙'=>1,'罺'=>1,'𦌾'=>1,'羕'=>1,'翺'=>1,'者'=>1,'𦓚'=>1,'𦔣'=>1,'聠'=>1,'𦖨'=>1,'聰'=>1,'𣍟'=>1,'ð¯¦'=>1,'育'=>1,'脃'=>1,'䐋'=>1,'脾'=>1,'媵'=>1,'𦞧'=>1,'𦞵'=>1,'𣎓'=>1,'𣎜'=>1,'舁'=>1,'舄'=>1,'ð¯¦'=>1,'䑫'=>1,'ð¯¦'=>1,'ð¯¦'=>1,'芝'=>1,'劳'=>1,'花'=>1,'芳'=>1,'芽'=>1,'苦'=>1,'𦬼'=>1,'若'=>1,'茝'=>1,'荣'=>1,'莭'=>1,'茣'=>1,'ð¯¦'=>1,'菧'=>1,'著'=>1,'荓'=>1,'菊'=>1,'菌'=>1,'菜'=>1,'𦰶'=>1,'𦵫'=>1,'𦳕'=>1,'䔫'=>1,'蓱'=>1,'蓳'=>1,'蔖'=>1,'𧏊'=>1,'蕤'=>1,'𦼬'=>1,'䕝'=>1,'䕡'=>1,'𦾱'=>1,'𧃒'=>1,'䕫'=>1,'虐'=>1,'虜'=>1,'虧'=>1,'虩'=>1,'蚩'=>1,'蚈'=>1,'蜎'=>1,'蛢'=>1,'蝹'=>1,'蜨'=>1,'蝫'=>1,'螆'=>1,'䗗'=>1,'蟡'=>1,'ð¯§'=>1,'䗹'=>1,'衠'=>1,'衣'=>1,'𧙧'=>1,'裗'=>1,'裞'=>1,'䘵'=>1,'裺'=>1,'㒻'=>1,'𧢮'=>1,'𧥦'=>1,'ð¯§'=>1,'䛇'=>1,'ð¯§'=>1,'ð¯§'=>1,'變'=>1,'豕'=>1,'𧲨'=>1,'貫'=>1,'賁'=>1,'贛'=>1,'起'=>1,'𧼯'=>1,'𠠄'=>1,'跋'=>1,'趼'=>1,'跰'=>1,'ð¯§'=>1,'軔'=>1,'輸'=>1,'𨗒'=>1,'𨗭'=>1,'邔'=>1,'郱'=>1,'鄑'=>1,'𨜮'=>1,'鄛'=>1,'鈸'=>1,'鋗'=>1,'鋘'=>1,'鉼'=>1,'鏹'=>1,'鐕'=>1,'𨯺'=>1,'開'=>1,'䦕'=>1,'閷'=>1,'𨵷'=>1,'䧦'=>1,'雃'=>1,'嶲'=>1,'霣'=>1,'𩅅'=>1,'𩈚'=>1,'䩮'=>1,'䩶'=>1,'韠'=>1,'𩐊'=>1,'䪲'=>1,'𩒖'=>1,'頋'=>1,'頋'=>1,'頩'=>1,'ð¯¨'=>1,'飢'=>1,'䬳'=>1,'餩'=>1,'馧'=>1,'駂'=>1,'駾'=>1,'䯎'=>1,'𩬰'=>1,'鬒'=>1,'鱀'=>1,'鳽'=>1,'ð¯¨'=>1,'䳭'=>1,'ð¯¨'=>1,'ð¯¨'=>1,'䳸'=>1,'𪄅'=>1,'𪈎'=>1,'𪊑'=>1,'麻'=>1,'䵖'=>1,'黹'=>1,'黾'=>1,'鼅'=>1,'鼏'=>1,'鼖'=>1,'鼻'=>1,'ð¯¨'=>1,'Ì€'=>0,'Ì'=>0,'Ì‚'=>0,'̃'=>0,'Ì„'=>0,'̆'=>0,'̇'=>0,'̈'=>0,'̉'=>0,'ÌŠ'=>0,'Ì‹'=>0,'ÌŒ'=>0,'Ì'=>0,'Ì‘'=>0,'Ì“'=>0,'Ì”'=>0,'Ì›'=>0,'Ì£'=>0,'̤'=>0,'Ì¥'=>0,'̦'=>0,'̧'=>0,'̨'=>0,'Ì­'=>0,'Ì®'=>0,'Ì°'=>0,'̱'=>0,'̸'=>0,'Í‚'=>0,'Í…'=>0,'Ù“'=>0,'Ù”'=>0,'Ù•'=>0,'़'=>0,'া'=>0,'ৗ'=>0,'ା'=>0,'à­–'=>0,'à­—'=>0,'ா'=>0,'ௗ'=>0,'à±–'=>0,'ೂ'=>0,'ೕ'=>0,'à³–'=>0,'à´¾'=>0,'ൗ'=>0,'à·Š'=>0,'à·'=>0,'à·Ÿ'=>0,'ီ'=>0,'á…¡'=>0,'á…¢'=>0,'á…£'=>0,'á…¤'=>0,'á…¥'=>0,'á…¦'=>0,'á…§'=>0,'á…¨'=>0,'á…©'=>0,'á…ª'=>0,'á…«'=>0,'á…¬'=>0,'á…­'=>0,'á…®'=>0,'á…¯'=>0,'á…°'=>0,'á…±'=>0,'á…²'=>0,'á…³'=>0,'á…´'=>0,'á…µ'=>0,'ᆨ'=>0,'ᆩ'=>0,'ᆪ'=>0,'ᆫ'=>0,'ᆬ'=>0,'ᆭ'=>0,'ᆮ'=>0,'ᆯ'=>0,'ᆰ'=>0,'ᆱ'=>0,'ᆲ'=>0,'ᆳ'=>0,'ᆴ'=>0,'ᆵ'=>0,'ᆶ'=>0,'ᆷ'=>0,'ᆸ'=>0,'ᆹ'=>0,'ᆺ'=>0,'ᆻ'=>0,'ᆼ'=>0,'ᆽ'=>0,'ᆾ'=>0,'ᆿ'=>0,'ᇀ'=>0,'á‡'=>0,'ᇂ'=>0,'ᬵ'=>0,'ã‚™'=>0,'ã‚š'=>0);
diff --git a/phpBB/includes/utf/data/utf_nfkc_qc.php b/phpBB/includes/utf/data/utf_nfkc_qc.php
deleted file mode 100644
index 181a07b351..0000000000
--- a/phpBB/includes/utf/data/utf_nfkc_qc.php
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-$GLOBALS['utf_nfkc_qc']=array(' '=>1,'¨'=>1,'ª'=>1,'¯'=>1,'²'=>1,'³'=>1,'´'=>1,'µ'=>1,'¸'=>1,'¹'=>1,'º'=>1,'¼'=>1,'½'=>1,'¾'=>1,'IJ'=>1,'ij'=>1,'Ä¿'=>1,'Å€'=>1,'ʼn'=>1,'Å¿'=>1,'Ç„'=>1,'Ç…'=>1,'dž'=>1,'LJ'=>1,'Lj'=>1,'lj'=>1,'ÇŠ'=>1,'Ç‹'=>1,'ÇŒ'=>1,'DZ'=>1,'Dz'=>1,'dz'=>1,'Ê°'=>1,'ʱ'=>1,'ʲ'=>1,'ʳ'=>1,'Ê´'=>1,'ʵ'=>1,'ʶ'=>1,'Ê·'=>1,'ʸ'=>1,'˘'=>1,'Ë™'=>1,'Ëš'=>1,'Ë›'=>1,'Ëœ'=>1,'Ë'=>1,'Ë '=>1,'Ë¡'=>1,'Ë¢'=>1,'Ë£'=>1,'ˤ'=>1,'Í€'=>1,'Í'=>1,'̓'=>1,'Í„'=>1,'Í´'=>1,'ͺ'=>1,';'=>1,'΄'=>1,'Î…'=>1,'·'=>1,'Ï'=>1,'Ï‘'=>1,'Ï’'=>1,'Ï“'=>1,'Ï”'=>1,'Ï•'=>1,'Ï–'=>1,'Ï°'=>1,'ϱ'=>1,'ϲ'=>1,'Ï´'=>1,'ϵ'=>1,'Ϲ'=>1,'Ö‡'=>1,'Ùµ'=>1,'Ù¶'=>1,'Ù·'=>1,'Ù¸'=>1,'क़'=>1,'ख़'=>1,'ग़'=>1,'ज़'=>1,'ड़'=>1,'à¥'=>1,'फ़'=>1,'य़'=>1,'ড়'=>1,'à§'=>1,'য়'=>1,'ਲ਼'=>1,'ਸ਼'=>1,'à©™'=>1,'à©š'=>1,'à©›'=>1,'à©ž'=>1,'à­œ'=>1,'à­'=>1,'ำ'=>1,'ຳ'=>1,'ໜ'=>1,'à»'=>1,'༌'=>1,'གྷ'=>1,'à½'=>1,'དྷ'=>1,'བྷ'=>1,'ཛྷ'=>1,'ཀྵ'=>1,'ཱི'=>1,'ཱུ'=>1,'ྲྀ'=>1,'ཷ'=>1,'ླྀ'=>1,'ཹ'=>1,'à¾'=>1,'ྒྷ'=>1,'à¾'=>1,'ྡྷ'=>1,'ྦྷ'=>1,'ྫྷ'=>1,'ྐྵ'=>1,'ჼ'=>1,'á´¬'=>1,'á´­'=>1,'á´®'=>1,'á´°'=>1,'á´±'=>1,'á´²'=>1,'á´³'=>1,'á´´'=>1,'á´µ'=>1,'á´¶'=>1,'á´·'=>1,'á´¸'=>1,'á´¹'=>1,'á´º'=>1,'á´¼'=>1,'á´½'=>1,'á´¾'=>1,'á´¿'=>1,'áµ€'=>1,'áµ'=>1,'ᵂ'=>1,'ᵃ'=>1,'ᵄ'=>1,'áµ…'=>1,'ᵆ'=>1,'ᵇ'=>1,'ᵈ'=>1,'ᵉ'=>1,'ᵊ'=>1,'ᵋ'=>1,'ᵌ'=>1,'áµ'=>1,'áµ'=>1,'áµ'=>1,'ᵑ'=>1,'áµ’'=>1,'ᵓ'=>1,'áµ”'=>1,'ᵕ'=>1,'áµ–'=>1,'áµ—'=>1,'ᵘ'=>1,'áµ™'=>1,'ᵚ'=>1,'áµ›'=>1,'ᵜ'=>1,'áµ'=>1,'ᵞ'=>1,'ᵟ'=>1,'áµ '=>1,'ᵡ'=>1,'áµ¢'=>1,'áµ£'=>1,'ᵤ'=>1,'áµ¥'=>1,'ᵦ'=>1,'ᵧ'=>1,'ᵨ'=>1,'ᵩ'=>1,'ᵪ'=>1,'ᵸ'=>1,'ᶛ'=>1,'ᶜ'=>1,'á¶'=>1,'ᶞ'=>1,'ᶟ'=>1,'ᶠ'=>1,'ᶡ'=>1,'ᶢ'=>1,'ᶣ'=>1,'ᶤ'=>1,'ᶥ'=>1,'ᶦ'=>1,'ᶧ'=>1,'ᶨ'=>1,'ᶩ'=>1,'ᶪ'=>1,'ᶫ'=>1,'ᶬ'=>1,'ᶭ'=>1,'ᶮ'=>1,'ᶯ'=>1,'ᶰ'=>1,'ᶱ'=>1,'ᶲ'=>1,'ᶳ'=>1,'ᶴ'=>1,'ᶵ'=>1,'ᶶ'=>1,'ᶷ'=>1,'ᶸ'=>1,'ᶹ'=>1,'ᶺ'=>1,'ᶻ'=>1,'ᶼ'=>1,'ᶽ'=>1,'ᶾ'=>1,'ᶿ'=>1,'ẚ'=>1,'ẛ'=>1,'á½±'=>1,'á½³'=>1,'á½µ'=>1,'á½·'=>1,'á½¹'=>1,'á½»'=>1,'á½½'=>1,'á¾»'=>1,'á¾½'=>1,'á¾¾'=>1,'᾿'=>1,'á¿€'=>1,'á¿'=>1,'Έ'=>1,'á¿‹'=>1,'á¿'=>1,'á¿Ž'=>1,'á¿'=>1,'á¿“'=>1,'á¿›'=>1,'á¿'=>1,'á¿ž'=>1,'á¿Ÿ'=>1,'á¿£'=>1,'á¿«'=>1,'á¿­'=>1,'á¿®'=>1,'`'=>1,'Ό'=>1,'á¿»'=>1,'´'=>1,'῾'=>1,' '=>1,'â€'=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,' '=>1,'‑'=>1,'‗'=>1,'․'=>1,'‥'=>1,'…'=>1,' '=>1,'″'=>1,'‴'=>1,'‶'=>1,'‷'=>1,'‼'=>1,'‾'=>1,'â‡'=>1,'âˆ'=>1,'â‰'=>1,'â—'=>1,'âŸ'=>1,'â°'=>1,'â±'=>1,'â´'=>1,'âµ'=>1,'â¶'=>1,'â·'=>1,'â¸'=>1,'â¹'=>1,'âº'=>1,'â»'=>1,'â¼'=>1,'â½'=>1,'â¾'=>1,'â¿'=>1,'â‚€'=>1,'â‚'=>1,'â‚‚'=>1,'₃'=>1,'â‚„'=>1,'â‚…'=>1,'₆'=>1,'₇'=>1,'₈'=>1,'₉'=>1,'â‚Š'=>1,'â‚‹'=>1,'â‚Œ'=>1,'â‚'=>1,'â‚Ž'=>1,'â‚'=>1,'â‚‘'=>1,'â‚’'=>1,'â‚“'=>1,'â‚”'=>1,'₨'=>1,'â„€'=>1,'â„'=>1,'â„‚'=>1,'℃'=>1,'â„…'=>1,'℆'=>1,'ℇ'=>1,'℉'=>1,'â„Š'=>1,'â„‹'=>1,'â„Œ'=>1,'â„'=>1,'â„Ž'=>1,'â„'=>1,'â„'=>1,'â„‘'=>1,'â„’'=>1,'â„“'=>1,'â„•'=>1,'â„–'=>1,'â„™'=>1,'â„š'=>1,'â„›'=>1,'â„œ'=>1,'â„'=>1,'â„ '=>1,'â„¡'=>1,'â„¢'=>1,'ℤ'=>1,'Ω'=>1,'ℨ'=>1,'K'=>1,'â„«'=>1,'ℬ'=>1,'â„­'=>1,'ℯ'=>1,'â„°'=>1,'ℱ'=>1,'ℳ'=>1,'â„´'=>1,'ℵ'=>1,'ℶ'=>1,'â„·'=>1,'ℸ'=>1,'ℹ'=>1,'â„»'=>1,'ℼ'=>1,'ℽ'=>1,'ℾ'=>1,'â„¿'=>1,'â…€'=>1,'â……'=>1,'â…†'=>1,'â…‡'=>1,'â…ˆ'=>1,'â…‰'=>1,'â…“'=>1,'â…”'=>1,'â…•'=>1,'â…–'=>1,'â…—'=>1,'â…˜'=>1,'â…™'=>1,'â…š'=>1,'â…›'=>1,'â…œ'=>1,'â…'=>1,'â…ž'=>1,'â…Ÿ'=>1,'â… '=>1,'â…¡'=>1,'â…¢'=>1,'â…£'=>1,'â…¤'=>1,'â…¥'=>1,'â…¦'=>1,'â…§'=>1,'â…¨'=>1,'â…©'=>1,'â…ª'=>1,'â…«'=>1,'â…¬'=>1,'â…­'=>1,'â…®'=>1,'â…¯'=>1,'â…°'=>1,'â…±'=>1,'â…²'=>1,'â…³'=>1,'â…´'=>1,'â…µ'=>1,'â…¶'=>1,'â…·'=>1,'â…¸'=>1,'â…¹'=>1,'â…º'=>1,'â…»'=>1,'â…¼'=>1,'â…½'=>1,'â…¾'=>1,'â…¿'=>1,'∬'=>1,'∭'=>1,'∯'=>1,'∰'=>1,'〈'=>1,'〉'=>1,'â‘ '=>1,'â‘¡'=>1,'â‘¢'=>1,'â‘£'=>1,'⑤'=>1,'â‘¥'=>1,'⑦'=>1,'⑧'=>1,'⑨'=>1,'â‘©'=>1,'⑪'=>1,'â‘«'=>1,'⑬'=>1,'â‘­'=>1,'â‘®'=>1,'⑯'=>1,'â‘°'=>1,'⑱'=>1,'⑲'=>1,'⑳'=>1,'â‘´'=>1,'⑵'=>1,'⑶'=>1,'â‘·'=>1,'⑸'=>1,'⑹'=>1,'⑺'=>1,'â‘»'=>1,'⑼'=>1,'⑽'=>1,'⑾'=>1,'â‘¿'=>1,'â’€'=>1,'â’'=>1,'â’‚'=>1,'â’ƒ'=>1,'â’„'=>1,'â’…'=>1,'â’†'=>1,'â’‡'=>1,'â’ˆ'=>1,'â’‰'=>1,'â’Š'=>1,'â’‹'=>1,'â’Œ'=>1,'â’'=>1,'â’Ž'=>1,'â’'=>1,'â’'=>1,'â’‘'=>1,'â’’'=>1,'â’“'=>1,'â’”'=>1,'â’•'=>1,'â’–'=>1,'â’—'=>1,'â’˜'=>1,'â’™'=>1,'â’š'=>1,'â’›'=>1,'â’œ'=>1,'â’'=>1,'â’ž'=>1,'â’Ÿ'=>1,'â’ '=>1,'â’¡'=>1,'â’¢'=>1,'â’£'=>1,'â’¤'=>1,'â’¥'=>1,'â’¦'=>1,'â’§'=>1,'â’¨'=>1,'â’©'=>1,'â’ª'=>1,'â’«'=>1,'â’¬'=>1,'â’­'=>1,'â’®'=>1,'â’¯'=>1,'â’°'=>1,'â’±'=>1,'â’²'=>1,'â’³'=>1,'â’´'=>1,'â’µ'=>1,'â’¶'=>1,'â’·'=>1,'â’¸'=>1,'â’¹'=>1,'â’º'=>1,'â’»'=>1,'â’¼'=>1,'â’½'=>1,'â’¾'=>1,'â’¿'=>1,'â“€'=>1,'â“'=>1,'â“‚'=>1,'Ⓝ'=>1,'â“„'=>1,'â“…'=>1,'Ⓠ'=>1,'Ⓡ'=>1,'Ⓢ'=>1,'Ⓣ'=>1,'â“Š'=>1,'â“‹'=>1,'â“Œ'=>1,'â“'=>1,'â“Ž'=>1,'â“'=>1,'â“'=>1,'â“‘'=>1,'â“’'=>1,'â““'=>1,'â“”'=>1,'â“•'=>1,'â“–'=>1,'â“—'=>1,'ⓘ'=>1,'â“™'=>1,'â“š'=>1,'â“›'=>1,'â“œ'=>1,'â“'=>1,'â“ž'=>1,'â“Ÿ'=>1,'â“ '=>1,'â“¡'=>1,'â“¢'=>1,'â“£'=>1,'ⓤ'=>1,'â“¥'=>1,'ⓦ'=>1,'ⓧ'=>1,'ⓨ'=>1,'â“©'=>1,'⓪'=>1,'⨌'=>1,'â©´'=>1,'⩵'=>1,'⩶'=>1,'â«œ'=>1,'ⵯ'=>1,'⺟'=>1,'⻳'=>1,'â¼€'=>1,'â¼'=>1,'⼂'=>1,'⼃'=>1,'⼄'=>1,'â¼…'=>1,'⼆'=>1,'⼇'=>1,'⼈'=>1,'⼉'=>1,'⼊'=>1,'⼋'=>1,'⼌'=>1,'â¼'=>1,'⼎'=>1,'â¼'=>1,'â¼'=>1,'⼑'=>1,'â¼’'=>1,'⼓'=>1,'â¼”'=>1,'⼕'=>1,'â¼–'=>1,'â¼—'=>1,'⼘'=>1,'â¼™'=>1,'⼚'=>1,'â¼›'=>1,'⼜'=>1,'â¼'=>1,'⼞'=>1,'⼟'=>1,'â¼ '=>1,'⼡'=>1,'â¼¢'=>1,'â¼£'=>1,'⼤'=>1,'â¼¥'=>1,'⼦'=>1,'⼧'=>1,'⼨'=>1,'⼩'=>1,'⼪'=>1,'⼫'=>1,'⼬'=>1,'â¼­'=>1,'â¼®'=>1,'⼯'=>1,'â¼°'=>1,'â¼±'=>1,'â¼²'=>1,'â¼³'=>1,'â¼´'=>1,'â¼µ'=>1,'⼶'=>1,'â¼·'=>1,'⼸'=>1,'â¼¹'=>1,'⼺'=>1,'â¼»'=>1,'â¼¼'=>1,'â¼½'=>1,'â¼¾'=>1,'⼿'=>1,'â½€'=>1,'â½'=>1,'⽂'=>1,'⽃'=>1,'⽄'=>1,'â½…'=>1,'⽆'=>1,'⽇'=>1,'⽈'=>1,'⽉'=>1,'⽊'=>1,'⽋'=>1,'⽌'=>1,'â½'=>1,'⽎'=>1,'â½'=>1,'â½'=>1,'⽑'=>1,'â½’'=>1,'⽓'=>1,'â½”'=>1,'⽕'=>1,'â½–'=>1,'â½—'=>1,'⽘'=>1,'â½™'=>1,'⽚'=>1,'â½›'=>1,'⽜'=>1,'â½'=>1,'⽞'=>1,'⽟'=>1,'â½ '=>1,'⽡'=>1,'â½¢'=>1,'â½£'=>1,'⽤'=>1,'â½¥'=>1,'⽦'=>1,'⽧'=>1,'⽨'=>1,'⽩'=>1,'⽪'=>1,'⽫'=>1,'⽬'=>1,'â½­'=>1,'â½®'=>1,'⽯'=>1,'â½°'=>1,'â½±'=>1,'â½²'=>1,'â½³'=>1,'â½´'=>1,'â½µ'=>1,'⽶'=>1,'â½·'=>1,'⽸'=>1,'â½¹'=>1,'⽺'=>1,'â½»'=>1,'â½¼'=>1,'â½½'=>1,'â½¾'=>1,'⽿'=>1,'â¾€'=>1,'â¾'=>1,'⾂'=>1,'⾃'=>1,'⾄'=>1,'â¾…'=>1,'⾆'=>1,'⾇'=>1,'⾈'=>1,'⾉'=>1,'⾊'=>1,'⾋'=>1,'⾌'=>1,'â¾'=>1,'⾎'=>1,'â¾'=>1,'â¾'=>1,'⾑'=>1,'â¾’'=>1,'⾓'=>1,'â¾”'=>1,'⾕'=>1,'â¾–'=>1,'â¾—'=>1,'⾘'=>1,'â¾™'=>1,'⾚'=>1,'â¾›'=>1,'⾜'=>1,'â¾'=>1,'⾞'=>1,'⾟'=>1,'â¾ '=>1,'⾡'=>1,'â¾¢'=>1,'â¾£'=>1,'⾤'=>1,'â¾¥'=>1,'⾦'=>1,'⾧'=>1,'⾨'=>1,'⾩'=>1,'⾪'=>1,'⾫'=>1,'⾬'=>1,'â¾­'=>1,'â¾®'=>1,'⾯'=>1,'â¾°'=>1,'â¾±'=>1,'â¾²'=>1,'â¾³'=>1,'â¾´'=>1,'â¾µ'=>1,'⾶'=>1,'â¾·'=>1,'⾸'=>1,'â¾¹'=>1,'⾺'=>1,'â¾»'=>1,'â¾¼'=>1,'â¾½'=>1,'â¾¾'=>1,'⾿'=>1,'â¿€'=>1,'â¿'=>1,'â¿‚'=>1,'⿃'=>1,'â¿„'=>1,'â¿…'=>1,'⿆'=>1,'⿇'=>1,'⿈'=>1,'⿉'=>1,'â¿Š'=>1,'â¿‹'=>1,'â¿Œ'=>1,'â¿'=>1,'â¿Ž'=>1,'â¿'=>1,'â¿'=>1,'â¿‘'=>1,'â¿’'=>1,'â¿“'=>1,'â¿”'=>1,'â¿•'=>1,' '=>1,'〶'=>1,'〸'=>1,'〹'=>1,'〺'=>1,'ã‚›'=>1,'ã‚œ'=>1,'ã‚Ÿ'=>1,'ヿ'=>1,'ㄱ'=>1,'ㄲ'=>1,'ㄳ'=>1,'ã„´'=>1,'ㄵ'=>1,'ㄶ'=>1,'ã„·'=>1,'ㄸ'=>1,'ㄹ'=>1,'ㄺ'=>1,'ã„»'=>1,'ㄼ'=>1,'ㄽ'=>1,'ㄾ'=>1,'ã„¿'=>1,'ã…€'=>1,'ã…'=>1,'ã…‚'=>1,'ã…ƒ'=>1,'ã…„'=>1,'ã……'=>1,'ã…†'=>1,'ã…‡'=>1,'ã…ˆ'=>1,'ã…‰'=>1,'ã…Š'=>1,'ã…‹'=>1,'ã…Œ'=>1,'ã…'=>1,'ã…Ž'=>1,'ã…'=>1,'ã…'=>1,'ã…‘'=>1,'ã…’'=>1,'ã…“'=>1,'ã…”'=>1,'ã…•'=>1,'ã…–'=>1,'ã…—'=>1,'ã…˜'=>1,'ã…™'=>1,'ã…š'=>1,'ã…›'=>1,'ã…œ'=>1,'ã…'=>1,'ã…ž'=>1,'ã…Ÿ'=>1,'ã… '=>1,'ã…¡'=>1,'ã…¢'=>1,'ã…£'=>1,'ã…¤'=>1,'ã…¥'=>1,'ã…¦'=>1,'ã…§'=>1,'ã…¨'=>1,'ã…©'=>1,'ã…ª'=>1,'ã…«'=>1,'ã…¬'=>1,'ã…­'=>1,'ã…®'=>1,'ã…¯'=>1,'ã…°'=>1,'ã…±'=>1,'ã…²'=>1,'ã…³'=>1,'ã…´'=>1,'ã…µ'=>1,'ã…¶'=>1,'ã…·'=>1,'ã…¸'=>1,'ã…¹'=>1,'ã…º'=>1,'ã…»'=>1,'ã…¼'=>1,'ã…½'=>1,'ã…¾'=>1,'ã…¿'=>1,'ㆀ'=>1,'ã†'=>1,'ㆂ'=>1,'ㆃ'=>1,'ㆄ'=>1,'ㆅ'=>1,'ㆆ'=>1,'ㆇ'=>1,'ㆈ'=>1,'ㆉ'=>1,'ㆊ'=>1,'ㆋ'=>1,'ㆌ'=>1,'ã†'=>1,'ㆎ'=>1,'㆒'=>1,'㆓'=>1,'㆔'=>1,'㆕'=>1,'㆖'=>1,'㆗'=>1,'㆘'=>1,'㆙'=>1,'㆚'=>1,'㆛'=>1,'㆜'=>1,'ã†'=>1,'㆞'=>1,'㆟'=>1,'㈀'=>1,'ãˆ'=>1,'㈂'=>1,'㈃'=>1,'㈄'=>1,'㈅'=>1,'㈆'=>1,'㈇'=>1,'㈈'=>1,'㈉'=>1,'㈊'=>1,'㈋'=>1,'㈌'=>1,'ãˆ'=>1,'㈎'=>1,'ãˆ'=>1,'ãˆ'=>1,'㈑'=>1,'㈒'=>1,'㈓'=>1,'㈔'=>1,'㈕'=>1,'㈖'=>1,'㈗'=>1,'㈘'=>1,'㈙'=>1,'㈚'=>1,'㈛'=>1,'㈜'=>1,'ãˆ'=>1,'㈞'=>1,'㈠'=>1,'㈡'=>1,'㈢'=>1,'㈣'=>1,'㈤'=>1,'㈥'=>1,'㈦'=>1,'㈧'=>1,'㈨'=>1,'㈩'=>1,'㈪'=>1,'㈫'=>1,'㈬'=>1,'㈭'=>1,'㈮'=>1,'㈯'=>1,'㈰'=>1,'㈱'=>1,'㈲'=>1,'㈳'=>1,'㈴'=>1,'㈵'=>1,'㈶'=>1,'㈷'=>1,'㈸'=>1,'㈹'=>1,'㈺'=>1,'㈻'=>1,'㈼'=>1,'㈽'=>1,'㈾'=>1,'㈿'=>1,'㉀'=>1,'ã‰'=>1,'㉂'=>1,'㉃'=>1,'ã‰'=>1,'㉑'=>1,'㉒'=>1,'㉓'=>1,'㉔'=>1,'㉕'=>1,'㉖'=>1,'㉗'=>1,'㉘'=>1,'㉙'=>1,'㉚'=>1,'㉛'=>1,'㉜'=>1,'ã‰'=>1,'㉞'=>1,'㉟'=>1,'㉠'=>1,'㉡'=>1,'㉢'=>1,'㉣'=>1,'㉤'=>1,'㉥'=>1,'㉦'=>1,'㉧'=>1,'㉨'=>1,'㉩'=>1,'㉪'=>1,'㉫'=>1,'㉬'=>1,'㉭'=>1,'㉮'=>1,'㉯'=>1,'㉰'=>1,'㉱'=>1,'㉲'=>1,'㉳'=>1,'㉴'=>1,'㉵'=>1,'㉶'=>1,'㉷'=>1,'㉸'=>1,'㉹'=>1,'㉺'=>1,'㉻'=>1,'㉼'=>1,'㉽'=>1,'㉾'=>1,'㊀'=>1,'ãŠ'=>1,'㊂'=>1,'㊃'=>1,'㊄'=>1,'㊅'=>1,'㊆'=>1,'㊇'=>1,'㊈'=>1,'㊉'=>1,'㊊'=>1,'㊋'=>1,'㊌'=>1,'ãŠ'=>1,'㊎'=>1,'ãŠ'=>1,'ãŠ'=>1,'㊑'=>1,'㊒'=>1,'㊓'=>1,'㊔'=>1,'㊕'=>1,'㊖'=>1,'㊗'=>1,'㊘'=>1,'㊙'=>1,'㊚'=>1,'㊛'=>1,'㊜'=>1,'ãŠ'=>1,'㊞'=>1,'㊟'=>1,'㊠'=>1,'㊡'=>1,'㊢'=>1,'㊣'=>1,'㊤'=>1,'㊥'=>1,'㊦'=>1,'㊧'=>1,'㊨'=>1,'㊩'=>1,'㊪'=>1,'㊫'=>1,'㊬'=>1,'㊭'=>1,'㊮'=>1,'㊯'=>1,'㊰'=>1,'㊱'=>1,'㊲'=>1,'㊳'=>1,'㊴'=>1,'㊵'=>1,'㊶'=>1,'㊷'=>1,'㊸'=>1,'㊹'=>1,'㊺'=>1,'㊻'=>1,'㊼'=>1,'㊽'=>1,'㊾'=>1,'㊿'=>1,'ã‹€'=>1,'ã‹'=>1,'ã‹‚'=>1,'㋃'=>1,'ã‹„'=>1,'ã‹…'=>1,'㋆'=>1,'㋇'=>1,'㋈'=>1,'㋉'=>1,'ã‹Š'=>1,'ã‹‹'=>1,'ã‹Œ'=>1,'ã‹'=>1,'ã‹Ž'=>1,'ã‹'=>1,'ã‹'=>1,'ã‹‘'=>1,'ã‹’'=>1,'ã‹“'=>1,'ã‹”'=>1,'ã‹•'=>1,'ã‹–'=>1,'ã‹—'=>1,'㋘'=>1,'ã‹™'=>1,'ã‹š'=>1,'ã‹›'=>1,'ã‹œ'=>1,'ã‹'=>1,'ã‹ž'=>1,'ã‹Ÿ'=>1,'ã‹ '=>1,'ã‹¡'=>1,'ã‹¢'=>1,'ã‹£'=>1,'㋤'=>1,'ã‹¥'=>1,'㋦'=>1,'㋧'=>1,'㋨'=>1,'ã‹©'=>1,'㋪'=>1,'ã‹«'=>1,'㋬'=>1,'ã‹­'=>1,'ã‹®'=>1,'㋯'=>1,'ã‹°'=>1,'㋱'=>1,'㋲'=>1,'㋳'=>1,'ã‹´'=>1,'㋵'=>1,'㋶'=>1,'ã‹·'=>1,'㋸'=>1,'㋹'=>1,'㋺'=>1,'ã‹»'=>1,'㋼'=>1,'㋽'=>1,'㋾'=>1,'㌀'=>1,'ãŒ'=>1,'㌂'=>1,'㌃'=>1,'㌄'=>1,'㌅'=>1,'㌆'=>1,'㌇'=>1,'㌈'=>1,'㌉'=>1,'㌊'=>1,'㌋'=>1,'㌌'=>1,'ãŒ'=>1,'㌎'=>1,'ãŒ'=>1,'ãŒ'=>1,'㌑'=>1,'㌒'=>1,'㌓'=>1,'㌔'=>1,'㌕'=>1,'㌖'=>1,'㌗'=>1,'㌘'=>1,'㌙'=>1,'㌚'=>1,'㌛'=>1,'㌜'=>1,'ãŒ'=>1,'㌞'=>1,'㌟'=>1,'㌠'=>1,'㌡'=>1,'㌢'=>1,'㌣'=>1,'㌤'=>1,'㌥'=>1,'㌦'=>1,'㌧'=>1,'㌨'=>1,'㌩'=>1,'㌪'=>1,'㌫'=>1,'㌬'=>1,'㌭'=>1,'㌮'=>1,'㌯'=>1,'㌰'=>1,'㌱'=>1,'㌲'=>1,'㌳'=>1,'㌴'=>1,'㌵'=>1,'㌶'=>1,'㌷'=>1,'㌸'=>1,'㌹'=>1,'㌺'=>1,'㌻'=>1,'㌼'=>1,'㌽'=>1,'㌾'=>1,'㌿'=>1,'ã€'=>1,'ã'=>1,'ã‚'=>1,'ãƒ'=>1,'ã„'=>1,'ã…'=>1,'ã†'=>1,'ã‡'=>1,'ãˆ'=>1,'ã‰'=>1,'ãŠ'=>1,'ã‹'=>1,'ãŒ'=>1,'ã'=>1,'ãŽ'=>1,'ã'=>1,'ã'=>1,'ã‘'=>1,'ã’'=>1,'ã“'=>1,'ã”'=>1,'ã•'=>1,'ã–'=>1,'ã—'=>1,'ã˜'=>1,'ã™'=>1,'ãš'=>1,'ã›'=>1,'ãœ'=>1,'ã'=>1,'ãž'=>1,'ãŸ'=>1,'ã '=>1,'ã¡'=>1,'ã¢'=>1,'ã£'=>1,'ã¤'=>1,'ã¥'=>1,'ã¦'=>1,'ã§'=>1,'ã¨'=>1,'ã©'=>1,'ãª'=>1,'ã«'=>1,'ã¬'=>1,'ã­'=>1,'ã®'=>1,'ã¯'=>1,'ã°'=>1,'ã±'=>1,'ã²'=>1,'ã³'=>1,'ã´'=>1,'ãµ'=>1,'ã¶'=>1,'ã·'=>1,'ã¸'=>1,'ã¹'=>1,'ãº'=>1,'ã»'=>1,'ã¼'=>1,'ã½'=>1,'ã¾'=>1,'ã¿'=>1,'㎀'=>1,'ãŽ'=>1,'㎂'=>1,'㎃'=>1,'㎄'=>1,'㎅'=>1,'㎆'=>1,'㎇'=>1,'㎈'=>1,'㎉'=>1,'㎊'=>1,'㎋'=>1,'㎌'=>1,'ãŽ'=>1,'㎎'=>1,'ãŽ'=>1,'ãŽ'=>1,'㎑'=>1,'㎒'=>1,'㎓'=>1,'㎔'=>1,'㎕'=>1,'㎖'=>1,'㎗'=>1,'㎘'=>1,'㎙'=>1,'㎚'=>1,'㎛'=>1,'㎜'=>1,'ãŽ'=>1,'㎞'=>1,'㎟'=>1,'㎠'=>1,'㎡'=>1,'㎢'=>1,'㎣'=>1,'㎤'=>1,'㎥'=>1,'㎦'=>1,'㎧'=>1,'㎨'=>1,'㎩'=>1,'㎪'=>1,'㎫'=>1,'㎬'=>1,'㎭'=>1,'㎮'=>1,'㎯'=>1,'㎰'=>1,'㎱'=>1,'㎲'=>1,'㎳'=>1,'㎴'=>1,'㎵'=>1,'㎶'=>1,'㎷'=>1,'㎸'=>1,'㎹'=>1,'㎺'=>1,'㎻'=>1,'㎼'=>1,'㎽'=>1,'㎾'=>1,'㎿'=>1,'ã€'=>1,'ã'=>1,'ã‚'=>1,'ãƒ'=>1,'ã„'=>1,'ã…'=>1,'ã†'=>1,'ã‡'=>1,'ãˆ'=>1,'ã‰'=>1,'ãŠ'=>1,'ã‹'=>1,'ãŒ'=>1,'ã'=>1,'ãŽ'=>1,'ã'=>1,'ã'=>1,'ã‘'=>1,'ã’'=>1,'ã“'=>1,'ã”'=>1,'ã•'=>1,'ã–'=>1,'ã—'=>1,'ã˜'=>1,'ã™'=>1,'ãš'=>1,'ã›'=>1,'ãœ'=>1,'ã'=>1,'ãž'=>1,'ãŸ'=>1,'ã '=>1,'ã¡'=>1,'ã¢'=>1,'ã£'=>1,'ã¤'=>1,'ã¥'=>1,'ã¦'=>1,'ã§'=>1,'ã¨'=>1,'ã©'=>1,'ãª'=>1,'ã«'=>1,'ã¬'=>1,'ã­'=>1,'ã®'=>1,'ã¯'=>1,'ã°'=>1,'ã±'=>1,'ã²'=>1,'ã³'=>1,'ã´'=>1,'ãµ'=>1,'ã¶'=>1,'ã·'=>1,'ã¸'=>1,'ã¹'=>1,'ãº'=>1,'ã»'=>1,'ã¼'=>1,'ã½'=>1,'ã¾'=>1,'ã¿'=>1,'豈'=>1,'ï¤'=>1,'車'=>1,'賈'=>1,'滑'=>1,'串'=>1,'句'=>1,'龜'=>1,'龜'=>1,'契'=>1,'金'=>1,'喇'=>1,'奈'=>1,'ï¤'=>1,'癩'=>1,'ï¤'=>1,'ï¤'=>1,'螺'=>1,'裸'=>1,'邏'=>1,'樂'=>1,'洛'=>1,'烙'=>1,'珞'=>1,'落'=>1,'酪'=>1,'駱'=>1,'亂'=>1,'卵'=>1,'ï¤'=>1,'爛'=>1,'蘭'=>1,'鸞'=>1,'嵐'=>1,'濫'=>1,'藍'=>1,'襤'=>1,'拉'=>1,'臘'=>1,'蠟'=>1,'廊'=>1,'朗'=>1,'浪'=>1,'狼'=>1,'郎'=>1,'來'=>1,'冷'=>1,'勞'=>1,'擄'=>1,'櫓'=>1,'爐'=>1,'盧'=>1,'老'=>1,'蘆'=>1,'虜'=>1,'路'=>1,'露'=>1,'魯'=>1,'鷺'=>1,'碌'=>1,'祿'=>1,'綠'=>1,'菉'=>1,'錄'=>1,'鹿'=>1,'ï¥'=>1,'壟'=>1,'弄'=>1,'籠'=>1,'聾'=>1,'牢'=>1,'磊'=>1,'賂'=>1,'雷'=>1,'壘'=>1,'屢'=>1,'樓'=>1,'ï¥'=>1,'漏'=>1,'ï¥'=>1,'ï¥'=>1,'陋'=>1,'勒'=>1,'肋'=>1,'凜'=>1,'凌'=>1,'稜'=>1,'綾'=>1,'菱'=>1,'陵'=>1,'讀'=>1,'拏'=>1,'樂'=>1,'ï¥'=>1,'丹'=>1,'寧'=>1,'怒'=>1,'率'=>1,'異'=>1,'北'=>1,'磻'=>1,'便'=>1,'復'=>1,'不'=>1,'泌'=>1,'數'=>1,'索'=>1,'參'=>1,'塞'=>1,'省'=>1,'葉'=>1,'說'=>1,'殺'=>1,'辰'=>1,'沈'=>1,'拾'=>1,'若'=>1,'掠'=>1,'略'=>1,'亮'=>1,'兩'=>1,'凉'=>1,'梁'=>1,'糧'=>1,'良'=>1,'諒'=>1,'量'=>1,'勵'=>1,'呂'=>1,'ï¦'=>1,'廬'=>1,'旅'=>1,'濾'=>1,'礪'=>1,'閭'=>1,'驪'=>1,'麗'=>1,'黎'=>1,'力'=>1,'曆'=>1,'歷'=>1,'ï¦'=>1,'年'=>1,'ï¦'=>1,'ï¦'=>1,'撚'=>1,'漣'=>1,'煉'=>1,'璉'=>1,'秊'=>1,'練'=>1,'聯'=>1,'輦'=>1,'蓮'=>1,'連'=>1,'鍊'=>1,'列'=>1,'ï¦'=>1,'咽'=>1,'烈'=>1,'裂'=>1,'說'=>1,'廉'=>1,'念'=>1,'捻'=>1,'殮'=>1,'簾'=>1,'獵'=>1,'令'=>1,'囹'=>1,'寧'=>1,'嶺'=>1,'怜'=>1,'玲'=>1,'瑩'=>1,'羚'=>1,'聆'=>1,'鈴'=>1,'零'=>1,'靈'=>1,'領'=>1,'例'=>1,'禮'=>1,'醴'=>1,'隸'=>1,'惡'=>1,'了'=>1,'僚'=>1,'寮'=>1,'尿'=>1,'料'=>1,'樂'=>1,'燎'=>1,'ï§'=>1,'蓼'=>1,'遼'=>1,'龍'=>1,'暈'=>1,'阮'=>1,'劉'=>1,'杻'=>1,'柳'=>1,'流'=>1,'溜'=>1,'琉'=>1,'ï§'=>1,'硫'=>1,'ï§'=>1,'ï§'=>1,'六'=>1,'戮'=>1,'陸'=>1,'倫'=>1,'崙'=>1,'淪'=>1,'輪'=>1,'律'=>1,'慄'=>1,'栗'=>1,'率'=>1,'隆'=>1,'ï§'=>1,'吏'=>1,'履'=>1,'易'=>1,'李'=>1,'梨'=>1,'泥'=>1,'理'=>1,'痢'=>1,'罹'=>1,'裏'=>1,'裡'=>1,'里'=>1,'離'=>1,'匿'=>1,'溺'=>1,'吝'=>1,'燐'=>1,'璘'=>1,'藺'=>1,'隣'=>1,'鱗'=>1,'麟'=>1,'林'=>1,'淋'=>1,'臨'=>1,'立'=>1,'笠'=>1,'粒'=>1,'狀'=>1,'炙'=>1,'識'=>1,'什'=>1,'茶'=>1,'刺'=>1,'切'=>1,'ï¨'=>1,'拓'=>1,'糖'=>1,'宅'=>1,'洞'=>1,'暴'=>1,'輻'=>1,'行'=>1,'降'=>1,'見'=>1,'廓'=>1,'兀'=>1,'ï¨'=>1,'ï¨'=>1,'晴'=>1,'凞'=>1,'猪'=>1,'益'=>1,'礼'=>1,'神'=>1,'祥'=>1,'福'=>1,'靖'=>1,'ï¨'=>1,'羽'=>1,'蘒'=>1,'諸'=>1,'逸'=>1,'都'=>1,'飯'=>1,'飼'=>1,'館'=>1,'鶴'=>1,'侮'=>1,'僧'=>1,'免'=>1,'勉'=>1,'勤'=>1,'卑'=>1,'喝'=>1,'嘆'=>1,'器'=>1,'塀'=>1,'墨'=>1,'層'=>1,'屮'=>1,'悔'=>1,'慨'=>1,'憎'=>1,'ï©€'=>1,'ï©'=>1,'ï©‚'=>1,'暑'=>1,'ï©„'=>1,'ï©…'=>1,'渚'=>1,'漢'=>1,'煮'=>1,'爫'=>1,'ï©Š'=>1,'ï©‹'=>1,'ï©Œ'=>1,'ï©'=>1,'ï©Ž'=>1,'ï©'=>1,'ï©'=>1,'ï©‘'=>1,'ï©’'=>1,'ï©“'=>1,'ï©”'=>1,'ï©•'=>1,'ï©–'=>1,'ï©—'=>1,'縉'=>1,'ï©™'=>1,'ï©š'=>1,'ï©›'=>1,'ï©œ'=>1,'ï©'=>1,'ï©ž'=>1,'ï©Ÿ'=>1,'ï© '=>1,'ï©¡'=>1,'ï©¢'=>1,'ï©£'=>1,'賓'=>1,'ï©¥'=>1,'辶'=>1,'逸'=>1,'難'=>1,'ï©©'=>1,'頻'=>1,'ï©°'=>1,'况'=>1,'全'=>1,'侀'=>1,'ï©´'=>1,'冀'=>1,'勇'=>1,'ï©·'=>1,'喝'=>1,'啕'=>1,'喙'=>1,'ï©»'=>1,'塚'=>1,'墳'=>1,'奄'=>1,'ï©¿'=>1,'婢'=>1,'ïª'=>1,'廒'=>1,'廙'=>1,'彩'=>1,'徭'=>1,'惘'=>1,'慎'=>1,'愈'=>1,'憎'=>1,'慠'=>1,'懲'=>1,'戴'=>1,'ïª'=>1,'搜'=>1,'ïª'=>1,'ïª'=>1,'晴'=>1,'朗'=>1,'望'=>1,'杖'=>1,'歹'=>1,'殺'=>1,'流'=>1,'滛'=>1,'滋'=>1,'漢'=>1,'瀞'=>1,'煮'=>1,'ïª'=>1,'爵'=>1,'犯'=>1,'猪'=>1,'瑱'=>1,'甆'=>1,'画'=>1,'瘝'=>1,'瘟'=>1,'益'=>1,'盛'=>1,'直'=>1,'睊'=>1,'着'=>1,'磌'=>1,'窱'=>1,'節'=>1,'类'=>1,'絛'=>1,'練'=>1,'缾'=>1,'者'=>1,'荒'=>1,'華'=>1,'蝹'=>1,'襁'=>1,'覆'=>1,'視'=>1,'調'=>1,'諸'=>1,'請'=>1,'謁'=>1,'諾'=>1,'諭'=>1,'謹'=>1,'ï«€'=>1,'ï«'=>1,'ï«‚'=>1,'遲'=>1,'ï«„'=>1,'ï«…'=>1,'陼'=>1,'難'=>1,'靖'=>1,'韛'=>1,'ï«Š'=>1,'ï«‹'=>1,'ï«Œ'=>1,'ï«'=>1,'ï«Ž'=>1,'ï«'=>1,'ï«'=>1,'ï«‘'=>1,'ï«’'=>1,'ï«“'=>1,'ï«”'=>1,'ï«•'=>1,'ï«–'=>1,'ï«—'=>1,'齃'=>1,'ï«™'=>1,'ff'=>1,'ï¬'=>1,'fl'=>1,'ffi'=>1,'ffl'=>1,'ſt'=>1,'st'=>1,'ﬓ'=>1,'ﬔ'=>1,'ﬕ'=>1,'ﬖ'=>1,'ﬗ'=>1,'ï¬'=>1,'ײַ'=>1,'ﬠ'=>1,'ﬡ'=>1,'ﬢ'=>1,'ﬣ'=>1,'ﬤ'=>1,'ﬥ'=>1,'ﬦ'=>1,'ﬧ'=>1,'ﬨ'=>1,'﬩'=>1,'שׁ'=>1,'שׂ'=>1,'שּׁ'=>1,'שּׂ'=>1,'אַ'=>1,'אָ'=>1,'אּ'=>1,'בּ'=>1,'גּ'=>1,'דּ'=>1,'הּ'=>1,'וּ'=>1,'זּ'=>1,'טּ'=>1,'יּ'=>1,'ךּ'=>1,'כּ'=>1,'לּ'=>1,'מּ'=>1,'ï­€'=>1,'ï­'=>1,'ï­ƒ'=>1,'ï­„'=>1,'ï­†'=>1,'ï­‡'=>1,'ï­ˆ'=>1,'ï­‰'=>1,'ï­Š'=>1,'ï­‹'=>1,'ï­Œ'=>1,'ï­'=>1,'ï­Ž'=>1,'ï­'=>1,'ï­'=>1,'ï­‘'=>1,'ï­’'=>1,'ï­“'=>1,'ï­”'=>1,'ï­•'=>1,'ï­–'=>1,'ï­—'=>1,'ï­˜'=>1,'ï­™'=>1,'ï­š'=>1,'ï­›'=>1,'ï­œ'=>1,'ï­'=>1,'ï­ž'=>1,'ï­Ÿ'=>1,'ï­ '=>1,'ï­¡'=>1,'ï­¢'=>1,'ï­£'=>1,'ï­¤'=>1,'ï­¥'=>1,'ï­¦'=>1,'ï­§'=>1,'ï­¨'=>1,'ï­©'=>1,'ï­ª'=>1,'ï­«'=>1,'ï­¬'=>1,'ï­­'=>1,'ï­®'=>1,'ï­¯'=>1,'ï­°'=>1,'ï­±'=>1,'ï­²'=>1,'ï­³'=>1,'ï­´'=>1,'ï­µ'=>1,'ï­¶'=>1,'ï­·'=>1,'ï­¸'=>1,'ï­¹'=>1,'ï­º'=>1,'ï­»'=>1,'ï­¼'=>1,'ï­½'=>1,'ï­¾'=>1,'ï­¿'=>1,'ﮀ'=>1,'ï®'=>1,'ﮂ'=>1,'ﮃ'=>1,'ﮄ'=>1,'ï®…'=>1,'ﮆ'=>1,'ﮇ'=>1,'ﮈ'=>1,'ﮉ'=>1,'ﮊ'=>1,'ﮋ'=>1,'ﮌ'=>1,'ï®'=>1,'ﮎ'=>1,'ï®'=>1,'ï®'=>1,'ﮑ'=>1,'ï®’'=>1,'ﮓ'=>1,'ï®”'=>1,'ﮕ'=>1,'ï®–'=>1,'ï®—'=>1,'ﮘ'=>1,'ï®™'=>1,'ﮚ'=>1,'ï®›'=>1,'ﮜ'=>1,'ï®'=>1,'ﮞ'=>1,'ﮟ'=>1,'ï® '=>1,'ﮡ'=>1,'ﮢ'=>1,'ﮣ'=>1,'ﮤ'=>1,'ﮥ'=>1,'ﮦ'=>1,'ﮧ'=>1,'ﮨ'=>1,'ﮩ'=>1,'ﮪ'=>1,'ﮫ'=>1,'ﮬ'=>1,'ï®­'=>1,'ï®®'=>1,'ﮯ'=>1,'ï®°'=>1,'ï®±'=>1,'ﯓ'=>1,'ﯔ'=>1,'ﯕ'=>1,'ﯖ'=>1,'ﯗ'=>1,'ﯘ'=>1,'ﯙ'=>1,'ﯚ'=>1,'ﯛ'=>1,'ﯜ'=>1,'ï¯'=>1,'ﯞ'=>1,'ﯟ'=>1,'ﯠ'=>1,'ﯡ'=>1,'ﯢ'=>1,'ﯣ'=>1,'ﯤ'=>1,'ﯥ'=>1,'ﯦ'=>1,'ﯧ'=>1,'ﯨ'=>1,'ﯩ'=>1,'ﯪ'=>1,'ﯫ'=>1,'ﯬ'=>1,'ﯭ'=>1,'ﯮ'=>1,'ﯯ'=>1,'ﯰ'=>1,'ﯱ'=>1,'ﯲ'=>1,'ﯳ'=>1,'ﯴ'=>1,'ﯵ'=>1,'ﯶ'=>1,'ﯷ'=>1,'ﯸ'=>1,'ﯹ'=>1,'ﯺ'=>1,'ﯻ'=>1,'ﯼ'=>1,'ﯽ'=>1,'ﯾ'=>1,'ﯿ'=>1,'ï°€'=>1,'ï°'=>1,'ï°‚'=>1,'ï°ƒ'=>1,'ï°„'=>1,'ï°…'=>1,'ï°†'=>1,'ï°‡'=>1,'ï°ˆ'=>1,'ï°‰'=>1,'ï°Š'=>1,'ï°‹'=>1,'ï°Œ'=>1,'ï°'=>1,'ï°Ž'=>1,'ï°'=>1,'ï°'=>1,'ï°‘'=>1,'ï°’'=>1,'ï°“'=>1,'ï°”'=>1,'ï°•'=>1,'ï°–'=>1,'ï°—'=>1,'ï°˜'=>1,'ï°™'=>1,'ï°š'=>1,'ï°›'=>1,'ï°œ'=>1,'ï°'=>1,'ï°ž'=>1,'ï°Ÿ'=>1,'ï° '=>1,'ï°¡'=>1,'ï°¢'=>1,'ï°£'=>1,'ï°¤'=>1,'ï°¥'=>1,'ï°¦'=>1,'ï°§'=>1,'ï°¨'=>1,'ï°©'=>1,'ï°ª'=>1,'ï°«'=>1,'ï°¬'=>1,'ï°­'=>1,'ï°®'=>1,'ï°¯'=>1,'ï°°'=>1,'ï°±'=>1,'ï°²'=>1,'ï°³'=>1,'ï°´'=>1,'ï°µ'=>1,'ï°¶'=>1,'ï°·'=>1,'ï°¸'=>1,'ï°¹'=>1,'ï°º'=>1,'ï°»'=>1,'ï°¼'=>1,'ï°½'=>1,'ï°¾'=>1,'ï°¿'=>1,'ï±€'=>1,'ï±'=>1,'ﱂ'=>1,'ﱃ'=>1,'ﱄ'=>1,'ï±…'=>1,'ﱆ'=>1,'ﱇ'=>1,'ﱈ'=>1,'ﱉ'=>1,'ﱊ'=>1,'ﱋ'=>1,'ﱌ'=>1,'ï±'=>1,'ﱎ'=>1,'ï±'=>1,'ï±'=>1,'ﱑ'=>1,'ï±’'=>1,'ﱓ'=>1,'ï±”'=>1,'ﱕ'=>1,'ï±–'=>1,'ï±—'=>1,'ﱘ'=>1,'ï±™'=>1,'ﱚ'=>1,'ï±›'=>1,'ﱜ'=>1,'ï±'=>1,'ﱞ'=>1,'ﱟ'=>1,'ï± '=>1,'ﱡ'=>1,'ï±¢'=>1,'ï±£'=>1,'ﱤ'=>1,'ï±¥'=>1,'ﱦ'=>1,'ﱧ'=>1,'ﱨ'=>1,'ﱩ'=>1,'ﱪ'=>1,'ﱫ'=>1,'ﱬ'=>1,'ï±­'=>1,'ï±®'=>1,'ﱯ'=>1,'ï±°'=>1,'ï±±'=>1,'ï±²'=>1,'ï±³'=>1,'ï±´'=>1,'ï±µ'=>1,'ﱶ'=>1,'ï±·'=>1,'ﱸ'=>1,'ï±¹'=>1,'ﱺ'=>1,'ï±»'=>1,'ï±¼'=>1,'ï±½'=>1,'ï±¾'=>1,'ﱿ'=>1,'ï²€'=>1,'ï²'=>1,'ﲂ'=>1,'ﲃ'=>1,'ﲄ'=>1,'ï²…'=>1,'ﲆ'=>1,'ﲇ'=>1,'ﲈ'=>1,'ﲉ'=>1,'ﲊ'=>1,'ﲋ'=>1,'ﲌ'=>1,'ï²'=>1,'ﲎ'=>1,'ï²'=>1,'ï²'=>1,'ﲑ'=>1,'ï²’'=>1,'ﲓ'=>1,'ï²”'=>1,'ﲕ'=>1,'ï²–'=>1,'ï²—'=>1,'ﲘ'=>1,'ï²™'=>1,'ﲚ'=>1,'ï²›'=>1,'ﲜ'=>1,'ï²'=>1,'ﲞ'=>1,'ﲟ'=>1,'ï² '=>1,'ﲡ'=>1,'ï²¢'=>1,'ï²£'=>1,'ﲤ'=>1,'ï²¥'=>1,'ﲦ'=>1,'ﲧ'=>1,'ﲨ'=>1,'ﲩ'=>1,'ﲪ'=>1,'ﲫ'=>1,'ﲬ'=>1,'ï²­'=>1,'ï²®'=>1,'ﲯ'=>1,'ï²°'=>1,'ï²±'=>1,'ï²²'=>1,'ï²³'=>1,'ï²´'=>1,'ï²µ'=>1,'ﲶ'=>1,'ï²·'=>1,'ﲸ'=>1,'ï²¹'=>1,'ﲺ'=>1,'ï²»'=>1,'ï²¼'=>1,'ï²½'=>1,'ï²¾'=>1,'ﲿ'=>1,'ï³€'=>1,'ï³'=>1,'ﳂ'=>1,'ﳃ'=>1,'ﳄ'=>1,'ï³…'=>1,'ﳆ'=>1,'ﳇ'=>1,'ﳈ'=>1,'ﳉ'=>1,'ﳊ'=>1,'ﳋ'=>1,'ﳌ'=>1,'ï³'=>1,'ﳎ'=>1,'ï³'=>1,'ï³'=>1,'ﳑ'=>1,'ï³’'=>1,'ﳓ'=>1,'ï³”'=>1,'ﳕ'=>1,'ï³–'=>1,'ï³—'=>1,'ﳘ'=>1,'ï³™'=>1,'ﳚ'=>1,'ï³›'=>1,'ﳜ'=>1,'ï³'=>1,'ﳞ'=>1,'ﳟ'=>1,'ï³ '=>1,'ﳡ'=>1,'ï³¢'=>1,'ï³£'=>1,'ﳤ'=>1,'ï³¥'=>1,'ﳦ'=>1,'ﳧ'=>1,'ﳨ'=>1,'ﳩ'=>1,'ﳪ'=>1,'ﳫ'=>1,'ﳬ'=>1,'ï³­'=>1,'ï³®'=>1,'ﳯ'=>1,'ï³°'=>1,'ï³±'=>1,'ï³²'=>1,'ï³³'=>1,'ï³´'=>1,'ï³µ'=>1,'ﳶ'=>1,'ï³·'=>1,'ﳸ'=>1,'ï³¹'=>1,'ﳺ'=>1,'ï³»'=>1,'ï³¼'=>1,'ï³½'=>1,'ï³¾'=>1,'ﳿ'=>1,'ï´€'=>1,'ï´'=>1,'ï´‚'=>1,'ï´ƒ'=>1,'ï´„'=>1,'ï´…'=>1,'ï´†'=>1,'ï´‡'=>1,'ï´ˆ'=>1,'ï´‰'=>1,'ï´Š'=>1,'ï´‹'=>1,'ï´Œ'=>1,'ï´'=>1,'ï´Ž'=>1,'ï´'=>1,'ï´'=>1,'ï´‘'=>1,'ï´’'=>1,'ï´“'=>1,'ï´”'=>1,'ï´•'=>1,'ï´–'=>1,'ï´—'=>1,'ï´˜'=>1,'ï´™'=>1,'ï´š'=>1,'ï´›'=>1,'ï´œ'=>1,'ï´'=>1,'ï´ž'=>1,'ï´Ÿ'=>1,'ï´ '=>1,'ï´¡'=>1,'ï´¢'=>1,'ï´£'=>1,'ï´¤'=>1,'ï´¥'=>1,'ï´¦'=>1,'ï´§'=>1,'ï´¨'=>1,'ï´©'=>1,'ï´ª'=>1,'ï´«'=>1,'ï´¬'=>1,'ï´­'=>1,'ï´®'=>1,'ï´¯'=>1,'ï´°'=>1,'ï´±'=>1,'ï´²'=>1,'ï´³'=>1,'ï´´'=>1,'ï´µ'=>1,'ï´¶'=>1,'ï´·'=>1,'ï´¸'=>1,'ï´¹'=>1,'ï´º'=>1,'ï´»'=>1,'ï´¼'=>1,'ï´½'=>1,'ïµ'=>1,'ﵑ'=>1,'ïµ’'=>1,'ﵓ'=>1,'ïµ”'=>1,'ﵕ'=>1,'ïµ–'=>1,'ïµ—'=>1,'ﵘ'=>1,'ïµ™'=>1,'ﵚ'=>1,'ïµ›'=>1,'ﵜ'=>1,'ïµ'=>1,'ﵞ'=>1,'ﵟ'=>1,'ïµ '=>1,'ﵡ'=>1,'ïµ¢'=>1,'ïµ£'=>1,'ﵤ'=>1,'ïµ¥'=>1,'ﵦ'=>1,'ﵧ'=>1,'ﵨ'=>1,'ﵩ'=>1,'ﵪ'=>1,'ﵫ'=>1,'ﵬ'=>1,'ïµ­'=>1,'ïµ®'=>1,'ﵯ'=>1,'ïµ°'=>1,'ïµ±'=>1,'ïµ²'=>1,'ïµ³'=>1,'ïµ´'=>1,'ïµµ'=>1,'ﵶ'=>1,'ïµ·'=>1,'ﵸ'=>1,'ïµ¹'=>1,'ﵺ'=>1,'ïµ»'=>1,'ïµ¼'=>1,'ïµ½'=>1,'ïµ¾'=>1,'ﵿ'=>1,'ﶀ'=>1,'ï¶'=>1,'ﶂ'=>1,'ﶃ'=>1,'ﶄ'=>1,'ﶅ'=>1,'ﶆ'=>1,'ﶇ'=>1,'ﶈ'=>1,'ﶉ'=>1,'ﶊ'=>1,'ﶋ'=>1,'ﶌ'=>1,'ï¶'=>1,'ﶎ'=>1,'ï¶'=>1,'ﶒ'=>1,'ﶓ'=>1,'ﶔ'=>1,'ﶕ'=>1,'ﶖ'=>1,'ﶗ'=>1,'ﶘ'=>1,'ﶙ'=>1,'ﶚ'=>1,'ﶛ'=>1,'ﶜ'=>1,'ï¶'=>1,'ﶞ'=>1,'ﶟ'=>1,'ﶠ'=>1,'ﶡ'=>1,'ﶢ'=>1,'ﶣ'=>1,'ﶤ'=>1,'ﶥ'=>1,'ﶦ'=>1,'ﶧ'=>1,'ﶨ'=>1,'ﶩ'=>1,'ﶪ'=>1,'ﶫ'=>1,'ﶬ'=>1,'ﶭ'=>1,'ﶮ'=>1,'ﶯ'=>1,'ﶰ'=>1,'ﶱ'=>1,'ﶲ'=>1,'ﶳ'=>1,'ﶴ'=>1,'ﶵ'=>1,'ﶶ'=>1,'ﶷ'=>1,'ﶸ'=>1,'ﶹ'=>1,'ﶺ'=>1,'ﶻ'=>1,'ﶼ'=>1,'ﶽ'=>1,'ﶾ'=>1,'ﶿ'=>1,'ï·€'=>1,'ï·'=>1,'ï·‚'=>1,'ï·ƒ'=>1,'ï·„'=>1,'ï·…'=>1,'ï·†'=>1,'ï·‡'=>1,'ï·°'=>1,'ï·±'=>1,'ï·²'=>1,'ï·³'=>1,'ï·´'=>1,'ï·µ'=>1,'ï·¶'=>1,'ï··'=>1,'ï·¸'=>1,'ï·¹'=>1,'ï·º'=>1,'ï·»'=>1,'ï·¼'=>1,'ï¸'=>1,'︑'=>1,'︒'=>1,'︓'=>1,'︔'=>1,'︕'=>1,'︖'=>1,'︗'=>1,'︘'=>1,'︙'=>1,'︰'=>1,'︱'=>1,'︲'=>1,'︳'=>1,'︴'=>1,'︵'=>1,'︶'=>1,'︷'=>1,'︸'=>1,'︹'=>1,'︺'=>1,'︻'=>1,'︼'=>1,'︽'=>1,'︾'=>1,'︿'=>1,'ï¹€'=>1,'ï¹'=>1,'﹂'=>1,'﹃'=>1,'﹄'=>1,'﹇'=>1,'﹈'=>1,'﹉'=>1,'﹊'=>1,'﹋'=>1,'﹌'=>1,'ï¹'=>1,'﹎'=>1,'ï¹'=>1,'ï¹'=>1,'﹑'=>1,'ï¹’'=>1,'ï¹”'=>1,'﹕'=>1,'ï¹–'=>1,'ï¹—'=>1,'﹘'=>1,'ï¹™'=>1,'﹚'=>1,'ï¹›'=>1,'﹜'=>1,'ï¹'=>1,'﹞'=>1,'﹟'=>1,'ï¹ '=>1,'﹡'=>1,'ï¹¢'=>1,'ï¹£'=>1,'﹤'=>1,'ï¹¥'=>1,'﹦'=>1,'﹨'=>1,'﹩'=>1,'﹪'=>1,'﹫'=>1,'ï¹°'=>1,'ï¹±'=>1,'ï¹²'=>1,'ï¹´'=>1,'ﹶ'=>1,'ï¹·'=>1,'ﹸ'=>1,'ï¹¹'=>1,'ﹺ'=>1,'ï¹»'=>1,'ï¹¼'=>1,'ï¹½'=>1,'ï¹¾'=>1,'ﹿ'=>1,'ﺀ'=>1,'ïº'=>1,'ﺂ'=>1,'ﺃ'=>1,'ﺄ'=>1,'ﺅ'=>1,'ﺆ'=>1,'ﺇ'=>1,'ﺈ'=>1,'ﺉ'=>1,'ﺊ'=>1,'ﺋ'=>1,'ﺌ'=>1,'ïº'=>1,'ﺎ'=>1,'ïº'=>1,'ïº'=>1,'ﺑ'=>1,'ﺒ'=>1,'ﺓ'=>1,'ﺔ'=>1,'ﺕ'=>1,'ﺖ'=>1,'ﺗ'=>1,'ﺘ'=>1,'ﺙ'=>1,'ﺚ'=>1,'ﺛ'=>1,'ﺜ'=>1,'ïº'=>1,'ﺞ'=>1,'ﺟ'=>1,'ﺠ'=>1,'ﺡ'=>1,'ﺢ'=>1,'ﺣ'=>1,'ﺤ'=>1,'ﺥ'=>1,'ﺦ'=>1,'ﺧ'=>1,'ﺨ'=>1,'ﺩ'=>1,'ﺪ'=>1,'ﺫ'=>1,'ﺬ'=>1,'ﺭ'=>1,'ﺮ'=>1,'ﺯ'=>1,'ﺰ'=>1,'ﺱ'=>1,'ﺲ'=>1,'ﺳ'=>1,'ﺴ'=>1,'ﺵ'=>1,'ﺶ'=>1,'ﺷ'=>1,'ﺸ'=>1,'ﺹ'=>1,'ﺺ'=>1,'ﺻ'=>1,'ﺼ'=>1,'ﺽ'=>1,'ﺾ'=>1,'ﺿ'=>1,'ﻀ'=>1,'ï»'=>1,'ﻂ'=>1,'ﻃ'=>1,'ﻄ'=>1,'ï»…'=>1,'ﻆ'=>1,'ﻇ'=>1,'ﻈ'=>1,'ﻉ'=>1,'ﻊ'=>1,'ﻋ'=>1,'ﻌ'=>1,'ï»'=>1,'ﻎ'=>1,'ï»'=>1,'ï»'=>1,'ﻑ'=>1,'ï»’'=>1,'ﻓ'=>1,'ï»”'=>1,'ﻕ'=>1,'ï»–'=>1,'ï»—'=>1,'ﻘ'=>1,'ï»™'=>1,'ﻚ'=>1,'ï»›'=>1,'ﻜ'=>1,'ï»'=>1,'ﻞ'=>1,'ﻟ'=>1,'ï» '=>1,'ﻡ'=>1,'ﻢ'=>1,'ﻣ'=>1,'ﻤ'=>1,'ﻥ'=>1,'ﻦ'=>1,'ﻧ'=>1,'ﻨ'=>1,'ﻩ'=>1,'ﻪ'=>1,'ﻫ'=>1,'ﻬ'=>1,'ï»­'=>1,'ï»®'=>1,'ﻯ'=>1,'ï»°'=>1,'ï»±'=>1,'ﻲ'=>1,'ﻳ'=>1,'ï»´'=>1,'ﻵ'=>1,'ﻶ'=>1,'ï»·'=>1,'ﻸ'=>1,'ﻹ'=>1,'ﻺ'=>1,'ï»»'=>1,'ﻼ'=>1,'ï¼'=>1,'"'=>1,'#'=>1,'$'=>1,'ï¼…'=>1,'&'=>1,'''=>1,'('=>1,')'=>1,'*'=>1,'+'=>1,','=>1,'ï¼'=>1,'.'=>1,'ï¼'=>1,'ï¼'=>1,'1'=>1,'ï¼’'=>1,'3'=>1,'ï¼”'=>1,'5'=>1,'ï¼–'=>1,'ï¼—'=>1,'8'=>1,'ï¼™'=>1,':'=>1,'ï¼›'=>1,'<'=>1,'ï¼'=>1,'>'=>1,'?'=>1,'ï¼ '=>1,'A'=>1,'ï¼¢'=>1,'ï¼£'=>1,'D'=>1,'ï¼¥'=>1,'F'=>1,'G'=>1,'H'=>1,'I'=>1,'J'=>1,'K'=>1,'L'=>1,'ï¼­'=>1,'ï¼®'=>1,'O'=>1,'ï¼°'=>1,'ï¼±'=>1,'ï¼²'=>1,'ï¼³'=>1,'ï¼´'=>1,'ï¼µ'=>1,'V'=>1,'ï¼·'=>1,'X'=>1,'ï¼¹'=>1,'Z'=>1,'ï¼»'=>1,'ï¼¼'=>1,'ï¼½'=>1,'ï¼¾'=>1,'_'=>1,'ï½€'=>1,'ï½'=>1,'b'=>1,'c'=>1,'d'=>1,'ï½…'=>1,'f'=>1,'g'=>1,'h'=>1,'i'=>1,'j'=>1,'k'=>1,'l'=>1,'ï½'=>1,'n'=>1,'ï½'=>1,'ï½'=>1,'q'=>1,'ï½’'=>1,'s'=>1,'ï½”'=>1,'u'=>1,'ï½–'=>1,'ï½—'=>1,'x'=>1,'ï½™'=>1,'z'=>1,'ï½›'=>1,'|'=>1,'ï½'=>1,'~'=>1,'⦅'=>1,'ï½ '=>1,'。'=>1,'ï½¢'=>1,'ï½£'=>1,'、'=>1,'ï½¥'=>1,'ヲ'=>1,'ァ'=>1,'ィ'=>1,'ゥ'=>1,'ェ'=>1,'ォ'=>1,'ャ'=>1,'ï½­'=>1,'ï½®'=>1,'ッ'=>1,'ï½°'=>1,'ï½±'=>1,'ï½²'=>1,'ï½³'=>1,'ï½´'=>1,'ï½µ'=>1,'カ'=>1,'ï½·'=>1,'ク'=>1,'ï½¹'=>1,'コ'=>1,'ï½»'=>1,'ï½¼'=>1,'ï½½'=>1,'ï½¾'=>1,'ソ'=>1,'ï¾€'=>1,'ï¾'=>1,'ツ'=>1,'テ'=>1,'ト'=>1,'ï¾…'=>1,'ニ'=>1,'ヌ'=>1,'ネ'=>1,'ノ'=>1,'ハ'=>1,'ヒ'=>1,'フ'=>1,'ï¾'=>1,'ホ'=>1,'ï¾'=>1,'ï¾'=>1,'ム'=>1,'ï¾’'=>1,'モ'=>1,'ï¾”'=>1,'ユ'=>1,'ï¾–'=>1,'ï¾—'=>1,'リ'=>1,'ï¾™'=>1,'レ'=>1,'ï¾›'=>1,'ワ'=>1,'ï¾'=>1,'゙'=>1,'゚'=>1,'ï¾ '=>1,'ᄀ'=>1,'ï¾¢'=>1,'ï¾£'=>1,'ᄂ'=>1,'ï¾¥'=>1,'ᆭ'=>1,'ᄃ'=>1,'ᄄ'=>1,'ᄅ'=>1,'ᆰ'=>1,'ᆱ'=>1,'ᆲ'=>1,'ï¾­'=>1,'ï¾®'=>1,'ᆵ'=>1,'ï¾°'=>1,'ï¾±'=>1,'ï¾²'=>1,'ï¾³'=>1,'ï¾´'=>1,'ï¾µ'=>1,'ᄊ'=>1,'ï¾·'=>1,'ᄌ'=>1,'ï¾¹'=>1,'ᄎ'=>1,'ï¾»'=>1,'ï¾¼'=>1,'ï¾½'=>1,'ï¾¾'=>1,'ï¿‚'=>1,'ᅢ'=>1,'ï¿„'=>1,'ï¿…'=>1,'ᅥ'=>1,'ᅦ'=>1,'ï¿Š'=>1,'ï¿‹'=>1,'ï¿Œ'=>1,'ï¿'=>1,'ï¿Ž'=>1,'ï¿'=>1,'ï¿’'=>1,'ï¿“'=>1,'ï¿”'=>1,'ï¿•'=>1,'ï¿–'=>1,'ï¿—'=>1,'ï¿š'=>1,'ï¿›'=>1,'ï¿œ'=>1,'ï¿ '=>1,'ï¿¡'=>1,'ï¿¢'=>1,'ï¿£'=>1,'¦'=>1,'ï¿¥'=>1,'₩'=>1,'│'=>1,'ï¿©'=>1,'↑'=>1,'ï¿«'=>1,'↓'=>1,'ï¿­'=>1,'ï¿®'=>1,'ð…ž'=>1,'ð…Ÿ'=>1,'ð… '=>1,'ð…¡'=>1,'ð…¢'=>1,'ð…£'=>1,'ð…¤'=>1,'ð†»'=>1,'ð†¼'=>1,'ð†½'=>1,'ð†¾'=>1,'ð†¿'=>1,'ð‡€'=>1,'ð€'=>1,'ð'=>1,'ð‚'=>1,'ðƒ'=>1,'ð„'=>1,'ð…'=>1,'ð†'=>1,'ð‡'=>1,'ðˆ'=>1,'ð‰'=>1,'ðŠ'=>1,'ð‹'=>1,'ðŒ'=>1,'ð'=>1,'ðŽ'=>1,'ð'=>1,'ð'=>1,'ð‘'=>1,'ð’'=>1,'ð“'=>1,'ð”'=>1,'ð•'=>1,'ð–'=>1,'ð—'=>1,'ð˜'=>1,'ð™'=>1,'ðš'=>1,'ð›'=>1,'ðœ'=>1,'ð'=>1,'ðž'=>1,'ðŸ'=>1,'ð '=>1,'ð¡'=>1,'ð¢'=>1,'ð£'=>1,'ð¤'=>1,'ð¥'=>1,'ð¦'=>1,'ð§'=>1,'ð¨'=>1,'ð©'=>1,'ðª'=>1,'ð«'=>1,'ð¬'=>1,'ð­'=>1,'ð®'=>1,'ð¯'=>1,'ð°'=>1,'ð±'=>1,'ð²'=>1,'ð³'=>1,'ð´'=>1,'ðµ'=>1,'ð¶'=>1,'ð·'=>1,'ð¸'=>1,'ð¹'=>1,'ðº'=>1,'ð»'=>1,'ð¼'=>1,'ð½'=>1,'ð¾'=>1,'ð¿'=>1,'ð‘€'=>1,'ð‘'=>1,'ð‘‚'=>1,'ð‘ƒ'=>1,'ð‘„'=>1,'ð‘…'=>1,'ð‘†'=>1,'ð‘‡'=>1,'ð‘ˆ'=>1,'ð‘‰'=>1,'ð‘Š'=>1,'ð‘‹'=>1,'ð‘Œ'=>1,'ð‘'=>1,'ð‘Ž'=>1,'ð‘'=>1,'ð‘'=>1,'ð‘‘'=>1,'ð‘’'=>1,'ð‘“'=>1,'ð‘”'=>1,'ð‘–'=>1,'ð‘—'=>1,'ð‘˜'=>1,'ð‘™'=>1,'ð‘š'=>1,'ð‘›'=>1,'ð‘œ'=>1,'ð‘'=>1,'ð‘ž'=>1,'ð‘Ÿ'=>1,'ð‘ '=>1,'ð‘¡'=>1,'ð‘¢'=>1,'ð‘£'=>1,'ð‘¤'=>1,'ð‘¥'=>1,'ð‘¦'=>1,'ð‘§'=>1,'ð‘¨'=>1,'ð‘©'=>1,'ð‘ª'=>1,'ð‘«'=>1,'ð‘¬'=>1,'ð‘­'=>1,'ð‘®'=>1,'ð‘¯'=>1,'ð‘°'=>1,'ð‘±'=>1,'ð‘²'=>1,'ð‘³'=>1,'ð‘´'=>1,'ð‘µ'=>1,'ð‘¶'=>1,'ð‘·'=>1,'ð‘¸'=>1,'ð‘¹'=>1,'ð‘º'=>1,'ð‘»'=>1,'ð‘¼'=>1,'ð‘½'=>1,'ð‘¾'=>1,'ð‘¿'=>1,'ð’€'=>1,'ð’'=>1,'ð’‚'=>1,'ð’ƒ'=>1,'ð’„'=>1,'ð’…'=>1,'ð’†'=>1,'ð’‡'=>1,'ð’ˆ'=>1,'ð’‰'=>1,'ð’Š'=>1,'ð’‹'=>1,'ð’Œ'=>1,'ð’'=>1,'ð’Ž'=>1,'ð’'=>1,'ð’'=>1,'ð’‘'=>1,'ð’’'=>1,'ð’“'=>1,'ð’”'=>1,'ð’•'=>1,'ð’–'=>1,'ð’—'=>1,'ð’˜'=>1,'ð’™'=>1,'ð’š'=>1,'ð’›'=>1,'ð’œ'=>1,'ð’ž'=>1,'ð’Ÿ'=>1,'ð’¢'=>1,'ð’¥'=>1,'ð’¦'=>1,'ð’©'=>1,'ð’ª'=>1,'ð’«'=>1,'ð’¬'=>1,'ð’®'=>1,'ð’¯'=>1,'ð’°'=>1,'ð’±'=>1,'ð’²'=>1,'ð’³'=>1,'ð’´'=>1,'ð’µ'=>1,'ð’¶'=>1,'ð’·'=>1,'ð’¸'=>1,'ð’¹'=>1,'ð’»'=>1,'ð’½'=>1,'ð’¾'=>1,'ð’¿'=>1,'ð“€'=>1,'ð“'=>1,'ð“‚'=>1,'ð“ƒ'=>1,'ð“…'=>1,'ð“†'=>1,'ð“‡'=>1,'ð“ˆ'=>1,'ð“‰'=>1,'ð“Š'=>1,'ð“‹'=>1,'ð“Œ'=>1,'ð“'=>1,'ð“Ž'=>1,'ð“'=>1,'ð“'=>1,'ð“‘'=>1,'ð“’'=>1,'ð““'=>1,'ð“”'=>1,'ð“•'=>1,'ð“–'=>1,'ð“—'=>1,'ð“˜'=>1,'ð“™'=>1,'ð“š'=>1,'ð“›'=>1,'ð“œ'=>1,'ð“'=>1,'ð“ž'=>1,'ð“Ÿ'=>1,'ð“ '=>1,'ð“¡'=>1,'ð“¢'=>1,'ð“£'=>1,'ð“¤'=>1,'ð“¥'=>1,'ð“¦'=>1,'ð“§'=>1,'ð“¨'=>1,'ð“©'=>1,'ð“ª'=>1,'ð“«'=>1,'ð“¬'=>1,'ð“­'=>1,'ð“®'=>1,'ð“¯'=>1,'ð“°'=>1,'ð“±'=>1,'ð“²'=>1,'ð“³'=>1,'ð“´'=>1,'ð“µ'=>1,'ð“¶'=>1,'ð“·'=>1,'ð“¸'=>1,'ð“¹'=>1,'ð“º'=>1,'ð“»'=>1,'ð“¼'=>1,'ð“½'=>1,'ð“¾'=>1,'ð“¿'=>1,'ð”€'=>1,'ð”'=>1,'ð”‚'=>1,'ð”ƒ'=>1,'ð”„'=>1,'ð”…'=>1,'ð”‡'=>1,'ð”ˆ'=>1,'ð”‰'=>1,'ð”Š'=>1,'ð”'=>1,'ð”Ž'=>1,'ð”'=>1,'ð”'=>1,'ð”‘'=>1,'ð”’'=>1,'ð”“'=>1,'ð””'=>1,'ð”–'=>1,'ð”—'=>1,'ð”˜'=>1,'ð”™'=>1,'ð”š'=>1,'ð”›'=>1,'ð”œ'=>1,'ð”ž'=>1,'ð”Ÿ'=>1,'ð” '=>1,'ð”¡'=>1,'ð”¢'=>1,'ð”£'=>1,'ð”¤'=>1,'ð”¥'=>1,'ð”¦'=>1,'ð”§'=>1,'ð”¨'=>1,'ð”©'=>1,'ð”ª'=>1,'ð”«'=>1,'ð”¬'=>1,'ð”­'=>1,'ð”®'=>1,'ð”¯'=>1,'ð”°'=>1,'ð”±'=>1,'ð”²'=>1,'ð”³'=>1,'ð”´'=>1,'ð”µ'=>1,'ð”¶'=>1,'ð”·'=>1,'ð”¸'=>1,'ð”¹'=>1,'ð”»'=>1,'ð”¼'=>1,'ð”½'=>1,'ð”¾'=>1,'ð•€'=>1,'ð•'=>1,'ð•‚'=>1,'ð•ƒ'=>1,'ð•„'=>1,'ð•†'=>1,'ð•Š'=>1,'ð•‹'=>1,'ð•Œ'=>1,'ð•'=>1,'ð•Ž'=>1,'ð•'=>1,'ð•'=>1,'ð•’'=>1,'ð•“'=>1,'ð•”'=>1,'ð••'=>1,'ð•–'=>1,'ð•—'=>1,'ð•˜'=>1,'ð•™'=>1,'ð•š'=>1,'ð•›'=>1,'ð•œ'=>1,'ð•'=>1,'ð•ž'=>1,'ð•Ÿ'=>1,'ð• '=>1,'ð•¡'=>1,'ð•¢'=>1,'ð•£'=>1,'ð•¤'=>1,'ð•¥'=>1,'ð•¦'=>1,'ð•§'=>1,'ð•¨'=>1,'ð•©'=>1,'ð•ª'=>1,'ð•«'=>1,'ð•¬'=>1,'ð•­'=>1,'ð•®'=>1,'ð•¯'=>1,'ð•°'=>1,'ð•±'=>1,'ð•²'=>1,'ð•³'=>1,'ð•´'=>1,'ð•µ'=>1,'ð•¶'=>1,'ð•·'=>1,'ð•¸'=>1,'ð•¹'=>1,'ð•º'=>1,'ð•»'=>1,'ð•¼'=>1,'ð•½'=>1,'ð•¾'=>1,'ð•¿'=>1,'ð–€'=>1,'ð–'=>1,'ð–‚'=>1,'ð–ƒ'=>1,'ð–„'=>1,'ð–…'=>1,'ð–†'=>1,'ð–‡'=>1,'ð–ˆ'=>1,'ð–‰'=>1,'ð–Š'=>1,'ð–‹'=>1,'ð–Œ'=>1,'ð–'=>1,'ð–Ž'=>1,'ð–'=>1,'ð–'=>1,'ð–‘'=>1,'ð–’'=>1,'ð–“'=>1,'ð–”'=>1,'ð–•'=>1,'ð––'=>1,'ð–—'=>1,'ð–˜'=>1,'ð–™'=>1,'ð–š'=>1,'ð–›'=>1,'ð–œ'=>1,'ð–'=>1,'ð–ž'=>1,'ð–Ÿ'=>1,'ð– '=>1,'ð–¡'=>1,'ð–¢'=>1,'ð–£'=>1,'ð–¤'=>1,'ð–¥'=>1,'ð–¦'=>1,'ð–§'=>1,'ð–¨'=>1,'ð–©'=>1,'ð–ª'=>1,'ð–«'=>1,'ð–¬'=>1,'ð–­'=>1,'ð–®'=>1,'ð–¯'=>1,'ð–°'=>1,'ð–±'=>1,'ð–²'=>1,'ð–³'=>1,'ð–´'=>1,'ð–µ'=>1,'ð–¶'=>1,'ð–·'=>1,'ð–¸'=>1,'ð–¹'=>1,'ð–º'=>1,'ð–»'=>1,'ð–¼'=>1,'ð–½'=>1,'ð–¾'=>1,'ð–¿'=>1,'ð—€'=>1,'ð—'=>1,'ð—‚'=>1,'ð—ƒ'=>1,'ð—„'=>1,'ð—…'=>1,'ð—†'=>1,'ð—‡'=>1,'ð—ˆ'=>1,'ð—‰'=>1,'ð—Š'=>1,'ð—‹'=>1,'ð—Œ'=>1,'ð—'=>1,'ð—Ž'=>1,'ð—'=>1,'ð—'=>1,'ð—‘'=>1,'ð—’'=>1,'ð—“'=>1,'ð—”'=>1,'ð—•'=>1,'ð—–'=>1,'ð——'=>1,'ð—˜'=>1,'ð—™'=>1,'ð—š'=>1,'ð—›'=>1,'ð—œ'=>1,'ð—'=>1,'ð—ž'=>1,'ð—Ÿ'=>1,'ð— '=>1,'ð—¡'=>1,'ð—¢'=>1,'ð—£'=>1,'ð—¤'=>1,'ð—¥'=>1,'ð—¦'=>1,'ð—§'=>1,'ð—¨'=>1,'ð—©'=>1,'ð—ª'=>1,'ð—«'=>1,'ð—¬'=>1,'ð—­'=>1,'ð—®'=>1,'ð—¯'=>1,'ð—°'=>1,'ð—±'=>1,'ð—²'=>1,'ð—³'=>1,'ð—´'=>1,'ð—µ'=>1,'ð—¶'=>1,'ð—·'=>1,'ð—¸'=>1,'ð—¹'=>1,'ð—º'=>1,'ð—»'=>1,'ð—¼'=>1,'ð—½'=>1,'ð—¾'=>1,'ð—¿'=>1,'ð˜€'=>1,'ð˜'=>1,'ð˜‚'=>1,'ð˜ƒ'=>1,'ð˜„'=>1,'ð˜…'=>1,'ð˜†'=>1,'ð˜‡'=>1,'ð˜ˆ'=>1,'ð˜‰'=>1,'ð˜Š'=>1,'ð˜‹'=>1,'ð˜Œ'=>1,'ð˜'=>1,'ð˜Ž'=>1,'ð˜'=>1,'ð˜'=>1,'ð˜‘'=>1,'ð˜’'=>1,'ð˜“'=>1,'ð˜”'=>1,'ð˜•'=>1,'ð˜–'=>1,'ð˜—'=>1,'ð˜˜'=>1,'ð˜™'=>1,'ð˜š'=>1,'ð˜›'=>1,'ð˜œ'=>1,'ð˜'=>1,'ð˜ž'=>1,'ð˜Ÿ'=>1,'ð˜ '=>1,'ð˜¡'=>1,'ð˜¢'=>1,'ð˜£'=>1,'ð˜¤'=>1,'ð˜¥'=>1,'ð˜¦'=>1,'ð˜§'=>1,'ð˜¨'=>1,'ð˜©'=>1,'ð˜ª'=>1,'ð˜«'=>1,'ð˜¬'=>1,'ð˜­'=>1,'ð˜®'=>1,'ð˜¯'=>1,'ð˜°'=>1,'ð˜±'=>1,'ð˜²'=>1,'ð˜³'=>1,'ð˜´'=>1,'ð˜µ'=>1,'ð˜¶'=>1,'ð˜·'=>1,'ð˜¸'=>1,'ð˜¹'=>1,'ð˜º'=>1,'ð˜»'=>1,'ð˜¼'=>1,'ð˜½'=>1,'ð˜¾'=>1,'ð˜¿'=>1,'ð™€'=>1,'ð™'=>1,'ð™‚'=>1,'ð™ƒ'=>1,'ð™„'=>1,'ð™…'=>1,'ð™†'=>1,'ð™‡'=>1,'ð™ˆ'=>1,'ð™‰'=>1,'ð™Š'=>1,'ð™‹'=>1,'ð™Œ'=>1,'ð™'=>1,'ð™Ž'=>1,'ð™'=>1,'ð™'=>1,'ð™‘'=>1,'ð™’'=>1,'ð™“'=>1,'ð™”'=>1,'ð™•'=>1,'ð™–'=>1,'ð™—'=>1,'ð™˜'=>1,'ð™™'=>1,'ð™š'=>1,'ð™›'=>1,'ð™œ'=>1,'ð™'=>1,'ð™ž'=>1,'ð™Ÿ'=>1,'ð™ '=>1,'ð™¡'=>1,'ð™¢'=>1,'ð™£'=>1,'ð™¤'=>1,'ð™¥'=>1,'ð™¦'=>1,'ð™§'=>1,'ð™¨'=>1,'ð™©'=>1,'ð™ª'=>1,'ð™«'=>1,'ð™¬'=>1,'ð™­'=>1,'ð™®'=>1,'ð™¯'=>1,'ð™°'=>1,'ð™±'=>1,'ð™²'=>1,'ð™³'=>1,'ð™´'=>1,'ð™µ'=>1,'ð™¶'=>1,'ð™·'=>1,'ð™¸'=>1,'ð™¹'=>1,'ð™º'=>1,'ð™»'=>1,'ð™¼'=>1,'ð™½'=>1,'ð™¾'=>1,'ð™¿'=>1,'ðš€'=>1,'ðš'=>1,'ðš‚'=>1,'ðšƒ'=>1,'ðš„'=>1,'ðš…'=>1,'ðš†'=>1,'ðš‡'=>1,'ðšˆ'=>1,'ðš‰'=>1,'ðšŠ'=>1,'ðš‹'=>1,'ðšŒ'=>1,'ðš'=>1,'ðšŽ'=>1,'ðš'=>1,'ðš'=>1,'ðš‘'=>1,'ðš’'=>1,'ðš“'=>1,'ðš”'=>1,'ðš•'=>1,'ðš–'=>1,'ðš—'=>1,'ðš˜'=>1,'ðš™'=>1,'ðšš'=>1,'ðš›'=>1,'ðšœ'=>1,'ðš'=>1,'ðšž'=>1,'ðšŸ'=>1,'ðš '=>1,'ðš¡'=>1,'ðš¢'=>1,'ðš£'=>1,'ðš¤'=>1,'ðš¥'=>1,'ðš¨'=>1,'ðš©'=>1,'ðšª'=>1,'ðš«'=>1,'ðš¬'=>1,'ðš­'=>1,'ðš®'=>1,'ðš¯'=>1,'ðš°'=>1,'ðš±'=>1,'ðš²'=>1,'ðš³'=>1,'ðš´'=>1,'ðšµ'=>1,'ðš¶'=>1,'ðš·'=>1,'ðš¸'=>1,'ðš¹'=>1,'ðšº'=>1,'ðš»'=>1,'ðš¼'=>1,'ðš½'=>1,'ðš¾'=>1,'ðš¿'=>1,'ð›€'=>1,'ð›'=>1,'ð›‚'=>1,'ð›ƒ'=>1,'ð›„'=>1,'ð›…'=>1,'ð›†'=>1,'ð›‡'=>1,'ð›ˆ'=>1,'ð›‰'=>1,'ð›Š'=>1,'ð›‹'=>1,'ð›Œ'=>1,'ð›'=>1,'ð›Ž'=>1,'ð›'=>1,'ð›'=>1,'ð›‘'=>1,'ð›’'=>1,'ð›“'=>1,'ð›”'=>1,'ð›•'=>1,'ð›–'=>1,'ð›—'=>1,'ð›˜'=>1,'ð›™'=>1,'ð›š'=>1,'ð››'=>1,'ð›œ'=>1,'ð›'=>1,'ð›ž'=>1,'ð›Ÿ'=>1,'ð› '=>1,'ð›¡'=>1,'ð›¢'=>1,'ð›£'=>1,'ð›¤'=>1,'ð›¥'=>1,'ð›¦'=>1,'ð›§'=>1,'ð›¨'=>1,'ð›©'=>1,'ð›ª'=>1,'ð›«'=>1,'ð›¬'=>1,'ð›­'=>1,'ð›®'=>1,'ð›¯'=>1,'ð›°'=>1,'ð›±'=>1,'ð›²'=>1,'ð›³'=>1,'ð›´'=>1,'ð›µ'=>1,'ð›¶'=>1,'ð›·'=>1,'ð›¸'=>1,'ð›¹'=>1,'ð›º'=>1,'ð›»'=>1,'ð›¼'=>1,'ð›½'=>1,'ð›¾'=>1,'ð›¿'=>1,'ðœ€'=>1,'ðœ'=>1,'ðœ‚'=>1,'ðœƒ'=>1,'ðœ„'=>1,'ðœ…'=>1,'ðœ†'=>1,'ðœ‡'=>1,'ðœˆ'=>1,'ðœ‰'=>1,'ðœŠ'=>1,'ðœ‹'=>1,'ðœŒ'=>1,'ðœ'=>1,'ðœŽ'=>1,'ðœ'=>1,'ðœ'=>1,'ðœ‘'=>1,'ðœ’'=>1,'ðœ“'=>1,'ðœ”'=>1,'ðœ•'=>1,'ðœ–'=>1,'ðœ—'=>1,'ðœ˜'=>1,'ðœ™'=>1,'ðœš'=>1,'ðœ›'=>1,'ðœœ'=>1,'ðœ'=>1,'ðœž'=>1,'ðœŸ'=>1,'ðœ '=>1,'ðœ¡'=>1,'ðœ¢'=>1,'ðœ£'=>1,'ðœ¤'=>1,'ðœ¥'=>1,'ðœ¦'=>1,'ðœ§'=>1,'ðœ¨'=>1,'ðœ©'=>1,'ðœª'=>1,'ðœ«'=>1,'ðœ¬'=>1,'ðœ­'=>1,'ðœ®'=>1,'ðœ¯'=>1,'ðœ°'=>1,'ðœ±'=>1,'ðœ²'=>1,'ðœ³'=>1,'ðœ´'=>1,'ðœµ'=>1,'ðœ¶'=>1,'ðœ·'=>1,'ðœ¸'=>1,'ðœ¹'=>1,'ðœº'=>1,'ðœ»'=>1,'ðœ¼'=>1,'ðœ½'=>1,'ðœ¾'=>1,'ðœ¿'=>1,'ð€'=>1,'ð'=>1,'ð‚'=>1,'ðƒ'=>1,'ð„'=>1,'ð…'=>1,'ð†'=>1,'ð‡'=>1,'ðˆ'=>1,'ð‰'=>1,'ðŠ'=>1,'ð‹'=>1,'ðŒ'=>1,'ð'=>1,'ðŽ'=>1,'ð'=>1,'ð'=>1,'ð‘'=>1,'ð’'=>1,'ð“'=>1,'ð”'=>1,'ð•'=>1,'ð–'=>1,'ð—'=>1,'ð˜'=>1,'ð™'=>1,'ðš'=>1,'ð›'=>1,'ðœ'=>1,'ð'=>1,'ðž'=>1,'ðŸ'=>1,'ð '=>1,'ð¡'=>1,'ð¢'=>1,'ð£'=>1,'ð¤'=>1,'ð¥'=>1,'ð¦'=>1,'ð§'=>1,'ð¨'=>1,'ð©'=>1,'ðª'=>1,'ð«'=>1,'ð¬'=>1,'ð­'=>1,'ð®'=>1,'ð¯'=>1,'ð°'=>1,'ð±'=>1,'ð²'=>1,'ð³'=>1,'ð´'=>1,'ðµ'=>1,'ð¶'=>1,'ð·'=>1,'ð¸'=>1,'ð¹'=>1,'ðº'=>1,'ð»'=>1,'ð¼'=>1,'ð½'=>1,'ð¾'=>1,'ð¿'=>1,'ðž€'=>1,'ðž'=>1,'ðž‚'=>1,'ðžƒ'=>1,'ðž„'=>1,'ðž…'=>1,'ðž†'=>1,'ðž‡'=>1,'ðžˆ'=>1,'ðž‰'=>1,'ðžŠ'=>1,'ðž‹'=>1,'ðžŒ'=>1,'ðž'=>1,'ðžŽ'=>1,'ðž'=>1,'ðž'=>1,'ðž‘'=>1,'ðž’'=>1,'ðž“'=>1,'ðž”'=>1,'ðž•'=>1,'ðž–'=>1,'ðž—'=>1,'ðž˜'=>1,'ðž™'=>1,'ðžš'=>1,'ðž›'=>1,'ðžœ'=>1,'ðž'=>1,'ðžž'=>1,'ðžŸ'=>1,'ðž '=>1,'ðž¡'=>1,'ðž¢'=>1,'ðž£'=>1,'ðž¤'=>1,'ðž¥'=>1,'ðž¦'=>1,'ðž§'=>1,'ðž¨'=>1,'ðž©'=>1,'ðžª'=>1,'ðž«'=>1,'ðž¬'=>1,'ðž­'=>1,'ðž®'=>1,'ðž¯'=>1,'ðž°'=>1,'ðž±'=>1,'ðž²'=>1,'ðž³'=>1,'ðž´'=>1,'ðžµ'=>1,'ðž¶'=>1,'ðž·'=>1,'ðž¸'=>1,'ðž¹'=>1,'ðžº'=>1,'ðž»'=>1,'ðž¼'=>1,'ðž½'=>1,'ðž¾'=>1,'ðž¿'=>1,'ðŸ€'=>1,'ðŸ'=>1,'ðŸ‚'=>1,'ðŸƒ'=>1,'ðŸ„'=>1,'ðŸ…'=>1,'ðŸ†'=>1,'ðŸ‡'=>1,'ðŸˆ'=>1,'ðŸ‰'=>1,'ðŸŠ'=>1,'ðŸ‹'=>1,'ðŸŽ'=>1,'ðŸ'=>1,'ðŸ'=>1,'ðŸ‘'=>1,'ðŸ’'=>1,'ðŸ“'=>1,'ðŸ”'=>1,'ðŸ•'=>1,'ðŸ–'=>1,'ðŸ—'=>1,'ðŸ˜'=>1,'ðŸ™'=>1,'ðŸš'=>1,'ðŸ›'=>1,'ðŸœ'=>1,'ðŸ'=>1,'ðŸž'=>1,'ðŸŸ'=>1,'ðŸ '=>1,'ðŸ¡'=>1,'ðŸ¢'=>1,'ðŸ£'=>1,'ðŸ¤'=>1,'ðŸ¥'=>1,'ðŸ¦'=>1,'ðŸ§'=>1,'ðŸ¨'=>1,'ðŸ©'=>1,'ðŸª'=>1,'ðŸ«'=>1,'ðŸ¬'=>1,'ðŸ­'=>1,'ðŸ®'=>1,'ðŸ¯'=>1,'ðŸ°'=>1,'ðŸ±'=>1,'ðŸ²'=>1,'ðŸ³'=>1,'ðŸ´'=>1,'ðŸµ'=>1,'ðŸ¶'=>1,'ðŸ·'=>1,'ðŸ¸'=>1,'ðŸ¹'=>1,'ðŸº'=>1,'ðŸ»'=>1,'ðŸ¼'=>1,'ðŸ½'=>1,'ðŸ¾'=>1,'ðŸ¿'=>1,'丽'=>1,'ð¯ '=>1,'乁'=>1,'𠄢'=>1,'你'=>1,'侮'=>1,'侻'=>1,'倂'=>1,'偺'=>1,'備'=>1,'僧'=>1,'像'=>1,'㒞'=>1,'ð¯ '=>1,'免'=>1,'ð¯ '=>1,'ð¯ '=>1,'具'=>1,'𠔜'=>1,'㒹'=>1,'內'=>1,'再'=>1,'𠕋'=>1,'冗'=>1,'冤'=>1,'仌'=>1,'冬'=>1,'况'=>1,'𩇟'=>1,'ð¯ '=>1,'刃'=>1,'㓟'=>1,'刻'=>1,'剆'=>1,'割'=>1,'剷'=>1,'㔕'=>1,'勇'=>1,'勉'=>1,'勤'=>1,'勺'=>1,'包'=>1,'匆'=>1,'北'=>1,'卉'=>1,'卑'=>1,'博'=>1,'即'=>1,'卽'=>1,'卿'=>1,'卿'=>1,'卿'=>1,'𠨬'=>1,'灰'=>1,'及'=>1,'叟'=>1,'𠭣'=>1,'叫'=>1,'叱'=>1,'吆'=>1,'咞'=>1,'吸'=>1,'呈'=>1,'周'=>1,'咢'=>1,'ð¯¡'=>1,'唐'=>1,'啓'=>1,'啣'=>1,'善'=>1,'善'=>1,'喙'=>1,'喫'=>1,'喳'=>1,'嗂'=>1,'圖'=>1,'嘆'=>1,'ð¯¡'=>1,'噑'=>1,'ð¯¡'=>1,'ð¯¡'=>1,'壮'=>1,'城'=>1,'埴'=>1,'堍'=>1,'型'=>1,'堲'=>1,'報'=>1,'墬'=>1,'𡓤'=>1,'売'=>1,'壷'=>1,'夆'=>1,'ð¯¡'=>1,'夢'=>1,'奢'=>1,'𡚨'=>1,'𡛪'=>1,'姬'=>1,'娛'=>1,'娧'=>1,'姘'=>1,'婦'=>1,'㛮'=>1,'㛼'=>1,'嬈'=>1,'嬾'=>1,'嬾'=>1,'𡧈'=>1,'寃'=>1,'寘'=>1,'寧'=>1,'寳'=>1,'𡬘'=>1,'寿'=>1,'将'=>1,'当'=>1,'尢'=>1,'㞁'=>1,'屠'=>1,'屮'=>1,'峀'=>1,'岍'=>1,'𡷤'=>1,'嵃'=>1,'𡷦'=>1,'嵮'=>1,'嵫'=>1,'嵼'=>1,'ð¯¢'=>1,'巢'=>1,'㠯'=>1,'巽'=>1,'帨'=>1,'帽'=>1,'幩'=>1,'㡢'=>1,'𢆃'=>1,'㡼'=>1,'庰'=>1,'庳'=>1,'ð¯¢'=>1,'廊'=>1,'ð¯¢'=>1,'ð¯¢'=>1,'𢌱'=>1,'𢌱'=>1,'舁'=>1,'弢'=>1,'弢'=>1,'㣇'=>1,'𣊸'=>1,'𦇚'=>1,'形'=>1,'彫'=>1,'㣣'=>1,'徚'=>1,'ð¯¢'=>1,'志'=>1,'忹'=>1,'悁'=>1,'㤺'=>1,'㤜'=>1,'悔'=>1,'𢛔'=>1,'惇'=>1,'慈'=>1,'慌'=>1,'慎'=>1,'慌'=>1,'慺'=>1,'憎'=>1,'憲'=>1,'憤'=>1,'憯'=>1,'懞'=>1,'懲'=>1,'懶'=>1,'成'=>1,'戛'=>1,'扝'=>1,'抱'=>1,'拔'=>1,'捐'=>1,'𢬌'=>1,'挽'=>1,'拼'=>1,'捨'=>1,'掃'=>1,'揤'=>1,'𢯱'=>1,'搢'=>1,'揅'=>1,'ð¯£'=>1,'㨮'=>1,'摩'=>1,'摾'=>1,'撝'=>1,'摷'=>1,'㩬'=>1,'敏'=>1,'敬'=>1,'𣀊'=>1,'旣'=>1,'書'=>1,'ð¯£'=>1,'㬙'=>1,'ð¯£'=>1,'ð¯£'=>1,'㫤'=>1,'冒'=>1,'冕'=>1,'最'=>1,'暜'=>1,'肭'=>1,'䏙'=>1,'朗'=>1,'望'=>1,'朡'=>1,'杞'=>1,'杓'=>1,'ð¯£'=>1,'㭉'=>1,'柺'=>1,'枅'=>1,'桒'=>1,'梅'=>1,'𣑭'=>1,'梎'=>1,'栟'=>1,'椔'=>1,'㮝'=>1,'楂'=>1,'榣'=>1,'槪'=>1,'檨'=>1,'𣚣'=>1,'櫛'=>1,'㰘'=>1,'次'=>1,'𣢧'=>1,'歔'=>1,'㱎'=>1,'歲'=>1,'殟'=>1,'殺'=>1,'殻'=>1,'𣪍'=>1,'𡴋'=>1,'𣫺'=>1,'汎'=>1,'𣲼'=>1,'沿'=>1,'泍'=>1,'汧'=>1,'洖'=>1,'派'=>1,'ð¯¤'=>1,'流'=>1,'浩'=>1,'浸'=>1,'涅'=>1,'𣴞'=>1,'洴'=>1,'港'=>1,'湮'=>1,'㴳'=>1,'滋'=>1,'滇'=>1,'ð¯¤'=>1,'淹'=>1,'ð¯¤'=>1,'ð¯¤'=>1,'𣾎'=>1,'濆'=>1,'瀹'=>1,'瀞'=>1,'瀛'=>1,'㶖'=>1,'灊'=>1,'災'=>1,'灷'=>1,'炭'=>1,'𠔥'=>1,'煅'=>1,'ð¯¤'=>1,'熜'=>1,'𤎫'=>1,'爨'=>1,'爵'=>1,'牐'=>1,'𤘈'=>1,'犀'=>1,'犕'=>1,'𤜵'=>1,'𤠔'=>1,'獺'=>1,'王'=>1,'㺬'=>1,'玥'=>1,'㺸'=>1,'㺸'=>1,'瑇'=>1,'瑜'=>1,'瑱'=>1,'璅'=>1,'瓊'=>1,'㼛'=>1,'甤'=>1,'𤰶'=>1,'甾'=>1,'𤲒'=>1,'異'=>1,'𢆟'=>1,'瘐'=>1,'𤾡'=>1,'𤾸'=>1,'𥁄'=>1,'㿼'=>1,'䀈'=>1,'直'=>1,'ð¯¥'=>1,'𥃲'=>1,'𥄙'=>1,'𥄳'=>1,'眞'=>1,'真'=>1,'真'=>1,'睊'=>1,'䀹'=>1,'瞋'=>1,'䁆'=>1,'䂖'=>1,'ð¯¥'=>1,'硎'=>1,'ð¯¥'=>1,'ð¯¥'=>1,'䃣'=>1,'𥘦'=>1,'祖'=>1,'𥚚'=>1,'𥛅'=>1,'福'=>1,'秫'=>1,'䄯'=>1,'穀'=>1,'穊'=>1,'穏'=>1,'𥥼'=>1,'ð¯¥'=>1,'𥪧'=>1,'竮'=>1,'䈂'=>1,'𥮫'=>1,'篆'=>1,'築'=>1,'䈧'=>1,'𥲀'=>1,'糒'=>1,'䊠'=>1,'糨'=>1,'糣'=>1,'紀'=>1,'𥾆'=>1,'絣'=>1,'䌁'=>1,'緇'=>1,'縂'=>1,'繅'=>1,'䌴'=>1,'𦈨'=>1,'𦉇'=>1,'䍙'=>1,'𦋙'=>1,'罺'=>1,'𦌾'=>1,'羕'=>1,'翺'=>1,'者'=>1,'𦓚'=>1,'𦔣'=>1,'聠'=>1,'𦖨'=>1,'聰'=>1,'𣍟'=>1,'ð¯¦'=>1,'育'=>1,'脃'=>1,'䐋'=>1,'脾'=>1,'媵'=>1,'𦞧'=>1,'𦞵'=>1,'𣎓'=>1,'𣎜'=>1,'舁'=>1,'舄'=>1,'ð¯¦'=>1,'䑫'=>1,'ð¯¦'=>1,'ð¯¦'=>1,'芝'=>1,'劳'=>1,'花'=>1,'芳'=>1,'芽'=>1,'苦'=>1,'𦬼'=>1,'若'=>1,'茝'=>1,'荣'=>1,'莭'=>1,'茣'=>1,'ð¯¦'=>1,'菧'=>1,'著'=>1,'荓'=>1,'菊'=>1,'菌'=>1,'菜'=>1,'𦰶'=>1,'𦵫'=>1,'𦳕'=>1,'䔫'=>1,'蓱'=>1,'蓳'=>1,'蔖'=>1,'𧏊'=>1,'蕤'=>1,'𦼬'=>1,'䕝'=>1,'䕡'=>1,'𦾱'=>1,'𧃒'=>1,'䕫'=>1,'虐'=>1,'虜'=>1,'虧'=>1,'虩'=>1,'蚩'=>1,'蚈'=>1,'蜎'=>1,'蛢'=>1,'蝹'=>1,'蜨'=>1,'蝫'=>1,'螆'=>1,'䗗'=>1,'蟡'=>1,'ð¯§'=>1,'䗹'=>1,'衠'=>1,'衣'=>1,'𧙧'=>1,'裗'=>1,'裞'=>1,'䘵'=>1,'裺'=>1,'㒻'=>1,'𧢮'=>1,'𧥦'=>1,'ð¯§'=>1,'䛇'=>1,'ð¯§'=>1,'ð¯§'=>1,'變'=>1,'豕'=>1,'𧲨'=>1,'貫'=>1,'賁'=>1,'贛'=>1,'起'=>1,'𧼯'=>1,'𠠄'=>1,'跋'=>1,'趼'=>1,'跰'=>1,'ð¯§'=>1,'軔'=>1,'輸'=>1,'𨗒'=>1,'𨗭'=>1,'邔'=>1,'郱'=>1,'鄑'=>1,'𨜮'=>1,'鄛'=>1,'鈸'=>1,'鋗'=>1,'鋘'=>1,'鉼'=>1,'鏹'=>1,'鐕'=>1,'𨯺'=>1,'開'=>1,'䦕'=>1,'閷'=>1,'𨵷'=>1,'䧦'=>1,'雃'=>1,'嶲'=>1,'霣'=>1,'𩅅'=>1,'𩈚'=>1,'䩮'=>1,'䩶'=>1,'韠'=>1,'𩐊'=>1,'䪲'=>1,'𩒖'=>1,'頋'=>1,'頋'=>1,'頩'=>1,'ð¯¨'=>1,'飢'=>1,'䬳'=>1,'餩'=>1,'馧'=>1,'駂'=>1,'駾'=>1,'䯎'=>1,'𩬰'=>1,'鬒'=>1,'鱀'=>1,'鳽'=>1,'ð¯¨'=>1,'䳭'=>1,'ð¯¨'=>1,'ð¯¨'=>1,'䳸'=>1,'𪄅'=>1,'𪈎'=>1,'𪊑'=>1,'麻'=>1,'䵖'=>1,'黹'=>1,'黾'=>1,'鼅'=>1,'鼏'=>1,'鼖'=>1,'鼻'=>1,'ð¯¨'=>1,'Ì€'=>0,'Ì'=>0,'Ì‚'=>0,'̃'=>0,'Ì„'=>0,'̆'=>0,'̇'=>0,'̈'=>0,'̉'=>0,'ÌŠ'=>0,'Ì‹'=>0,'ÌŒ'=>0,'Ì'=>0,'Ì‘'=>0,'Ì“'=>0,'Ì”'=>0,'Ì›'=>0,'Ì£'=>0,'̤'=>0,'Ì¥'=>0,'̦'=>0,'̧'=>0,'̨'=>0,'Ì­'=>0,'Ì®'=>0,'Ì°'=>0,'̱'=>0,'̸'=>0,'Í‚'=>0,'Í…'=>0,'Ù“'=>0,'Ù”'=>0,'Ù•'=>0,'़'=>0,'া'=>0,'ৗ'=>0,'ା'=>0,'à­–'=>0,'à­—'=>0,'ா'=>0,'ௗ'=>0,'à±–'=>0,'ೂ'=>0,'ೕ'=>0,'à³–'=>0,'à´¾'=>0,'ൗ'=>0,'à·Š'=>0,'à·'=>0,'à·Ÿ'=>0,'ီ'=>0,'á…¡'=>0,'á…¢'=>0,'á…£'=>0,'á…¤'=>0,'á…¥'=>0,'á…¦'=>0,'á…§'=>0,'á…¨'=>0,'á…©'=>0,'á…ª'=>0,'á…«'=>0,'á…¬'=>0,'á…­'=>0,'á…®'=>0,'á…¯'=>0,'á…°'=>0,'á…±'=>0,'á…²'=>0,'á…³'=>0,'á…´'=>0,'á…µ'=>0,'ᆨ'=>0,'ᆩ'=>0,'ᆪ'=>0,'ᆫ'=>0,'ᆬ'=>0,'ᆭ'=>0,'ᆮ'=>0,'ᆯ'=>0,'ᆰ'=>0,'ᆱ'=>0,'ᆲ'=>0,'ᆳ'=>0,'ᆴ'=>0,'ᆵ'=>0,'ᆶ'=>0,'ᆷ'=>0,'ᆸ'=>0,'ᆹ'=>0,'ᆺ'=>0,'ᆻ'=>0,'ᆼ'=>0,'ᆽ'=>0,'ᆾ'=>0,'ᆿ'=>0,'ᇀ'=>0,'á‡'=>0,'ᇂ'=>0,'ᬵ'=>0,'ã‚™'=>0,'ã‚š'=>0);
diff --git a/phpBB/includes/utf/data/utf_normalizer_common.php b/phpBB/includes/utf/data/utf_normalizer_common.php
deleted file mode 100644
index 2eb7feac69..0000000000
--- a/phpBB/includes/utf/data/utf_normalizer_common.php
+++ /dev/null
@@ -1,4 +0,0 @@
-<?php
-$GLOBALS['utf_jamo_index']=array('á„€'=>44032,'á„'=>44620,'á„‚'=>45208,'ᄃ'=>45796,'á„„'=>46384,'á„…'=>46972,'ᄆ'=>47560,'ᄇ'=>48148,'ᄈ'=>48736,'ᄉ'=>49324,'á„Š'=>49912,'á„‹'=>50500,'á„Œ'=>51088,'á„'=>51676,'á„Ž'=>52264,'á„'=>52852,'á„'=>53440,'á„‘'=>54028,'á„’'=>54616,'á…¡'=>0,'á…¢'=>28,'á…£'=>56,'á…¤'=>84,'á…¥'=>112,'á…¦'=>140,'á…§'=>168,'á…¨'=>196,'á…©'=>224,'á…ª'=>252,'á…«'=>280,'á…¬'=>308,'á…­'=>336,'á…®'=>364,'á…¯'=>392,'á…°'=>420,'á…±'=>448,'á…²'=>476,'á…³'=>504,'á…´'=>532,'á…µ'=>560,'ᆧ'=>0,'ᆨ'=>1,'ᆩ'=>2,'ᆪ'=>3,'ᆫ'=>4,'ᆬ'=>5,'ᆭ'=>6,'ᆮ'=>7,'ᆯ'=>8,'ᆰ'=>9,'ᆱ'=>10,'ᆲ'=>11,'ᆳ'=>12,'ᆴ'=>13,'ᆵ'=>14,'ᆶ'=>15,'ᆷ'=>16,'ᆸ'=>17,'ᆹ'=>18,'ᆺ'=>19,'ᆻ'=>20,'ᆼ'=>21,'ᆽ'=>22,'ᆾ'=>23,'ᆿ'=>24,'ᇀ'=>25,'á‡'=>26,'ᇂ'=>27);
-$GLOBALS['utf_jamo_type']=array('á„€'=>0,'á„'=>0,'á„‚'=>0,'ᄃ'=>0,'á„„'=>0,'á„…'=>0,'ᄆ'=>0,'ᄇ'=>0,'ᄈ'=>0,'ᄉ'=>0,'á„Š'=>0,'á„‹'=>0,'á„Œ'=>0,'á„'=>0,'á„Ž'=>0,'á„'=>0,'á„'=>0,'á„‘'=>0,'á„’'=>0,'á…¡'=>1,'á…¢'=>1,'á…£'=>1,'á…¤'=>1,'á…¥'=>1,'á…¦'=>1,'á…§'=>1,'á…¨'=>1,'á…©'=>1,'á…ª'=>1,'á…«'=>1,'á…¬'=>1,'á…­'=>1,'á…®'=>1,'á…¯'=>1,'á…°'=>1,'á…±'=>1,'á…²'=>1,'á…³'=>1,'á…´'=>1,'á…µ'=>1,'ᆧ'=>2,'ᆨ'=>2,'ᆩ'=>2,'ᆪ'=>2,'ᆫ'=>2,'ᆬ'=>2,'ᆭ'=>2,'ᆮ'=>2,'ᆯ'=>2,'ᆰ'=>2,'ᆱ'=>2,'ᆲ'=>2,'ᆳ'=>2,'ᆴ'=>2,'ᆵ'=>2,'ᆶ'=>2,'ᆷ'=>2,'ᆸ'=>2,'ᆹ'=>2,'ᆺ'=>2,'ᆻ'=>2,'ᆼ'=>2,'ᆽ'=>2,'ᆾ'=>2,'ᆿ'=>2,'ᇀ'=>2,'á‡'=>2,'ᇂ'=>2);
-$GLOBALS['utf_combining_class']=array('Ì€'=>230,'Ì'=>230,'Ì‚'=>230,'̃'=>230,'Ì„'=>230,'Ì…'=>230,'̆'=>230,'̇'=>230,'̈'=>230,'̉'=>230,'ÌŠ'=>230,'Ì‹'=>230,'ÌŒ'=>230,'Ì'=>230,'ÌŽ'=>230,'Ì'=>230,'Ì'=>230,'Ì‘'=>230,'Ì’'=>230,'Ì“'=>230,'Ì”'=>230,'Ì•'=>232,'Ì–'=>220,'Ì—'=>220,'̘'=>220,'Ì™'=>220,'Ìš'=>232,'Ì›'=>216,'Ìœ'=>220,'Ì'=>220,'Ìž'=>220,'ÌŸ'=>220,'Ì '=>220,'Ì¡'=>202,'Ì¢'=>202,'Ì£'=>220,'̤'=>220,'Ì¥'=>220,'̦'=>220,'̧'=>202,'̨'=>202,'Ì©'=>220,'̪'=>220,'Ì«'=>220,'̬'=>220,'Ì­'=>220,'Ì®'=>220,'̯'=>220,'Ì°'=>220,'̱'=>220,'̲'=>220,'̳'=>220,'Ì´'=>1,'̵'=>1,'̶'=>1,'Ì·'=>1,'̸'=>1,'̹'=>220,'̺'=>220,'Ì»'=>220,'̼'=>220,'̽'=>230,'̾'=>230,'Ì¿'=>230,'Í€'=>230,'Í'=>230,'Í‚'=>230,'̓'=>230,'Í„'=>230,'Í…'=>240,'͆'=>230,'͇'=>220,'͈'=>220,'͉'=>220,'ÍŠ'=>230,'Í‹'=>230,'ÍŒ'=>230,'Í'=>220,'ÍŽ'=>220,'Í'=>230,'Í‘'=>230,'Í’'=>230,'Í“'=>220,'Í”'=>220,'Í•'=>220,'Í–'=>220,'Í—'=>230,'͘'=>232,'Í™'=>220,'Íš'=>220,'Í›'=>230,'Íœ'=>233,'Í'=>234,'Íž'=>234,'ÍŸ'=>233,'Í '=>234,'Í¡'=>234,'Í¢'=>233,'Í£'=>230,'ͤ'=>230,'Í¥'=>230,'ͦ'=>230,'ͧ'=>230,'ͨ'=>230,'Í©'=>230,'ͪ'=>230,'Í«'=>230,'ͬ'=>230,'Í­'=>230,'Í®'=>230,'ͯ'=>230,'Òƒ'=>230,'Ò„'=>230,'Ò…'=>230,'Ò†'=>230,'Ö‘'=>220,'Ö’'=>230,'Ö“'=>230,'Ö”'=>230,'Ö•'=>230,'Ö–'=>220,'Ö—'=>230,'Ö˜'=>230,'Ö™'=>230,'Öš'=>222,'Ö›'=>220,'Öœ'=>230,'Ö'=>230,'Öž'=>230,'ÖŸ'=>230,'Ö '=>230,'Ö¡'=>230,'Ö¢'=>220,'Ö£'=>220,'Ö¤'=>220,'Ö¥'=>220,'Ö¦'=>220,'Ö§'=>220,'Ö¨'=>230,'Ö©'=>230,'Öª'=>220,'Ö«'=>230,'Ö¬'=>230,'Ö­'=>222,'Ö®'=>228,'Ö¯'=>230,'Ö°'=>10,'Ö±'=>11,'Ö²'=>12,'Ö³'=>13,'Ö´'=>14,'Öµ'=>15,'Ö¶'=>16,'Ö·'=>17,'Ö¸'=>18,'Ö¹'=>19,'Öº'=>19,'Ö»'=>20,'Ö¼'=>21,'Ö½'=>22,'Ö¿'=>23,'×'=>24,'ׂ'=>25,'ׄ'=>230,'×…'=>220,'ׇ'=>18,'Ø'=>230,'Ø‘'=>230,'Ø’'=>230,'Ø“'=>230,'Ø”'=>230,'Ø•'=>230,'Ù‹'=>27,'ÙŒ'=>28,'Ù'=>29,'ÙŽ'=>30,'Ù'=>31,'Ù'=>32,'Ù‘'=>33,'Ù’'=>34,'Ù“'=>230,'Ù”'=>230,'Ù•'=>220,'Ù–'=>220,'Ù—'=>230,'Ù˜'=>230,'Ù™'=>230,'Ùš'=>230,'Ù›'=>230,'Ùœ'=>220,'Ù'=>230,'Ùž'=>230,'Ù°'=>35,'Û–'=>230,'Û—'=>230,'Û˜'=>230,'Û™'=>230,'Ûš'=>230,'Û›'=>230,'Ûœ'=>230,'ÛŸ'=>230,'Û '=>230,'Û¡'=>230,'Û¢'=>230,'Û£'=>220,'Û¤'=>230,'Û§'=>230,'Û¨'=>230,'Ûª'=>220,'Û«'=>230,'Û¬'=>230,'Û­'=>220,'Ü‘'=>36,'Ü°'=>230,'ܱ'=>220,'ܲ'=>230,'ܳ'=>230,'Ü´'=>220,'ܵ'=>230,'ܶ'=>230,'Ü·'=>220,'ܸ'=>220,'ܹ'=>220,'ܺ'=>230,'Ü»'=>220,'ܼ'=>220,'ܽ'=>230,'ܾ'=>220,'Ü¿'=>230,'Ý€'=>230,'Ý'=>230,'Ý‚'=>220,'݃'=>230,'Ý„'=>220,'Ý…'=>230,'݆'=>220,'݇'=>230,'݈'=>220,'݉'=>230,'ÝŠ'=>230,'ß«'=>230,'߬'=>230,'ß­'=>230,'ß®'=>230,'߯'=>230,'ß°'=>230,'ß±'=>230,'ß²'=>220,'ß³'=>230,'़'=>7,'à¥'=>9,'॑'=>230,'॒'=>220,'॓'=>230,'॔'=>230,'়'=>7,'à§'=>9,'਼'=>7,'à©'=>9,'઼'=>7,'à«'=>9,'଼'=>7,'à­'=>9,'à¯'=>9,'à±'=>9,'ౕ'=>84,'à±–'=>91,'಼'=>7,'à³'=>9,'àµ'=>9,'à·Š'=>9,'ุ'=>103,'ู'=>103,'ฺ'=>9,'่'=>107,'้'=>107,'๊'=>107,'๋'=>107,'ຸ'=>118,'ູ'=>118,'່'=>122,'້'=>122,'໊'=>122,'໋'=>122,'༘'=>220,'༙'=>220,'༵'=>220,'༷'=>220,'༹'=>216,'ཱ'=>129,'ི'=>130,'ུ'=>132,'ེ'=>130,'ཻ'=>130,'ོ'=>130,'ཽ'=>130,'ྀ'=>130,'ྂ'=>230,'ྃ'=>230,'྄'=>9,'྆'=>230,'྇'=>230,'࿆'=>220,'့'=>7,'္'=>9,'áŸ'=>230,'᜔'=>9,'᜴'=>9,'្'=>9,'áŸ'=>230,'ᢩ'=>228,'᤹'=>222,'᤺'=>230,'᤻'=>220,'ᨗ'=>230,'ᨘ'=>220,'᬴'=>7,'á­„'=>9,'á­«'=>230,'á­¬'=>220,'á­­'=>230,'á­®'=>230,'á­¯'=>230,'á­°'=>230,'á­±'=>230,'á­²'=>230,'á­³'=>230,'á·€'=>230,'á·'=>230,'á·‚'=>220,'á·ƒ'=>230,'á·„'=>230,'á·…'=>230,'á·†'=>230,'á·‡'=>230,'á·ˆ'=>230,'á·‰'=>230,'á·Š'=>220,'á·¾'=>230,'á·¿'=>220,'âƒ'=>230,'⃑'=>230,'⃒'=>1,'⃓'=>1,'⃔'=>230,'⃕'=>230,'⃖'=>230,'⃗'=>230,'⃘'=>1,'⃙'=>1,'⃚'=>1,'⃛'=>230,'⃜'=>230,'⃡'=>230,'⃥'=>1,'⃦'=>1,'⃧'=>230,'⃨'=>220,'⃩'=>230,'⃪'=>1,'⃫'=>1,'⃬'=>220,'⃭'=>220,'⃮'=>220,'⃯'=>220,'〪'=>218,'〫'=>228,'〬'=>232,'〭'=>222,'〮'=>224,'〯'=>224,'ã‚™'=>8,'ã‚š'=>8,'ê †'=>9,'ﬞ'=>26,'︠'=>230,'︡'=>230,'︢'=>230,'︣'=>230,'ð¨'=>220,'ð¨'=>230,'ð¨¸'=>230,'ð¨¹'=>1,'ð¨º'=>220,'ð¨¿'=>9,'ð…¥'=>216,'ð…¦'=>216,'ð…§'=>1,'ð…¨'=>1,'ð…©'=>1,'ð…­'=>226,'ð…®'=>216,'ð…¯'=>216,'ð…°'=>216,'ð…±'=>216,'ð…²'=>216,'ð…»'=>220,'ð…¼'=>220,'ð…½'=>220,'ð…¾'=>220,'ð…¿'=>220,'ð†€'=>220,'ð†'=>220,'ð†‚'=>220,'ð†…'=>230,'ð††'=>230,'ð†‡'=>230,'ð†ˆ'=>230,'ð†‰'=>230,'ð†Š'=>220,'ð†‹'=>220,'ð†ª'=>230,'ð†«'=>230,'ð†¬'=>230,'ð†­'=>230,'ð‰‚'=>230,'ð‰ƒ'=>230,'ð‰„'=>230);
diff --git a/phpBB/includes/utf/utf_normalizer.php b/phpBB/includes/utf/utf_normalizer.php
deleted file mode 100644
index bbb23a6617..0000000000
--- a/phpBB/includes/utf/utf_normalizer.php
+++ /dev/null
@@ -1,1509 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Some Unicode characters encoded in UTF-8
-*
-* Preserved for compatibility
-*/
-define('UTF8_REPLACEMENT', "\xEF\xBF\xBD");
-define('UTF8_MAX', "\xF4\x8F\xBF\xBF");
-define('UTF8_FFFE', "\xEF\xBF\xBE");
-define('UTF8_FFFF', "\xEF\xBF\xBF");
-define('UTF8_SURROGATE_FIRST', "\xED\xA0\x80");
-define('UTF8_SURROGATE_LAST', "\xED\xBF\xBF");
-define('UTF8_HANGUL_FIRST', "\xEA\xB0\x80");
-define('UTF8_HANGUL_LAST', "\xED\x9E\xA3");
-
-define('UTF8_CJK_FIRST', "\xE4\xB8\x80");
-define('UTF8_CJK_LAST', "\xE9\xBE\xBB");
-define('UTF8_CJK_B_FIRST', "\xF0\xA0\x80\x80");
-define('UTF8_CJK_B_LAST', "\xF0\xAA\x9B\x96");
-
-// Unset global variables
-unset($GLOBALS['utf_jamo_index'], $GLOBALS['utf_jamo_type'], $GLOBALS['utf_nfc_qc'], $GLOBALS['utf_combining_class'], $GLOBALS['utf_canonical_comp'], $GLOBALS['utf_canonical_decomp'], $GLOBALS['utf_nfkc_qc'], $GLOBALS['utf_compatibility_decomp']);
-
-// NFC_QC and NFKC_QC values
-define('UNICODE_QC_MAYBE', 0);
-define('UNICODE_QC_NO', 1);
-
-// Contains all the ASCII characters appearing in UTF-8, sorted by frequency
-define('UTF8_ASCII_RANGE', "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F");
-
-// Contains all the tail bytes that can appear in the composition of a UTF-8 char
-define('UTF8_TRAILING_BYTES', "\xA9\xA0\xA8\x80\xAA\x99\xA7\xBB\xAB\x89\x94\x82\xB4\xA2\xAE\x83\xB0\xB9\xB8\x93\xAF\xBC\xB3\x81\xA4\xB2\x9C\xA1\xB5\xBE\xBD\xBA\x98\xAD\xB1\x84\x95\xA6\xB6\x88\x8D\x90\xB7\xBF\x92\x85\xA5\x97\x8C\x86\xA3\x8E\x9F\x8F\x87\x91\x9D\xAC\x9E\x8B\x96\x9B\x8A\x9A");
-
-// Constants used by the Hangul [de]composition algorithms
-define('UNICODE_HANGUL_SBASE', 0xAC00);
-define('UNICODE_HANGUL_LBASE', 0x1100);
-define('UNICODE_HANGUL_VBASE', 0x1161);
-define('UNICODE_HANGUL_TBASE', 0x11A7);
-define('UNICODE_HANGUL_SCOUNT', 11172);
-define('UNICODE_HANGUL_LCOUNT', 19);
-define('UNICODE_HANGUL_VCOUNT', 21);
-define('UNICODE_HANGUL_TCOUNT', 28);
-define('UNICODE_HANGUL_NCOUNT', 588);
-define('UNICODE_JAMO_L', 0);
-define('UNICODE_JAMO_V', 1);
-define('UNICODE_JAMO_T', 2);
-
-/**
-* Unicode normalization routines
-*/
-class utf_normalizer
-{
- /**
- * Validate, cleanup and normalize a string
- *
- * The ultimate convenience function! Clean up invalid UTF-8 sequences,
- * and convert to Normal Form C, canonical composition.
- *
- * @param string &$str The dirty string
- * @return string The same string, all shiny and cleaned-up
- */
- static function cleanup(&$str)
- {
- // The string below is the list of all autorized characters, sorted by frequency in latin text
- $pos = strspn($str, "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x0D");
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings with no special chars return immediately
- return;
- }
-
- // Note: we do not check for $GLOBALS['utf_canonical_decomp']. It is assumed they are always loaded together
- if (!isset($GLOBALS['utf_nfc_qc']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_nfc_qc.' . $phpEx);
- }
-
- if (!isset($GLOBALS['utf_canonical_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_canonical_decomp.' . $phpEx);
- }
-
- // Replace any byte in the range 0x00..0x1F, except for \r, \n and \t
- // We replace those characters with a 0xFF byte, which is illegal in UTF-8 and will in turn be replaced with a UTF replacement char
- $str = strtr(
- $str,
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
- );
-
- $str = utf_normalizer::recompose($str, $pos, $len, $GLOBALS['utf_nfc_qc'], $GLOBALS['utf_canonical_decomp']);
- }
-
- /**
- * Validate and normalize a UTF string to NFC
- *
- * @param string &$str Unchecked UTF string
- * @return string The string, validated and in normal form
- */
- static function nfc(&$str)
- {
- $pos = strspn($str, UTF8_ASCII_RANGE);
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings return immediately
- return;
- }
-
- if (!isset($GLOBALS['utf_nfc_qc']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_nfc_qc.' . $phpEx);
- }
-
- if (!isset($GLOBALS['utf_canonical_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_canonical_decomp.' . $phpEx);
- }
-
- $str = utf_normalizer::recompose($str, $pos, $len, $GLOBALS['utf_nfc_qc'], $GLOBALS['utf_canonical_decomp']);
- }
-
- /**
- * Validate and normalize a UTF string to NFKC
- *
- * @param string &$str Unchecked UTF string
- * @return string The string, validated and in normal form
- */
- static function nfkc(&$str)
- {
- $pos = strspn($str, UTF8_ASCII_RANGE);
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings return immediately
- return;
- }
-
- if (!isset($GLOBALS['utf_nfkc_qc']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_nfkc_qc.' . $phpEx);
- }
-
- if (!isset($GLOBALS['utf_compatibility_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_compatibility_decomp.' . $phpEx);
- }
-
- $str = utf_normalizer::recompose($str, $pos, $len, $GLOBALS['utf_nfkc_qc'], $GLOBALS['utf_compatibility_decomp']);
- }
-
- /**
- * Validate and normalize a UTF string to NFD
- *
- * @param string &$str Unchecked UTF string
- * @return string The string, validated and in normal form
- */
- static function nfd(&$str)
- {
- $pos = strspn($str, UTF8_ASCII_RANGE);
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings return immediately
- return;
- }
-
- if (!isset($GLOBALS['utf_canonical_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_canonical_decomp.' . $phpEx);
- }
-
- $str = utf_normalizer::decompose($str, $pos, $len, $GLOBALS['utf_canonical_decomp']);
- }
-
- /**
- * Validate and normalize a UTF string to NFKD
- *
- * @param string &$str Unchecked UTF string
- * @return string The string, validated and in normal form
- */
- static function nfkd(&$str)
- {
- $pos = strspn($str, UTF8_ASCII_RANGE);
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings return immediately
- return;
- }
-
- if (!isset($GLOBALS['utf_compatibility_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_compatibility_decomp.' . $phpEx);
- }
-
- $str = utf_normalizer::decompose($str, $pos, $len, $GLOBALS['utf_compatibility_decomp']);
- }
-
-
- /**
- * Recompose a UTF string
- *
- * @param string $str Unchecked UTF string
- * @param integer $pos Position of the first UTF char (in bytes)
- * @param integer $len Length of the string (in bytes)
- * @param array &$qc Quick-check array, passed by reference but never modified
- * @param array &$decomp_map Decomposition mapping, passed by reference but never modified
- * @return string The string, validated and recomposed
- *
- * @access private
- */
- static function recompose($str, $pos, $len, &$qc, &$decomp_map)
- {
- global $utf_combining_class, $utf_canonical_comp, $utf_jamo_type, $utf_jamo_index;
-
- // Load some commonly-used tables
- if (!isset($utf_jamo_index, $utf_jamo_type, $utf_combining_class))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_normalizer_common.' . $phpEx);
- }
-
- // Load the canonical composition table
- if (!isset($utf_canonical_comp))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_canonical_comp.' . $phpEx);
- }
-
- // Buffer the last ASCII char before the UTF-8 stuff if applicable
- $tmp = '';
- $i = $tmp_pos = $last_cc = 0;
-
- $buffer = ($pos) ? array(++$i => $str[$pos - 1]) : array();
-
- // UTF char length array
- // This array is used to determine the length of a UTF character.
- // Be $c the result of ($str[$pos] & "\xF0") --where $str is the string we're operating on and $pos
- // the position of the cursor--, if $utf_len_mask[$c] does not exist, the byte is an ASCII char.
- // Otherwise, if $utf_len_mask[$c] is greater than 0, we have a the leading byte of a multibyte character
- // whose length is $utf_len_mask[$c] and if it is equal to 0, the byte is a trailing byte.
- $utf_len_mask = array(
- // Leading bytes masks
- "\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4,
- // Trailing bytes masks
- "\x80" => 0, "\x90" => 0, "\xA0" => 0, "\xB0" => 0
- );
-
- $extra_check = array(
- "\xED" => 1, "\xEF" => 1, "\xC0" => 1, "\xC1" => 1, "\xE0" => 1, "\xF0" => 1,
- "\xF4" => 1, "\xF5" => 1, "\xF6" => 1, "\xF7" => 1, "\xF8" => 1, "\xF9" => 1,
- "\xFA" => 1, "\xFB" => 1, "\xFC" => 1, "\xFD" => 1, "\xFE" => 1, "\xFF" => 1
- );
-
- $utf_validation_mask = array(
- 2 => "\xE0\xC0",
- 3 => "\xF0\xC0\xC0",
- 4 => "\xF8\xC0\xC0\xC0"
- );
-
- $utf_validation_check = array(
- 2 => "\xC0\x80",
- 3 => "\xE0\x80\x80",
- 4 => "\xF0\x80\x80\x80"
- );
-
- // Main loop
- do
- {
- // STEP 0: Capture the current char and buffer it
- $c = $str[$pos];
- $c_mask = $c & "\xF0";
-
- if (isset($utf_len_mask[$c_mask]))
- {
- // Byte at $pos is either a leading byte or a missplaced trailing byte
- if ($utf_len = $utf_len_mask[$c_mask])
- {
- // Capture the char
- $buffer[++$i & 7] = $utf_char = substr($str, $pos, $utf_len);
-
- // Let's find out if a thorough check is needed
- if (isset($qc[$utf_char]))
- {
- // If the UTF char is in the qc array then it may not be in normal form. We do nothing here, the actual processing is below this "if" block
- }
- else if (isset($utf_combining_class[$utf_char]))
- {
- if ($utf_combining_class[$utf_char] < $last_cc)
- {
- // A combining character that is NOT canonically ordered
- }
- else
- {
- // A combining character that IS canonically ordered, skip to the next char
- $last_cc = $utf_combining_class[$utf_char];
-
- $pos += $utf_len;
- continue;
- }
- }
- else
- {
- // At this point, $utf_char holds a UTF char that we know is not a NF[K]C_QC and is not a combining character.
- // It can be a singleton, a canonical composite, a replacement char or an even an ill-formed bunch of bytes. Let's find out
- $last_cc = 0;
-
- // Check that we have the correct number of trailing bytes
- if (($utf_char & $utf_validation_mask[$utf_len]) != $utf_validation_check[$utf_len])
- {
- // Current char isn't well-formed or legal: either one or several trailing bytes are missing, or the Unicode char
- // has been encoded in a five- or six- byte sequence
- if ($utf_char[0] >= "\xF8")
- {
- if ($utf_char[0] < "\xFC")
- {
- $trailing_bytes = 4;
- }
- else if ($utf_char[0] > "\xFD")
- {
- $trailing_bytes = 0;
- }
- else
- {
- $trailing_bytes = 5;
- }
- }
- else
- {
- $trailing_bytes = $utf_len - 1;
- }
-
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT;
- $pos += strspn($str, UTF8_TRAILING_BYTES, ++$pos, $trailing_bytes);
- $tmp_pos = $pos;
-
- continue;
- }
-
- if (isset($extra_check[$c]))
- {
- switch ($c)
- {
- // Note: 0xED is quite common in Korean
- case "\xED":
- if ($utf_char >= "\xED\xA0\x80")
- {
- // Surrogates (U+D800..U+DFFF) are not allowed in UTF-8 (UTF sequence 0xEDA080..0xEDBFBF)
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT;
- $pos += $utf_len;
- $tmp_pos = $pos;
- continue 2;
- }
- break;
-
- // Note: 0xEF is quite common in Japanese
- case "\xEF":
- if ($utf_char == "\xEF\xBF\xBE" || $utf_char == "\xEF\xBF\xBF")
- {
- // U+FFFE and U+FFFF are explicitly disallowed (UTF sequence 0xEFBFBE..0xEFBFBF)
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT;
- $pos += $utf_len;
- $tmp_pos = $pos;
- continue 2;
- }
- break;
-
- case "\xC0":
- case "\xC1":
- if ($utf_char <= "\xC1\xBF")
- {
- // Overlong sequence: Unicode char U+0000..U+007F encoded as a double-byte UTF char
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT;
- $pos += $utf_len;
- $tmp_pos = $pos;
- continue 2;
- }
- break;
-
- case "\xE0":
- if ($utf_char <= "\xE0\x9F\xBF")
- {
- // Unicode char U+0000..U+07FF encoded in 3 bytes
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT;
- $pos += $utf_len;
- $tmp_pos = $pos;
- continue 2;
- }
- break;
-
- case "\xF0":
- if ($utf_char <= "\xF0\x8F\xBF\xBF")
- {
- // Unicode char U+0000..U+FFFF encoded in 4 bytes
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT;
- $pos += $utf_len;
- $tmp_pos = $pos;
- continue 2;
- }
- break;
-
- default:
- // Five- and six- byte sequences do not need being checked for here anymore
- if ($utf_char > UTF8_MAX)
- {
- // Out of the Unicode range
- if ($utf_char[0] < "\xF8")
- {
- $trailing_bytes = 3;
- }
- else if ($utf_char[0] < "\xFC")
- {
- $trailing_bytes = 4;
- }
- else if ($utf_char[0] > "\xFD")
- {
- $trailing_bytes = 0;
- }
- else
- {
- $trailing_bytes = 5;
- }
-
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT;
- $pos += strspn($str, UTF8_TRAILING_BYTES, ++$pos, $trailing_bytes);
- $tmp_pos = $pos;
- continue 2;
- }
- break;
- }
- }
-
- // The char is a valid starter, move the cursor and go on
- $pos += $utf_len;
- continue;
- }
- }
- else
- {
- // A trailing byte came out of nowhere, we will advance the cursor and treat the this byte and all following trailing bytes as if
- // each of them was a Unicode replacement char
- $spn = strspn($str, UTF8_TRAILING_BYTES, $pos);
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . str_repeat(UTF8_REPLACEMENT, $spn);
-
- $pos += $spn;
- $tmp_pos = $pos;
- continue;
- }
-
- // STEP 1: Decompose current char
-
- // We have found a character that is either:
- // - in the NFC_QC/NFKC_QC list
- // - a non-starter char that is not canonically ordered
- //
- // We are going to capture the shortest UTF sequence that satisfies these two conditions:
- //
- // 1 - If the sequence does not start at the begginning of the string, it must begin with a starter,
- // and that starter must not have the NF[K]C_QC property equal to "MAYBE"
- //
- // 2 - If the sequence does not end at the end of the string, it must end with a non-starter and be
- // immediately followed by a starter that is not on the QC list
- //
- $utf_seq = array();
- $last_cc = 0;
- $lpos = $pos;
- $pos += $utf_len;
-
- if (isset($decomp_map[$utf_char]))
- {
- $_pos = 0;
- $_len = strlen($decomp_map[$utf_char]);
-
- do
- {
- $_utf_len =& $utf_len_mask[$decomp_map[$utf_char][$_pos] & "\xF0"];
-
- if (isset($_utf_len))
- {
- $utf_seq[] = substr($decomp_map[$utf_char], $_pos, $_utf_len);
- $_pos += $_utf_len;
- }
- else
- {
- $utf_seq[] = $decomp_map[$utf_char][$_pos];
- ++$_pos;
- }
- }
- while ($_pos < $_len);
- }
- else
- {
- // The char is not decomposable
- $utf_seq = array($utf_char);
- }
-
- // STEP 2: Capture the starter
-
- // Check out the combining class of the first character of the UTF sequence
- $k = 0;
- if (isset($utf_combining_class[$utf_seq[0]]) || $qc[$utf_char] == UNICODE_QC_MAYBE)
- {
- // Not a starter, inspect previous characters
- // The last 8 characters are kept in a buffer so that we don't have to capture them everytime.
- // This is enough for all real-life strings but even if it wasn't, we can capture characters in backward mode,
- // although it is slower than this method.
- //
- // In the following loop, $j starts at the previous buffered character ($i - 1, because current character is
- // at offset $i) and process them in backward mode until we find a starter.
- //
- // $k is the index on each UTF character inside of our UTF sequence. At this time, $utf_seq contains one or more
- // characters numbered 0 to n. $k starts at 0 and for each char we prepend we pre-decrement it and for numbering
- $starter_found = 0;
- $j_min = max(1, $i - 7);
-
- for ($j = $i - 1; $j >= $j_min && $lpos > $tmp_pos; --$j)
- {
- $utf_char = $buffer[$j & 7];
- $lpos -= strlen($utf_char);
-
- if (isset($decomp_map[$utf_char]))
- {
- // The char is a composite, decompose for storage
- $decomp_seq = array();
- $_pos = 0;
- $_len = strlen($decomp_map[$utf_char]);
-
- do
- {
- $c = $decomp_map[$utf_char][$_pos];
- $_utf_len =& $utf_len_mask[$c & "\xF0"];
-
- if (isset($_utf_len))
- {
- $decomp_seq[] = substr($decomp_map[$utf_char], $_pos, $_utf_len);
- $_pos += $_utf_len;
- }
- else
- {
- $decomp_seq[] = $c;
- ++$_pos;
- }
- }
- while ($_pos < $_len);
-
- // Prepend the UTF sequence with our decomposed sequence
- if (isset($decomp_seq[1]))
- {
- // The char expanded into several chars
- $decomp_cnt = sizeof($decomp_seq);
-
- foreach ($decomp_seq as $decomp_i => $decomp_char)
- {
- $utf_seq[$k + $decomp_i - $decomp_cnt] = $decomp_char;
- }
- $k -= $decomp_cnt;
- }
- else
- {
- // Decomposed to a single char, easier to prepend
- $utf_seq[--$k] = $decomp_seq[0];
- }
- }
- else
- {
- $utf_seq[--$k] = $utf_char;
- }
-
- if (!isset($utf_combining_class[$utf_seq[$k]]))
- {
- // We have found our starter
- $starter_found = 1;
- break;
- }
- }
-
- if (!$starter_found && $lpos > $tmp_pos)
- {
- // The starter was not found in the buffer, let's rewind some more
- do
- {
- // $utf_len_mask contains the masks of both leading bytes and trailing bytes. If $utf_en > 0 then it's a leading byte, otherwise it's a trailing byte.
- $c = $str[--$lpos];
- $c_mask = $c & "\xF0";
-
- if (isset($utf_len_mask[$c_mask]))
- {
- // UTF byte
- if ($utf_len = $utf_len_mask[$c_mask])
- {
- // UTF *leading* byte
- $utf_char = substr($str, $lpos, $utf_len);
-
- if (isset($decomp_map[$utf_char]))
- {
- // Decompose the character
- $decomp_seq = array();
- $_pos = 0;
- $_len = strlen($decomp_map[$utf_char]);
-
- do
- {
- $c = $decomp_map[$utf_char][$_pos];
- $_utf_len =& $utf_len_mask[$c & "\xF0"];
-
- if (isset($_utf_len))
- {
- $decomp_seq[] = substr($decomp_map[$utf_char], $_pos, $_utf_len);
- $_pos += $_utf_len;
- }
- else
- {
- $decomp_seq[] = $c;
- ++$_pos;
- }
- }
- while ($_pos < $_len);
-
- // Prepend the UTF sequence with our decomposed sequence
- if (isset($decomp_seq[1]))
- {
- // The char expanded into several chars
- $decomp_cnt = sizeof($decomp_seq);
- foreach ($decomp_seq as $decomp_i => $utf_char)
- {
- $utf_seq[$k + $decomp_i - $decomp_cnt] = $utf_char;
- }
- $k -= $decomp_cnt;
- }
- else
- {
- // Decomposed to a single char, easier to prepend
- $utf_seq[--$k] = $decomp_seq[0];
- }
- }
- else
- {
- $utf_seq[--$k] = $utf_char;
- }
- }
- }
- else
- {
- // ASCII char
- $utf_seq[--$k] = $c;
- }
- }
- while ($lpos > $tmp_pos);
- }
- }
-
- // STEP 3: Capture following combining modifiers
-
- while ($pos < $len)
- {
- $c_mask = $str[$pos] & "\xF0";
-
- if (isset($utf_len_mask[$c_mask]))
- {
- if ($utf_len = $utf_len_mask[$c_mask])
- {
- $utf_char = substr($str, $pos, $utf_len);
- }
- else
- {
- // A trailing byte came out of nowhere
- // Trailing bytes are replaced with Unicode replacement chars, we will just ignore it for now, break out of the loop
- // as if it was a starter (replacement chars ARE starters) and let the next loop replace it
- break;
- }
-
- if (isset($utf_combining_class[$utf_char]) || isset($qc[$utf_char]))
- {
- // Combining character, add it to the sequence and move the cursor
- if (isset($decomp_map[$utf_char]))
- {
- // Decompose the character
- $_pos = 0;
- $_len = strlen($decomp_map[$utf_char]);
-
- do
- {
- $c = $decomp_map[$utf_char][$_pos];
- $_utf_len =& $utf_len_mask[$c & "\xF0"];
-
- if (isset($_utf_len))
- {
- $utf_seq[] = substr($decomp_map[$utf_char], $_pos, $_utf_len);
- $_pos += $_utf_len;
- }
- else
- {
- $utf_seq[] = $c;
- ++$_pos;
- }
- }
- while ($_pos < $_len);
- }
- else
- {
- $utf_seq[] = $utf_char;
- }
-
- $pos += $utf_len;
- }
- else
- {
- // Combining class 0 and no QC, break out of the loop
- // Note: we do not know if that character is valid. If it's not, the next iteration will replace it
- break;
- }
- }
- else
- {
- // ASCII chars are starters
- break;
- }
- }
-
- // STEP 4: Sort and combine
-
- // Here we sort...
- $k_max = $k + sizeof($utf_seq);
-
- if (!$k && $k_max == 1)
- {
- // There is only one char in the UTF sequence, add it then jump to the next iteration of main loop
- // Note: the two commented lines below can be enabled under PHP5 for a very small performance gain in most cases
-// if (substr_compare($str, $utf_seq[0], $lpos, $pos - $lpos))
-// {
- $tmp .= substr($str, $tmp_pos, $lpos - $tmp_pos) . $utf_seq[0];
- $tmp_pos = $pos;
-// }
-
- continue;
- }
-
- // ...there we combine
- if (isset($utf_combining_class[$utf_seq[$k]]))
- {
- $starter = $nf_seq = '';
- }
- else
- {
- $starter = $utf_seq[$k++];
- $nf_seq = '';
- }
- $utf_sort = array();
-
- // We add an empty char at the end of the UTF char sequence. It will act as a starter and trigger the sort/combine routine
- // at the end of the string without altering it
- $utf_seq[] = '';
-
- do
- {
- $utf_char = $utf_seq[$k++];
-
- if (isset($utf_combining_class[$utf_char]))
- {
- $utf_sort[$utf_combining_class[$utf_char]][] = $utf_char;
- }
- else
- {
- if (empty($utf_sort))
- {
- // No combining characters... check for a composite of the two starters
- if (isset($utf_canonical_comp[$starter . $utf_char]))
- {
- // Good ol' composite character
- $starter = $utf_canonical_comp[$starter . $utf_char];
- }
- else if (isset($utf_jamo_type[$utf_char]))
- {
- // Current char is a composable jamo
- if (isset($utf_jamo_type[$starter]) && $utf_jamo_type[$starter] == UNICODE_JAMO_L && $utf_jamo_type[$utf_char] == UNICODE_JAMO_V)
- {
- // We have a L jamo followed by a V jamo, we are going to prefetch the next char to see if it's a T jamo
- if (isset($utf_jamo_type[$utf_seq[$k]]) && $utf_jamo_type[$utf_seq[$k]] == UNICODE_JAMO_T)
- {
- // L+V+T jamos, combine to a LVT Hangul syllable ($k is incremented)
- $cp = $utf_jamo_index[$starter] + $utf_jamo_index[$utf_char] + $utf_jamo_index[$utf_seq[$k]];
- ++$k;
- }
- else
- {
- // L+V jamos, combine to a LV Hangul syllable
- $cp = $utf_jamo_index[$starter] + $utf_jamo_index[$utf_char];
- }
-
- $starter = chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
- }
- else
- {
- // Non-composable jamo, just add it to the sequence
- $nf_seq .= $starter;
- $starter = $utf_char;
- }
- }
- else
- {
- // No composite, just add the first starter to the sequence then continue with the other one
- $nf_seq .= $starter;
- $starter = $utf_char;
- }
- }
- else
- {
- ksort($utf_sort);
-
- // For each class of combining characters
- foreach ($utf_sort as $cc => $utf_chars)
- {
- $j = 0;
-
- do
- {
- // Look for a composite
- if (isset($utf_canonical_comp[$starter . $utf_chars[$j]]))
- {
- // Found a composite, replace the starter
- $starter = $utf_canonical_comp[$starter . $utf_chars[$j]];
- unset($utf_sort[$cc][$j]);
- }
- else
- {
- // No composite, all following characters in that class are blocked
- break;
- }
- }
- while (isset($utf_sort[$cc][++$j]));
- }
-
- // Add the starter to the normalized sequence, followed by non-starters in canonical order
- $nf_seq .= $starter;
-
- foreach ($utf_sort as $utf_chars)
- {
- if (!empty($utf_chars))
- {
- $nf_seq .= implode('', $utf_chars);
- }
- }
-
- // Reset the array and go on
- $utf_sort = array();
- $starter = $utf_char;
- }
- }
- }
- while ($k <= $k_max);
-
- $tmp .= substr($str, $tmp_pos, $lpos - $tmp_pos) . $nf_seq;
- $tmp_pos = $pos;
- }
- else
- {
- // Only a ASCII char can make the program get here
- //
- // First we skip the current byte with ++$pos, then we quickly skip following ASCII chars with strspn().
- //
- // The first two "if"'s here can be removed, with the consequences of being faster on latin text (lots of ASCII) and slower on
- // multi-byte text (where the only ASCII chars are spaces and punctuation)
- if (++$pos != $len)
- {
- if ($str[$pos] < "\x80")
- {
- $pos += strspn($str, UTF8_ASCII_RANGE, ++$pos);
- $buffer[++$i & 7] = $str[$pos - 1];
- }
- else
- {
- $buffer[++$i & 7] = $c;
- }
- }
- }
- }
- while ($pos < $len);
-
- // Now is time to return the string
- if ($tmp_pos)
- {
- // If the $tmp_pos cursor is not at the beggining of the string then at least one character was not in normal form. Replace $str with the fixed version
- if ($tmp_pos == $len)
- {
- // The $tmp_pos cursor is at the end of $str, therefore $tmp holds the whole $str
- return $tmp;
- }
- else
- {
- // The rightmost chunk of $str has not been appended to $tmp yet
- return $tmp . substr($str, $tmp_pos);
- }
- }
-
- // The string was already in normal form
- return $str;
- }
-
- /**
- * Decompose a UTF string
- *
- * @param string $str UTF string
- * @param integer $pos Position of the first UTF char (in bytes)
- * @param integer $len Length of the string (in bytes)
- * @param array &$decomp_map Decomposition mapping, passed by reference but never modified
- * @return string The string, decomposed and sorted canonically
- *
- * @access private
- */
- static function decompose($str, $pos, $len, &$decomp_map)
- {
- global $utf_combining_class;
-
- // Load some commonly-used tables
- if (!isset($utf_combining_class))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_normalizer_common.' . $phpEx);
- }
-
- // UTF char length array
- $utf_len_mask = array(
- // Leading bytes masks
- "\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4,
- // Trailing bytes masks
- "\x80" => 0, "\x90" => 0, "\xA0" => 0, "\xB0" => 0
- );
-
- // Some extra checks are triggered on the first byte of a UTF sequence
- $extra_check = array(
- "\xED" => 1, "\xEF" => 1, "\xC0" => 1, "\xC1" => 1, "\xE0" => 1, "\xF0" => 1,
- "\xF4" => 1, "\xF5" => 1, "\xF6" => 1, "\xF7" => 1, "\xF8" => 1, "\xF9" => 1,
- "\xFA" => 1, "\xFB" => 1, "\xFC" => 1, "\xFD" => 1, "\xFE" => 1, "\xFF" => 1
- );
-
- // These masks are used to check if a UTF sequence is well formed. Here are the only 3 lengths we acknowledge:
- // - 2-byte: 110? ???? 10?? ????
- // - 3-byte: 1110 ???? 10?? ???? 10?? ????
- // - 4-byte: 1111 0??? 10?? ???? 10?? ???? 10?? ????
- // Note that 5- and 6- byte sequences are automatically discarded
- $utf_validation_mask = array(
- 2 => "\xE0\xC0",
- 3 => "\xF0\xC0\xC0",
- 4 => "\xF8\xC0\xC0\xC0"
- );
-
- $utf_validation_check = array(
- 2 => "\xC0\x80",
- 3 => "\xE0\x80\x80",
- 4 => "\xF0\x80\x80\x80"
- );
-
- $tmp = '';
- $starter_pos = $pos;
- $tmp_pos = $last_cc = $sort = $dump = 0;
- $utf_sort = array();
-
- // Main loop
- do
- {
- // STEP 0: Capture the current char
-
- $cur_mask = $str[$pos] & "\xF0";
- if (isset($utf_len_mask[$cur_mask]))
- {
- if ($utf_len = $utf_len_mask[$cur_mask])
- {
- // Multibyte char
- $utf_char = substr($str, $pos, $utf_len);
- $pos += $utf_len;
- }
- else
- {
- // A trailing byte came out of nowhere, we will treat it and all following trailing bytes as if each of them was a Unicode
- // replacement char and we will advance the cursor
- $spn = strspn($str, UTF8_TRAILING_BYTES, $pos);
-
- if ($dump)
- {
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- // Dump combiners
- if (!empty($utf_sort))
- {
- if ($sort)
- {
- ksort($utf_sort);
- }
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- }
-
- $tmp .= str_repeat(UTF8_REPLACEMENT, $spn);
- $dump = $sort = 0;
- }
- else
- {
- $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . str_repeat(UTF8_REPLACEMENT, $spn);
- }
-
- $pos += $spn;
- $tmp_pos = $starter_pos = $pos;
-
- $utf_sort = array();
- $last_cc = 0;
-
- continue;
- }
-
- // STEP 1: Decide what to do with current char
-
- // Now, in that order:
- // - check if that character is decomposable
- // - check if that character is a non-starter
- // - check if that character requires extra checks to be performed
- if (isset($decomp_map[$utf_char]))
- {
- // Decompose the char
- $_pos = 0;
- $_len = strlen($decomp_map[$utf_char]);
-
- do
- {
- $c = $decomp_map[$utf_char][$_pos];
- $_utf_len =& $utf_len_mask[$c & "\xF0"];
-
- if (isset($_utf_len))
- {
- $_utf_char = substr($decomp_map[$utf_char], $_pos, $_utf_len);
- $_pos += $_utf_len;
-
- if (isset($utf_combining_class[$_utf_char]))
- {
- // The character decomposed to a non-starter, buffer it for sorting
- $utf_sort[$utf_combining_class[$_utf_char]][] = $_utf_char;
-
- if ($utf_combining_class[$_utf_char] < $last_cc)
- {
- // Not canonically ordered, will require sorting
- $sort = $dump = 1;
- }
- else
- {
- $dump = 1;
- $last_cc = $utf_combining_class[$_utf_char];
- }
- }
- else
- {
- // This character decomposition contains a starter, dump the buffer and continue
- if ($dump)
- {
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- // Dump combiners
- if (!empty($utf_sort))
- {
- if ($sort)
- {
- ksort($utf_sort);
- }
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- }
-
- $tmp .= $_utf_char;
- $dump = $sort = 0;
- }
- else
- {
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos) . $_utf_char;
- }
-
- $tmp_pos = $starter_pos = $pos;
- $utf_sort = array();
- $last_cc = 0;
- }
- }
- else
- {
- // This character decomposition contains an ASCII char, which is a starter. Dump the buffer and continue
- ++$_pos;
-
- if ($dump)
- {
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- // Dump combiners
- if (!empty($utf_sort))
- {
- if ($sort)
- {
- ksort($utf_sort);
- }
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- }
-
- $tmp .= $c;
- $dump = $sort = 0;
- }
- else
- {
- $tmp .= substr($str, $tmp_pos, $pos - $utf_len - $tmp_pos) . $c;
- }
-
- $tmp_pos = $starter_pos = $pos;
- $utf_sort = array();
- $last_cc = 0;
- }
- }
- while ($_pos < $_len);
- }
- else if (isset($utf_combining_class[$utf_char]))
- {
- // Combining character
- if ($utf_combining_class[$utf_char] < $last_cc)
- {
- // Not in canonical order
- $sort = $dump = 1;
- }
- else
- {
- $last_cc = $utf_combining_class[$utf_char];
- }
-
- $utf_sort[$utf_combining_class[$utf_char]][] = $utf_char;
- }
- else
- {
- // Non-decomposable starter, check out if it's a Hangul syllable
- if ($utf_char < UTF8_HANGUL_FIRST || $utf_char > UTF8_HANGUL_LAST)
- {
- // Nope, regular UTF char, check that we have the correct number of trailing bytes
- if (($utf_char & $utf_validation_mask[$utf_len]) != $utf_validation_check[$utf_len])
- {
- // Current char isn't well-formed or legal: either one or several trailing bytes are missing, or the Unicode char
- // has been encoded in a five- or six- byte sequence.
- // Move the cursor back to its original position then advance it to the position it should really be at
- $pos -= $utf_len;
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- if (!empty($utf_sort))
- {
- ksort($utf_sort);
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- $utf_sort = array();
- }
-
- // Add a replacement char then another replacement char for every trailing byte.
- //
- // @todo I'm not entirely sure that's how we're supposed to mark invalidated byte sequences, check this
- $spn = strspn($str, UTF8_TRAILING_BYTES, ++$pos);
- $tmp .= str_repeat(UTF8_REPLACEMENT, $spn + 1);
-
- $dump = $sort = 0;
-
- $pos += $spn;
- $tmp_pos = $pos;
- continue;
- }
-
- if (isset($extra_check[$utf_char[0]]))
- {
- switch ($utf_char[0])
- {
- // Note: 0xED is quite common in Korean
- case "\xED":
- if ($utf_char >= "\xED\xA0\x80")
- {
- // Surrogates (U+D800..U+DFFF) are not allowed in UTF-8 (UTF sequence 0xEDA080..0xEDBFBF)
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- if (!empty($utf_sort))
- {
- ksort($utf_sort);
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- $utf_sort = array();
- }
-
- $tmp .= UTF8_REPLACEMENT;
- $dump = $sort = 0;
-
- $tmp_pos = $starter_pos = $pos;
- continue 2;
- }
- break;
-
- // Note: 0xEF is quite common in Japanese
- case "\xEF":
- if ($utf_char == "\xEF\xBF\xBE" || $utf_char == "\xEF\xBF\xBF")
- {
- // U+FFFE and U+FFFF are explicitly disallowed (UTF sequence 0xEFBFBE..0xEFBFBF)
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- if (!empty($utf_sort))
- {
- ksort($utf_sort);
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- $utf_sort = array();
- }
-
- $tmp .= UTF8_REPLACEMENT;
- $dump = $sort = 0;
-
- $tmp_pos = $starter_pos = $pos;
- continue 2;
- }
- break;
-
- case "\xC0":
- case "\xC1":
- if ($utf_char <= "\xC1\xBF")
- {
- // Overlong sequence: Unicode char U+0000..U+007F encoded as a double-byte UTF char
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- if (!empty($utf_sort))
- {
- ksort($utf_sort);
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- $utf_sort = array();
- }
-
- $tmp .= UTF8_REPLACEMENT;
- $dump = $sort = 0;
-
- $tmp_pos = $starter_pos = $pos;
- continue 2;
- }
- break;
-
- case "\xE0":
- if ($utf_char <= "\xE0\x9F\xBF")
- {
- // Unicode char U+0000..U+07FF encoded in 3 bytes
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- if (!empty($utf_sort))
- {
- ksort($utf_sort);
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- $utf_sort = array();
- }
-
- $tmp .= UTF8_REPLACEMENT;
- $dump = $sort = 0;
-
- $tmp_pos = $starter_pos = $pos;
- continue 2;
- }
- break;
-
- case "\xF0":
- if ($utf_char <= "\xF0\x8F\xBF\xBF")
- {
- // Unicode char U+0000..U+FFFF encoded in 4 bytes
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- if (!empty($utf_sort))
- {
- ksort($utf_sort);
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- $utf_sort = array();
- }
-
- $tmp .= UTF8_REPLACEMENT;
- $dump = $sort = 0;
-
- $tmp_pos = $starter_pos = $pos;
- continue 2;
- }
- break;
-
- default:
- if ($utf_char > UTF8_MAX)
- {
- // Out of the Unicode range
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- if (!empty($utf_sort))
- {
- ksort($utf_sort);
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- $utf_sort = array();
- }
-
- $tmp .= UTF8_REPLACEMENT;
- $dump = $sort = 0;
-
- $tmp_pos = $starter_pos = $pos;
- continue 2;
- }
- break;
- }
- }
- }
- else
- {
- // Hangul syllable
- $idx = (((ord($utf_char[0]) & 0x0F) << 12) | ((ord($utf_char[1]) & 0x3F) << 6) | (ord($utf_char[2]) & 0x3F)) - UNICODE_HANGUL_SBASE;
-
- // LIndex can only range from 0 to 18, therefore it cannot influence the first two bytes of the L Jamo, which allows us to hardcode them (based on LBase).
- //
- // The same goes for VIndex, but for TIndex there's a catch: the value of the third byte could exceed 0xBF and we would have to increment the second byte
- if ($t_index = $idx % UNICODE_HANGUL_TCOUNT)
- {
- if ($t_index < 25)
- {
- $utf_char = "\xE1\x84\x00\xE1\x85\x00\xE1\x86\x00";
- $utf_char[8] = chr(0xA7 + $t_index);
- }
- else
- {
- $utf_char = "\xE1\x84\x00\xE1\x85\x00\xE1\x87\x00";
- $utf_char[8] = chr(0x67 + $t_index);
- }
- }
- else
- {
- $utf_char = "\xE1\x84\x00\xE1\x85\x00";
- }
-
- $utf_char[2] = chr(0x80 + (int) ($idx / UNICODE_HANGUL_NCOUNT));
- $utf_char[5] = chr(0xA1 + (int) (($idx % UNICODE_HANGUL_NCOUNT) / UNICODE_HANGUL_TCOUNT));
-
- // Just like other decompositions, the resulting Jamos must be dumped to the tmp string
- $dump = 1;
- }
-
- // Do we need to dump stuff to the tmp string?
- if ($dump)
- {
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- // Dump combiners
- if (!empty($utf_sort))
- {
- if ($sort)
- {
- ksort($utf_sort);
- }
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- }
-
- $tmp .= $utf_char;
- $dump = $sort = 0;
- $tmp_pos = $pos;
- }
-
- $last_cc = 0;
- $utf_sort = array();
- $starter_pos = $pos;
- }
- }
- else
- {
- // ASCII char, which happens to be a starter (as any other ASCII char)
- if ($dump)
- {
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- // Dump combiners
- if (!empty($utf_sort))
- {
- if ($sort)
- {
- ksort($utf_sort);
- }
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- }
-
- $tmp .= $str[$pos];
- $dump = $sort = 0;
- $tmp_pos = ++$pos;
-
- $pos += strspn($str, UTF8_ASCII_RANGE, $pos);
- }
- else
- {
- $pos += strspn($str, UTF8_ASCII_RANGE, ++$pos);
- }
-
- $last_cc = 0;
- $utf_sort = array();
- $starter_pos = $pos;
- }
- }
- while ($pos < $len);
-
- // Now is time to return the string
- if ($dump)
- {
- $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos);
-
- // Dump combiners
- if (!empty($utf_sort))
- {
- if ($sort)
- {
- ksort($utf_sort);
- }
-
- foreach ($utf_sort as $utf_chars)
- {
- $tmp .= implode('', $utf_chars);
- }
- }
-
- return $tmp;
- }
- else if ($tmp_pos)
- {
- // If the $tmp_pos cursor was moved then at least one character was not in normal form. Replace $str with the fixed version
- if ($tmp_pos == $len)
- {
- // The $tmp_pos cursor is at the end of $str, therefore $tmp holds the whole $str
- return $tmp;
- }
- else
- {
- // The rightmost chunk of $str has not been appended to $tmp yet
- return $tmp . substr($str, $tmp_pos);
- }
- }
-
- // The string was already in normal form
- return $str;
- }
-}
diff --git a/phpBB/includes/utf/utf_tools.php b/phpBB/includes/utf/utf_tools.php
index e60a40a195..bb155aeae5 100644
--- a/phpBB/includes/utf/utf_tools.php
+++ b/phpBB/includes/utf/utf_tools.php
@@ -22,6 +22,13 @@ if (!defined('IN_PHPBB'))
setlocale(LC_CTYPE, 'C');
/**
+* Setup the UTF-8 portability layer
+*/
+Patchwork\Utf8\Bootup::initUtf8Encode();
+Patchwork\Utf8\Bootup::initMbstring();
+Patchwork\Utf8\Bootup::initIntl();
+
+/**
* UTF-8 tools
*
* Whenever possible, these functions will try to use PHP's built-in functions or
@@ -29,544 +36,85 @@ setlocale(LC_CTYPE, 'C');
*
*/
-if (!extension_loaded('xml'))
-{
- /**
- * Implementation of PHP's native utf8_encode for people without XML support
- * This function exploits some nice things that ISO-8859-1 and UTF-8 have in common
- *
- * @param string $str ISO-8859-1 encoded data
- * @return string UTF-8 encoded data
- */
- function utf8_encode($str)
- {
- $out = '';
- for ($i = 0, $len = strlen($str); $i < $len; $i++)
- {
- $letter = $str[$i];
- $num = ord($letter);
- if ($num < 0x80)
- {
- $out .= $letter;
- }
- else if ($num < 0xC0)
- {
- $out .= "\xC2" . $letter;
- }
- else
- {
- $out .= "\xC3" . chr($num - 64);
- }
- }
- return $out;
- }
-
- /**
- * Implementation of PHP's native utf8_decode for people without XML support
- *
- * @param string $str UTF-8 encoded data
- * @return string ISO-8859-1 encoded data
- */
- function utf8_decode($str)
- {
- $pos = 0;
- $len = strlen($str);
- $ret = '';
-
- while ($pos < $len)
- {
- $ord = ord($str[$pos]) & 0xF0;
- if ($ord === 0xC0 || $ord === 0xD0)
- {
- $charval = ((ord($str[$pos]) & 0x1F) << 6) | (ord($str[$pos + 1]) & 0x3F);
- $pos += 2;
- $ret .= (($charval < 256) ? chr($charval) : '?');
- }
- else if ($ord === 0xE0)
- {
- $ret .= '?';
- $pos += 3;
- }
- else if ($ord === 0xF0)
- {
- $ret .= '?';
- $pos += 4;
- }
- else
- {
- $ret .= $str[$pos];
- ++$pos;
- }
- }
- return $ret;
- }
-}
-
-// mbstring is old and has it's functions around for older versions of PHP.
-// if mbstring is not loaded, we go into native mode.
-if (extension_loaded('mbstring'))
+/**
+* UTF-8 aware alternative to strrpos
+* @ignore
+*/
+function utf8_strrpos($str, $needle, $offset = null)
{
- mb_internal_encoding('UTF-8');
-
- /**
- * UTF-8 aware alternative to strrpos
- * Find position of last occurrence of a char in a string
- */
- /**
- * UTF-8 aware alternative to strrpos
- * @ignore
- */
- function utf8_strrpos($str, $needle, $offset = null)
- {
- // Emulate behaviour of strrpos rather than raising warning
- if (empty($str))
- {
- return false;
- }
-
- if (is_null($offset))
- {
- return mb_strrpos($str, $needle);
- }
- else
- {
- return mb_strrpos($str, $needle, $offset);
- }
- }
-
- /**
- * UTF-8 aware alternative to strpos
- * @ignore
- */
- function utf8_strpos($str, $needle, $offset = null)
+ // Emulate behaviour of strrpos rather than raising warning
+ if (empty($str))
{
- if (is_null($offset))
- {
- return mb_strpos($str, $needle);
- }
- else
- {
- return mb_strpos($str, $needle, $offset);
- }
+ return false;
}
- /**
- * UTF-8 aware alternative to strtolower
- * @ignore
- */
- function utf8_strtolower($str)
+ if (is_null($offset))
{
- return mb_strtolower($str);
+ return mb_strrpos($str, $needle);
}
-
- /**
- * UTF-8 aware alternative to strtoupper
- * @ignore
- */
- function utf8_strtoupper($str)
+ else
{
- return mb_strtoupper($str);
+ return mb_strrpos($str, $needle, $offset);
}
+}
- /**
- * UTF-8 aware alternative to substr
- * @ignore
- */
- function utf8_substr($str, $offset, $length = null)
+/**
+* UTF-8 aware alternative to strpos
+* @ignore
+*/
+function utf8_strpos($str, $needle, $offset = null)
+{
+ if (is_null($offset))
{
- if (is_null($length))
- {
- return mb_substr($str, $offset);
- }
- else
- {
- return mb_substr($str, $offset, $length);
- }
+ return mb_strpos($str, $needle);
}
-
- /**
- * Return the length (in characters) of a UTF-8 string
- * @ignore
- */
- function utf8_strlen($text)
+ else
{
- return mb_strlen($text, 'utf-8');
+ return mb_strpos($str, $needle, $offset);
}
}
-else
-{
- /**
- * UTF-8 aware alternative to strrpos
- * Find position of last occurrence of a char in a string
- *
- * @author Harry Fuecks
- * @param string $str haystack
- * @param string $needle needle
- * @param integer $offset (optional) offset (from left)
- * @return mixed integer position or FALSE on failure
- */
- function utf8_strrpos($str, $needle, $offset = null)
- {
- if (is_null($offset))
- {
- $ar = explode($needle, $str);
-
- if (sizeof($ar) > 1)
- {
- // Pop off the end of the string where the last match was made
- array_pop($ar);
- $str = join($needle, $ar);
-
- return utf8_strlen($str);
- }
- return false;
- }
- else
- {
- if (!is_int($offset))
- {
- trigger_error('utf8_strrpos expects parameter 3 to be long', E_USER_ERROR);
- return false;
- }
-
- $str = utf8_substr($str, $offset);
-
- if (false !== ($pos = utf8_strrpos($str, $needle)))
- {
- return $pos + $offset;
- }
-
- return false;
- }
- }
- /**
- * UTF-8 aware alternative to strpos
- * Find position of first occurrence of a string
- *
- * @author Harry Fuecks
- * @param string $str haystack
- * @param string $needle needle
- * @param integer $offset offset in characters (from left)
- * @return mixed integer position or FALSE on failure
- */
- function utf8_strpos($str, $needle, $offset = null)
- {
- if (is_null($offset))
- {
- $ar = explode($needle, $str);
- if (sizeof($ar) > 1)
- {
- return utf8_strlen($ar[0]);
- }
- return false;
- }
- else
- {
- if (!is_int($offset))
- {
- trigger_error('utf8_strpos: Offset must be an integer', E_USER_ERROR);
- return false;
- }
-
- $str = utf8_substr($str, $offset);
-
- if (false !== ($pos = utf8_strpos($str, $needle)))
- {
- return $pos + $offset;
- }
+/**
+* UTF-8 aware alternative to strtolower
+* @ignore
+*/
+function utf8_strtolower($str)
+{
+ return mb_strtolower($str);
+}
- return false;
- }
- }
+/**
+* UTF-8 aware alternative to strtoupper
+* @ignore
+*/
+function utf8_strtoupper($str)
+{
+ return mb_strtoupper($str);
+}
- /**
- * UTF-8 aware alternative to strtolower
- * Make a string lowercase
- * Note: The concept of a characters "case" only exists is some alphabets
- * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
- * not exist in the Chinese alphabet, for example. See Unicode Standard
- * Annex #21: Case Mappings
- *
- * @param string
- * @return string string in lowercase
- */
- function utf8_strtolower($string)
+/**
+* UTF-8 aware alternative to substr
+* @ignore
+*/
+function utf8_substr($str, $offset, $length = null)
+{
+ if (is_null($length))
{
- static $utf8_upper_to_lower = array(
- "\xC3\x80" => "\xC3\xA0", "\xC3\x81" => "\xC3\xA1",
- "\xC3\x82" => "\xC3\xA2", "\xC3\x83" => "\xC3\xA3", "\xC3\x84" => "\xC3\xA4", "\xC3\x85" => "\xC3\xA5",
- "\xC3\x86" => "\xC3\xA6", "\xC3\x87" => "\xC3\xA7", "\xC3\x88" => "\xC3\xA8", "\xC3\x89" => "\xC3\xA9",
- "\xC3\x8A" => "\xC3\xAA", "\xC3\x8B" => "\xC3\xAB", "\xC3\x8C" => "\xC3\xAC", "\xC3\x8D" => "\xC3\xAD",
- "\xC3\x8E" => "\xC3\xAE", "\xC3\x8F" => "\xC3\xAF", "\xC3\x90" => "\xC3\xB0", "\xC3\x91" => "\xC3\xB1",
- "\xC3\x92" => "\xC3\xB2", "\xC3\x93" => "\xC3\xB3", "\xC3\x94" => "\xC3\xB4", "\xC3\x95" => "\xC3\xB5",
- "\xC3\x96" => "\xC3\xB6", "\xC3\x98" => "\xC3\xB8", "\xC3\x99" => "\xC3\xB9", "\xC3\x9A" => "\xC3\xBA",
- "\xC3\x9B" => "\xC3\xBB", "\xC3\x9C" => "\xC3\xBC", "\xC3\x9D" => "\xC3\xBD", "\xC3\x9E" => "\xC3\xBE",
- "\xC4\x80" => "\xC4\x81", "\xC4\x82" => "\xC4\x83", "\xC4\x84" => "\xC4\x85", "\xC4\x86" => "\xC4\x87",
- "\xC4\x88" => "\xC4\x89", "\xC4\x8A" => "\xC4\x8B", "\xC4\x8C" => "\xC4\x8D", "\xC4\x8E" => "\xC4\x8F",
- "\xC4\x90" => "\xC4\x91", "\xC4\x92" => "\xC4\x93", "\xC4\x96" => "\xC4\x97", "\xC4\x98" => "\xC4\x99",
- "\xC4\x9A" => "\xC4\x9B", "\xC4\x9C" => "\xC4\x9D", "\xC4\x9E" => "\xC4\x9F", "\xC4\xA0" => "\xC4\xA1",
- "\xC4\xA2" => "\xC4\xA3", "\xC4\xA4" => "\xC4\xA5", "\xC4\xA6" => "\xC4\xA7", "\xC4\xA8" => "\xC4\xA9",
- "\xC4\xAA" => "\xC4\xAB", "\xC4\xAE" => "\xC4\xAF", "\xC4\xB4" => "\xC4\xB5", "\xC4\xB6" => "\xC4\xB7",
- "\xC4\xB9" => "\xC4\xBA", "\xC4\xBB" => "\xC4\xBC", "\xC4\xBD" => "\xC4\xBE", "\xC5\x81" => "\xC5\x82",
- "\xC5\x83" => "\xC5\x84", "\xC5\x85" => "\xC5\x86", "\xC5\x87" => "\xC5\x88", "\xC5\x8A" => "\xC5\x8B",
- "\xC5\x8C" => "\xC5\x8D", "\xC5\x90" => "\xC5\x91", "\xC5\x94" => "\xC5\x95", "\xC5\x96" => "\xC5\x97",
- "\xC5\x98" => "\xC5\x99", "\xC5\x9A" => "\xC5\x9B", "\xC5\x9C" => "\xC5\x9D", "\xC5\x9E" => "\xC5\x9F",
- "\xC5\xA0" => "\xC5\xA1", "\xC5\xA2" => "\xC5\xA3", "\xC5\xA4" => "\xC5\xA5", "\xC5\xA6" => "\xC5\xA7",
- "\xC5\xA8" => "\xC5\xA9", "\xC5\xAA" => "\xC5\xAB", "\xC5\xAC" => "\xC5\xAD", "\xC5\xAE" => "\xC5\xAF",
- "\xC5\xB0" => "\xC5\xB1", "\xC5\xB2" => "\xC5\xB3", "\xC5\xB4" => "\xC5\xB5", "\xC5\xB6" => "\xC5\xB7",
- "\xC5\xB8" => "\xC3\xBF", "\xC5\xB9" => "\xC5\xBA", "\xC5\xBB" => "\xC5\xBC", "\xC5\xBD" => "\xC5\xBE",
- "\xC6\xA0" => "\xC6\xA1", "\xC6\xAF" => "\xC6\xB0", "\xC8\x98" => "\xC8\x99", "\xC8\x9A" => "\xC8\x9B",
- "\xCE\x86" => "\xCE\xAC", "\xCE\x88" => "\xCE\xAD", "\xCE\x89" => "\xCE\xAE", "\xCE\x8A" => "\xCE\xAF",
- "\xCE\x8C" => "\xCF\x8C", "\xCE\x8E" => "\xCF\x8D", "\xCE\x8F" => "\xCF\x8E", "\xCE\x91" => "\xCE\xB1",
- "\xCE\x92" => "\xCE\xB2", "\xCE\x93" => "\xCE\xB3", "\xCE\x94" => "\xCE\xB4", "\xCE\x95" => "\xCE\xB5",
- "\xCE\x96" => "\xCE\xB6", "\xCE\x97" => "\xCE\xB7", "\xCE\x98" => "\xCE\xB8", "\xCE\x99" => "\xCE\xB9",
- "\xCE\x9A" => "\xCE\xBA", "\xCE\x9B" => "\xCE\xBB", "\xCE\x9C" => "\xCE\xBC", "\xCE\x9D" => "\xCE\xBD",
- "\xCE\x9E" => "\xCE\xBE", "\xCE\x9F" => "\xCE\xBF", "\xCE\xA0" => "\xCF\x80", "\xCE\xA1" => "\xCF\x81",
- "\xCE\xA3" => "\xCF\x83", "\xCE\xA4" => "\xCF\x84", "\xCE\xA5" => "\xCF\x85", "\xCE\xA6" => "\xCF\x86",
- "\xCE\xA7" => "\xCF\x87", "\xCE\xA8" => "\xCF\x88", "\xCE\xA9" => "\xCF\x89", "\xCE\xAA" => "\xCF\x8A",
- "\xCE\xAB" => "\xCF\x8B", "\xD0\x81" => "\xD1\x91", "\xD0\x82" => "\xD1\x92", "\xD0\x83" => "\xD1\x93",
- "\xD0\x84" => "\xD1\x94", "\xD0\x85" => "\xD1\x95", "\xD0\x86" => "\xD1\x96", "\xD0\x87" => "\xD1\x97",
- "\xD0\x88" => "\xD1\x98", "\xD0\x89" => "\xD1\x99", "\xD0\x8A" => "\xD1\x9A", "\xD0\x8B" => "\xD1\x9B",
- "\xD0\x8C" => "\xD1\x9C", "\xD0\x8E" => "\xD1\x9E", "\xD0\x8F" => "\xD1\x9F", "\xD0\x90" => "\xD0\xB0",
- "\xD0\x91" => "\xD0\xB1", "\xD0\x92" => "\xD0\xB2", "\xD0\x93" => "\xD0\xB3", "\xD0\x94" => "\xD0\xB4",
- "\xD0\x95" => "\xD0\xB5", "\xD0\x96" => "\xD0\xB6", "\xD0\x97" => "\xD0\xB7", "\xD0\x98" => "\xD0\xB8",
- "\xD0\x99" => "\xD0\xB9", "\xD0\x9A" => "\xD0\xBA", "\xD0\x9B" => "\xD0\xBB", "\xD0\x9C" => "\xD0\xBC",
- "\xD0\x9D" => "\xD0\xBD", "\xD0\x9E" => "\xD0\xBE", "\xD0\x9F" => "\xD0\xBF", "\xD0\xA0" => "\xD1\x80",
- "\xD0\xA1" => "\xD1\x81", "\xD0\xA2" => "\xD1\x82", "\xD0\xA3" => "\xD1\x83", "\xD0\xA4" => "\xD1\x84",
- "\xD0\xA5" => "\xD1\x85", "\xD0\xA6" => "\xD1\x86", "\xD0\xA7" => "\xD1\x87", "\xD0\xA8" => "\xD1\x88",
- "\xD0\xA9" => "\xD1\x89", "\xD0\xAA" => "\xD1\x8A", "\xD0\xAB" => "\xD1\x8B", "\xD0\xAC" => "\xD1\x8C",
- "\xD0\xAD" => "\xD1\x8D", "\xD0\xAE" => "\xD1\x8E", "\xD0\xAF" => "\xD1\x8F", "\xD2\x90" => "\xD2\x91",
- "\xE1\xB8\x82" => "\xE1\xB8\x83", "\xE1\xB8\x8A" => "\xE1\xB8\x8B", "\xE1\xB8\x9E" => "\xE1\xB8\x9F", "\xE1\xB9\x80" => "\xE1\xB9\x81",
- "\xE1\xB9\x96" => "\xE1\xB9\x97", "\xE1\xB9\xA0" => "\xE1\xB9\xA1", "\xE1\xB9\xAA" => "\xE1\xB9\xAB", "\xE1\xBA\x80" => "\xE1\xBA\x81",
- "\xE1\xBA\x82" => "\xE1\xBA\x83", "\xE1\xBA\x84" => "\xE1\xBA\x85", "\xE1\xBB\xB2" => "\xE1\xBB\xB3"
- );
-
- return strtr(strtolower($string), $utf8_upper_to_lower);
+ return mb_substr($str, $offset);
}
-
- /**
- * UTF-8 aware alternative to strtoupper
- * Make a string uppercase
- * Note: The concept of a characters "case" only exists is some alphabets
- * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
- * not exist in the Chinese alphabet, for example. See Unicode Standard
- * Annex #21: Case Mappings
- *
- * @param string
- * @return string string in uppercase
- */
- function utf8_strtoupper($string)
+ else
{
- static $utf8_lower_to_upper = array(
- "\xC3\xA0" => "\xC3\x80", "\xC3\xA1" => "\xC3\x81",
- "\xC3\xA2" => "\xC3\x82", "\xC3\xA3" => "\xC3\x83", "\xC3\xA4" => "\xC3\x84", "\xC3\xA5" => "\xC3\x85",
- "\xC3\xA6" => "\xC3\x86", "\xC3\xA7" => "\xC3\x87", "\xC3\xA8" => "\xC3\x88", "\xC3\xA9" => "\xC3\x89",
- "\xC3\xAA" => "\xC3\x8A", "\xC3\xAB" => "\xC3\x8B", "\xC3\xAC" => "\xC3\x8C", "\xC3\xAD" => "\xC3\x8D",
- "\xC3\xAE" => "\xC3\x8E", "\xC3\xAF" => "\xC3\x8F", "\xC3\xB0" => "\xC3\x90", "\xC3\xB1" => "\xC3\x91",
- "\xC3\xB2" => "\xC3\x92", "\xC3\xB3" => "\xC3\x93", "\xC3\xB4" => "\xC3\x94", "\xC3\xB5" => "\xC3\x95",
- "\xC3\xB6" => "\xC3\x96", "\xC3\xB8" => "\xC3\x98", "\xC3\xB9" => "\xC3\x99", "\xC3\xBA" => "\xC3\x9A",
- "\xC3\xBB" => "\xC3\x9B", "\xC3\xBC" => "\xC3\x9C", "\xC3\xBD" => "\xC3\x9D", "\xC3\xBE" => "\xC3\x9E",
- "\xC3\xBF" => "\xC5\xB8", "\xC4\x81" => "\xC4\x80", "\xC4\x83" => "\xC4\x82", "\xC4\x85" => "\xC4\x84",
- "\xC4\x87" => "\xC4\x86", "\xC4\x89" => "\xC4\x88", "\xC4\x8B" => "\xC4\x8A", "\xC4\x8D" => "\xC4\x8C",
- "\xC4\x8F" => "\xC4\x8E", "\xC4\x91" => "\xC4\x90", "\xC4\x93" => "\xC4\x92", "\xC4\x97" => "\xC4\x96",
- "\xC4\x99" => "\xC4\x98", "\xC4\x9B" => "\xC4\x9A", "\xC4\x9D" => "\xC4\x9C", "\xC4\x9F" => "\xC4\x9E",
- "\xC4\xA1" => "\xC4\xA0", "\xC4\xA3" => "\xC4\xA2", "\xC4\xA5" => "\xC4\xA4", "\xC4\xA7" => "\xC4\xA6",
- "\xC4\xA9" => "\xC4\xA8", "\xC4\xAB" => "\xC4\xAA", "\xC4\xAF" => "\xC4\xAE", "\xC4\xB5" => "\xC4\xB4",
- "\xC4\xB7" => "\xC4\xB6", "\xC4\xBA" => "\xC4\xB9", "\xC4\xBC" => "\xC4\xBB", "\xC4\xBE" => "\xC4\xBD",
- "\xC5\x82" => "\xC5\x81", "\xC5\x84" => "\xC5\x83", "\xC5\x86" => "\xC5\x85", "\xC5\x88" => "\xC5\x87",
- "\xC5\x8B" => "\xC5\x8A", "\xC5\x8D" => "\xC5\x8C", "\xC5\x91" => "\xC5\x90", "\xC5\x95" => "\xC5\x94",
- "\xC5\x97" => "\xC5\x96", "\xC5\x99" => "\xC5\x98", "\xC5\x9B" => "\xC5\x9A", "\xC5\x9D" => "\xC5\x9C",
- "\xC5\x9F" => "\xC5\x9E", "\xC5\xA1" => "\xC5\xA0", "\xC5\xA3" => "\xC5\xA2", "\xC5\xA5" => "\xC5\xA4",
- "\xC5\xA7" => "\xC5\xA6", "\xC5\xA9" => "\xC5\xA8", "\xC5\xAB" => "\xC5\xAA", "\xC5\xAD" => "\xC5\xAC",
- "\xC5\xAF" => "\xC5\xAE", "\xC5\xB1" => "\xC5\xB0", "\xC5\xB3" => "\xC5\xB2", "\xC5\xB5" => "\xC5\xB4",
- "\xC5\xB7" => "\xC5\xB6", "\xC5\xBA" => "\xC5\xB9", "\xC5\xBC" => "\xC5\xBB", "\xC5\xBE" => "\xC5\xBD",
- "\xC6\xA1" => "\xC6\xA0", "\xC6\xB0" => "\xC6\xAF", "\xC8\x99" => "\xC8\x98", "\xC8\x9B" => "\xC8\x9A",
- "\xCE\xAC" => "\xCE\x86", "\xCE\xAD" => "\xCE\x88", "\xCE\xAE" => "\xCE\x89", "\xCE\xAF" => "\xCE\x8A",
- "\xCE\xB1" => "\xCE\x91", "\xCE\xB2" => "\xCE\x92", "\xCE\xB3" => "\xCE\x93", "\xCE\xB4" => "\xCE\x94",
- "\xCE\xB5" => "\xCE\x95", "\xCE\xB6" => "\xCE\x96", "\xCE\xB7" => "\xCE\x97", "\xCE\xB8" => "\xCE\x98",
- "\xCE\xB9" => "\xCE\x99", "\xCE\xBA" => "\xCE\x9A", "\xCE\xBB" => "\xCE\x9B", "\xCE\xBC" => "\xCE\x9C",
- "\xCE\xBD" => "\xCE\x9D", "\xCE\xBE" => "\xCE\x9E", "\xCE\xBF" => "\xCE\x9F", "\xCF\x80" => "\xCE\xA0",
- "\xCF\x81" => "\xCE\xA1", "\xCF\x83" => "\xCE\xA3", "\xCF\x84" => "\xCE\xA4", "\xCF\x85" => "\xCE\xA5",
- "\xCF\x86" => "\xCE\xA6", "\xCF\x87" => "\xCE\xA7", "\xCF\x88" => "\xCE\xA8", "\xCF\x89" => "\xCE\xA9",
- "\xCF\x8A" => "\xCE\xAA", "\xCF\x8B" => "\xCE\xAB", "\xCF\x8C" => "\xCE\x8C", "\xCF\x8D" => "\xCE\x8E",
- "\xCF\x8E" => "\xCE\x8F", "\xD0\xB0" => "\xD0\x90", "\xD0\xB1" => "\xD0\x91", "\xD0\xB2" => "\xD0\x92",
- "\xD0\xB3" => "\xD0\x93", "\xD0\xB4" => "\xD0\x94", "\xD0\xB5" => "\xD0\x95", "\xD0\xB6" => "\xD0\x96",
- "\xD0\xB7" => "\xD0\x97", "\xD0\xB8" => "\xD0\x98", "\xD0\xB9" => "\xD0\x99", "\xD0\xBA" => "\xD0\x9A",
- "\xD0\xBB" => "\xD0\x9B", "\xD0\xBC" => "\xD0\x9C", "\xD0\xBD" => "\xD0\x9D", "\xD0\xBE" => "\xD0\x9E",
- "\xD0\xBF" => "\xD0\x9F", "\xD1\x80" => "\xD0\xA0", "\xD1\x81" => "\xD0\xA1", "\xD1\x82" => "\xD0\xA2",
- "\xD1\x83" => "\xD0\xA3", "\xD1\x84" => "\xD0\xA4", "\xD1\x85" => "\xD0\xA5", "\xD1\x86" => "\xD0\xA6",
- "\xD1\x87" => "\xD0\xA7", "\xD1\x88" => "\xD0\xA8", "\xD1\x89" => "\xD0\xA9", "\xD1\x8A" => "\xD0\xAA",
- "\xD1\x8B" => "\xD0\xAB", "\xD1\x8C" => "\xD0\xAC", "\xD1\x8D" => "\xD0\xAD", "\xD1\x8E" => "\xD0\xAE",
- "\xD1\x8F" => "\xD0\xAF", "\xD1\x91" => "\xD0\x81", "\xD1\x92" => "\xD0\x82", "\xD1\x93" => "\xD0\x83",
- "\xD1\x94" => "\xD0\x84", "\xD1\x95" => "\xD0\x85", "\xD1\x96" => "\xD0\x86", "\xD1\x97" => "\xD0\x87",
- "\xD1\x98" => "\xD0\x88", "\xD1\x99" => "\xD0\x89", "\xD1\x9A" => "\xD0\x8A", "\xD1\x9B" => "\xD0\x8B",
- "\xD1\x9C" => "\xD0\x8C", "\xD1\x9E" => "\xD0\x8E", "\xD1\x9F" => "\xD0\x8F", "\xD2\x91" => "\xD2\x90",
- "\xE1\xB8\x83" => "\xE1\xB8\x82", "\xE1\xB8\x8B" => "\xE1\xB8\x8A", "\xE1\xB8\x9F" => "\xE1\xB8\x9E", "\xE1\xB9\x81" => "\xE1\xB9\x80",
- "\xE1\xB9\x97" => "\xE1\xB9\x96", "\xE1\xB9\xA1" => "\xE1\xB9\xA0", "\xE1\xB9\xAB" => "\xE1\xB9\xAA", "\xE1\xBA\x81" => "\xE1\xBA\x80",
- "\xE1\xBA\x83" => "\xE1\xBA\x82", "\xE1\xBA\x85" => "\xE1\xBA\x84", "\xE1\xBB\xB3" => "\xE1\xBB\xB2"
- );
-
- return strtr(strtoupper($string), $utf8_lower_to_upper);
- }
-
- /**
- * UTF-8 aware alternative to substr
- * Return part of a string given character offset (and optionally length)
- *
- * Note arguments: comparied to substr - if offset or length are
- * not integers, this version will not complain but rather massages them
- * into an integer.
- *
- * Note on returned values: substr documentation states false can be
- * returned in some cases (e.g. offset > string length)
- * mb_substr never returns false, it will return an empty string instead.
- * This adopts the mb_substr approach
- *
- * Note on implementation: PCRE only supports repetitions of less than
- * 65536, in order to accept up to MAXINT values for offset and length,
- * we'll repeat a group of 65535 characters when needed.
- *
- * Note on implementation: calculating the number of characters in the
- * string is a relatively expensive operation, so we only carry it out when
- * necessary. It isn't necessary for +ve offsets and no specified length
- *
- * @author Chris Smith<chris@jalakai.co.uk>
- * @param string $str
- * @param integer $offset number of UTF-8 characters offset (from left)
- * @param integer $length (optional) length in UTF-8 characters from offset
- * @return mixed string or FALSE if failure
- */
- function utf8_substr($str, $offset, $length = NULL)
- {
- // generates E_NOTICE
- // for PHP4 objects, but not PHP5 objects
- $str = (string) $str;
- $offset = (int) $offset;
- if (!is_null($length))
- {
- $length = (int) $length;
- }
-
- // handle trivial cases
- if ($length === 0 || ($offset < 0 && $length < 0 && $length < $offset))
- {
- return '';
- }
-
- // normalise negative offsets (we could use a tail
- // anchored pattern, but they are horribly slow!)
- if ($offset < 0)
- {
- // see notes
- $strlen = utf8_strlen($str);
- $offset = $strlen + $offset;
- if ($offset < 0)
- {
- $offset = 0;
- }
- }
-
- $op = '';
- $lp = '';
-
- // establish a pattern for offset, a
- // non-captured group equal in length to offset
- if ($offset > 0)
- {
- $ox = (int) ($offset / 65535);
- $oy = $offset % 65535;
-
- if ($ox)
- {
- $op = '(?:.{65535}){' . $ox . '}';
- }
-
- $op = '^(?:' . $op . '.{' . $oy . '})';
- }
- else
- {
- // offset == 0; just anchor the pattern
- $op = '^';
- }
-
- // establish a pattern for length
- if (is_null($length))
- {
- // the rest of the string
- $lp = '(.*)$';
- }
- else
- {
- if (!isset($strlen))
- {
- // see notes
- $strlen = utf8_strlen($str);
- }
-
- // another trivial case
- if ($offset > $strlen)
- {
- return '';
- }
-
- if ($length > 0)
- {
- // reduce any length that would
- // go passed the end of the string
- $length = min($strlen - $offset, $length);
-
- $lx = (int) ($length / 65535);
- $ly = $length % 65535;
-
- // negative length requires a captured group
- // of length characters
- if ($lx)
- {
- $lp = '(?:.{65535}){' . $lx . '}';
- }
- $lp = '(' . $lp . '.{'. $ly . '})';
- }
- else if ($length < 0)
- {
- if ($length < ($offset - $strlen))
- {
- return '';
- }
-
- $lx = (int) ((-$length) / 65535);
- $ly = (-$length) % 65535;
-
- // negative length requires ... capture everything
- // except a group of -length characters
- // anchored at the tail-end of the string
- if ($lx)
- {
- $lp = '(?:.{65535}){' . $lx . '}';
- }
- $lp = '(.*)(?:' . $lp . '.{' . $ly . '})$';
- }
- }
-
- if (!preg_match('#' . $op . $lp . '#us', $str, $match))
- {
- return '';
- }
-
- return $match[1];
+ return mb_substr($str, $offset, $length);
}
+}
- /**
- * Return the length (in characters) of a UTF-8 string
- *
- * @param string $text UTF-8 string
- * @return integer Length (in chars) of given string
- */
- function utf8_strlen($text)
- {
- // Since utf8_decode is replacing multibyte characters to ? strlen works fine
- return strlen(utf8_decode($text));
- }
+/**
+* Return the length (in characters) of a UTF-8 string
+* @ignore
+*/
+function utf8_strlen($text)
+{
+ return mb_strlen($text, 'utf-8');
}
/**
@@ -867,28 +415,46 @@ function utf8_recode($string, $encoding)
// Trigger an error?! Fow now just give bad data :-(
trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR);
- //return $string; // use utf_normalizer::cleanup() ?
}
/**
-* Replace all UTF-8 chars that are not in ASCII with their NCR
-*
-* @param string $text UTF-8 string in NFC
-* @return string ASCII string using NCRs for non-ASCII chars
-*/
+ * Replace some special UTF-8 chars that are not in ASCII with their UCR.
+ * using their Numeric Character Reference's Hexadecimal notation.
+ *
+ * Doesn't interfere with Japanese or Cyrillic etc.
+ * Unicode character visualization will depend on the character support
+ * of your web browser and the fonts installed on your system.
+ *
+ * @see https://en.wikibooks.org/wiki/Unicode/Character_reference/1F000-1FFFF
+ *
+ * @param string $text UTF-8 string in NFC
+ * @return string ASCII string using NCR for non-ASCII chars
+ */
+function utf8_encode_ucr($text)
+{
+ return preg_replace_callback('/[\\xF0-\\xF4].../', 'utf8_encode_ncr_callback', $text);
+}
+
+/**
+ * Replace all UTF-8 chars that are not in ASCII with their NCR
+ * using their Numeric Character Reference's Hexadecimal notation.
+ *
+ * @param string $text UTF-8 string in NFC
+ * @return string ASCII string using NCRs for non-ASCII chars
+ */
function utf8_encode_ncr($text)
{
return preg_replace_callback('#[\\xC2-\\xF4][\\x80-\\xBF]{1,3}#', 'utf8_encode_ncr_callback', $text);
}
/**
-* Callback used in encode_ncr()
-*
-* Takes a UTF-8 char and replaces it with its NCR. Attention, $m is an array
-*
-* @param array $m 0-based numerically indexed array passed by preg_replace_callback()
-* @return string A HTML NCR if the character is valid, or the original string otherwise
-*/
+ * Callback used in utf8_encode_ncr() and utf8_encode_ucr()
+ *
+ * Takes a UTF-8 char and replaces it with its NCR. Attention, $m is an array
+ *
+ * @param array $m 0-based numerically indexed array passed by preg_replace_callback()
+ * @return string A HTML NCR if the character is valid, or the original string otherwise
+ */
function utf8_encode_ncr_callback($m)
{
return '&#' . utf8_ord($m[0]) . ';';
@@ -1606,19 +1172,12 @@ function utf8_case_fold_nfkc($text, $option = 'full')
"\xF0\x9D\x9E\xBB" => "\xCF\x83",
"\xF0\x9D\x9F\x8A" => "\xCF\x9D",
);
- global $phpbb_root_path, $phpEx;
// do the case fold
$text = utf8_case_fold($text, $option);
- if (!class_exists('utf_normalizer'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx);
- }
-
// convert to NFKC
- utf_normalizer::nfkc($text);
+ Normalizer::normalize($text, Normalizer::NFKC);
// FC_NFKC_Closure, http://www.unicode.org/Public/5.0.0/ucd/DerivedNormalizationProps.txt
$text = strtr($text, $fc_nfkc_closure);
@@ -1703,7 +1262,6 @@ function utf8_case_fold_nfc($text, $option = 'full')
"\xE1\xBF\xB7" => "\xE1\xBF\xB6\xCD\x85",
"\xE1\xBF\xBC" => "\xCE\xA9\xCD\x85",
);
- global $phpbb_root_path, $phpEx;
// perform a small trick, avoid further normalization on composed points that contain U+0345 in their decomposition
$text = strtr($text, $ypogegrammeni);
@@ -1714,106 +1272,56 @@ function utf8_case_fold_nfc($text, $option = 'full')
return $text;
}
-if (extension_loaded('intl'))
+/**
+* wrapper around PHP's native normalizer from intl
+* previously a PECL extension, included in the core since PHP 5.3.0
+* http://php.net/manual/en/normalizer.normalize.php
+*
+* @param mixed $strings a string or an array of strings to normalize
+* @return mixed the normalized content, preserving array keys if array given.
+*/
+function utf8_normalize_nfc($strings)
{
- /**
- * wrapper around PHP's native normalizer from intl
- * previously a PECL extension, included in the core since PHP 5.3.0
- * http://php.net/manual/en/normalizer.normalize.php
- *
- * @param mixed $strings a string or an array of strings to normalize
- * @return mixed the normalized content, preserving array keys if array given.
- */
- function utf8_normalize_nfc($strings)
+ if (empty($strings))
{
- if (empty($strings))
- {
- return $strings;
- }
-
- if (!is_array($strings))
- {
- if (Normalizer::isNormalized($strings))
- {
- return $strings;
- }
- return (string) Normalizer::normalize($strings);
- }
- else
- {
- foreach ($strings as $key => $string)
- {
- if (is_array($string))
- {
- foreach ($string as $_key => $_string)
- {
- if (Normalizer::isNormalized($strings[$key][$_key]))
- {
- continue;
- }
- $strings[$key][$_key] = (string) Normalizer::normalize($strings[$key][$_key]);
- }
- }
- else
- {
- if (Normalizer::isNormalized($strings[$key]))
- {
- continue;
- }
- $strings[$key] = (string) Normalizer::normalize($strings[$key]);
- }
- }
- }
-
return $strings;
}
-}
-else
-{
- /**
- * A wrapper function for the normalizer which takes care of including the class if
- * required and modifies the passed strings to be in NFC (Normalization Form Composition).
- *
- * @param mixed $strings a string or an array of strings to normalize
- * @return mixed the normalized content, preserving array keys if array given.
- */
- function utf8_normalize_nfc($strings)
+
+ if (!is_array($strings))
{
- if (empty($strings))
+ if (Normalizer::isNormalized($strings))
{
return $strings;
}
-
- if (!class_exists('utf_normalizer'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx);
- }
-
- if (!is_array($strings))
- {
- utf_normalizer::nfc($strings);
- }
- else if (is_array($strings))
+ return (string) Normalizer::normalize($strings);
+ }
+ else
+ {
+ foreach ($strings as $key => $string)
{
- foreach ($strings as $key => $string)
+ if (is_array($string))
{
- if (is_array($string))
+ foreach ($string as $_key => $_string)
{
- foreach ($string as $_key => $_string)
+ if (Normalizer::isNormalized($strings[$key][$_key]))
{
- utf_normalizer::nfc($strings[$key][$_key]);
+ continue;
}
+ $strings[$key][$_key] = (string) Normalizer::normalize($strings[$key][$_key]);
}
- else
+ }
+ else
+ {
+ if (Normalizer::isNormalized($strings[$key]))
{
- utf_normalizer::nfc($strings[$key]);
+ continue;
}
+ $strings[$key] = (string) Normalizer::normalize($strings[$key]);
}
}
-
- return $strings;
}
+
+ return $strings;
}
/**
@@ -1901,7 +1409,7 @@ function utf8_wordwrap($string, $width = 75, $break = "\n", $cut = false)
{
$words = explode(' ', $line);
- for ($i = 0, $size = sizeof($words); $i < $size; $i++)
+ for ($i = 0, $size = count($words); $i < $size; $i++)
{
$word = $words[$i];
@@ -1959,50 +1467,3 @@ function utf8_basename($filename)
return $filename;
}
-
-/**
-* UTF8-safe str_replace() function
-*
-* @param string $search The value to search for
-* @param string $replace The replacement string
-* @param string $subject The target string
-* @return string The resultant string
-*/
-function utf8_str_replace($search, $replace, $subject)
-{
- if (!is_array($search))
- {
- $search = array($search);
- if (is_array($replace))
- {
- $replace = (string) $replace;
- trigger_error('Array to string conversion', E_USER_NOTICE);
- }
- }
-
- $length = sizeof($search);
-
- if (!is_array($replace))
- {
- $replace = array_fill(0, $length, $replace);
- }
- else
- {
- $replace = array_pad($replace, $length, '');
- }
-
- for ($i = 0; $i < $length; $i++)
- {
- $search_length = utf8_strlen($search[$i]);
- $replace_length = utf8_strlen($replace[$i]);
-
- $offset = 0;
- while (($start = utf8_strpos($subject, $search[$i], $offset)) !== false)
- {
- $subject = utf8_substr($subject, 0, $start) . $replace[$i] . utf8_substr($subject, $start + $search_length);
- $offset = $start + $replace_length;
- }
- }
-
- return $subject;
-}
diff --git a/phpBB/index.php b/phpBB/index.php
index e4c03949c1..13b914abd3 100644
--- a/phpBB/index.php
+++ b/phpBB/index.php
@@ -42,9 +42,10 @@ if (($mark_notification = $request->variable('mark_notification', 0)))
if (check_link_hash($request->variable('hash', ''), 'mark_notification_read'))
{
+ /* @var $phpbb_notifications \phpbb\notification\manager */
$phpbb_notifications = $phpbb_container->get('notification_manager');
- $notification = $phpbb_notifications->load_notifications(array(
+ $notification = $phpbb_notifications->load_notifications('notification.method.board', array(
'notification_id' => $mark_notification,
));
@@ -54,6 +55,17 @@ if (($mark_notification = $request->variable('mark_notification', 0)))
$notification->mark_read();
+ /**
+ * You can use this event to perform additional tasks or redirect user elsewhere.
+ *
+ * @event core.index_mark_notification_after
+ * @var int mark_notification Notification ID
+ * @var \phpbb\notification\type\type_interface notification Notification instance
+ * @since 3.2.6-RC1
+ */
+ $vars = array('mark_notification', 'notification');
+ extract($phpbb_dispatcher->trigger_event('core.index_mark_notification_after', compact($vars)));
+
if ($request->is_ajax())
{
$json_response = new \phpbb\json_response();
@@ -99,11 +111,14 @@ else
}
$result = $db->sql_query($sql);
+/** @var \phpbb\group\helper $group_helper */
+$group_helper = $phpbb_container->get('group_helper');
+
$legend = array();
while ($row = $db->sql_fetchrow($result))
{
$colour_text = ($row['group_colour']) ? ' style="color:#' . $row['group_colour'] . '"' : '';
- $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $group_name = $group_helper->get_name($row['group_name']);
if ($row['group_name'] == 'BOTS' || ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')))
{
@@ -119,8 +134,10 @@ $db->sql_freeresult($result);
$legend = implode($user->lang['COMMA_SEPARATOR'], $legend);
// Generate birthday list if required ...
+$show_birthdays = ($config['load_birthdays'] && $config['allow_birthdays'] && $auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel'));
+
$birthdays = $birthday_list = array();
-if ($config['load_birthdays'] && $config['allow_birthdays'] && $auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel'))
+if ($show_birthdays)
{
$time = $user->create_datetime();
$now = phpbb_gmgetdate($time->getTimestamp() + $time->getOffset());
@@ -211,7 +228,7 @@ $template->assign_vars(array(
'S_LOGIN_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login'),
'U_SEND_PASSWORD' => ($config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '',
- 'S_DISPLAY_BIRTHDAY_LIST' => ($config['load_birthdays']) ? true : false,
+ 'S_DISPLAY_BIRTHDAY_LIST' => $show_birthdays,
'S_INDEX' => true,
'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}index.$phpEx", 'hash=' . generate_link_hash('global') . '&amp;mark=forums&amp;mark_time=' . time()) : '',
diff --git a/phpBB/install/app.php b/phpBB/install/app.php
new file mode 100644
index 0000000000..710f49570b
--- /dev/null
+++ b/phpBB/install/app.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * @ignore
+ */
+define('IN_PHPBB', true);
+define('IN_INSTALL', true);
+define('PHPBB_ENVIRONMENT', 'production');
+$phpbb_root_path = '../';
+$phpEx = substr(strrchr(__FILE__, '.'), 1);
+
+if (version_compare(PHP_VERSION, '5.4.7', '<') || version_compare(PHP_VERSION, '7.3-dev', '>='))
+{
+ die('You are running an unsupported PHP version. Please upgrade to PHP equal to or greater than 5.4.7 but less than 7.3-dev in order to install or update to phpBB 3.2');
+}
+
+$startup_new_path = $phpbb_root_path . 'install/update/update/new/install/startup.' . $phpEx;
+$startup_path = (file_exists($startup_new_path)) ? $startup_new_path : $phpbb_root_path . 'install/startup.' . $phpEx;
+require($startup_path);
+
+/** @var \phpbb\filesystem\filesystem $phpbb_filesystem */
+$phpbb_filesystem = $phpbb_installer_container->get('filesystem');
+
+/** @var \phpbb\template\template $template */
+$template = $phpbb_installer_container->get('template');
+
+// Path to templates
+$paths = array($phpbb_root_path . 'install/update/new/adm/style', $phpbb_admin_path . 'style');
+$paths = array_filter($paths, 'is_dir');
+
+$template->set_custom_style(array(
+ array(
+ 'name' => 'adm',
+ 'ext_path' => 'adm/style/',
+ ),
+), $paths);
+
+/** @var $phpbb_dispatcher \phpbb\event\dispatcher */
+$phpbb_dispatcher = $phpbb_installer_container->get('dispatcher');
+
+/** @var \phpbb\language\language $language */
+$language = $phpbb_installer_container->get('language');
+$language->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
+
+/** @var $http_kernel \Symfony\Component\HttpKernel\HttpKernel */
+$http_kernel = $phpbb_installer_container->get('http_kernel');
+
+/** @var $symfony_request \phpbb\symfony_request */
+$symfony_request = $phpbb_installer_container->get('symfony_request');
+$response = $http_kernel->handle($symfony_request);
+$response->send();
+$http_kernel->terminate($symfony_request, $response);
diff --git a/phpBB/install/convert/controller/convertor.php b/phpBB/install/convert/controller/convertor.php
new file mode 100644
index 0000000000..3639b10dc5
--- /dev/null
+++ b/phpBB/install/convert/controller/convertor.php
@@ -0,0 +1,865 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\convert\controller;
+
+use phpbb\cache\driver\driver_interface;
+use phpbb\exception\http_exception;
+use phpbb\install\controller\helper;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\database;
+use phpbb\install\helper\install_helper;
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\helper\navigation\navigation_provider;
+use phpbb\language\language;
+use phpbb\request\request_interface;
+use phpbb\template\template;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+
+/**
+ * Controller for forum convertors
+ *
+ * WARNING: This file did not meant to be present in a production environment, so moving
+ * this file to a location which is accessible after board installation might
+ * lead to security issues.
+ */
+class convertor
+{
+ /**
+ * @var driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var driver_interface
+ */
+ protected $installer_cache;
+
+ /**
+ * @var \phpbb\config\db
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\config_php_file
+ */
+ protected $config_php_file;
+
+ /**
+ * @var string
+ */
+ protected $config_table;
+
+ /**
+ * @var helper
+ */
+ protected $controller_helper;
+
+ /**
+ * @var database
+ */
+ protected $db_helper;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var install_helper
+ */
+ protected $install_helper;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * @var navigation_provider
+ */
+ protected $navigation_provider;
+
+ /**
+ * @var request_interface
+ */
+ protected $request;
+
+ /**
+ * @var string
+ */
+ protected $session_keys_table;
+
+ /**
+ * @var string
+ */
+ protected $session_table;
+
+ /**
+ * @var template
+ */
+ protected $template;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param driver_interface $cache
+ * @param container_factory $container
+ * @param database $db_helper
+ * @param helper $controller_helper
+ * @param install_helper $install_helper
+ * @param factory $iohandler
+ * @param language $language
+ * @param navigation_provider $nav
+ * @param request_interface $request
+ * @param template $template
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(driver_interface $cache, container_factory $container, database $db_helper, helper $controller_helper, install_helper $install_helper, factory $iohandler, language $language, navigation_provider $nav, request_interface $request, template $template, $phpbb_root_path, $php_ext)
+ {
+ $this->installer_cache = $cache;
+ $this->controller_helper = $controller_helper;
+ $this->db_helper = $db_helper;
+ $this->install_helper = $install_helper;
+ $this->language = $language;
+ $this->navigation_provider = $nav;
+ $this->request = $request;
+ $this->template = $template;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $iohandler->set_environment('ajax');
+ $this->iohandler = $iohandler->get();
+
+ if (!$this->install_helper->is_phpbb_installed() || !defined('IN_INSTALL'))
+ {
+ throw new http_exception(403, 'INSTALL_PHPBB_NOT_INSTALLED');
+ }
+
+ $this->controller_helper->handle_language_select();
+
+ $this->cache = $container->get('cache.driver');
+ $this->config = $container->get('config');
+ $this->config_php_file = new \phpbb\config_php_file($this->phpbb_root_path, $this->php_ext);
+ $this->db = $container->get('dbal.conn.driver');
+
+ $this->config_table = $container->get_parameter('tables.config');
+ $this->session_keys_table = $container->get_parameter('tables.sessions_keys');
+ $this->session_table = $container->get_parameter('tables.sessions');
+ }
+
+ /**
+ * Render the intro page
+ *
+ * @param bool|int $start_new Whether or not to force to start a new convertor
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ */
+ public function intro($start_new)
+ {
+ $this->setup_navigation('intro');
+
+ if ($start_new)
+ {
+ if ($this->request->is_ajax())
+ {
+ $response = new StreamedResponse();
+ $iohandler = $this->iohandler;
+ $url = $this->controller_helper->route('phpbb_convert_intro', array('start_new' => 'new'));
+ $response->setCallback(function() use ($iohandler, $url) {
+ $iohandler->redirect($url);
+ });
+ $response->headers->set('X-Accel-Buffering', 'no');
+
+ return $response;
+ }
+
+ $this->config['convert_progress'] = '';
+ $this->config['convert_db_server'] = '';
+ $this->config['convert_db_user'] = '';
+ $this->db->sql_query('DELETE FROM ' . $this->config_table . "
+ WHERE config_name = 'convert_progress'
+ OR config_name = 'convert_db_server'
+ OR config_name = 'convert_db_user'"
+ );
+ }
+
+ // Let's see if there is a conversion in the works...
+ $options = array();
+ if (!empty($this->config['convert_progress']) &&
+ !empty($this->config['convert_db_server']) &&
+ !empty($this->config['convert_db_user']) &&
+ !empty($this->config['convert_options']))
+ {
+ $options = unserialize($this->config['convert_progress']);
+ $options = array_merge($options,
+ unserialize($this->config['convert_db_server']),
+ unserialize($this->config['convert_db_user']),
+ unserialize($this->config['convert_options'])
+ );
+ }
+
+ // This information should have already been checked once, but do it again for safety
+ if (!empty($options) && !empty($options['tag']) &&
+ isset($options['dbms']) &&
+ isset($options['dbhost']) &&
+ isset($options['dbport']) &&
+ isset($options['dbuser']) &&
+ isset($options['dbpasswd']) &&
+ isset($options['dbname']) &&
+ isset($options['table_prefix']))
+ {
+ $this->template->assign_vars(array(
+ 'TITLE' => $this->language->lang('CONTINUE_CONVERT'),
+ 'BODY' => $this->language->lang('CONTINUE_CONVERT_BODY'),
+ 'S_CONTINUE' => true,
+ 'U_NEW_ACTION' => $this->controller_helper->route('phpbb_convert_intro', array('start_new' => 'new')),
+ 'U_CONTINUE_ACTION' => $this->controller_helper->route('phpbb_convert_convert', array('converter' => $options['tag'])),
+ ));
+
+ return $this->controller_helper->render('installer_convert.html', 'CONTINUE_CONVERT', true);
+ }
+
+ return $this->render_convert_list();
+ }
+
+ /**
+ * Obtain convertor settings
+ *
+ * @param string $converter Name of the convertor
+ *
+ * @return \Symfony\Component\HttpFoundation\Response|StreamedResponse
+ */
+ public function settings($converter)
+ {
+ $this->setup_navigation('settings');
+
+ require_once ($this->phpbb_root_path . 'includes/constants.' . $this->php_ext);
+ require_once ($this->phpbb_root_path . 'includes/functions_convert.' . $this->php_ext);
+
+ // Include convertor if available
+ $convertor_file_path = $this->phpbb_root_path . 'install/convertors/convert_' . $converter . '.' . $this->php_ext;
+ if (!file_exists($convertor_file_path))
+ {
+ if ($this->request->is_ajax())
+ {
+ $response = new StreamedResponse();
+ $ref = $this;
+ $response->setCallback(function() use ($ref) {
+ $ref->render_error('CONVERT_NOT_EXIST');
+ });
+ $response->headers->set('X-Accel-Buffering', 'no');
+
+ return $response;
+ }
+
+ $this->render_error('CONVERT_NOT_EXIST');
+ return $this->controller_helper->render('installer_convert.html', 'STAGE_SETTINGS', true);
+ }
+
+ $get_info = true;
+ $phpbb_root_path = $this->phpbb_root_path; // These globals are required
+ $phpEx = $this->php_ext; // See above
+ include_once ($convertor_file_path);
+
+ // The test_file is a file that should be present in the location of the old board.
+ if (!isset($test_file))
+ {
+ if ($this->request->is_ajax())
+ {
+ $response = new StreamedResponse();
+ $ref = $this;
+ $response->setCallback(function() use ($ref) {
+ $ref->render_error('DEV_NO_TEST_FILE');
+ });
+ $response->headers->set('X-Accel-Buffering', 'no');
+
+ return $response;
+ }
+
+ $this->render_error('DEV_NO_TEST_FILE');
+ return $this->controller_helper->render('installer_convert.html', 'STAGE_SETTINGS', true);
+ }
+
+ if ($this->request->variable('submit', false))
+ {
+ // It must be an AJAX request at this point
+ $response = new StreamedResponse();
+ $ref = $this;
+ $response->setCallback(function() use ($ref, $converter) {
+ $ref->proccess_settings_form($converter);
+ });
+ $response->headers->set('X-Accel-Buffering', 'no');
+
+ return $response;
+ }
+ else
+ {
+ $this->template->assign_vars(array(
+ 'U_ACTION' => $this->controller_helper->route('phpbb_convert_settings', array(
+ 'converter' => $converter,
+ ))
+ ));
+
+ if ($this->request->is_ajax())
+ {
+ $response = new StreamedResponse();
+ $ref = $this;
+ $response->setCallback(function() use ($ref) {
+ $ref->render_settings_form();
+ });
+ $response->headers->set('X-Accel-Buffering', 'no');
+
+ return $response;
+ }
+
+ $this->render_settings_form();
+ }
+
+ return $this->controller_helper->render('installer_convert.html', 'STAGE_SETTINGS', true);
+ }
+
+ /**
+ * Run conversion
+ */
+ public function convert($converter)
+ {
+ $this->setup_navigation('convert');
+
+ if ($this->request->is_ajax())
+ {
+ $route = $this->controller_helper->route('phpbb_convert_convert', array('converter' => $converter));
+ $response = new StreamedResponse();
+ $ref = $this;
+ $response->setCallback(function() use ($ref, $route) {
+ $ref->redirect_to_html($route);
+ });
+ $response->headers->set('X-Accel-Buffering', 'no');
+
+ return $response;
+ }
+
+ $convertor = new \phpbb\convert\convertor($this->template, $this->controller_helper);
+ $convertor->convert_data($converter);
+
+ return $this->controller_helper->render('installer_convert.html', 'STAGE_IN_PROGRESS');
+ }
+
+ /**
+ * Render the final page of the convertor
+ */
+ public function finish()
+ {
+ $this->setup_navigation('finish');
+
+ $this->template->assign_vars(array(
+ 'TITLE' => $this->language->lang('CONVERT_COMPLETE'),
+ 'BODY' => $this->language->lang('CONVERT_COMPLETE_EXPLAIN'),
+ ));
+
+ // If we reached this step (conversion completed) we want to purge the cache and log the user out.
+ // This is for making sure the session get not screwed due to the 3.0.x users table being completely new.
+ $this->cache->purge();
+ $this->installer_cache->purge();
+
+ require_once($this->phpbb_root_path . 'includes/constants.' . $this->php_ext);
+ require_once($this->phpbb_root_path . 'includes/functions_convert.' . $this->php_ext);
+
+ $sql = 'SELECT config_value
+ FROM ' . $this->config_table . '
+ WHERE config_name = \'search_type\'';
+ $result = $this->db->sql_query($sql);
+
+ if ($this->db->sql_fetchfield('config_value') != 'fulltext_mysql')
+ {
+ $this->template->assign_vars(array(
+ 'S_ERROR_BOX' => true,
+ 'ERROR_TITLE' => $this->language->lang('SEARCH_INDEX_UNCONVERTED'),
+ 'ERROR_MSG' => $this->language->lang('SEARCH_INDEX_UNCONVERTED_EXPLAIN'),
+ ));
+ }
+
+ $this->db->sql_freeresult($result);
+
+ switch ($this->db->get_sql_layer())
+ {
+ case 'sqlite3':
+ $this->db->sql_query('DELETE FROM ' . $this->session_keys_table);
+ $this->db->sql_query('DELETE FROM ' . $this->session_table);
+ break;
+
+ default:
+ $this->db->sql_query('TRUNCATE TABLE ' . $this->session_keys_table);
+ $this->db->sql_query('TRUNCATE TABLE ' . $this->session_table);
+ break;
+ }
+
+ return $this->controller_helper->render('installer_convert.html', 'CONVERT_COMPLETE');
+ }
+
+ /**
+ * Validates settings form
+ *
+ * @param string $convertor
+ */
+ public function proccess_settings_form($convertor)
+ {
+ global $phpbb_root_path, $phpEx, $get_info;
+
+ $phpbb_root_path = $this->phpbb_root_path;
+ $phpEx = $this->php_ext;
+ $get_info = true;
+
+ require_once($this->phpbb_root_path . 'includes/constants.' . $this->php_ext);
+ require_once($this->phpbb_root_path . 'includes/functions_convert.' . $this->php_ext);
+
+ // Include convertor if available
+ $convertor_file_path = $this->phpbb_root_path . 'install/convertors/convert_' . $convertor . '.' . $this->php_ext;
+ include ($convertor_file_path);
+
+ // We expect to have an AJAX request here
+ $src_dbms = $this->request->variable('src_dbms', $convertor_data['dbms']);
+ $src_dbhost = $this->request->variable('src_dbhost', $convertor_data['dbhost']);
+ $src_dbport = $this->request->variable('src_dbport', $convertor_data['dbport']);
+ $src_dbuser = $this->request->variable('src_dbuser', $convertor_data['dbuser']);
+ $src_dbpasswd = $this->request->variable('src_dbpasswd', $convertor_data['dbpasswd']);
+ $src_dbname = $this->request->variable('src_dbname', $convertor_data['dbname']);
+ $src_table_prefix = $this->request->variable('src_table_prefix', $convertor_data['table_prefix']);
+ $forum_path = $this->request->variable('forum_path', $convertor_data['forum_path']);
+ $refresh = $this->request->variable('refresh', 1);
+
+ // Default URL of the old board
+ // @todo Are we going to use this for attempting to convert URL references in posts, or should we remove it?
+ // -> We should convert old urls to the new relative urls format
+ // $src_url = $request->variable('src_url', 'Not in use at the moment');
+
+ // strip trailing slash from old forum path
+ $forum_path = (strlen($forum_path) && $forum_path[strlen($forum_path) - 1] == '/') ? substr($forum_path, 0, -1) : $forum_path;
+
+ $error = array();
+ if (!file_exists($this->phpbb_root_path . $forum_path . '/' . $test_file))
+ {
+ $error[] = $this->language->lang('COULD_NOT_FIND_PATH', $forum_path);
+ }
+
+ $connect_test = false;
+ $available_dbms = $this->db_helper->get_available_dbms(false, true, true);
+ if (!isset($available_dbms[$src_dbms]) || !$available_dbms[$src_dbms]['AVAILABLE'])
+ {
+ $error[] = $this->language->lang('INST_ERR_NO_DB');
+ }
+ else
+ {
+ $connect_test = $this->db_helper->check_database_connection($src_dbms, $src_dbhost, $src_dbport, $src_dbuser, $src_dbpasswd, $src_dbname, $src_table_prefix);
+ }
+
+ extract($this->config_php_file->get_all());
+
+ // The forum prefix of the old and the new forum can only be the same if two different databases are used.
+ if ($src_table_prefix === $table_prefix && $src_dbms === $dbms && $src_dbhost === $dbhost && $src_dbport === $dbport && $src_dbname === $dbname)
+ {
+ $error[] = $this->language->lang('TABLE_PREFIX_SAME', $src_table_prefix);
+ }
+
+ if (!$connect_test)
+ {
+ $error[] = $this->language->lang('INST_ERR_DB_CONNECT');
+ }
+
+ $src_dbms = $this->config_php_file->convert_30_dbms_to_31($src_dbms);
+
+ // Check table prefix
+ if (empty($error))
+ {
+ // initiate database connection to old db if old and new db differ
+ global $src_db, $same_db;
+ $src_db = $same_db = false;
+
+ if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser)
+ {
+ /** @var \phpbb\db\driver\driver_interface $src_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;
+ }
+ else
+ {
+ $src_db = $this->db;
+ $same_db = true;
+ }
+
+ $src_db->sql_return_on_error(true);
+ $this->db->sql_return_on_error(true);
+
+ // Try to select one row from the first table to see if the prefix is OK
+ $result = $src_db->sql_query_limit('SELECT * FROM ' . $src_table_prefix . $tables[0], 1);
+
+ if (!$result)
+ {
+ $prefixes = array();
+
+ $db_tools_factory = new \phpbb\db\tools\factory();
+ $db_tools = $db_tools_factory->get($src_db);
+ $tables_existing = $db_tools->sql_list_tables();
+ $tables_existing = array_map('strtolower', $tables_existing);
+ foreach ($tables_existing as $table_name)
+ {
+ compare_table($tables, $table_name, $prefixes);
+ }
+ unset($tables_existing);
+
+ foreach ($prefixes as $prefix => $count)
+ {
+ if ($count >= count($tables))
+ {
+ $possible_prefix = $prefix;
+ break;
+ }
+ }
+
+ $msg = '';
+ if (!empty($convertor_data['table_prefix']))
+ {
+ $msg .= $this->language->lang_array('DEFAULT_PREFIX_IS', array($convertor_data['forum_name'], $convertor_data['table_prefix']));
+ }
+
+ if (!empty($possible_prefix))
+ {
+ $msg .= '<br />';
+ $msg .= ($possible_prefix == '*') ? $this->language->lang('BLANK_PREFIX_FOUND') : $this->language->lang_array('PREFIX_FOUND', array($possible_prefix));
+ $src_table_prefix = ($possible_prefix == '*') ? '' : $possible_prefix;
+ }
+
+ $error[] = $msg;
+ }
+
+ $src_db->sql_freeresult($result);
+ $src_db->sql_return_on_error(false);
+ }
+
+ if (empty($error))
+ {
+ // Save convertor Status
+ $this->config->set('convert_progress', serialize(array(
+ 'step' => '',
+ 'table_prefix' => $src_table_prefix,
+ 'tag' => $convertor,
+ )), false);
+ $this->config->set('convert_db_server', serialize(array(
+ 'dbms' => $src_dbms,
+ 'dbhost' => $src_dbhost,
+ 'dbport' => $src_dbport,
+ 'dbname' => $src_dbname,
+ )), false);
+ $this->config->set('convert_db_user', serialize(array(
+ 'dbuser' => $src_dbuser,
+ 'dbpasswd' => $src_dbpasswd,
+ )), false);
+
+ // Save options
+ $this->config->set('convert_options', serialize(array(
+ 'forum_path' => $this->phpbb_root_path . $forum_path,
+ 'refresh' => $refresh
+ )), false);
+
+ $url = $this->controller_helper->route('phpbb_convert_convert', array('converter' => $convertor));
+ $this->iohandler->redirect($url);
+ $this->iohandler->send_response(true);
+ }
+ else
+ {
+ $this->render_settings_form($error);
+ }
+ }
+
+ /**
+ * Renders settings form
+ *
+ * @param array $error Array of errors
+ */
+ public function render_settings_form($error = array())
+ {
+ foreach ($error as $msg)
+ {
+ $this->iohandler->add_error_message($msg);
+ }
+
+ $dbms_options = array();
+ foreach ($this->db_helper->get_available_dbms() as $dbms_key => $dbms_array)
+ {
+ $dbms_options[] = array(
+ 'value' => $dbms_key,
+ 'label' => 'DB_OPTION_' . strtoupper($dbms_key),
+ );
+ }
+
+ $form_title = 'SPECIFY_OPTIONS';
+ $form_data = array(
+ 'src_dbms' => array(
+ 'label' => 'DBMS',
+ 'type' => 'select',
+ 'options' => $dbms_options,
+ ),
+ 'src_dbhost' => array(
+ 'label' => 'DB_HOST',
+ 'description' => 'DB_HOST_EXPLAIN',
+ 'type' => 'text',
+ ),
+ 'src_dbport' => array(
+ 'label' => 'DB_PORT',
+ 'description' => 'DB_PORT_EXPLAIN',
+ 'type' => 'text',
+ ),
+ 'src_dbname' => array(
+ 'label' => 'DB_NAME',
+ 'type' => 'text',
+ ),
+ 'src_dbuser' => array(
+ 'label' => 'DB_USERNAME',
+ 'type' => 'text',
+ ),
+ 'src_dbpasswd' => array(
+ 'label' => 'DB_PASSWORD',
+ 'type' => 'password',
+ ),
+ 'src_table_prefix' => array(
+ 'label' => 'TABLE_PREFIX',
+ 'description' => 'TABLE_PREFIX_EXPLAIN',
+ 'type' => 'text',
+ ),
+ 'forum_path' => array(
+ 'label' => 'FORUM_PATH',
+ 'description' => 'FORUM_PATH_EXPLAIN',
+ 'type' => 'text',
+ ),
+ 'refresh' => array(
+ 'label' => 'REFRESH_PAGE',
+ 'description' => 'REFRESH_PAGE_EXPLAIN',
+ 'type' => 'radio',
+ 'options' => array(
+ array(
+ 'value' => 0,
+ 'label' => 'NO',
+ 'selected' => true,
+ ),
+ array(
+ 'value' => 1,
+ 'label' => 'YES',
+ 'selected' => false,
+ ),
+ ),
+ ),
+ 'submit' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ );
+
+ if ($this->request->is_ajax())
+ {
+ $this->iohandler->add_user_form_group($form_title, $form_data);
+ $this->iohandler->send_response(true);
+ }
+ else
+ {
+ $rendered_form = $this->iohandler->generate_form_render_data($form_title, $form_data);
+
+ $this->template->assign_vars(array(
+ 'TITLE' => $this->language->lang('STAGE_SETTINGS'),
+ 'CONTENT' => $rendered_form,
+ ));
+ }
+ }
+
+ /**
+ * Render the list of available convertors
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ */
+ protected function render_convert_list()
+ {
+ $this->template->assign_vars(array(
+ 'TITLE' => $this->language->lang('CONVERT_INTRO'),
+ 'BODY' => $this->language->lang('CONVERT_INTRO_BODY'),
+ 'S_LIST' => true,
+ ));
+
+ $convertors = $sort = array();
+ $get_info = true; // Global flag
+
+ $handle = @opendir($this->phpbb_root_path . 'install/convertors/');
+
+ if (!$handle)
+ {
+ die('Unable to access the convertors directory');
+ }
+
+ while ($entry = readdir($handle))
+ {
+ if (preg_match('/^convert_([a-z0-9_]+).' . $this->php_ext . '$/i', $entry, $m))
+ {
+ $phpbb_root_path = $this->phpbb_root_path; // These globals are required
+ $phpEx = $this->php_ext; // See above
+ include_once($this->phpbb_root_path . 'install/convertors/' . $entry);
+ if (isset($convertor_data))
+ {
+ $sort[strtolower($convertor_data['forum_name'])] = count($convertors);
+
+ $convertors[] = array(
+ 'tag' => $m[1],
+ 'forum_name' => $convertor_data['forum_name'],
+ 'version' => $convertor_data['version'],
+ 'dbms' => $convertor_data['dbms'],
+ 'dbhost' => $convertor_data['dbhost'],
+ 'dbport' => $convertor_data['dbport'],
+ 'dbuser' => $convertor_data['dbuser'],
+ 'dbpasswd' => $convertor_data['dbpasswd'],
+ 'dbname' => $convertor_data['dbname'],
+ 'table_prefix' => $convertor_data['table_prefix'],
+ 'author' => $convertor_data['author']
+ );
+ }
+ unset($convertor_data);
+ }
+ }
+ closedir($handle);
+
+ @ksort($sort);
+
+ foreach ($sort as $void => $index)
+ {
+ $this->template->assign_block_vars('convertors', array(
+ 'AUTHOR' => $convertors[$index]['author'],
+ 'SOFTWARE' => $convertors[$index]['forum_name'],
+ 'VERSION' => $convertors[$index]['version'],
+
+ 'U_CONVERT' => $this->controller_helper->route('phpbb_convert_settings', array('converter' => $convertors[$index]['tag'])),
+ ));
+ }
+
+ return $this->controller_helper->render('installer_convert.html', 'SUB_INTRO', true);
+ }
+
+ /**
+ * Renders an error form
+ *
+ * @param string $msg
+ * @param string|bool $desc
+ */
+ public function render_error($msg, $desc = false)
+ {
+ if ($this->request->is_ajax())
+ {
+ $this->iohandler->add_error_message($msg, $desc);
+ $this->iohandler->send_response(true);
+ }
+ else
+ {
+ $this->template->assign_vars(array(
+ 'S_ERROR_BOX' => true,
+ 'ERROR_TITLE' => $this->language->lang($msg),
+ ));
+
+ if ($desc)
+ {
+ $this->template->assign_var('ERROR_MSG', $this->language->lang($desc));
+ }
+ }
+ }
+
+ /**
+ * Redirects an AJAX request to a non-JS version
+ *
+ * @param string $url URL to redirect to
+ */
+ public function redirect_to_html($url)
+ {
+ $this->iohandler->redirect($url);
+ $this->iohandler->send_response(true);
+ }
+
+ private function setup_navigation($stage)
+ {
+ $active = true;
+ $completed = false;
+
+ switch ($stage)
+ {
+ case 'finish':
+ $this->navigation_provider->set_nav_property(
+ array('convert', 0, 'finish'),
+ array(
+ 'selected' => $active,
+ 'completed' => $completed,
+ )
+ );
+
+ $active = false;
+ $completed = true;
+ // no break;
+
+ case 'convert':
+ $this->navigation_provider->set_nav_property(
+ array('convert', 0, 'convert'),
+ array(
+ 'selected' => $active,
+ 'completed' => $completed,
+ )
+ );
+
+ $active = false;
+ $completed = true;
+ // no break;
+
+ case 'settings':
+ $this->navigation_provider->set_nav_property(
+ array('convert', 0, 'settings'),
+ array(
+ 'selected' => $active,
+ 'completed' => $completed,
+ )
+ );
+
+ $active = false;
+ $completed = true;
+ // no break;
+
+ case 'intro':
+ $this->navigation_provider->set_nav_property(
+ array('convert', 0, 'intro'),
+ array(
+ 'selected' => $active,
+ 'completed' => $completed,
+ )
+ );
+ break;
+ }
+ }
+}
diff --git a/phpBB/install/convert/convert.php b/phpBB/install/convert/convert.php
new file mode 100644
index 0000000000..3e9e562f2e
--- /dev/null
+++ b/phpBB/install/convert/convert.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\convert;
+
+/**
+ * Class holding all convertor-specific details.
+ *
+ * WARNING: This file did not meant to be present in a production environment, so moving this file to a location which
+ * is accessible after board installation might lead to security issues.
+ */
+class convert
+{
+ var $options = array();
+
+ var $convertor_tag = '';
+ var $src_dbms = '';
+ var $src_dbhost = '';
+ var $src_dbport = '';
+ var $src_dbuser = '';
+ var $src_dbpasswd = '';
+ var $src_dbname = '';
+ var $src_table_prefix = '';
+
+ var $convertor_data = array();
+ var $tables = array();
+ var $config_schema = array();
+ var $convertor = array();
+ var $src_truncate_statement = 'DELETE FROM ';
+ var $truncate_statement = 'DELETE FROM ';
+
+ var $fulltext_search;
+
+ // Batch size, can be adjusted by the conversion file
+ // For big boards a value of 6000 seems to be optimal
+ var $batch_size = 2000;
+ // Number of rows to be inserted at once (extended insert) if supported
+ // For installations having enough memory a value of 60 may be good.
+ var $num_wait_rows = 20;
+
+ // Mysqls internal recoding engine messing up with our (better) functions? We at least support more encodings than mysql so should use it in favor.
+ var $mysql_convert = false;
+
+ var $p_master;
+
+ function __construct($p_master)
+ {
+ $this->p_master = $p_master;
+ }
+}
diff --git a/phpBB/install/convert/convertor.php b/phpBB/install/convert/convertor.php
new file mode 100644
index 0000000000..5118651b71
--- /dev/null
+++ b/phpBB/install/convert/convertor.php
@@ -0,0 +1,1614 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\convert;
+
+use phpbb\install\controller\helper;
+use phpbb\template\template;
+
+/**
+ * Convertor backend class
+ *
+ * WARNING: This file did not meant to be present in a production environment, so moving this file to a location which
+ * is accessible after board installation might lead to security issues.
+ */
+class convertor
+{
+ /**
+ * @var helper
+ */
+ protected $controller_helper;
+
+ /**
+ * @var \phpbb\filesystem\filesystem
+ */
+ protected $filesystem;
+
+ /**
+ * @var \phpbb\template\template
+ */
+ protected $template;
+
+ /**
+ * Constructor
+ *
+ * @param template $template
+ * @param helper $controller_helper
+ */
+ public function __construct(template $template, helper $controller_helper)
+ {
+ global $convert, $phpbb_filesystem;
+
+ $this->template = $template;
+ $this->filesystem = $phpbb_filesystem;
+ $this->controller_helper = $controller_helper;
+
+ $convert = new convert($this);
+ }
+
+ /**
+ * The function which does the actual work (or dispatches it to the relevant places)
+ */
+ function convert_data($converter)
+ {
+ global $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache, $auth;
+ global $convert, $convert_row, $message_parser, $skip_rows, $language;
+ global $request, $phpbb_dispatcher;
+
+ $phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
+ extract($phpbb_config_php_file->get_all());
+
+ require_once($phpbb_root_path . 'includes/constants.' . $phpEx);
+ require_once($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
+
+ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
+
+ /** @var \phpbb\db\driver\driver_interface $db */
+ $db = new $dbms();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
+ unset($dbpasswd);
+
+ // We need to fill the config to let internal functions correctly work
+ $config = new \phpbb\config\db($db, new \phpbb\cache\driver\dummy, CONFIG_TABLE);
+
+ // Override a couple of config variables for the duration
+ $config['max_quote_depth'] = 0;
+
+ // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
+ $config['max_post_chars'] = $config['min_post_chars'] = 0;
+
+ // Set up a user as well. We _should_ have enough of a database here at this point to do this
+ // and it helps for any core code we call
+ $user->session_begin();
+ $user->page = $user->extract_current_page($phpbb_root_path);
+
+ $convert->options = array();
+ if (isset($config['convert_progress']))
+ {
+ $convert->options = unserialize($config['convert_progress']);
+ $convert->options = array_merge($convert->options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
+ }
+
+ // This information should have already been checked once, but do it again for safety
+ if (empty($convert->options) || empty($convert->options['tag']) ||
+ !isset($convert->options['dbms']) ||
+ !isset($convert->options['dbhost']) ||
+ !isset($convert->options['dbport']) ||
+ !isset($convert->options['dbuser']) ||
+ !isset($convert->options['dbpasswd']) ||
+ !isset($convert->options['dbname']) ||
+ !isset($convert->options['table_prefix']))
+ {
+ $this->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
+ }
+
+ $this->template->assign_var('S_CONV_IN_PROGRESS', true);
+
+ // Make some short variables accessible, for easier referencing
+ $convert->convertor_tag = basename($convert->options['tag']);
+ $convert->src_dbms = $convert->options['dbms'];
+ $convert->src_dbhost = $convert->options['dbhost'];
+ $convert->src_dbport = $convert->options['dbport'];
+ $convert->src_dbuser = $convert->options['dbuser'];
+ $convert->src_dbpasswd = $convert->options['dbpasswd'];
+ $convert->src_dbname = $convert->options['dbname'];
+ $convert->src_table_prefix = $convert->options['table_prefix'];
+
+ // initiate database connection to old db if old and new db differ
+ global $src_db, $same_db;
+ $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)
+ {
+ $dbms = $convert->src_dbms;
+ /** @var \phpbb\db\driver\driver $src_db */
+ $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;
+ }
+ else
+ {
+ $src_db = $db;
+ $same_db = true;
+ }
+
+ $convert->mysql_convert = false;
+ switch ($src_db->sql_layer)
+ {
+ case 'sqlite3':
+ $convert->src_truncate_statement = 'DELETE FROM ';
+ break;
+
+ // Thanks MySQL, for silently converting...
+ case 'mysql':
+ case 'mysql4':
+ if (version_compare($src_db->sql_server_info(true, false), '4.1.3', '>='))
+ {
+ $convert->mysql_convert = true;
+ }
+ $convert->src_truncate_statement = 'TRUNCATE TABLE ';
+ break;
+
+ case 'mysqli':
+ $convert->mysql_convert = true;
+ $convert->src_truncate_statement = 'TRUNCATE TABLE ';
+ break;
+
+ default:
+ $convert->src_truncate_statement = 'TRUNCATE TABLE ';
+ break;
+ }
+
+ if ($convert->mysql_convert && !$same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ switch ($db->get_sql_layer())
+ {
+ case 'sqlite3':
+ $convert->truncate_statement = 'DELETE FROM ';
+ break;
+
+ default:
+ $convert->truncate_statement = 'TRUNCATE TABLE ';
+ break;
+ }
+
+ $get_info = false;
+
+ // check security implications of direct inclusion
+ if (!file_exists('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx))
+ {
+ $this->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
+ }
+
+ if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx))
+ {
+ include_once('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx);
+ }
+
+ $get_info = true;
+ include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
+
+ // Map some variables...
+ $convert->convertor_data = $convertor_data;
+ $convert->tables = $tables;
+ $convert->config_schema = $config_schema;
+
+ // Now include the real data
+ $get_info = false;
+ include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
+
+ $convert->convertor_data = $convertor_data;
+ $convert->tables = $tables;
+ $convert->config_schema = $config_schema;
+ $convert->convertor = $convertor;
+
+ // The test_file is a file that should be present in the location of the old board.
+ if (!file_exists($convert->options['forum_path'] . '/' . $test_file))
+ {
+ $this->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->options['forum_path']), __LINE__, __FILE__);
+ }
+
+ $search_type = $config['search_type'];
+
+ // For conversions we are a bit less strict and set to a search backend we know exist...
+ if (!class_exists($search_type))
+ {
+ $search_type = '\phpbb\search\fulltext_native';
+ $config->set('search_type', $search_type);
+ }
+
+ if (!class_exists($search_type))
+ {
+ trigger_error('NO_SUCH_SEARCH_MODULE');
+ }
+
+ $error = false;
+ $convert->fulltext_search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
+
+ if ($error)
+ {
+ trigger_error($error);
+ }
+
+ include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx);
+ $message_parser = new \parse_message();
+
+ $jump = $request->variable('jump', 0);
+ $final_jump = $request->variable('final_jump', 0);
+ $sync_batch = $request->variable('sync_batch', -1);
+ $last_statement = $request->variable('last', 0);
+
+ // We are running sync...
+ if ($sync_batch >= 0)
+ {
+ $this->sync_forums($converter, $sync_batch);
+ return;
+ }
+
+ if ($jump)
+ {
+ $this->jump($converter, $jump, $last_statement);
+ return;
+ }
+
+ if ($final_jump)
+ {
+ $this->final_jump($final_jump);
+ return;
+ }
+
+ $current_table = $request->variable('current_table', 0);
+ $old_current_table = min(-1, $current_table - 1);
+ $skip_rows = $request->variable('skip_rows', 0);
+
+ if (!$current_table && !$skip_rows)
+ {
+ if (!$request->variable('confirm', false))
+ {
+ // If avatars / ranks / smilies folders are specified make sure they are writable
+ $bad_folders = array();
+
+ $local_paths = array(
+ 'avatar_path' => path($config['avatar_path']),
+ 'avatar_gallery_path' => path($config['avatar_gallery_path']),
+ 'icons_path' => path($config['icons_path']),
+ 'ranks_path' => path($config['ranks_path']),
+ 'smilies_path' => path($config['smilies_path'])
+ );
+
+ foreach ($local_paths as $folder => $local_path)
+ {
+ if (isset($convert->convertor[$folder]))
+ {
+ if (empty($convert->convertor['test_file']))
+ {
+ // test_file is mandantory at the moment so this should never be reached, but just in case...
+ $this->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
+ }
+
+ if (!$local_path || !$this->filesystem->is_writable($phpbb_root_path . $local_path))
+ {
+ if (!$local_path)
+ {
+ $bad_folders[] = sprintf($user->lang['CONFIG_PHPBB_EMPTY'], $folder);
+ }
+ else
+ {
+ $bad_folders[] = $local_path;
+ }
+ }
+ }
+ }
+
+ if (count($bad_folders))
+ {
+ $msg = (count($bad_folders) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
+ sort($bad_folders);
+ $this->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true);
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['INSTALL_TEST'],
+ 'U_ACTION' => $this->controller_helper->route('phpbb_convert_convert', array('converter' => $converter)),
+ ));
+ return;
+ }
+
+ // Grab all the tables used in convertor
+ $missing_tables = $tables_list = $aliases = array();
+
+ foreach ($convert->convertor['schema'] as $schema)
+ {
+ // Skip those not used (because of addons/plugins not detected)
+ if (!$schema['target'])
+ {
+ continue;
+ }
+
+ foreach ($schema as $key => $val)
+ {
+ // we're dealing with an array like:
+ // array('forum_status', 'forums.forum_status', 'is_item_locked')
+ if (is_int($key) && !empty($val[1]))
+ {
+ $temp_data = $val[1];
+ if (!is_array($temp_data))
+ {
+ $temp_data = array($temp_data);
+ }
+
+ foreach ($temp_data as $value)
+ {
+ if (preg_match('/([a-z0-9_]+)\.([a-z0-9_]+)\)* ?A?S? ?([a-z0-9_]*?)\.?([a-z0-9_]*)$/i', $value, $m))
+ {
+ $table = $convert->src_table_prefix . $m[1];
+ $tables_list[$table] = $table;
+
+ if (!empty($m[3]))
+ {
+ $aliases[] = $convert->src_table_prefix . $m[3];
+ }
+ }
+ }
+ }
+ // 'left_join' => 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1'
+ else if ($key == 'left_join')
+ {
+ // Convert the value if it wasn't an array already.
+ if (!is_array($val))
+ {
+ $val = array($val);
+ }
+
+ for ($j = 0, $size = count($val); $j < $size; ++$j)
+ {
+ if (preg_match('/LEFT JOIN ([a-z0-9_]+) AS ([a-z0-9_]+)/i', $val[$j], $m))
+ {
+ $table = $convert->src_table_prefix . $m[1];
+ $tables_list[$table] = $table;
+
+ if (!empty($m[2]))
+ {
+ $aliases[] = $convert->src_table_prefix . $m[2];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Remove aliased tables from $tables_list
+ foreach ($aliases as $alias)
+ {
+ unset($tables_list[$alias]);
+ }
+
+ // Check if the tables that we need exist
+ $src_db->sql_return_on_error(true);
+ foreach ($tables_list as $table => $null)
+ {
+ $sql = 'SELECT 1 FROM ' . $table;
+ $_result = $src_db->sql_query_limit($sql, 1);
+
+ if (!$_result)
+ {
+ $missing_tables[] = $table;
+ }
+ $src_db->sql_freeresult($_result);
+ }
+ $src_db->sql_return_on_error(false);
+
+ // Throw an error if some tables are missing
+ // We used to do some guessing here, but since we have a suggestion of possible values earlier, I don't see it adding anything here to do it again
+
+ if (count($missing_tables) == count($tables_list))
+ {
+ $this->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
+ }
+ else if (count($missing_tables))
+ {
+ $this->error(sprintf($user->lang['TABLES_MISSING'], implode($user->lang['COMMA_SEPARATOR'], $missing_tables)) . '<br /><br />' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
+ }
+
+ $url = $this->save_convert_progress($converter, 'confirm=1');
+ $msg = $user->lang['PRE_CONVERT_COMPLETE'];
+
+ if ($convert->convertor_data['author_notes'])
+ {
+ $msg .= '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
+ }
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'BODY' => $msg,
+ 'U_ACTION' => $url,
+ ));
+
+ return;
+ } // if (!$request->variable('confirm', false)))
+
+ $this->template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['STARTING_CONVERT'],
+ ));
+
+ // Convert the config table and load the settings of the old board
+ if (!empty($convert->config_schema))
+ {
+ restore_config($convert->config_schema);
+
+ // Override a couple of config variables for the duration
+ $config['max_quote_depth'] = 0;
+
+ // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
+ $config['max_post_chars'] = $config['min_post_chars'] = 0;
+ }
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['CONFIG_CONVERT'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ // Now process queries and execute functions that have to be executed prior to the conversion
+ if (!empty($convert->convertor['execute_first']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($convert->convertor['execute_first']);
+ // @codingStandardsIgnoreEnd
+ }
+
+ if (!empty($convert->convertor['query_first']))
+ {
+ if (!is_array($convert->convertor['query_first']))
+ {
+ $convert->convertor['query_first'] = array('target', array($convert->convertor['query_first']));
+ }
+ else if (!is_array($convert->convertor['query_first'][0]))
+ {
+ $convert->convertor['query_first'] = array(array($convert->convertor['query_first'][0], $convert->convertor['query_first'][1]));
+ }
+
+ foreach ($convert->convertor['query_first'] as $query_first)
+ {
+ if ($query_first[0] == 'src')
+ {
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $src_db->sql_query($query_first[1]);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+ }
+ else
+ {
+ $db->sql_query($query_first[1]);
+ }
+ }
+ }
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['PREPROCESS_STEP'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+ } // if (!$current_table && !$skip_rows)
+
+ $this->template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['FILLING_TABLES'],
+ ));
+
+ // This loop takes one target table and processes it
+ while ($current_table < count($convert->convertor['schema']))
+ {
+ $schema = $convert->convertor['schema'][$current_table];
+
+ // The target table isn't set, this can be because a module (for example the attachement mod) is taking care of this.
+ if (empty($schema['target']))
+ {
+ $current_table++;
+ continue;
+ }
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => sprintf($user->lang['FILLING_TABLE'], $schema['target']),
+ ));
+
+ // This is only the case when we first start working on the tables.
+ if (!$skip_rows)
+ {
+ // process execute_first and query_first for this table...
+ if (!empty($schema['execute_first']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($schema['execute_first']);
+ // @codingStandardsIgnoreEnd
+ }
+
+ if (!empty($schema['query_first']))
+ {
+ if (!is_array($schema['query_first']))
+ {
+ $schema['query_first'] = array('target', array($schema['query_first']));
+ }
+ else if (!is_array($schema['query_first'][0]))
+ {
+ $schema['query_first'] = array(array($schema['query_first'][0], $schema['query_first'][1]));
+ }
+
+ foreach ($schema['query_first'] as $query_first)
+ {
+ if ($query_first[0] == 'src')
+ {
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+ $src_db->sql_query($query_first[1]);
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+ }
+ else
+ {
+ $db->sql_query($query_first[1]);
+ }
+ }
+ }
+
+ if (!empty($schema['autoincrement']))
+ {
+ switch ($db->get_sql_layer())
+ {
+ case 'postgres':
+ $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
+ break;
+
+ case 'oracle':
+ $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ $largest_id = (int) $row['max_id'];
+
+ if ($largest_id)
+ {
+ $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
+ $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
+ }
+ break;
+ }
+ }
+ }
+
+ // Process execute_always for this table
+ // This is for code which needs to be executed on every pass of this table if
+ // it gets split because of time restrictions
+ if (!empty($schema['execute_always']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($schema['execute_always']);
+ // @codingStandardsIgnoreEnd
+ }
+
+ //
+ // Set up some variables
+ //
+ // $waiting_rows holds rows for multirows insertion (MySQL only)
+ // $src_tables holds unique tables with aliases to select from
+ // $src_fields will quickly refer source fields (or aliases) corresponding to the current index
+ // $select_fields holds the names of the fields to retrieve
+ //
+
+ $sql_data = array(
+ 'source_fields' => array(),
+ 'target_fields' => array(),
+ 'source_tables' => array(),
+ 'select_fields' => array(),
+ );
+
+ // This statement is building the keys for later insertion.
+ $insert_query = $this->build_insert_query($schema, $sql_data, $current_table);
+
+ // If no source table is affected, we skip the table
+ if (empty($sql_data['source_tables']))
+ {
+ $skip_rows = 0;
+ $current_table++;
+ continue;
+ }
+
+ $distinct = (!empty($schema['distinct'])) ? 'DISTINCT ' : '';
+
+ $sql = 'SELECT ' . $distinct . implode(', ', $sql_data['select_fields']) . " \nFROM " . implode(', ', $sql_data['source_tables']);
+
+ // Where
+ $sql .= (!empty($schema['where'])) ? "\nWHERE (" . $schema['where'] . ')' : '';
+
+ // Group By
+ if (!empty($schema['group_by']))
+ {
+ $schema['group_by'] = array($schema['group_by']);
+ foreach ($sql_data['select_fields'] as $select)
+ {
+ $alias = strpos(strtolower($select), ' as ');
+ $select = ($alias) ? substr($select, 0, $alias) : $select;
+ if (!in_array($select, $schema['group_by']))
+ {
+ $schema['group_by'][] = $select;
+ }
+ }
+ }
+ $sql .= (!empty($schema['group_by'])) ? "\nGROUP BY " . implode(', ', $schema['group_by']) : '';
+
+ // Having
+ $sql .= (!empty($schema['having'])) ? "\nHAVING " . $schema['having'] : '';
+
+ // Order By
+ if (empty($schema['order_by']) && !empty($schema['primary']))
+ {
+ $schema['order_by'] = $schema['primary'];
+ }
+ $sql .= (!empty($schema['order_by'])) ? "\nORDER BY " . $schema['order_by'] : '';
+
+ // Counting basically holds the amount of rows processed.
+ $counting = -1;
+ $batch_time = 0;
+
+ while ($counting === -1 || ($counting >= $convert->batch_size && still_on_time()))
+ {
+ $old_current_table = $current_table;
+
+ $rows = '';
+ $waiting_rows = array();
+
+ if (!empty($batch_time))
+ {
+ $mtime = explode(' ', microtime());
+ $mtime = $mtime[0] + $mtime[1];
+ $rows = ceil($counting/($mtime - $batch_time)) . " rows/s ($counting rows) | ";
+ }
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => "skip_rows = $skip_rows",
+ 'RESULT' => $rows . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] : ''),
+ ));
+
+ $mtime = explode(' ', microtime());
+ $batch_time = $mtime[0] + $mtime[1];
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ // Take skip rows into account and only fetch batch_size amount of rows
+ $___result = $src_db->sql_query_limit($sql, $convert->batch_size, $skip_rows);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+
+ // This loop processes each row
+ $counting = 0;
+
+ $convert->row = $convert_row = array();
+
+ if (!empty($schema['autoincrement']))
+ {
+ switch ($db->get_sql_layer())
+ {
+ case 'mssql_odbc':
+ case 'mssqlnative':
+ $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' ON');
+ break;
+ }
+ }
+
+ // Now handle the rows until time is over or no more rows to process...
+ while ($counting === 0 || still_on_time())
+ {
+ $convert_row = $src_db->sql_fetchrow($___result);
+
+ if (!$convert_row)
+ {
+ // move to the next batch or table
+ break;
+ }
+
+ // With this we are able to always save the last state
+ $convert->row = $convert_row;
+
+ // Increment the counting variable, it stores the number of rows we have processed
+ $counting++;
+
+ $insert_values = array();
+
+ $sql_flag = $this->process_row($schema, $sql_data, $insert_values);
+
+ if ($sql_flag === true)
+ {
+ switch ($db->get_sql_layer())
+ {
+ // If MySQL, we'll wait to have num_wait_rows rows to submit at once
+ case 'mysql':
+ case 'mysql4':
+ case 'mysqli':
+ $waiting_rows[] = '(' . implode(', ', $insert_values) . ')';
+
+ if (count($waiting_rows) >= $convert->num_wait_rows)
+ {
+ $errored = false;
+
+ $db->sql_return_on_error(true);
+
+ if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
+ {
+ $errored = true;
+ }
+ $db->sql_return_on_error(false);
+
+ if ($errored)
+ {
+ $db->sql_return_on_error(true);
+
+ // Because it errored out we will try to insert the rows one by one... most of the time this
+ // is caused by duplicate entries - but we also do not want to miss one...
+ foreach ($waiting_rows as $waiting_sql)
+ {
+ if (!$db->sql_query($insert_query . $waiting_sql))
+ {
+ $this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
+ }
+ }
+
+ $db->sql_return_on_error(false);
+ }
+
+ $waiting_rows = array();
+ }
+
+ break;
+
+ default:
+ $insert_sql = $insert_query . '(' . implode(', ', $insert_values) . ')';
+
+ $db->sql_return_on_error(true);
+
+ if (!$db->sql_query($insert_sql))
+ {
+ $this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
+ }
+ $db->sql_return_on_error(false);
+
+ $waiting_rows = array();
+
+ break;
+ }
+ }
+
+ $skip_rows++;
+ }
+ $src_db->sql_freeresult($___result);
+
+ // We might still have some rows waiting
+ if (count($waiting_rows))
+ {
+ $errored = false;
+ $db->sql_return_on_error(true);
+
+ if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
+ {
+ $errored = true;
+ }
+ $db->sql_return_on_error(false);
+
+ if ($errored)
+ {
+ $db->sql_return_on_error(true);
+
+ // Because it errored out we will try to insert the rows one by one... most of the time this
+ // is caused by duplicate entries - but we also do not want to miss one...
+ foreach ($waiting_rows as $waiting_sql)
+ {
+ $db->sql_query($insert_query . $waiting_sql);
+ $this->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
+ }
+
+ $db->sql_return_on_error(false);
+ }
+
+ $waiting_rows = array();
+ }
+
+ if (!empty($schema['autoincrement']))
+ {
+ switch ($db->get_sql_layer())
+ {
+ case 'mssql_odbc':
+ case 'mssqlnative':
+ $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' OFF');
+ break;
+
+ case 'postgres':
+ $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
+ break;
+
+ case 'oracle':
+ $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ $largest_id = (int) $row['max_id'];
+
+ if ($largest_id)
+ {
+ $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
+ $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
+ }
+ break;
+ }
+ }
+ }
+
+ // When we reach this point, either the current table has been processed or we're running out of time.
+ if (still_on_time() && $counting < $convert->batch_size/* && !defined('DEBUG')*/)
+ {
+ $skip_rows = 0;
+ $current_table++;
+ }
+ else
+ {/*
+ if (still_on_time() && $counting < $convert->batch_size)
+ {
+ $skip_rows = 0;
+ $current_table++;
+ }*/
+
+ // Looks like we ran out of time.
+ $url = $this->save_convert_progress($converter, 'current_table=' . $current_table . '&amp;skip_rows=' . $skip_rows);
+
+ $current_table++;
+// $percentage = ($skip_rows == 0) ? 0 : floor(100 / ($total_rows / $skip_rows));
+
+ $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $current_table, count($convert->convertor['schema']));
+
+ $this->template->assign_vars(array(
+ 'BODY' => $msg,
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ }
+
+ // Process execute_last then we'll be done
+ $url = $this->save_convert_progress($converter, 'jump=1');
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['FINAL_STEP'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * Sync function being executed at the middle, some functions need to be executed after a successful sync.
+ */
+ function sync_forums($converter, $sync_batch)
+ {
+ global $user, $db, $phpbb_root_path, $phpEx, $config, $cache;
+ global $convert;
+
+ include_once ($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
+
+ $this->template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['SYNC_TOPICS'],
+ ));
+
+ $batch_size = $convert->batch_size;
+
+ $sql = 'SELECT MIN(topic_id) as min_value, MAX(topic_id) AS max_value
+ FROM ' . TOPICS_TABLE;
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ // Set values of minimum/maximum primary value for this table.
+ $primary_min = $row['min_value'];
+ $primary_max = $row['max_value'];
+
+ if ($sync_batch == 0)
+ {
+ $sync_batch = (int) $primary_min;
+ }
+
+ if ($sync_batch == 0)
+ {
+ $sync_batch = 1;
+ }
+
+ // Fetch a batch of rows, process and insert them.
+ while ($sync_batch <= $primary_max && still_on_time())
+ {
+ $end = ($sync_batch + $batch_size - 1);
+
+ // Sync all topics in batch mode...
+ sync('topic', 'range', 'topic_id BETWEEN ' . $sync_batch . ' AND ' . $end, true, true);
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => sprintf($user->lang['SYNC_TOPIC_ID'], $sync_batch, ($sync_batch + $batch_size)) . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ' [' . ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] . ']' : ''),
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $sync_batch += $batch_size;
+ }
+
+ if ($sync_batch >= $primary_max)
+ {
+ $url = $this->save_convert_progress($converter, 'final_jump=1');
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ else
+ {
+ $sync_batch--;
+ }
+
+ $url = $this->save_convert_progress($converter, 'sync_batch=' . $sync_batch);
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * Save the convertor status
+ */
+ function save_convert_progress($convertor_tag, $step)
+ {
+ global $config, $convert, $language;
+
+ // Save convertor Status
+ $config->set('convert_progress', serialize(array(
+ 'step' => $step,
+ 'table_prefix' => $convert->src_table_prefix,
+ 'tag' => $convert->convertor_tag,
+ )), false);
+
+ $config->set('convert_db_server', serialize(array(
+ 'dbms' => $convert->src_dbms,
+ 'dbhost' => $convert->src_dbhost,
+ 'dbport' => $convert->src_dbport,
+ 'dbname' => $convert->src_dbname,
+ )), false);
+
+ $config->set('convert_db_user', serialize(array(
+ 'dbuser' => $convert->src_dbuser,
+ 'dbpasswd' => $convert->src_dbpasswd,
+ )), false);
+
+ return $this->controller_helper->route('phpbb_convert_convert', array('converter' => $convertor_tag)) . '?' . $step;
+ }
+
+ /**
+ * Finish conversion, the last function to be called.
+ */
+ function finish_conversion()
+ {
+ global $db, $phpbb_root_path, $phpEx, $convert, $config, $language, $user;
+ global $cache, $auth, $phpbb_container, $phpbb_log;
+
+ include_once ($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
+
+ $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
+ WHERE config_name = 'convert_progress'
+ OR config_name = 'convert_options'
+ OR config_name = 'convert_db_server'
+ OR config_name = 'convert_db_user'");
+ $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
+
+ @unlink($phpbb_container->getParameter('core.cache_dir') . 'data_global.' . $phpEx);
+ phpbb_cache_moderators($db, $cache, $auth);
+
+ // And finally, add a note to the log
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_INSTALL_CONVERTED', false, array($convert->convertor_data['forum_name'], $config['version']));
+
+ $url = $this->controller_helper->route('phpbb_convert_finish');
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['FINAL_STEP'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ /**
+ * This function marks the steps after syncing
+ */
+ function final_jump($final_jump)
+ {
+ global $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
+ global $convert;
+
+ $this->template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['PROCESS_LAST'],
+ ));
+
+ if ($final_jump == 1)
+ {
+ $db->sql_return_on_error(true);
+
+ update_topics_posted();
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['UPDATE_TOPICS_POSTED'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ if ($db->get_sql_error_triggered())
+ {
+ $this->template->assign_vars(array(
+ 'S_ERROR_BOX' => true,
+ 'ERROR_TITLE' => $user->lang['UPDATE_TOPICS_POSTED'],
+ 'ERROR_MSG' => $user->lang['UPDATE_TOPICS_POSTED_ERR'],
+ ));
+ }
+ $db->sql_return_on_error(false);
+
+ $this->finish_conversion();
+ return;
+ }
+ }
+
+ /**
+ * This function marks the steps before syncing (jump=1)
+ */
+ function jump($converter, $jump, $last_statement)
+ {
+ /** @var \phpbb\db\driver\driver_interface $src_db */
+ /** @var \phpbb\cache\driver\driver_interface $cache */
+ global $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
+ global $convert;
+
+ include_once ($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
+
+ $this->template->assign_block_vars('checks', array(
+ 'S_LEGEND' => true,
+ 'LEGEND' => $user->lang['PROCESS_LAST'],
+ ));
+
+ if ($jump == 1)
+ {
+ // Execute 'last' statements/queries
+ if (!empty($convert->convertor['execute_last']))
+ {
+ if (!is_array($convert->convertor['execute_last']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($convert->convertor['execute_last']);
+ // @codingStandardsIgnoreEnd
+ }
+ else
+ {
+ while ($last_statement < count($convert->convertor['execute_last']))
+ {
+ // @codingStandardsIgnoreStart
+ eval($convert->convertor['execute_last'][$last_statement]);
+ // @codingStandardsIgnoreEnd
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => $convert->convertor['execute_last'][$last_statement],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $last_statement++;
+ $url = $this->save_convert_progress($converter, 'jump=1&amp;last=' . $last_statement);
+
+ $percentage = ($last_statement == 0) ? 0 : floor(100 / (count($convert->convertor['execute_last']) / $last_statement));
+ $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $last_statement, count($convert->convertor['execute_last']), $percentage);
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_LAST'],
+ 'BODY' => $msg,
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ }
+ }
+
+ if (!empty($convert->convertor['query_last']))
+ {
+ if (!is_array($convert->convertor['query_last']))
+ {
+ $convert->convertor['query_last'] = array('target', array($convert->convertor['query_last']));
+ }
+ else if (!is_array($convert->convertor['query_last'][0]))
+ {
+ $convert->convertor['query_last'] = array(array($convert->convertor['query_last'][0], $convert->convertor['query_last'][1]));
+ }
+
+ foreach ($convert->convertor['query_last'] as $query_last)
+ {
+ if ($query_last[0] == 'src')
+ {
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'binary'");
+ }
+
+ $src_db->sql_query($query_last[1]);
+
+ if ($convert->mysql_convert && $same_db)
+ {
+ $src_db->sql_query("SET NAMES 'utf8'");
+ }
+ }
+ else
+ {
+ $db->sql_query($query_last[1]);
+ }
+ }
+ }
+
+ // Sanity check
+ $db->sql_return_on_error(false);
+ $src_db->sql_return_on_error(false);
+
+ fix_empty_primary_groups();
+
+ $sql = 'SELECT MIN(user_regdate) AS board_startdate
+ FROM ' . USERS_TABLE;
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ if (!isset($config['board_startdate']) || ($row['board_startdate'] < $config['board_startdate'] && $row['board_startdate'] > 0))
+ {
+ $config->set('board_startdate', $row['board_startdate']);
+ $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_regdate = ' . $row['board_startdate'] . ' WHERE user_id = ' . ANONYMOUS);
+ }
+
+ update_dynamic_config();
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['CLEAN_VERIFY'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ $url = $this->save_convert_progress($converter, 'jump=2');
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+
+ if ($jump == 2)
+ {
+ $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_permissions = ''");
+
+ // TODO: sync() is likely going to bomb out on forums with a considerable amount of topics.
+ // TODO: the sync function is able to handle FROM-TO values, we should use them here (batch processing)
+ sync('forum', '', '', false, true);
+ $cache->destroy('sql', FORUMS_TABLE);
+
+ $this->template->assign_block_vars('checks', array(
+ 'TITLE' => $user->lang['SYNC_FORUMS'],
+ 'RESULT' => $user->lang['DONE'],
+ ));
+
+ // Continue with synchronizing the forums...
+ $url = $this->save_convert_progress($converter, 'sync_batch=0');
+
+ $this->template->assign_vars(array(
+ 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
+ 'U_ACTION' => $url,
+ ));
+
+ $this->meta_refresh($url);
+ return;
+ }
+ }
+
+ function build_insert_query(&$schema, &$sql_data, $current_table)
+ {
+ global $db, $user;
+ global $convert;
+
+ // Can we use IGNORE with this DBMS?
+ $sql_ignore = (strpos($db->get_sql_layer(), 'mysql') === 0 && !defined('DEBUG')) ? 'IGNORE ' : '';
+ $insert_query = 'INSERT ' . $sql_ignore . 'INTO ' . $schema['target'] . ' (';
+
+ $aliases = array();
+
+ $sql_data = array(
+ 'source_fields' => array(),
+ 'target_fields' => array(),
+ 'source_tables' => array(),
+ 'select_fields' => array(),
+ );
+
+ foreach ($schema as $key => $val)
+ {
+ // Example: array('group_name', 'extension_groups.group_name', 'htmlspecialchars'),
+ if (is_int($key))
+ {
+ if (!empty($val[0]))
+ {
+ // Target fields
+ $sql_data['target_fields'][$val[0]] = $key;
+ $insert_query .= $val[0] . ', ';
+ }
+
+ if (!is_array($val[1]))
+ {
+ $val[1] = array($val[1]);
+ }
+
+ foreach ($val[1] as $valkey => $value_1)
+ {
+ // This should cover about any case:
+ //
+ // table.field => SELECT table.field FROM table
+ // table.field AS alias => SELECT table.field AS alias FROM table
+ // table.field AS table2.alias => SELECT table2.field AS alias FROM table table2
+ // table.field AS table2.field => SELECT table2.field FROM table table2
+ //
+ if (preg_match('/^([a-z0-9_]+)\.([a-z0-9_]+)( +AS +(([a-z0-9_]+?)\.)?([a-z0-9_]+))?$/i', $value_1, $m))
+ {
+ // There is 'AS ...' in the field names
+ if (!empty($m[3]))
+ {
+ $value_1 = ($m[2] == $m[6]) ? $m[1] . '.' . $m[2] : $m[1] . '.' . $m[2] . ' AS ' . $m[6];
+
+ // Table alias: store it then replace the source table with it
+ if (!empty($m[5]) && $m[5] != $m[1])
+ {
+ $aliases[$m[5]] = $m[1];
+ $value_1 = str_replace($m[1] . '.' . $m[2], $m[5] . '.' . $m[2], $value_1);
+ }
+ }
+ else
+ {
+ // No table alias
+ $sql_data['source_tables'][$m[1]] = (empty($convert->src_table_prefix)) ? $m[1] : $convert->src_table_prefix . $m[1] . ' ' . $m[1];
+ }
+
+ $sql_data['select_fields'][$value_1] = $value_1;
+ $sql_data['source_fields'][$key][$valkey] = (!empty($m[6])) ? $m[6] : $m[2];
+ }
+ }
+ }
+ else if ($key == 'where' || $key == 'group_by' || $key == 'order_by' || $key == 'having')
+ {
+ if (@preg_match_all('/([a-z0-9_]+)\.([a-z0-9_]+)/i', $val, $m))
+ {
+ foreach ($m[1] as $value)
+ {
+ $sql_data['source_tables'][$value] = (empty($convert->src_table_prefix)) ? $value : $convert->src_table_prefix . $value . ' ' . $value;
+ }
+ }
+ }
+ }
+
+ // Add the aliases to the list of tables
+ foreach ($aliases as $alias => $table)
+ {
+ $sql_data['source_tables'][$alias] = $convert->src_table_prefix . $table . ' ' . $alias;
+ }
+
+ // 'left_join' => 'forums LEFT JOIN forum_prune ON forums.forum_id = forum_prune.forum_id',
+ if (!empty($schema['left_join']))
+ {
+ if (!is_array($schema['left_join']))
+ {
+ $schema['left_join'] = array($schema['left_join']);
+ }
+
+ foreach ($schema['left_join'] as $left_join)
+ {
+ // This won't handle concatened LEFT JOINs
+ if (!preg_match('/([a-z0-9_]+) LEFT JOIN ([a-z0-9_]+) A?S? ?([a-z0-9_]*?) ?(ON|USING)(.*)/i', $left_join, $m))
+ {
+ $this->error(sprintf($user->lang['NOT_UNDERSTAND'], 'LEFT JOIN', $left_join, $current_table, $schema['target']), __LINE__, __FILE__);
+ }
+
+ if (!empty($aliases[$m[2]]))
+ {
+ if (!empty($m[3]))
+ {
+ $this->error(sprintf($user->lang['NAMING_CONFLICT'], $m[2], $m[3], $schema['left_join']), __LINE__, __FILE__);
+ }
+
+ $m[2] = $aliases[$m[2]];
+ $m[3] = $m[2];
+ }
+
+ $right_table = $convert->src_table_prefix . $m[2];
+ if (!empty($m[3]))
+ {
+ unset($sql_data['source_tables'][$m[3]]);
+ }
+ else if ($m[2] != $m[1])
+ {
+ unset($sql_data['source_tables'][$m[2]]);
+ }
+
+ if (strpos($sql_data['source_tables'][$m[1]], "\nLEFT JOIN") !== false)
+ {
+ $sql_data['source_tables'][$m[1]] = '(' . $sql_data['source_tables'][$m[1]] . ")\nLEFT JOIN $right_table";
+ }
+ else
+ {
+ $sql_data['source_tables'][$m[1]] .= "\nLEFT JOIN $right_table";
+ }
+
+ if (!empty($m[3]))
+ {
+ unset($sql_data['source_tables'][$m[3]]);
+ $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[3];
+ }
+ else if (!empty($convert->src_table_prefix))
+ {
+ $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[2];
+ }
+ $sql_data['source_tables'][$m[1]] .= ' ' . $m[4] . $m[5];
+ }
+ }
+
+ // Remove ", " from the end of the insert query
+ $insert_query = substr($insert_query, 0, -2) . ') VALUES ';
+
+ return $insert_query;
+ }
+
+ /**
+ * Function for processing the currently handled row
+ */
+ function process_row(&$schema, &$sql_data, &$insert_values)
+ {
+ global $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache;
+ global $convert, $convert_row;
+
+ $sql_flag = false;
+
+ foreach ($schema as $key => $fields)
+ {
+ // We are only interested in the lines with:
+ // array('comment', 'attachments_desc.comment', 'htmlspecialchars'),
+ if (is_int($key))
+ {
+ if (!is_array($fields[1]))
+ {
+ $fields[1] = array($fields[1]);
+ }
+
+ $firstkey_set = false;
+ $firstkey = 0;
+
+ foreach ($fields[1] as $inner_key => $inner_value)
+ {
+ if (!$firstkey_set)
+ {
+ $firstkey = $inner_key;
+ $firstkey_set = true;
+ }
+
+ $src_field = isset($sql_data['source_fields'][$key][$inner_key]) ? $sql_data['source_fields'][$key][$inner_key] : '';
+
+ if (!empty($src_field))
+ {
+ $fields[1][$inner_key] = $convert->row[$src_field];
+ }
+ }
+
+ if (!empty($fields[0]))
+ {
+ // We have a target field, if we haven't set $sql_flag yet it will be set to TRUE.
+ // If a function has already set it to FALSE it won't change it.
+ if ($sql_flag === false)
+ {
+ $sql_flag = true;
+ }
+
+ // No function assigned?
+ if (empty($fields[2]))
+ {
+ $value = $fields[1][$firstkey];
+ }
+ else if (is_array($fields[2]) && !is_callable($fields[2]))
+ {
+ // Execute complex function/eval/typecast
+ $value = $fields[1];
+
+ foreach ($fields[2] as $type => $execution)
+ {
+ if (strpos($type, 'typecast') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+ $value = $value[0];
+ settype($value, $execution);
+ }
+ else if (strpos($type, 'function') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $value = call_user_func_array($execution, $value);
+ }
+ else if (strpos($type, 'execute') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $execution = str_replace('{RESULT}', '$value', $execution);
+ $execution = str_replace('{VALUE}', '$value', $execution);
+ // @codingStandardsIgnoreStart
+ eval($execution);
+ // @codingStandardsIgnoreEnd
+ }
+ }
+ }
+ else
+ {
+ $value = call_user_func_array($fields[2], $fields[1]);
+ }
+
+ if (is_null($value))
+ {
+ $value = '';
+ }
+
+ $insert_values[] = $db->_sql_validate_value($value);
+ }
+ else if (!empty($fields[2]))
+ {
+ if (is_array($fields[2]))
+ {
+ // Execute complex function/eval/typecast
+ $value = '';
+
+ foreach ($fields[2] as $type => $execution)
+ {
+ if (strpos($type, 'typecast') === 0)
+ {
+ $value = settype($value, $execution);
+ }
+ else if (strpos($type, 'function') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $value = call_user_func_array($execution, $value);
+ }
+ else if (strpos($type, 'execute') === 0)
+ {
+ if (!is_array($value))
+ {
+ $value = array($value);
+ }
+
+ $execution = str_replace('{RESULT}', '$value', $execution);
+ $execution = str_replace('{VALUE}', '$value', $execution);
+ // @codingStandardsIgnoreStart
+ eval($execution);
+ // @codingStandardsIgnoreEnd
+ }
+ }
+ }
+ else
+ {
+ call_user_func_array($fields[2], $fields[1]);
+ }
+ }
+ }
+ }
+
+ return $sql_flag;
+ }
+
+ /**
+ * Own meta refresh function to be able to change the global time used
+ */
+ function meta_refresh($url)
+ {
+ global $convert;
+
+ if ($convert->options['refresh'])
+ {
+ // Because we should not rely on correct settings, we simply use the relative path here directly.
+ $this->template->assign_vars(array(
+ 'S_REFRESH' => true,
+ 'META' => '<meta http-equiv="refresh" content="5; url=' . $url . '" />')
+ );
+ }
+ }
+
+ /**
+ * Error handler function
+ *
+ * This function needs to be kept for BC
+ *
+ * @param $error
+ * @param $line
+ * @param $file
+ * @param bool|false $skip
+ */
+ public function error($error, $line, $file, $skip = false)
+ {
+ $this->template->assign_block_vars('errors', array(
+ 'TITLE' => $error,
+ 'DESCRIPTION' => 'In ' . $file . ' on line ' . $line,
+ ));
+ }
+
+ /**
+ * Database error handler function
+ *
+ * This function needs to be kept for BC
+ *
+ * @param $error
+ * @param $sql
+ * @param $line
+ * @param $file
+ * @param bool|false $skip
+ */
+ public function db_error($error, $sql, $line, $file, $skip = false)
+ {
+ $this->template->assign_block_vars('errors', array(
+ 'TITLE' => $error,
+ 'DESCRIPTION' => 'In ' . $file . ' on line ' . $line . '<br /><br /><strong>SQL:</strong> ' . $sql,
+ ));
+ }
+}
diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php
index 4aca80188a..ff5ec29019 100644
--- a/phpBB/install/convertors/convert_phpbb20.php
+++ b/phpBB/install/convertors/convert_phpbb20.php
@@ -38,7 +38,7 @@ $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
$convertor_data = array(
'forum_name' => 'phpBB 2.0.x',
'version' => '1.0.3',
- 'phpbb_version' => '3.1.11',
+ 'phpbb_version' => '3.2.9',
'author' => '<a href="https://www.phpbb.com/">phpBB Limited</a>',
'dbms' => $dbms,
'dbhost' => $dbhost,
@@ -233,11 +233,11 @@ if (!$get_info)
$user_id = (int) $src_db->sql_fetchfield('max_user_id');
$src_db->sql_freeresult($result);
- set_config('increment_user_id', ($user_id + 1), true);
+ $config->set('increment_user_id', ($user_id + 1), false);
}
else
{
- set_config('increment_user_id', 0, true);
+ $config->set('increment_user_id', 0, false);
}
// Overwrite maximum avatar width/height
@@ -963,7 +963,6 @@ if (!$get_info)
array('pf_phpbb_interests', 'users.user_interests', array('function1' => 'phpbb_set_encoding')),
array('pf_phpbb_location', 'users.user_from', array('function1' => 'phpbb_set_encoding')),
array('pf_phpbb_icq', 'users.user_icq', array('function1' => 'phpbb_set_encoding')),
- array('pf_phpbb_wlm', 'users.user_msnm', array('function1' => 'phpbb_set_encoding')),
array('pf_phpbb_yahoo', 'users.user_yim', array('function1' => 'phpbb_set_encoding')),
array('pf_phpbb_aol', 'users.user_aim', array('function1' => 'phpbb_set_encoding')),
array('pf_phpbb_website', 'users.user_website', 'validate_website'),
diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php
index 817c007274..2da901d3de 100644
--- a/phpBB/install/convertors/functions_phpbb20.php
+++ b/phpBB/install/convertors/functions_phpbb20.php
@@ -54,7 +54,7 @@ function phpbb_forum_flags()
*/
function phpbb_insert_forums()
{
- global $db, $src_db, $same_db, $convert, $user, $config;
+ global $db, $src_db, $same_db, $convert, $user;
$db->sql_query($convert->truncate_statement . FORUMS_TABLE);
@@ -94,7 +94,6 @@ function phpbb_insert_forums()
switch ($db->get_sql_layer())
{
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$db->sql_query('SET IDENTITY_INSERT ' . FORUMS_TABLE . ' ON');
@@ -179,7 +178,6 @@ function phpbb_insert_forums()
$db->sql_query($sql);
$cats_added[$unknown_cat_id] = $max_forum_id;
- $max_forum_id++;
}
// Now insert the forums
@@ -295,7 +293,6 @@ function phpbb_insert_forums()
$db->sql_query("SELECT SETVAL('" . FORUMS_TABLE . "_seq',(select case when max(forum_id)>0 then max(forum_id)+1 else 1 end from " . FORUMS_TABLE . '));');
break;
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$db->sql_query('SET IDENTITY_INSERT ' . FORUMS_TABLE . ' OFF');
@@ -422,8 +419,6 @@ function phpbb_set_encoding($text, $grab_user_lang = true)
}
}
- $encoding = $lang_enc_array[$get_lang];
-
return utf8_recode($text, $lang_enc_array[$get_lang]);
}
@@ -514,12 +509,12 @@ function phpbb_user_id($user_id)
// If there is a user id 1, we need to increment user ids. :/
if ($id === 1)
{
- set_config('increment_user_id', ($max_id + 1), true);
+ $config->set('increment_user_id', ($max_id + 1), false);
$config['increment_user_id'] = $max_id + 1;
}
else
{
- set_config('increment_user_id', 0, true);
+ $config->set('increment_user_id', 0, false);
$config['increment_user_id'] = 0;
}
}
@@ -564,7 +559,7 @@ function phpbb_copy_table_fields()
*/
function phpbb_convert_authentication($mode)
{
- global $db, $src_db, $same_db, $convert, $user, $config, $cache;
+ global $db, $src_db, $same_db, $convert, $config;
if ($mode == 'start')
{
@@ -661,7 +656,7 @@ function phpbb_convert_authentication($mode)
'auth_delete' => 'f_delete',
'auth_pollcreate' => 'f_poll',
'auth_vote' => 'f_vote',
- 'auth_announce' => 'f_announce',
+ 'auth_announce' => array('f_announce', 'f_announce_global'),
'auth_sticky' => 'f_sticky',
'auth_attachments' => array('f_attach', 'f_download'),
'auth_download' => 'f_download',
@@ -990,7 +985,7 @@ function phpbb_convert_authentication($mode)
// We make sure that they have at least standard access to the forums they moderate in addition to the moderating permissions
$mod_post_map = array(
- 'auth_announce' => 'f_announce',
+ 'auth_announce' => array('f_announce', 'f_announce_global'),
'auth_sticky' => 'f_sticky'
);
@@ -1076,7 +1071,7 @@ function phpbb_convert_authentication($mode)
}
}
- if (sizeof($forum_ids))
+ if (count($forum_ids))
{
// Now make sure the user is able to read these forums
$hold_ary = $auth->acl_group_raw_data(false, 'f_list', $forum_ids);
@@ -1221,7 +1216,7 @@ function phpbb_replace_size($matches)
*/
function phpbb_prepare_message($message)
{
- global $phpbb_root_path, $phpEx, $db, $convert, $user, $config, $cache, $convert_row, $message_parser;
+ global $convert, $user, $convert_row, $message_parser;
if (!$message)
{
@@ -1251,9 +1246,6 @@ function phpbb_prepare_message($message)
$message = str_replace('\&quot;', '&quot;', $message);
}
- // Already the new user id ;)
- $user_id = $convert->row['poster_id'];
-
$message = str_replace('<br />', "\n", $message);
$message = str_replace('<', '&lt;', $message);
$message = str_replace('>', '&gt;', $message);
@@ -1275,7 +1267,7 @@ function phpbb_prepare_message($message)
// parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post')
$message_parser->parse($enable_bbcode, $enable_magic_url, $enable_smilies);
- if (sizeof($message_parser->warn_msg))
+ if (count($message_parser->warn_msg))
{
$msg_id = isset($convert->row['post_id']) ? $convert->row['post_id'] : $convert->row['privmsgs_id'];
$convert->p_master->error('<span style="color:red">' . $user->lang['POST_ID'] . ': ' . $msg_id . ' ' . $user->lang['CONV_ERROR_MESSAGE_PARSER'] . ': <br /><br />' . implode('<br />', $message_parser->warn_msg), __LINE__, __FILE__, true);
@@ -1305,7 +1297,7 @@ function get_bbcode_bitfield()
*/
function phpbb_post_edit_user()
{
- global $convert_row, $config;
+ global $convert_row;
if (isset($convert_row['post_edit_count']))
{
@@ -1326,7 +1318,7 @@ function phpbb_get_files_dir()
return;
}
- global $src_db, $same_db, $convert, $user, $config, $cache;
+ global $src_db, $same_db, $convert, $user;
if ($convert->mysql_convert && $same_db)
{
@@ -1365,7 +1357,7 @@ function phpbb_get_files_dir()
*/
function phpbb_copy_thumbnails()
{
- global $db, $convert, $user, $config, $cache, $phpbb_root_path;
+ global $convert, $config, $phpbb_root_path;
$src_path = $convert->options['forum_path'] . '/' . phpbb_get_files_dir() . '/thumbs/';
@@ -1503,7 +1495,7 @@ function phpbb_attachment_forum_perms($forum_permissions)
$forum_ids[] = (int) $forum_id;
}
- if (sizeof($forum_ids))
+ if (count($forum_ids))
{
return attachment_forum_perms($forum_ids);
}
@@ -1611,8 +1603,6 @@ function phpbb_get_avatar_width($user_avatar)
*/
function phpbb_privmsgs_to_userid($to_userid)
{
- global $config;
-
return 'u_' . phpbb_user_id($to_userid);
}
@@ -1659,7 +1649,7 @@ function phpbb_get_savebox_id($user_id)
*/
function phpbb_import_attach_config()
{
- global $db, $src_db, $same_db, $convert, $config;
+ global $src_db, $same_db, $convert, $config;
if ($convert->mysql_convert && $same_db)
{
@@ -1682,29 +1672,28 @@ function phpbb_import_attach_config()
}
$src_db->sql_freeresult($result);
- set_config('allow_attachments', 1);
+ $config->set('allow_attachments', 1);
// old attachment mod? Must be very old if this entry do not exist...
if (!empty($attach_config['display_order']))
{
- set_config('display_order', $attach_config['display_order']);
- }
- set_config('max_filesize', $attach_config['max_filesize']);
- set_config('max_filesize_pm', $attach_config['max_filesize_pm']);
- set_config('attachment_quota', $attach_config['attachment_quota']);
- set_config('max_attachments', $attach_config['max_attachments']);
- set_config('max_attachments_pm', $attach_config['max_attachments_pm']);
- set_config('allow_pm_attach', $attach_config['allow_pm_attach']);
-
- set_config('img_display_inlined', $attach_config['img_display_inlined']);
- set_config('img_max_width', $attach_config['img_max_width']);
- set_config('img_max_height', $attach_config['img_max_height']);
- set_config('img_link_width', $attach_config['img_link_width']);
- set_config('img_link_height', $attach_config['img_link_height']);
- set_config('img_create_thumbnail', $attach_config['img_create_thumbnail']);
- set_config('img_max_thumb_width', 400);
- set_config('img_min_thumb_filesize', $attach_config['img_min_thumb_filesize']);
- set_config('img_imagick', $attach_config['img_imagick']);
+ $config->set('display_order', $attach_config['display_order']);
+ }
+ $config->set('max_filesize', $attach_config['max_filesize']);
+ $config->set('max_filesize_pm', $attach_config['max_filesize_pm']);
+ $config->set('attachment_quota', $attach_config['attachment_quota']);
+ $config->set('max_attachments', $attach_config['max_attachments']);
+ $config->set('max_attachments_pm', $attach_config['max_attachments_pm']);
+ $config->set('allow_pm_attach', $attach_config['allow_pm_attach']);
+
+ $config->set('img_display_inlined', $attach_config['img_display_inlined']);
+ $config->set('img_max_width', $attach_config['img_max_width']);
+ $config->set('img_max_height', $attach_config['img_max_height']);
+ $config->set('img_link_width', $attach_config['img_link_width']);
+ $config->set('img_link_height', $attach_config['img_link_height']);
+ $config->set('img_create_thumbnail', $attach_config['img_create_thumbnail']);
+ $config->set('img_max_thumb_width', 400);
+ $config->set('img_min_thumb_filesize', $attach_config['img_min_thumb_filesize']);
}
/**
@@ -1765,9 +1754,8 @@ function phpbb_disallowed_username($username)
*/
function phpbb_create_userconv_table()
{
- global $db, $src_db, $convert, $table_prefix, $user, $lang;
+ global $db;
- $map_dbms = '';
switch ($db->get_sql_layer())
{
case 'mysql':
@@ -1789,7 +1777,6 @@ function phpbb_create_userconv_table()
$map_dbms = 'mysql_41';
break;
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$map_dbms = 'mssql';
@@ -1839,7 +1826,6 @@ function phpbb_create_userconv_table()
)';
break;
- case 'sqlite':
case 'sqlite3':
$create_sql = 'CREATE TABLE ' . USERCONV_TABLE . ' (
user_id INTEGER NOT NULL DEFAULT \'0\',
@@ -1856,7 +1842,7 @@ function phpbb_create_userconv_table()
function phpbb_check_username_collisions()
{
- global $db, $src_db, $convert, $table_prefix, $user, $lang;
+ global $db, $src_db, $convert, $user, $lang;
// now find the clean version of the usernames that collide
$sql = 'SELECT username_clean
@@ -1873,7 +1859,7 @@ function phpbb_check_username_collisions()
$db->sql_freeresult($result);
// there was at least one collision, the admin will have to solve it before conversion can continue
- if (sizeof($colliding_names))
+ if (count($colliding_names))
{
$sql = 'SELECT user_id, username_clean
FROM ' . USERCONV_TABLE . '
@@ -1926,7 +1912,9 @@ function phpbb_check_username_collisions()
function phpbb_convert_timezone($timezone)
{
global $config, $db, $phpbb_root_path, $phpEx, $table_prefix;
- $timezone_migration = new \phpbb\db\migration\data\v310\timezone($config, $db, new \phpbb\db\tools($db), $phpbb_root_path, $phpEx, $table_prefix);
+
+ $factory = new \phpbb\db\tools\factory();
+ $timezone_migration = new \phpbb\db\migration\data\v310\timezone($config, $db, $factory->get($db), $phpbb_root_path, $phpEx, $table_prefix);
return $timezone_migration->convert_phpbb30_timezone($timezone, 0);
}
@@ -1967,13 +1955,14 @@ function phpbb_add_notification_options($user_notify_pm)
);
}
- $sql = $db->sql_multi_insert(USER_NOTIFICATIONS_TABLE, $rows);
+ $db->sql_multi_insert(USER_NOTIFICATIONS_TABLE, $rows);
}
function phpbb_convert_password_hash($hash)
{
global $phpbb_container;
+ /* @var $manager \phpbb\passwords\manager */
$manager = $phpbb_container->get('passwords.manager');
$hash = $manager->hash($hash, '$H$');
diff --git a/phpBB/install/data/confusables.php b/phpBB/install/data/confusables.php
index e3e8c41e62..00e806f639 100644
--- a/phpBB/install/data/confusables.php
+++ b/phpBB/install/data/confusables.php
@@ -628,19 +628,12 @@ function utf8_new_case_fold_nfkc($text, $option = 'full')
"\xF0\x9D\x9E\xBB" => "\xCF\x83",
"\xF0\x9D\x9F\x8A" => "\xCF\x9D",
);
- global $phpbb_root_path, $phpEx;
// do the case fold
$text = utf8_new_case_fold($text, $option);
- if (!class_exists('utf_normalizer'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx);
- }
-
// convert to NFKC
- utf_new_normalizer::nfkc($text);
+ $text = Normalizer::normalize($text, Normalizer::NFKC);
// FC_NFKC_Closure, http://www.unicode.org/Public/5.0.0/ucd/DerivedNormalizationProps.txt
$text = strtr($text, $fc_nfkc_closure);
diff --git a/phpBB/install/data/new_normalizer.php b/phpBB/install/data/new_normalizer.php
deleted file mode 100644
index 52652a4f6d..0000000000
--- a/phpBB/install/data/new_normalizer.php
+++ /dev/null
@@ -1,197 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* A wrapper function for the normalizer which takes care of including the class if required and modifies the passed strings
-* to be in NFC (Normalization Form Composition).
-*
-* @param mixed $strings a string or an array of strings to normalize
-* @return mixed the normalized content, preserving array keys if array given.
-*/
-function utf8_new_normalize_nfc($strings)
-{
- if (empty($strings))
- {
- return $strings;
- }
-
- if (!is_array($strings))
- {
- utf_new_normalizer::nfc($strings);
- }
- else if (is_array($strings))
- {
- foreach ($strings as $key => $string)
- {
- if (is_array($string))
- {
- foreach ($string as $_key => $_string)
- {
- utf_new_normalizer::nfc($strings[$key][$_key]);
- }
- }
- else
- {
- utf_new_normalizer::nfc($strings[$key]);
- }
- }
- }
-
- return $strings;
-}
-
-class utf_new_normalizer
-{
- /**
- * Validate, cleanup and normalize a string
- *
- * The ultimate convenience function! Clean up invalid UTF-8 sequences,
- * and convert to Normal Form C, canonical composition.
- *
- * @param string &$str The dirty string
- * @return string The same string, all shiny and cleaned-up
- */
- function cleanup(&$str)
- {
- // The string below is the list of all autorized characters, sorted by frequency in latin text
- $pos = strspn($str, "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x0D");
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings with no special chars return immediately
- return;
- }
-
- // Note: we do not check for $GLOBALS['utf_canonical_decomp']. It is assumed they are always loaded together
- if (!isset($GLOBALS['utf_nfc_qc']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_nfc_qc.' . $phpEx);
- }
-
- if (!isset($GLOBALS['utf_canonical_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_canonical_decomp.' . $phpEx);
- }
-
- // Replace any byte in the range 0x00..0x1F, except for \r, \n and \t
- // We replace those characters with a 0xFF byte, which is illegal in UTF-8 and will in turn be replaced with a UTF replacement char
- $str = strtr(
- $str,
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
- );
-
- $str = utf_new_normalizer::recompose($str, $pos, $len, $GLOBALS['utf_nfc_qc'], $GLOBALS['utf_canonical_decomp']);
- }
-
- /**
- * Validate and normalize a UTF string to NFC
- *
- * @param string &$str Unchecked UTF string
- * @return string The string, validated and in normal form
- */
- function nfc(&$str)
- {
- $pos = strspn($str, UTF8_ASCII_RANGE);
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings return immediately
- return;
- }
-
- if (!isset($GLOBALS['utf_nfc_qc']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_nfc_qc.' . $phpEx);
- }
-
- if (!isset($GLOBALS['utf_canonical_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_canonical_decomp.' . $phpEx);
- }
-
- $str = utf_new_normalizer::recompose($str, $pos, $len, $GLOBALS['utf_nfc_qc'], $GLOBALS['utf_canonical_decomp']);
- }
-
- /**
- * Validate and normalize a UTF string to NFKC
- *
- * @param string &$str Unchecked UTF string
- * @return string The string, validated and in normal form
- */
- function nfkc(&$str)
- {
- $pos = strspn($str, UTF8_ASCII_RANGE);
- $len = strlen($str);
-
- if ($pos == $len)
- {
- // ASCII strings return immediately
- return;
- }
-
- if (!isset($GLOBALS['utf_nfkc_qc']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_nfkc_qc.' . $phpEx);
- }
-
- if (!isset($GLOBALS['utf_compatibility_decomp']))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_compatibility_decomp.' . $phpEx);
- }
-
- $str = utf_new_normalizer::recompose($str, $pos, $len, $GLOBALS['utf_nfkc_qc'], $GLOBALS['utf_compatibility_decomp']);
- }
-
- /**
- * Recompose a UTF string
- *
- * @param string $str Unchecked UTF string
- * @param integer $pos Position of the first UTF char (in bytes)
- * @param integer $len Length of the string (in bytes)
- * @param array &$qc Quick-check array, passed by reference but never modified
- * @param array &$decomp_map Decomposition mapping, passed by reference but never modified
- * @return string The string, validated and recomposed
- *
- * @access private
- */
- function recompose($str, $pos, $len, &$qc, &$decomp_map)
- {
- global $utf_canonical_comp;
-
- // Load the canonical composition table
- if (!isset($utf_canonical_comp))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/utf_canonical_comp.' . $phpEx);
- }
-
- return utf_normalizer::recompose($str, $pos, $len, $qc, $decomp_map);
- }
-}
diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php
deleted file mode 100644
index f367ae1fc0..0000000000
--- a/phpBB/install/database_update.php
+++ /dev/null
@@ -1,244 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-$update_start_time = time();
-
-/**
-* @ignore
-*/
-define('IN_PHPBB', true);
-define('IN_INSTALL', true);
-$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../';
-$phpEx = substr(strrchr(__FILE__, '.'), 1);
-
-function phpbb_end_update($cache, $config)
-{
- $cache->purge();
-
- $config->increment('assets_version', 1);
-
-?>
- </p>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div id="page-footer">
- <div class="copyright">
- Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited
- </div>
- </div>
- </div>
-</body>
-</html>
-
-<?php
-
- garbage_collection();
- exit_handler();
-}
-
-require($phpbb_root_path . 'includes/startup.' . $phpEx);
-require($phpbb_root_path . 'phpbb/class_loader.' . $phpEx);
-
-$phpbb_class_loader = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}phpbb/", $phpEx);
-$phpbb_class_loader->register();
-
-$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
-extract($phpbb_config_php_file->get_all());
-
-if (!defined('PHPBB_INSTALLED') || empty($dbms) || empty($acm_type))
-{
- die("Please read: <a href='../docs/INSTALL.html'>INSTALL.html</a> before attempting to update.");
-}
-
-// In case $phpbb_adm_relative_path is not set (in case of an update), use the default.
-$phpbb_adm_relative_path = (isset($phpbb_adm_relative_path)) ? $phpbb_adm_relative_path : 'adm/';
-$phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : $phpbb_root_path . $phpbb_adm_relative_path;
-
-// Include files
-require($phpbb_root_path . 'includes/functions.' . $phpEx);
-require($phpbb_root_path . 'includes/functions_content.' . $phpEx);
-
-require($phpbb_root_path . 'includes/constants.' . $phpEx);
-include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx);
-require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
-
-// Set PHP error handler to ours
-set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
-
-// Set up container (must be done here because extensions table may not exist)
-$phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
-$phpbb_container_builder->set_use_extensions(false);
-$phpbb_container_builder->set_use_kernel_pass(false);
-$phpbb_container_builder->set_dump_container(false);
-$phpbb_container = $phpbb_container_builder->get_container();
-
-// set up caching
-$cache = $phpbb_container->get('cache');
-
-// Instantiate some basic classes
-$phpbb_dispatcher = $phpbb_container->get('dispatcher');
-$request = $phpbb_container->get('request');
-$user = $phpbb_container->get('user');
-$auth = $phpbb_container->get('auth');
-$db = $phpbb_container->get('dbal.conn');
-$phpbb_log = $phpbb_container->get('log');
-
-// make sure request_var uses this request instance
-request_var('', 0, false, false, $request); // "dependency injection" for a function
-
-// Grab global variables, re-cache if necessary
-$config = $phpbb_container->get('config');
-set_config(null, null, null, $config);
-set_config_count(null, null, null, $config);
-
-if (!isset($config['version_update_from']))
-{
- $config->set('version_update_from', $config['version']);
-}
-
-$orig_version = $config['version_update_from'];
-
-$user->add_lang(array('common', 'acp/common', 'install', 'migrator'));
-
-// Add own hook handler, if present. :o
-if (file_exists($phpbb_root_path . 'includes/hooks/index.' . $phpEx))
-{
- require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
- $phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));
-
- $phpbb_hook_finder = $phpbb_container->get('hook_finder');
- foreach ($phpbb_hook_finder->find() as $hook)
- {
- @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx);
- }
-}
-else
-{
- $phpbb_hook = false;
-}
-
-header('Content-type: text/html; charset=UTF-8');
-?>
-<!DOCTYPE html>
-<html dir="<?php echo $user->lang['DIRECTION']; ?>" lang="<?php echo $user->lang['USER_LANG']; ?>">
-<head>
-<meta charset="utf-8">
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-
-<title><?php echo $user->lang['UPDATING_TO_LATEST_STABLE']; ?></title>
-
-<link href="<?php echo htmlspecialchars($phpbb_admin_path); ?>style/admin.css" rel="stylesheet" type="text/css" media="screen" />
-
-</head>
-
-<body>
- <div id="wrap">
- <div id="page-header">&nbsp;</div>
-
- <div id="page-body">
- <div id="acp">
- <div class="panel">
- <div id="content">
- <div id="main" class="install-body">
-
- <h1><?php echo $user->lang['UPDATING_TO_LATEST_STABLE']; ?></h1>
-
- <br />
-
- <p><?php echo $user->lang['DATABASE_TYPE']; ?> :: <strong><?php echo $db->get_sql_layer(); ?></strong><br />
- <?php echo $user->lang['PREVIOUS_VERSION']; ?> :: <strong><?php echo $config['version']; ?></strong><br />
-
-<?php
-
-define('IN_DB_UPDATE', true);
-
-/**
-* @todo mysql update?
-*/
-
-// End startup code
-
-$migrator = $phpbb_container->get('migrator');
-$migrator->set_output_handler(new \phpbb\db\log_wrapper_migrator_output_handler($user, new \phpbb\db\html_migrator_output_handler($user), $phpbb_root_path . 'store/migrations_' . time() . '.log'));
-
-$migrator->create_migrations_table();
-
-$phpbb_extension_manager = $phpbb_container->get('ext.manager');
-
-$migrations = $phpbb_extension_manager
- ->get_finder()
- ->core_path('phpbb/db/migration/data/')
- ->extension_directory('/migrations')
- ->get_classes();
-
-$migrator->set_migrations($migrations);
-
-// What is a safe limit of execution time? Half the max execution time should be safe.
-// No more than 15 seconds so the user isn't sitting and waiting for a very long time
-$phpbb_ini = new \phpbb\php\ini();
-$safe_time_limit = min(15, ($phpbb_ini->get_int('max_execution_time') / 2));
-
-// While we're going to try limit this to half the max execution time,
-// we want to try and take additional measures to prevent hitting the
-// max execution time (if, say, one migration step takes much longer
-// than the max execution time)
-@set_time_limit(0);
-
-while (!$migrator->finished())
-{
- try
- {
- $migrator->update();
- }
- catch (\phpbb\db\migration\exception $e)
- {
- echo $e->getLocalisedMessage($user);
-
- phpbb_end_update($cache, $config);
- }
-
- // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
- if ((time() - $update_start_time) >= $safe_time_limit)
- {
- echo '<br />' . $user->lang['DATABASE_UPDATE_NOT_COMPLETED'] . '<br /><br />';
- echo '<a href="' . append_sid($phpbb_root_path . 'install/database_update.' . $phpEx, 'type=' . $request->variable('type', 0) . '&amp;language=' . $request->variable('language', 'en')) . '" class="button1">' . $user->lang['DATABASE_UPDATE_CONTINUE'] . '</a>';
-
- phpbb_end_update($cache, $config);
- }
-}
-
-if ($orig_version != $config['version'])
-{
- add_log('admin', 'LOG_UPDATE_DATABASE', $orig_version, $config['version']);
-}
-
-echo $user->lang['DATABASE_UPDATE_COMPLETE'] . '<br />';
-
-if ($request->variable('type', 0))
-{
- echo $user->lang['INLINE_UPDATE_SUCCESSFUL'] . '<br /><br />';
- echo '<a href="' . append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=update&amp;sub=update_db&amp;language=' . $request->variable('language', 'en')) . '" class="button1">' . $user->lang['CONTINUE_UPDATE_NOW'] . '</a>';
-}
-else
-{
- echo '<div class="errorbox">' . $user->lang['UPDATE_FILES_NOTICE'] . '</div>';
- echo $user->lang['COMPLETE_LOGIN_TO_BOARD'];
-}
-
-$config->delete('version_update_from');
-
-phpbb_end_update($cache, $config);
diff --git a/phpBB/install/index.html b/phpBB/install/index.html
new file mode 100644
index 0000000000..8f8bfb4fb2
--- /dev/null
+++ b/phpBB/install/index.html
@@ -0,0 +1,11 @@
+<html>
+<head>
+<title></title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta http-equiv="refresh" content="0; url=./app.php" />
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+
+</body>
+</html>
diff --git a/phpBB/install/index.php b/phpBB/install/index.php
deleted file mode 100644
index b5d14f27cf..0000000000
--- a/phpBB/install/index.php
+++ /dev/null
@@ -1,834 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**#@+
-* @ignore
-*/
-define('IN_PHPBB', true);
-define('IN_INSTALL', true);
-/**#@-*/
-
-$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../';
-$phpEx = substr(strrchr(__FILE__, '.'), 1);
-
-if (version_compare(PHP_VERSION, '5.3.3') < 0)
-{
- die('You are running an unsupported PHP version. Please upgrade to PHP 5.3.3 or higher before trying to install phpBB 3.1');
-}
-
-function phpbb_require_updated($path, $optional = false)
-{
- global $phpbb_root_path, $table_prefix;
-
- $new_path = $phpbb_root_path . 'install/update/new/' . $path;
- $old_path = $phpbb_root_path . $path;
-
- if (file_exists($new_path))
- {
- require($new_path);
- }
- else if (!$optional || file_exists($old_path))
- {
- require($old_path);
- }
-}
-
-function phpbb_include_updated($path, $optional = false)
-{
- global $phpbb_root_path;
-
- $new_path = $phpbb_root_path . 'install/update/new/' . $path;
- $old_path = $phpbb_root_path . $path;
-
- if (file_exists($new_path))
- {
- include($new_path);
- }
- else if (!$optional || file_exists($old_path))
- {
- include($old_path);
- }
-}
-
-phpbb_require_updated('includes/startup.' . $phpEx);
-
-// Try to override some limits - maybe it helps some...
-@set_time_limit(0);
-$mem_limit = @ini_get('memory_limit');
-if (!empty($mem_limit))
-{
- $unit = strtolower(substr($mem_limit, -1, 1));
- $mem_limit = (int) $mem_limit;
-
- if ($unit == 'k')
- {
- $mem_limit = floor($mem_limit / 1024);
- }
- else if ($unit == 'g')
- {
- $mem_limit *= 1024;
- }
- else if (is_numeric($unit))
- {
- $mem_limit = floor((int) ($mem_limit . $unit) / 1048576);
- }
- $mem_limit = max(128, $mem_limit) . 'M';
-}
-else
-{
- $mem_limit = '128M';
-}
-@ini_set('memory_limit', $mem_limit);
-
-// In case $phpbb_adm_relative_path is not set (in case of an update), use the default.
-$phpbb_adm_relative_path = (isset($phpbb_adm_relative_path)) ? $phpbb_adm_relative_path : 'adm/';
-$phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : $phpbb_root_path . $phpbb_adm_relative_path;
-
-// Include essential scripts
-phpbb_require_updated('phpbb/class_loader.' . $phpEx);
-
-phpbb_require_updated('includes/functions.' . $phpEx);
-
-phpbb_require_updated('includes/functions_content.' . $phpEx, true);
-
-phpbb_include_updated('includes/functions_admin.' . $phpEx);
-phpbb_include_updated('includes/utf/utf_normalizer.' . $phpEx);
-phpbb_include_updated('includes/utf/utf_tools.' . $phpEx);
-phpbb_require_updated('includes/functions_install.' . $phpEx);
-
-// Setup class loader first
-$phpbb_class_loader_new = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}install/update/new/phpbb/", $phpEx);
-$phpbb_class_loader_new->register();
-$phpbb_class_loader = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}phpbb/", $phpEx);
-$phpbb_class_loader->register();
-$phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx);
-$phpbb_class_loader_ext->register();
-
-// Set up container
-$phpbb_config_php_file = new \phpbb\config_php_file($phpbb_root_path, $phpEx);
-$phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
-$phpbb_container_builder->set_use_extensions(false);
-$phpbb_container_builder->set_dump_container(false);
-$phpbb_container_builder->set_use_custom_pass(false);
-$phpbb_container_builder->set_inject_config(false);
-$phpbb_container_builder->set_compile_container(false);
-
-$other_config_path = $phpbb_root_path . 'install/update/new/config/';
-$config_path = file_exists($other_config_path . 'services.yml') ? $other_config_path : $phpbb_root_path . 'config/';
-$phpbb_container_builder->set_config_path($config_path);
-
-$phpbb_container_builder->set_custom_parameters(array(
- 'core.root_path' => $phpbb_root_path,
- 'core.adm_relative_path' => $phpbb_adm_relative_path,
- 'core.php_ext' => $phpEx,
- 'core.table_prefix' => '',
- 'cache.driver.class' => 'phpbb\cache\driver\file',
-));
-
-$phpbb_container = $phpbb_container_builder->get_container();
-$phpbb_container->register('dbal.conn.driver')->setSynthetic(true);
-$phpbb_container->compile();
-
-$phpbb_class_loader->set_cache($phpbb_container->get('cache.driver'));
-$phpbb_class_loader_ext->set_cache($phpbb_container->get('cache.driver'));
-
-$phpbb_dispatcher = $phpbb_container->get('dispatcher');
-$request = $phpbb_container->get('request');
-
-// make sure request_var uses this request instance
-request_var('', 0, false, false, $request); // "dependency injection" for a function
-
-// Try and load an appropriate language if required
-$language = basename($request->variable('language', ''));
-
-if ($request->header('Accept-Language') && !$language)
-{
- $accept_lang_ary = explode(',', strtolower($request->header('Accept-Language')));
- foreach ($accept_lang_ary as $accept_lang)
- {
- // Set correct format ... guess full xx_yy form
- $accept_lang = substr($accept_lang, 0, 2) . '_' . substr($accept_lang, 3, 2);
-
- if (file_exists($phpbb_root_path . 'language/' . $accept_lang) && is_dir($phpbb_root_path . 'language/' . $accept_lang))
- {
- $language = $accept_lang;
- break;
- }
- else
- {
- // No match on xx_yy so try xx
- $accept_lang = substr($accept_lang, 0, 2);
- if (file_exists($phpbb_root_path . 'language/' . $accept_lang) && is_dir($phpbb_root_path . 'language/' . $accept_lang))
- {
- $language = $accept_lang;
- break;
- }
- }
- }
-}
-
-// No appropriate language found ... so let's use the first one in the language
-// dir, this may or may not be English
-if (!$language)
-{
- $dir = @opendir($phpbb_root_path . 'language');
-
- if (!$dir)
- {
- die('Unable to access the language directory');
- exit;
- }
-
- while (($file = readdir($dir)) !== false)
- {
- $path = $phpbb_root_path . 'language/' . $file;
-
- if (!is_file($path) && !is_link($path) && file_exists($path . '/iso.txt'))
- {
- $language = $file;
- break;
- }
- }
- closedir($dir);
-}
-
-if (!file_exists($phpbb_root_path . 'language/' . $language) || !is_dir($phpbb_root_path . 'language/' . $language))
-{
- die('No language found!');
-}
-
-// And finally, load the relevant language files
-$load_lang_files = array('common', 'acp/common', 'acp/board', 'install', 'posting');
-$new_path = $phpbb_root_path . 'install/update/new/language/' . $language . '/';
-$old_path = $phpbb_root_path . 'language/' . $language . '/';
-
-// NOTE: we can not use "phpbb_include_updated" as the files uses vars which would be required
-// to be global while loading.
-foreach ($load_lang_files as $lang_file)
-{
- if (file_exists($new_path . $lang_file . '.' . $phpEx))
- {
- include($new_path . $lang_file . '.' . $phpEx);
- }
- else
- {
- include($old_path . $lang_file . '.' . $phpEx);
- }
-}
-
-// usually we would need every single constant here - and it would be consistent. For 3.0.x, use a dirty hack... :(
-
-// Define needed constants
-define('CHMOD_ALL', 7);
-define('CHMOD_READ', 4);
-define('CHMOD_WRITE', 2);
-define('CHMOD_EXECUTE', 1);
-
-$mode = $request->variable('mode', 'overview');
-$sub = $request->variable('sub', '');
-
-// Set PHP error handler to ours
-set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
-
-$user = new \phpbb\user('\phpbb\datetime');
-$auth = new \phpbb\auth\auth();
-
-// Add own hook handler, if present. :o
-if (file_exists($phpbb_root_path . 'includes/hooks/index.' . $phpEx))
-{
- require($phpbb_root_path . 'includes/hooks/index.' . $phpEx);
- $phpbb_hook = new phpbb_hook(array('exit_handler', 'phpbb_user_session_handler', 'append_sid', array('template', 'display')));
-
- $phpbb_hook_finder = $phpbb_container->get('hook_finder');
- foreach ($phpbb_hook_finder->find() as $hook)
- {
- @include($phpbb_root_path . 'includes/hooks/' . $hook . '.' . $phpEx);
- }
-}
-else
-{
- $phpbb_hook = false;
-}
-
-// Set some standard variables we want to force
-$config = new \phpbb\config\config(array(
- 'load_tplcompile' => '1'
-));
-
-$symfony_request = $phpbb_container->get('symfony_request');
-$phpbb_filesystem = $phpbb_container->get('filesystem');
-$phpbb_path_helper = $phpbb_container->get('path_helper');
-$template = new \phpbb\template\twig\twig($phpbb_path_helper, $config, $user, new \phpbb\template\context());
-$paths = array($phpbb_root_path . 'install/update/new/adm/style', $phpbb_admin_path . 'style');
-$paths = array_filter($paths, 'is_dir');
-$template->set_custom_style(array(
- array(
- 'name' => 'adm',
- 'ext_path' => 'adm/style/',
- ),
-), $paths);
-
-$path = array_shift($paths);
-
-$template->assign_var('T_ASSETS_PATH', $path . '/../../assets');
-$template->assign_var('T_TEMPLATE_PATH', $path);
-
-$install = new module();
-
-$install->create('install', "index.$phpEx", $mode, $sub);
-$install->load();
-
-// Generate the page
-$install->page_header();
-$install->generate_navigation();
-
-$template->set_filenames(array(
- 'body' => $install->get_tpl_name())
-);
-
-$install->page_footer();
-
-class module
-{
- var $id = 0;
- var $type = 'install';
- var $module_ary = array();
- var $filename;
- var $module_url = '';
- var $tpl_name = '';
- var $mode;
- var $sub;
-
- /**
- * Private methods, should not be overwritten
- */
- function create($module_type, $module_url, $selected_mod = false, $selected_submod = false)
- {
- global $db, $config, $phpEx, $phpbb_root_path;
-
- $module = array();
-
- // Grab module information using Bart's "neat-o-module" system (tm)
- $dir = @opendir('.');
-
- if (!$dir)
- {
- $this->error('Unable to access the installation directory', __LINE__, __FILE__);
- }
-
- $setmodules = 1;
- while (($file = readdir($dir)) !== false)
- {
- if (preg_match('#^install_(.*?)\.' . $phpEx . '$#', $file))
- {
- include($file);
- }
- }
- closedir($dir);
-
- unset($setmodules);
-
- if (!sizeof($module))
- {
- $this->error('No installation modules found', __LINE__, __FILE__);
- }
-
- // Order to use and count further if modules get assigned to the same position or not having an order
- $max_module_order = 1000;
-
- foreach ($module as $row)
- {
- // Module order not specified or module already assigned at this position?
- if (!isset($row['module_order']) || isset($this->module_ary[$row['module_order']]))
- {
- $row['module_order'] = $max_module_order;
- $max_module_order++;
- }
-
- $this->module_ary[$row['module_order']]['name'] = $row['module_title'];
- $this->module_ary[$row['module_order']]['filename'] = $row['module_filename'];
- $this->module_ary[$row['module_order']]['subs'] = $row['module_subs'];
- $this->module_ary[$row['module_order']]['stages'] = $row['module_stages'];
-
- if (strtolower($selected_mod) == strtolower($row['module_title']))
- {
- $this->id = (int) $row['module_order'];
- $this->filename = (string) $row['module_filename'];
- $this->module_url = (string) $module_url;
- $this->mode = (string) $selected_mod;
- // Check that the sub-mode specified is valid or set a default if not
- if (is_array($row['module_subs']))
- {
- $this->sub = strtolower((in_array(strtoupper($selected_submod), $row['module_subs'])) ? $selected_submod : $row['module_subs'][0]);
- }
- else if (is_array($row['module_stages']))
- {
- $this->sub = strtolower((in_array(strtoupper($selected_submod), $row['module_stages'])) ? $selected_submod : $row['module_stages'][0]);
- }
- else
- {
- $this->sub = '';
- }
- }
- } // END foreach
- } // END create
-
- /**
- * Load and run the relevant module if applicable
- */
- function load($mode = false, $run = true)
- {
- global $phpbb_root_path, $phpEx;
-
- if ($run)
- {
- if (!empty($mode))
- {
- $this->mode = $mode;
- }
-
- $module = $this->filename;
- if (!class_exists($module))
- {
- $this->error('Module "' . htmlspecialchars($module) . '" not accessible.', __LINE__, __FILE__);
- }
- $this->module = new $module($this);
-
- if (method_exists($this->module, 'main'))
- {
- $this->module->main($this->mode, $this->sub);
- }
- }
- }
-
- /**
- * Output the standard page header
- */
- function page_header()
- {
- if (defined('HEADER_INC'))
- {
- return;
- }
-
- define('HEADER_INC', true);
- global $template, $lang, $stage, $phpbb_admin_path, $path;
-
- $template->assign_vars(array(
- 'L_CHANGE' => $lang['CHANGE'],
- 'L_COLON' => $lang['COLON'],
- 'L_INSTALL_PANEL' => $lang['INSTALL_PANEL'],
- 'L_SELECT_LANG' => $lang['SELECT_LANG'],
- 'L_SKIP' => $lang['SKIP'],
- 'PAGE_TITLE' => $this->get_page_title(),
- 'T_IMAGE_PATH' => htmlspecialchars($phpbb_admin_path) . 'images/',
- 'T_JQUERY_LINK' => $path . '/../../assets/javascript/jquery.min.js',
-
- 'S_CONTENT_DIRECTION' => $lang['DIRECTION'],
- 'S_CONTENT_FLOW_BEGIN' => ($lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
- 'S_CONTENT_FLOW_END' => ($lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
- 'S_CONTENT_ENCODING' => 'UTF-8',
-
- 'S_USER_LANG' => $lang['USER_LANG'],
- )
- );
-
- header('Content-type: text/html; charset=UTF-8');
- header('Cache-Control: private, no-cache="set-cookie"');
- header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
-
- return;
- }
-
- /**
- * Output the standard page footer
- */
- function page_footer()
- {
- global $db, $template;
-
- $template->display('body');
-
- // Close our DB connection.
- if (!empty($db) && is_object($db))
- {
- $db->sql_close();
- }
-
- if (function_exists('exit_handler'))
- {
- exit_handler();
- }
- }
-
- /**
- * Returns desired template name
- */
- function get_tpl_name()
- {
- return $this->module->tpl_name . '.html';
- }
-
- /**
- * Returns the desired page title
- */
- function get_page_title()
- {
- global $lang;
-
- if (!isset($this->module->page_title))
- {
- return '';
- }
-
- return (isset($lang[$this->module->page_title])) ? $lang[$this->module->page_title] : $this->module->page_title;
- }
-
- /**
- * Generate an HTTP/1.1 header to redirect the user to another page
- * This is used during the installation when we do not have a database available to call the normal redirect function
- * @param string $page The page to redirect to relative to the installer root path
- */
- function redirect($page)
- {
- global $request;
-
- // HTTP_HOST is having the correct browser url in most cases...
- $server_name = strtolower(htmlspecialchars_decode($request->header('Host', $request->server('SERVER_NAME'))));
- $server_port = $request->server('SERVER_PORT', 0);
- $secure = $request->is_secure() ? 1 : 0;
-
- $script_name = htmlspecialchars_decode($request->server('PHP_SELF'));
- if (!$script_name)
- {
- $script_name = htmlspecialchars_decode($request->server('REQUEST_URI'));
- }
-
- // Replace backslashes and doubled slashes (could happen on some proxy setups)
- $script_name = str_replace(array('\\', '//'), '/', $script_name);
- $script_path = trim(dirname($script_name));
-
- $url = (($secure) ? 'https://' : 'http://') . $server_name;
-
- if ($server_port && (($secure && $server_port <> 443) || (!$secure && $server_port <> 80)))
- {
- // HTTP HOST can carry a port number...
- if (strpos($server_name, ':') === false)
- {
- $url .= ':' . $server_port;
- }
- }
-
- $url .= $script_path . '/' . $page;
- header('Location: ' . $url);
- exit;
- }
-
- /**
- * Generate the navigation tabs
- */
- function generate_navigation()
- {
- global $lang, $template, $phpEx, $language;
-
- if (is_array($this->module_ary))
- {
- @ksort($this->module_ary);
- foreach ($this->module_ary as $cat_ary)
- {
- $cat = $cat_ary['name'];
- $l_cat = (!empty($lang['CAT_' . $cat])) ? $lang['CAT_' . $cat] : preg_replace('#_#', ' ', $cat);
- $cat = strtolower($cat);
- $url = $this->module_url . "?mode=$cat&amp;language=$language";
-
- if ($this->mode == $cat)
- {
- $template->assign_block_vars('t_block1', array(
- 'L_TITLE' => $l_cat,
- 'S_SELECTED' => true,
- 'U_TITLE' => $url,
- ));
-
- if (is_array($this->module_ary[$this->id]['subs']))
- {
- $subs = $this->module_ary[$this->id]['subs'];
- foreach ($subs as $option)
- {
- $l_option = (!empty($lang['SUB_' . $option])) ? $lang['SUB_' . $option] : preg_replace('#_#', ' ', $option);
- $option = strtolower($option);
- $url = $this->module_url . '?mode=' . $this->mode . "&amp;sub=$option&amp;language=$language";
-
- $template->assign_block_vars('l_block1', array(
- 'L_TITLE' => $l_option,
- 'S_SELECTED' => ($this->sub == $option),
- 'U_TITLE' => $url,
- ));
- }
- }
-
- if (is_array($this->module_ary[$this->id]['stages']))
- {
- $subs = $this->module_ary[$this->id]['stages'];
- $matched = false;
- foreach ($subs as $option)
- {
- $l_option = (!empty($lang['STAGE_' . $option])) ? $lang['STAGE_' . $option] : preg_replace('#_#', ' ', $option);
- $option = strtolower($option);
- $matched = ($this->sub == $option) ? true : $matched;
-
- $template->assign_block_vars('l_block2', array(
- 'L_TITLE' => $l_option,
- 'S_SELECTED' => ($this->sub == $option),
- 'S_COMPLETE' => !$matched,
- ));
- }
- }
- }
- else
- {
- $template->assign_block_vars('t_block1', array(
- 'L_TITLE' => $l_cat,
- 'S_SELECTED' => false,
- 'U_TITLE' => $url,
- ));
- }
- }
- }
- }
-
- /**
- * Output an error message
- * If skip is true, return and continue execution, else exit
- */
- function error($error, $line, $file, $skip = false)
- {
- global $lang, $db, $template, $phpbb_admin_path;
-
- if ($skip)
- {
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['INST_ERR'],
- ));
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => basename($file) . ' [ ' . $line . ' ]',
- 'RESULT' => '<b style="color:red">' . $error . '</b>',
- ));
-
- return;
- }
-
- echo '<!DOCTYPE html>';
- echo '<html dir="ltr">';
- echo '<head>';
- echo '<meta charset="utf-8">';
- echo '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
- echo '<title>' . $lang['INST_ERR_FATAL'] . '</title>';
- echo '<link href="' . htmlspecialchars($phpbb_admin_path) . 'style/admin.css" rel="stylesheet" type="text/css" media="screen" />';
- echo '</head>';
- echo '<body id="errorpage">';
- echo '<div id="wrap">';
- echo ' <div id="page-header">';
- echo ' </div>';
- echo ' <div id="page-body">';
- echo ' <div id="acp">';
- echo ' <div class="panel">';
- echo ' <span class="corners-top"><span></span></span>';
- echo ' <div id="content">';
- echo ' <h1>' . $lang['INST_ERR_FATAL'] . '</h1>';
- echo ' <p>' . $lang['INST_ERR_FATAL'] . "</p>\n";
- echo ' <p>' . basename($file) . ' [ ' . $line . " ]</p>\n";
- echo ' <p><b>' . $error . "</b></p>\n";
- echo ' </div>';
- echo ' <span class="corners-bottom"><span></span></span>';
- echo ' </div>';
- echo ' </div>';
- echo ' </div>';
- echo ' <div id="page-footer">';
- echo ' Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited';
- echo ' </div>';
- echo '</div>';
- echo '</body>';
- echo '</html>';
-
- if (!empty($db) && is_object($db))
- {
- $db->sql_close();
- }
-
- exit_handler();
- }
-
- /**
- * Output an error message for a database related problem
- * If skip is true, return and continue execution, else exit
- */
- function db_error($error, $sql, $line, $file, $skip = false)
- {
- global $lang, $db, $template;
-
- if ($skip)
- {
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['INST_ERR_FATAL'],
- ));
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => basename($file) . ' [ ' . $line . ' ]',
- 'RESULT' => '<b style="color:red">' . $error . '</b><br />&#187; SQL:' . $sql,
- ));
-
- return;
- }
-
- $template->set_filenames(array(
- 'body' => 'install_error.html')
- );
- $this->page_header();
- $this->generate_navigation();
-
- $template->assign_vars(array(
- 'MESSAGE_TITLE' => $lang['INST_ERR_FATAL_DB'],
- 'MESSAGE_TEXT' => '<p>' . basename($file) . ' [ ' . $line . ' ]</p><p>SQL : ' . $sql . '</p><p><b>' . $error . '</b></p>',
- ));
-
- // Rollback if in transaction
- if ($db->get_transaction())
- {
- $db->sql_transaction('rollback');
- }
-
- $this->page_footer();
- }
-
- /**
- * Generate the relevant HTML for an input field and the associated label and explanatory text
- */
- function input_field($name, $type, $value = '', $options = '')
- {
- global $lang;
- $tpl_type = explode(':', $type);
- $tpl = '';
-
- switch ($tpl_type[0])
- {
- case 'text':
- case 'password':
- // HTML5 text-like input types
- case 'color':
- case 'date':
- case 'time':
- case 'datetime':
- case 'datetime-local':
- case 'email':
- case 'month':
- case 'number':
- case 'range':
- case 'search':
- case 'tel':
- case 'url':
- case 'week':
-
- $size = (int) $tpl_type[1];
- $maxlength = (int) $tpl_type[2];
- $autocomplete = (isset($options['autocomplete']) && $options['autocomplete'] == 'off') ? ' autocomplete="off"' : '';
-
- $tpl = '<input id="' . $name . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '"' . $autocomplete . ' value="' . $value . '" />';
- break;
-
- case 'textarea':
- $rows = (int) $tpl_type[1];
- $cols = (int) $tpl_type[2];
-
- $tpl = '<textarea id="' . $name . '" name="' . $name . '" rows="' . $rows . '" cols="' . $cols . '">' . $value . '</textarea>';
- break;
-
- case 'radio':
- $key_yes = ($value) ? ' checked="checked" id="' . $name . '"' : '';
- $key_no = (!$value) ? ' checked="checked" id="' . $name . '"' : '';
-
- $tpl_type_cond = explode('_', $tpl_type[1]);
- $type_no = ($tpl_type_cond[0] == 'disabled' || $tpl_type_cond[0] == 'enabled') ? false : true;
-
- $tpl_no = '<label><input type="radio" name="' . $name . '" value="0"' . $key_no . ' class="radio" /> ' . (($type_no) ? $lang['NO'] : $lang['DISABLED']) . '</label>';
- $tpl_yes = '<label><input type="radio" name="' . $name . '" value="1"' . $key_yes . ' class="radio" /> ' . (($type_no) ? $lang['YES'] : $lang['ENABLED']) . '</label>';
-
- $tpl = ($tpl_type_cond[0] == 'yes' || $tpl_type_cond[0] == 'enabled') ? $tpl_yes . '&nbsp;&nbsp;' . $tpl_no : $tpl_no . '&nbsp;&nbsp;' . $tpl_yes;
- break;
-
- case 'select':
- // @codingStandardsIgnoreStart
- eval('$s_options = ' . str_replace('{VALUE}', $value, $options) . ';');
- // @codingStandardsIgnoreEnd
- $tpl = '<select id="' . $name . '" name="' . $name . '">' . $s_options . '</select>';
- break;
-
- case 'custom':
- // @codingStandardsIgnoreStart
- eval('$tpl = ' . str_replace('{VALUE}', $value, $options) . ';');
- // @codingStandardsIgnoreEnd
- break;
-
- default:
- break;
- }
-
- return $tpl;
- }
-
- /**
- * Generate the drop down of available language packs
- */
- function inst_language_select($default = '')
- {
- global $phpbb_root_path, $phpEx;
-
- $dir = @opendir($phpbb_root_path . 'language');
-
- if (!$dir)
- {
- $this->error('Unable to access the language directory', __LINE__, __FILE__);
- }
-
- while ($file = readdir($dir))
- {
- $path = $phpbb_root_path . 'language/' . $file;
-
- if ($file == '.' || $file == '..' || is_link($path) || is_file($path) || $file == 'CVS')
- {
- continue;
- }
-
- if (file_exists($path . '/iso.txt'))
- {
- list($displayname, $localname) = @file($path . '/iso.txt');
- $lang[$localname] = $file;
- }
- }
- closedir($dir);
-
- @asort($lang);
- @reset($lang);
-
- $user_select = '';
- foreach ($lang as $displayname => $filename)
- {
- $selected = (strtolower($default) == strtolower($filename)) ? ' selected="selected"' : '';
- $user_select .= '<option value="' . $filename . '"' . $selected . '>' . ucwords($displayname) . '</option>';
- }
-
- return $user_select;
- }
-}
diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php
deleted file mode 100644
index 10b05eb559..0000000000
--- a/phpBB/install/install_convert.php
+++ /dev/null
@@ -1,2150 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-*/
-
-if (!defined('IN_INSTALL'))
-{
- // Someone has tried to access the file direct. This is not a good idea, so exit
- exit;
-}
-
-if (!empty($setmodules))
-{
- $module[] = array(
- 'module_type' => 'install',
- 'module_title' => 'CONVERT',
- 'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
- 'module_order' => 20,
- 'module_subs' => '',
- 'module_stages' => array('INTRO', 'SETTINGS', 'IN_PROGRESS', 'FINAL'),
- 'module_reqs' => ''
- );
-}
-
-/**
-* Class holding all convertor-specific details.
-*/
-class convert
-{
- var $options = array();
-
- var $convertor_tag = '';
- var $src_dbms = '';
- var $src_dbhost = '';
- var $src_dbport = '';
- var $src_dbuser = '';
- var $src_dbpasswd = '';
- var $src_dbname = '';
- var $src_table_prefix = '';
-
- var $convertor_data = array();
- var $tables = array();
- var $config_schema = array();
- var $convertor = array();
- var $src_truncate_statement = 'DELETE FROM ';
- var $truncate_statement = 'DELETE FROM ';
-
- var $fulltext_search;
-
- // Batch size, can be adjusted by the conversion file
- // For big boards a value of 6000 seems to be optimal
- var $batch_size = 2000;
- // Number of rows to be inserted at once (extended insert) if supported
- // For installations having enough memory a value of 60 may be good.
- var $num_wait_rows = 20;
-
- // Mysqls internal recoding engine messing up with our (better) functions? We at least support more encodings than mysql so should use it in favor.
- var $mysql_convert = false;
-
- var $p_master;
-
- function convert(&$p_master)
- {
- $this->p_master = &$p_master;
- }
-}
-
-/**
-* Convert class for conversions
-*/
-class install_convert extends module
-{
- /** @var array */
- protected $lang;
-
- /** @var string */
- protected $language;
-
- /** @var \phpbb\template\template */
- protected $template;
-
- /** @var string */
- protected $phpbb_root_path;
-
- /** @var string */
- protected $php_ext;
-
- /**
- * Variables used while converting, they are accessible from the global variable $convert
- */
- function install_convert(&$p_master)
- {
- $this->p_master = &$p_master;
- }
-
- function main($mode, $sub)
- {
- global $lang, $template, $phpbb_root_path, $phpEx, $cache, $config, $language, $table_prefix;
- global $convert, $request, $phpbb_container, $phpbb_config_php_file;
-
- $this->tpl_name = 'install_convert';
- $this->mode = $mode;
- $this->lang = $lang;
- $this->language = $language;
- $this->template = $template;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $phpEx;
-
- if (!$this->check_phpbb_installed())
- {
- return;
- }
-
- $convert = new convert($this->p_master);
-
- // Enable super globals to prevent issues with the new \phpbb\request\request object
- $request->enable_super_globals();
- // Create a normal container now
- $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
- $phpbb_container = $phpbb_container_builder->get_container();
-
- // Create cache
- $cache = $phpbb_container->get('cache');
-
- switch ($sub)
- {
- case 'intro':
- extract($phpbb_config_php_file->get_all());
-
- require($phpbb_root_path . 'includes/constants.' . $phpEx);
- require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
-
- $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
-
- $db = new $dbms();
- $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
- unset($dbpasswd);
-
- // We need to fill the config to let internal functions correctly work
- $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
-
- // Detect if there is already a conversion in progress at this point and offer to resume
- // It's quite possible that the user will get disconnected during a large conversion so they need to be able to resume it
- $new_conversion = request_var('new_conv', 0);
-
- if ($new_conversion)
- {
- $config['convert_progress'] = '';
- $config['convert_db_server'] = '';
- $config['convert_db_user'] = '';
- $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
- WHERE config_name = 'convert_progress'
- OR config_name = 'convert_db_server'
- OR config_name = 'convert_db_user'"
- );
- }
-
- // Let's see if there is a conversion in the works...
- $options = array();
- if (!empty($config['convert_progress']) && !empty($config['convert_db_server']) && !empty($config['convert_db_user']) && !empty($config['convert_options']))
- {
- $options = unserialize($config['convert_progress']);
- $options = array_merge($options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
- }
-
- // This information should have already been checked once, but do it again for safety
- if (!empty($options) && !empty($options['tag']) &&
- isset($options['dbms']) &&
- isset($options['dbhost']) &&
- isset($options['dbport']) &&
- isset($options['dbuser']) &&
- isset($options['dbpasswd']) &&
- isset($options['dbname']) &&
- isset($options['table_prefix']))
- {
- $this->page_title = $lang['CONTINUE_CONVERT'];
-
- $template->assign_vars(array(
- 'TITLE' => $lang['CONTINUE_CONVERT'],
- 'BODY' => $lang['CONTINUE_CONVERT_BODY'],
- 'L_NEW' => $lang['CONVERT_NEW_CONVERSION'],
- 'L_CONTINUE' => $lang['CONTINUE_OLD_CONVERSION'],
- 'S_CONTINUE' => true,
-
- 'U_NEW_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=intro&amp;new_conv=1&amp;language=$language",
- 'U_CONTINUE_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$options['tag']}{$options['step']}&amp;language=$language",
- ));
-
- return;
- }
-
- $this->list_convertors($sub);
-
- break;
-
- case 'settings':
- $this->get_convert_settings($sub);
- break;
-
- case 'in_progress':
- $this->convert_data($sub);
- break;
-
- case 'final':
- $this->page_title = $lang['CONVERT_COMPLETE'];
-
- $template->assign_vars(array(
- 'TITLE' => $lang['CONVERT_COMPLETE'],
- 'BODY' => $lang['CONVERT_COMPLETE_EXPLAIN'],
- ));
-
- // If we reached this step (conversion completed) we want to purge the cache and log the user out.
- // This is for making sure the session get not screwed due to the 3.0.x users table being completely new.
- $cache->purge();
-
- extract($phpbb_config_php_file->get_all());
-
- require($phpbb_root_path . 'includes/constants.' . $phpEx);
- require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
-
- $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
-
- $db = new $dbms();
- $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
- unset($dbpasswd);
-
- $sql = 'SELECT config_value
- FROM ' . CONFIG_TABLE . '
- WHERE config_name = \'search_type\'';
- $result = $db->sql_query($sql);
-
- if ($db->sql_fetchfield('config_value') != 'fulltext_mysql')
- {
- $template->assign_vars(array(
- 'S_ERROR_BOX' => true,
- 'ERROR_TITLE' => $lang['SEARCH_INDEX_UNCONVERTED'],
- 'ERROR_MSG' => $lang['SEARCH_INDEX_UNCONVERTED_EXPLAIN'],
- ));
- }
-
- switch ($db->get_sql_layer())
- {
- case 'sqlite':
- case 'sqlite3':
- $db->sql_query('DELETE FROM ' . SESSIONS_KEYS_TABLE);
- $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
- break;
-
- default:
- $db->sql_query('TRUNCATE TABLE ' . SESSIONS_KEYS_TABLE);
- $db->sql_query('TRUNCATE TABLE ' . SESSIONS_TABLE);
- break;
- }
-
- break;
- }
- }
-
- /**
- * Check whether phpBB is installed.
- * Assigns error template vars if not installed.
- *
- * @return bool Returns true if phpBB is installed.
- */
- public function check_phpbb_installed()
- {
- if (phpbb_check_installation_exists($this->phpbb_root_path, $this->php_ext))
- {
- return true;
- }
-
- $this->page_title = 'BOARD_NOT_INSTALLED';
- $install_url = append_sid($this->phpbb_root_path . 'install/index.' . $this->php_ext, 'mode=install&amp;language=' . $this->language);
-
- $this->template->assign_vars(array(
- 'S_NOT_INSTALLED' => true,
- 'BODY' => sprintf($this->lang['BOARD_NOT_INSTALLED_EXPLAIN'], $install_url),
- ));
-
- return false;
- }
-
- /**
- * Generate a list of all available conversion modules
- */
- function list_convertors($sub)
- {
- global $lang, $language, $template, $phpbb_root_path, $phpEx;
-
- $this->page_title = $lang['SUB_INTRO'];
-
- $template->assign_vars(array(
- 'TITLE' => $lang['CONVERT_INTRO'],
- 'BODY' => $lang['CONVERT_INTRO_BODY'],
-
- 'L_AUTHOR' => $lang['AUTHOR'],
- 'L_AVAILABLE_CONVERTORS' => $lang['AVAILABLE_CONVERTORS'],
- 'L_CONVERT' => $lang['CONVERT'],
- 'L_NO_CONVERTORS' => $lang['NO_CONVERTORS'],
- 'L_OPTIONS' => $lang['CONVERT_OPTIONS'],
- 'L_SOFTWARE' => $lang['SOFTWARE'],
- 'L_VERSION' => $lang['VERSION'],
-
- 'S_LIST' => true,
- ));
-
- $convertors = $sort = array();
- $get_info = true;
-
- $handle = @opendir('./convertors/');
-
- if (!$handle)
- {
- $this->error('Unable to access the convertors directory', __LINE__, __FILE__);
- }
-
- while ($entry = readdir($handle))
- {
- if (preg_match('/^convert_([a-z0-9_]+).' . $phpEx . '$/i', $entry, $m))
- {
- include('./convertors/' . $entry);
- if (isset($convertor_data))
- {
- $sort[strtolower($convertor_data['forum_name'])] = sizeof($convertors);
-
- $convertors[] = array(
- 'tag' => $m[1],
- 'forum_name' => $convertor_data['forum_name'],
- 'version' => $convertor_data['version'],
- 'dbms' => $convertor_data['dbms'],
- 'dbhost' => $convertor_data['dbhost'],
- 'dbport' => $convertor_data['dbport'],
- 'dbuser' => $convertor_data['dbuser'],
- 'dbpasswd' => $convertor_data['dbpasswd'],
- 'dbname' => $convertor_data['dbname'],
- 'table_prefix' => $convertor_data['table_prefix'],
- 'author' => $convertor_data['author']
- );
- }
- unset($convertor_data);
- }
- }
- closedir($handle);
-
- @ksort($sort);
-
- foreach ($sort as $void => $index)
- {
- $template->assign_block_vars('convertors', array(
- 'AUTHOR' => $convertors[$index]['author'],
- 'SOFTWARE' => $convertors[$index]['forum_name'],
- 'VERSION' => $convertors[$index]['version'],
-
- 'U_CONVERT' => $this->p_master->module_url . "?mode={$this->mode}&amp;language=$language&amp;sub=settings&amp;tag=" . $convertors[$index]['tag'],
- ));
- }
- }
-
- /**
- */
- function get_convert_settings($sub)
- {
- global $lang, $language, $template, $db, $phpbb_root_path, $phpEx, $config, $cache, $phpbb_config_php_file;
-
- extract($phpbb_config_php_file->get_all());
-
- require($phpbb_root_path . 'includes/constants.' . $phpEx);
- require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
-
- $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
-
- $db = new $dbms();
- $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
- unset($dbpasswd);
-
- $this->page_title = $lang['STAGE_SETTINGS'];
-
- // We need to fill the config to let internal functions correctly work
- $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
-
- $convertor_tag = request_var('tag', '');
-
- if (empty($convertor_tag))
- {
- $this->p_master->error($lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
- }
- $get_info = true;
-
- // check security implications of direct inclusion
- $convertor_tag = basename($convertor_tag);
- if (!file_exists('./convertors/convert_' . $convertor_tag . '.' . $phpEx))
- {
- $this->p_master->error($lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
- }
-
- include('./convertors/convert_' . $convertor_tag . '.' . $phpEx);
-
- // The test_file is a file that should be present in the location of the old board.
- if (!isset($test_file))
- {
- $this->p_master->error($lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
- }
-
- $submit = (isset($_POST['submit'])) ? true : false;
-
- $src_dbms = request_var('src_dbms', $convertor_data['dbms']);
- $src_dbhost = request_var('src_dbhost', $convertor_data['dbhost']);
- $src_dbport = request_var('src_dbport', $convertor_data['dbport']);
- $src_dbuser = request_var('src_dbuser', $convertor_data['dbuser']);
- $src_dbpasswd = request_var('src_dbpasswd', $convertor_data['dbpasswd']);
- $src_dbname = request_var('src_dbname', $convertor_data['dbname']);
- $src_table_prefix = request_var('src_table_prefix', $convertor_data['table_prefix']);
- $forum_path = request_var('forum_path', $convertor_data['forum_path']);
- $refresh = request_var('refresh', 1);
-
- // Default URL of the old board
- // @todo Are we going to use this for attempting to convert URL references in posts, or should we remove it?
- // -> We should convert old urls to the new relative urls format
- // $src_url = request_var('src_url', 'Not in use at the moment');
-
- // strip trailing slash from old forum path
- $forum_path = (strlen($forum_path) && $forum_path[strlen($forum_path) - 1] == '/') ? substr($forum_path, 0, -1) : $forum_path;
-
- $error = array();
- if ($submit)
- {
- if (!@file_exists('./../' . $forum_path . '/' . $test_file))
- {
- $error[] = sprintf($lang['COULD_NOT_FIND_PATH'], $forum_path);
- }
-
- $connect_test = false;
- $available_dbms = get_available_dbms(false, true, true);
-
- if (!isset($available_dbms[$src_dbms]) || !$available_dbms[$src_dbms]['AVAILABLE'])
- {
- $error[] = $lang['INST_ERR_NO_DB'];
- $connect_test = false;
- }
- else
- {
- $connect_test = connect_check_db(true, $error, $available_dbms[$src_dbms], $src_table_prefix, $src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, true, ($src_dbms == $dbms) ? false : true, false);
- }
-
- // The forum prefix of the old and the new forum can only be the same if two different databases are used.
- if ($src_table_prefix == $table_prefix && $src_dbms == $dbms && $src_dbhost == $dbhost && $src_dbport == $dbport && $src_dbname == $dbname)
- {
- $error[] = sprintf($lang['TABLE_PREFIX_SAME'], $src_table_prefix);
- }
-
- $src_dbms = $phpbb_config_php_file->convert_30_dbms_to_31($src_dbms);
-
- // Check table prefix
- if (!sizeof($error))
- {
- // initiate database connection to old db if old and new db differ
- global $src_db, $same_db;
- $src_db = $same_db = false;
-
- if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser)
- {
- $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;
- }
- else
- {
- $src_db = $db;
- $same_db = true;
- }
-
- $src_db->sql_return_on_error(true);
- $db->sql_return_on_error(true);
-
- // Try to select one row from the first table to see if the prefix is OK
- $result = $src_db->sql_query_limit('SELECT * FROM ' . $src_table_prefix . $tables[0], 1);
-
- if (!$result)
- {
- $prefixes = array();
-
- $tables_existing = get_tables($src_db);
- $tables_existing = array_map('strtolower', $tables_existing);
- foreach ($tables_existing as $table_name)
- {
- compare_table($tables, $table_name, $prefixes);
- }
- unset($tables_existing);
-
- foreach ($prefixes as $prefix => $count)
- {
- if ($count >= sizeof($tables))
- {
- $possible_prefix = $prefix;
- break;
- }
- }
-
- $msg = '';
- if (!empty($convertor_data['table_prefix']))
- {
- $msg .= sprintf($lang['DEFAULT_PREFIX_IS'], $convertor_data['forum_name'], $convertor_data['table_prefix']);
- }
-
- if (!empty($possible_prefix))
- {
- $msg .= '<br />';
- $msg .= ($possible_prefix == '*') ? $lang['BLANK_PREFIX_FOUND'] : sprintf($lang['PREFIX_FOUND'], $possible_prefix);
- $src_table_prefix = ($possible_prefix == '*') ? '' : $possible_prefix;
- }
-
- $error[] = $msg;
- }
- $src_db->sql_freeresult($result);
- $src_db->sql_return_on_error(false);
- }
-
- if (!sizeof($error))
- {
- // Save convertor Status
- set_config('convert_progress', serialize(array(
- 'step' => '',
- 'table_prefix' => $src_table_prefix,
- 'tag' => $convertor_tag,
- )), true);
- set_config('convert_db_server', serialize(array(
- 'dbms' => $src_dbms,
- 'dbhost' => $src_dbhost,
- 'dbport' => $src_dbport,
- 'dbname' => $src_dbname,
- )), true);
- set_config('convert_db_user', serialize(array(
- 'dbuser' => $src_dbuser,
- 'dbpasswd' => $src_dbpasswd,
- )), true);
-
- // Save options
- set_config('convert_options', serialize(array('forum_path' => './../' . $forum_path, 'refresh' => $refresh)), true);
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['VERIFY_OPTIONS'],
- 'RESULT' => $lang['CONVERT_SETTINGS_VERIFIED'],
- ));
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $lang['BEGIN_CONVERT'],
-// 'S_HIDDEN' => $s_hidden_fields,
- 'U_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag=$convertor_tag&amp;language=$language",
- ));
-
- return;
- }
- else
- {
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['VERIFY_OPTIONS'],
- 'RESULT' => '<b style="color:red">' . implode('<br />', $error) . '</b>',
- ));
- }
- } // end submit
-
- foreach ($this->convert_options as $config_key => $vars)
- {
- if (!is_array($vars) && strpos($config_key, 'legend') === false)
- {
- continue;
- }
-
- if (strpos($config_key, 'legend') !== false)
- {
- $template->assign_block_vars('options', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang[$vars])
- );
-
- continue;
- }
-
- $options = isset($vars['options']) ? $vars['options'] : '';
-
- $template->assign_block_vars('options', array(
- 'KEY' => $config_key,
- 'TITLE' => $lang[$vars['lang']],
- 'S_EXPLAIN' => $vars['explain'],
- 'S_LEGEND' => false,
- 'TITLE_EXPLAIN' => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
- 'CONTENT' => $this->p_master->input_field($config_key, $vars['type'], ${$config_key}, $options),
- )
- );
- }
-
- $template->assign_vars(array(
- 'TITLE' => $lang['STAGE_SETTINGS'],
- 'BODY' => $lang['CONV_OPTIONS_BODY'],
- 'L_SUBMIT' => $lang['BEGIN_CONVERT'],
- 'U_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=settings&amp;tag=$convertor_tag&amp;language=$language",
- ));
- }
-
- /**
- * The function which does the actual work (or dispatches it to the relevant places)
- */
- function convert_data($sub)
- {
- global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache, $auth;
- global $convert, $convert_row, $message_parser, $skip_rows, $language;
- global $request, $phpbb_config_php_file, $phpbb_dispatcher;
-
- extract($phpbb_config_php_file->get_all());
-
- require($phpbb_root_path . 'includes/constants.' . $phpEx);
- require($phpbb_root_path . 'includes/functions_convert.' . $phpEx);
-
- $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
-
- $db = new $dbms();
- $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true);
- unset($dbpasswd);
-
- // We need to fill the config to let internal functions correctly work
- $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
-
- // Override a couple of config variables for the duration
- $config['max_quote_depth'] = 0;
-
- // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
- $config['max_post_chars'] = $config['min_post_chars'] = 0;
-
- // Set up a user as well. We _should_ have enough of a database here at this point to do this
- // and it helps for any core code we call
- $user->session_begin();
- $user->page = $user->extract_current_page($phpbb_root_path);
-
- // This is a little bit of a fudge, but it allows the language entries to be available to the
- // core code without us loading them again
- $user->lang = &$lang;
-
- $this->page_title = $user->lang['STAGE_IN_PROGRESS'];
-
- $convert->options = array();
- if (isset($config['convert_progress']))
- {
- $convert->options = unserialize($config['convert_progress']);
- $convert->options = array_merge($convert->options, unserialize($config['convert_db_server']), unserialize($config['convert_db_user']), unserialize($config['convert_options']));
- }
-
- // This information should have already been checked once, but do it again for safety
- if (empty($convert->options) || empty($convert->options['tag']) ||
- !isset($convert->options['dbms']) ||
- !isset($convert->options['dbhost']) ||
- !isset($convert->options['dbport']) ||
- !isset($convert->options['dbuser']) ||
- !isset($convert->options['dbpasswd']) ||
- !isset($convert->options['dbname']) ||
- !isset($convert->options['table_prefix']))
- {
- $this->p_master->error($user->lang['NO_CONVERT_SPECIFIED'], __LINE__, __FILE__);
- }
-
- // Make some short variables accessible, for easier referencing
- $convert->convertor_tag = basename($convert->options['tag']);
- $convert->src_dbms = $convert->options['dbms'];
- $convert->src_dbhost = $convert->options['dbhost'];
- $convert->src_dbport = $convert->options['dbport'];
- $convert->src_dbuser = $convert->options['dbuser'];
- $convert->src_dbpasswd = $convert->options['dbpasswd'];
- $convert->src_dbname = $convert->options['dbname'];
- $convert->src_table_prefix = $convert->options['table_prefix'];
-
- // initiate database connection to old db if old and new db differ
- global $src_db, $same_db;
- $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)
- {
- $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;
- }
- else
- {
- $src_db = $db;
- $same_db = true;
- }
-
- $convert->mysql_convert = false;
- switch ($src_db->sql_layer)
- {
- case 'sqlite':
- case 'sqlite3':
- $convert->src_truncate_statement = 'DELETE FROM ';
- break;
-
- // Thanks MySQL, for silently converting...
- case 'mysql':
- case 'mysql4':
- if (version_compare($src_db->sql_server_info(true, false), '4.1.3', '>='))
- {
- $convert->mysql_convert = true;
- }
- $convert->src_truncate_statement = 'TRUNCATE TABLE ';
- break;
-
- case 'mysqli':
- $convert->mysql_convert = true;
- $convert->src_truncate_statement = 'TRUNCATE TABLE ';
- break;
-
- default:
- $convert->src_truncate_statement = 'TRUNCATE TABLE ';
- break;
- }
-
- if ($convert->mysql_convert && !$same_db)
- {
- $src_db->sql_query("SET NAMES 'binary'");
- }
-
- switch ($db->get_sql_layer())
- {
- case 'sqlite':
- case 'sqlite3':
- $convert->truncate_statement = 'DELETE FROM ';
- break;
-
- default:
- $convert->truncate_statement = 'TRUNCATE TABLE ';
- break;
- }
-
- $get_info = false;
-
- // check security implications of direct inclusion
- if (!file_exists('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx))
- {
- $this->p_master->error($user->lang['CONVERT_NOT_EXIST'], __LINE__, __FILE__);
- }
-
- if (file_exists('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx))
- {
- include('./convertors/functions_' . $convert->convertor_tag . '.' . $phpEx);
- }
-
- $get_info = true;
- include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
-
- // Map some variables...
- $convert->convertor_data = $convertor_data;
- $convert->tables = $tables;
- $convert->config_schema = $config_schema;
-
- // Now include the real data
- $get_info = false;
- include('./convertors/convert_' . $convert->convertor_tag . '.' . $phpEx);
-
- $convert->convertor_data = $convertor_data;
- $convert->tables = $tables;
- $convert->config_schema = $config_schema;
- $convert->convertor = $convertor;
-
- // The test_file is a file that should be present in the location of the old board.
- if (!file_exists($convert->options['forum_path'] . '/' . $test_file))
- {
- $this->p_master->error(sprintf($user->lang['COULD_NOT_FIND_PATH'], $convert->options['forum_path']), __LINE__, __FILE__);
- }
-
- $search_type = $config['search_type'];
-
- // For conversions we are a bit less strict and set to a search backend we know exist...
- if (!class_exists($search_type))
- {
- $search_type = '\phpbb\search\fulltext_native';
- set_config('search_type', $search_type);
- }
-
- if (!class_exists($search_type))
- {
- trigger_error('NO_SUCH_SEARCH_MODULE');
- }
-
- $error = false;
- $convert->fulltext_search = new $search_type($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
-
- if ($error)
- {
- trigger_error($error);
- }
-
- include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
- $message_parser = new parse_message();
-
- $jump = request_var('jump', 0);
- $final_jump = request_var('final_jump', 0);
- $sync_batch = request_var('sync_batch', -1);
- $last_statement = request_var('last', 0);
-
- // We are running sync...
- if ($sync_batch >= 0)
- {
- $this->sync_forums($sync_batch);
- return;
- }
-
- if ($jump)
- {
- $this->jump($jump, $last_statement);
- return;
- }
-
- if ($final_jump)
- {
- $this->final_jump($final_jump);
- return;
- }
-
- $current_table = request_var('current_table', 0);
- $old_current_table = min(-1, $current_table - 1);
- $skip_rows = request_var('skip_rows', 0);
-
- if (!$current_table && !$skip_rows)
- {
- if (!$request->variable('confirm', false))
- {
- // If avatars / ranks / smilies folders are specified make sure they are writable
- $bad_folders = array();
-
- $local_paths = array(
- 'avatar_path' => path($config['avatar_path']),
- 'avatar_gallery_path' => path($config['avatar_gallery_path']),
- 'icons_path' => path($config['icons_path']),
- 'ranks_path' => path($config['ranks_path']),
- 'smilies_path' => path($config['smilies_path'])
- );
-
- foreach ($local_paths as $folder => $local_path)
- {
- if (isset($convert->convertor[$folder]))
- {
- if (empty($convert->convertor['test_file']))
- {
- // test_file is mandantory at the moment so this should never be reached, but just in case...
- $this->p_master->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__);
- }
-
- if (!$local_path || !phpbb_is_writable($phpbb_root_path . $local_path))
- {
- if (!$local_path)
- {
- $bad_folders[] = sprintf($user->lang['CONFIG_PHPBB_EMPTY'], $folder);
- }
- else
- {
- $bad_folders[] = $local_path;
- }
- }
- }
- }
-
- if (sizeof($bad_folders))
- {
- $msg = (sizeof($bad_folders) == 1) ? $user->lang['MAKE_FOLDER_WRITABLE'] : $user->lang['MAKE_FOLDERS_WRITABLE'];
- sort($bad_folders);
- $this->p_master->error(sprintf($msg, implode('<br />', $bad_folders)), __LINE__, __FILE__, true);
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['INSTALL_TEST'],
- 'U_ACTION' => $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}&amp;language=$language",
- ));
- return;
- }
-
- // Grab all the tables used in convertor
- $missing_tables = $tables_list = $aliases = array();
-
- foreach ($convert->convertor['schema'] as $schema)
- {
- // Skip those not used (because of addons/plugins not detected)
- if (!$schema['target'])
- {
- continue;
- }
-
- foreach ($schema as $key => $val)
- {
- // we're dealing with an array like:
- // array('forum_status', 'forums.forum_status', 'is_item_locked')
- if (is_int($key) && !empty($val[1]))
- {
- $temp_data = $val[1];
- if (!is_array($temp_data))
- {
- $temp_data = array($temp_data);
- }
-
- foreach ($temp_data as $val)
- {
- if (preg_match('/([a-z0-9_]+)\.([a-z0-9_]+)\)* ?A?S? ?([a-z0-9_]*?)\.?([a-z0-9_]*)$/i', $val, $m))
- {
- $table = $convert->src_table_prefix . $m[1];
- $tables_list[$table] = $table;
-
- if (!empty($m[3]))
- {
- $aliases[] = $convert->src_table_prefix . $m[3];
- }
- }
- }
- }
- // 'left_join' => 'topics LEFT JOIN vote_desc ON topics.topic_id = vote_desc.topic_id AND topics.topic_vote = 1'
- else if ($key == 'left_join')
- {
- // Convert the value if it wasn't an array already.
- if (!is_array($val))
- {
- $val = array($val);
- }
-
- for ($j = 0, $size = sizeof($val); $j < $size; ++$j)
- {
- if (preg_match('/LEFT JOIN ([a-z0-9_]+) AS ([a-z0-9_]+)/i', $val[$j], $m))
- {
- $table = $convert->src_table_prefix . $m[1];
- $tables_list[$table] = $table;
-
- if (!empty($m[2]))
- {
- $aliases[] = $convert->src_table_prefix . $m[2];
- }
- }
- }
- }
- }
- }
-
- // Remove aliased tables from $tables_list
- foreach ($aliases as $alias)
- {
- unset($tables_list[$alias]);
- }
-
- // Check if the tables that we need exist
- $src_db->sql_return_on_error(true);
- foreach ($tables_list as $table => $null)
- {
- $sql = 'SELECT 1 FROM ' . $table;
- $_result = $src_db->sql_query_limit($sql, 1);
-
- if (!$_result)
- {
- $missing_tables[] = $table;
- }
- $src_db->sql_freeresult($_result);
- }
- $src_db->sql_return_on_error(false);
-
- // Throw an error if some tables are missing
- // We used to do some guessing here, but since we have a suggestion of possible values earlier, I don't see it adding anything here to do it again
-
- if (sizeof($missing_tables) == sizeof($tables_list))
- {
- $this->p_master->error($user->lang['NO_TABLES_FOUND'] . ' ' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
- }
- else if (sizeof($missing_tables))
- {
- $this->p_master->error(sprintf($user->lang['TABLES_MISSING'], implode($user->lang['COMMA_SEPARATOR'], $missing_tables)) . '<br /><br />' . $user->lang['CHECK_TABLE_PREFIX'], __LINE__, __FILE__);
- }
-
- $url = $this->save_convert_progress('&amp;confirm=1');
- $msg = $user->lang['PRE_CONVERT_COMPLETE'];
-
- if ($convert->convertor_data['author_notes'])
- {
- $msg .= '</p><p>' . sprintf($user->lang['AUTHOR_NOTES'], $convert->convertor_data['author_notes']);
- }
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
- 'L_MESSAGE' => $msg,
- 'U_ACTION' => $url,
- ));
-
- return;
- } // if (!$request->variable('confirm', false)))
-
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $user->lang['STARTING_CONVERT'],
- ));
-
- // Convert the config table and load the settings of the old board
- if (!empty($convert->config_schema))
- {
- restore_config($convert->config_schema);
-
- // Override a couple of config variables for the duration
- $config['max_quote_depth'] = 0;
-
- // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues
- $config['max_post_chars'] = $config['min_post_chars'] = 0;
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $user->lang['CONFIG_CONVERT'],
- 'RESULT' => $user->lang['DONE'],
- ));
-
- // Now process queries and execute functions that have to be executed prior to the conversion
- if (!empty($convert->convertor['execute_first']))
- {
- // @codingStandardsIgnoreStart
- eval($convert->convertor['execute_first']);
- // @codingStandardsIgnoreEnd
- }
-
- if (!empty($convert->convertor['query_first']))
- {
- if (!is_array($convert->convertor['query_first']))
- {
- $convert->convertor['query_first'] = array('target', array($convert->convertor['query_first']));
- }
- else if (!is_array($convert->convertor['query_first'][0]))
- {
- $convert->convertor['query_first'] = array(array($convert->convertor['query_first'][0], $convert->convertor['query_first'][1]));
- }
-
- foreach ($convert->convertor['query_first'] as $query_first)
- {
- if ($query_first[0] == 'src')
- {
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'binary'");
- }
-
- $src_db->sql_query($query_first[1]);
-
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'utf8'");
- }
- }
- else
- {
- $db->sql_query($query_first[1]);
- }
- }
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $user->lang['PREPROCESS_STEP'],
- 'RESULT' => $user->lang['DONE'],
- ));
- } // if (!$current_table && !$skip_rows)
-
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $user->lang['FILLING_TABLES'],
- ));
-
- // This loop takes one target table and processes it
- while ($current_table < sizeof($convert->convertor['schema']))
- {
- $schema = $convert->convertor['schema'][$current_table];
-
- // The target table isn't set, this can be because a module (for example the attachement mod) is taking care of this.
- if (empty($schema['target']))
- {
- $current_table++;
- continue;
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => sprintf($user->lang['FILLING_TABLE'], $schema['target']),
- ));
-
- // This is only the case when we first start working on the tables.
- if (!$skip_rows)
- {
- // process execute_first and query_first for this table...
- if (!empty($schema['execute_first']))
- {
- // @codingStandardsIgnoreStart
- eval($schema['execute_first']);
- // @codingStandardsIgnoreEnd
- }
-
- if (!empty($schema['query_first']))
- {
- if (!is_array($schema['query_first']))
- {
- $schema['query_first'] = array('target', array($schema['query_first']));
- }
- else if (!is_array($schema['query_first'][0]))
- {
- $schema['query_first'] = array(array($schema['query_first'][0], $schema['query_first'][1]));
- }
-
- foreach ($schema['query_first'] as $query_first)
- {
- if ($query_first[0] == 'src')
- {
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'binary'");
- }
- $src_db->sql_query($query_first[1]);
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'utf8'");
- }
- }
- else
- {
- $db->sql_query($query_first[1]);
- }
- }
- }
-
- if (!empty($schema['autoincrement']))
- {
- switch ($db->get_sql_layer())
- {
- case 'postgres':
- $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
- break;
-
- case 'oracle':
- $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $largest_id = (int) $row['max_id'];
-
- if ($largest_id)
- {
- $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
- $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
- }
- break;
- }
- }
- }
-
- // Process execute_always for this table
- // This is for code which needs to be executed on every pass of this table if
- // it gets split because of time restrictions
- if (!empty($schema['execute_always']))
- {
- // @codingStandardsIgnoreStart
- eval($schema['execute_always']);
- // @codingStandardsIgnoreEnd
- }
-
- //
- // Set up some variables
- //
- // $waiting_rows holds rows for multirows insertion (MySQL only)
- // $src_tables holds unique tables with aliases to select from
- // $src_fields will quickly refer source fields (or aliases) corresponding to the current index
- // $select_fields holds the names of the fields to retrieve
- //
-
- $sql_data = array(
- 'source_fields' => array(),
- 'target_fields' => array(),
- 'source_tables' => array(),
- 'select_fields' => array(),
- );
-
- // This statement is building the keys for later insertion.
- $insert_query = $this->build_insert_query($schema, $sql_data, $current_table);
-
- // If no source table is affected, we skip the table
- if (empty($sql_data['source_tables']))
- {
- $skip_rows = 0;
- $current_table++;
- continue;
- }
-
- $distinct = (!empty($schema['distinct'])) ? 'DISTINCT ' : '';
-
- $sql = 'SELECT ' . $distinct . implode(', ', $sql_data['select_fields']) . " \nFROM " . implode(', ', $sql_data['source_tables']);
-
- // Where
- $sql .= (!empty($schema['where'])) ? "\nWHERE (" . $schema['where'] . ')' : '';
-
- // Group By
- if (!empty($schema['group_by']))
- {
- $schema['group_by'] = array($schema['group_by']);
- foreach ($sql_data['select_fields'] as $select)
- {
- $alias = strpos(strtolower($select), ' as ');
- $select = ($alias) ? substr($select, 0, $alias) : $select;
- if (!in_array($select, $schema['group_by']))
- {
- $schema['group_by'][] = $select;
- }
- }
- }
- $sql .= (!empty($schema['group_by'])) ? "\nGROUP BY " . implode(', ', $schema['group_by']) : '';
-
- // Having
- $sql .= (!empty($schema['having'])) ? "\nHAVING " . $schema['having'] : '';
-
- // Order By
- if (empty($schema['order_by']) && !empty($schema['primary']))
- {
- $schema['order_by'] = $schema['primary'];
- }
- $sql .= (!empty($schema['order_by'])) ? "\nORDER BY " . $schema['order_by'] : '';
-
- // Counting basically holds the amount of rows processed.
- $counting = -1;
- $batch_time = 0;
-
- while ($counting === -1 || ($counting >= $convert->batch_size && still_on_time()))
- {
- $old_current_table = $current_table;
-
- $rows = '';
- $waiting_rows = array();
-
- if (!empty($batch_time))
- {
- $mtime = explode(' ', microtime());
- $mtime = $mtime[0] + $mtime[1];
- $rows = ceil($counting/($mtime - $batch_time)) . " rows/s ($counting rows) | ";
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => "skip_rows = $skip_rows",
- 'RESULT' => $rows . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] : ''),
- ));
-
- $mtime = explode(' ', microtime());
- $batch_time = $mtime[0] + $mtime[1];
-
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'binary'");
- }
-
- // Take skip rows into account and only fetch batch_size amount of rows
- $___result = $src_db->sql_query_limit($sql, $convert->batch_size, $skip_rows);
-
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'utf8'");
- }
-
- // This loop processes each row
- $counting = 0;
-
- $convert->row = $convert_row = array();
-
- if (!empty($schema['autoincrement']))
- {
- switch ($db->get_sql_layer())
- {
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
- $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' ON');
- break;
- }
- }
-
- // Now handle the rows until time is over or no more rows to process...
- while ($counting === 0 || still_on_time())
- {
- $convert_row = $src_db->sql_fetchrow($___result);
-
- if (!$convert_row)
- {
- // move to the next batch or table
- break;
- }
-
- // With this we are able to always save the last state
- $convert->row = $convert_row;
-
- // Increment the counting variable, it stores the number of rows we have processed
- $counting++;
-
- $insert_values = array();
-
- $sql_flag = $this->process_row($schema, $sql_data, $insert_values);
-
- if ($sql_flag === true)
- {
- switch ($db->get_sql_layer())
- {
- // If MySQL, we'll wait to have num_wait_rows rows to submit at once
- case 'mysql':
- case 'mysql4':
- case 'mysqli':
- $waiting_rows[] = '(' . implode(', ', $insert_values) . ')';
-
- if (sizeof($waiting_rows) >= $convert->num_wait_rows)
- {
- $errored = false;
-
- $db->sql_return_on_error(true);
-
- if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
- {
- $errored = true;
- }
- $db->sql_return_on_error(false);
-
- if ($errored)
- {
- $db->sql_return_on_error(true);
-
- // Because it errored out we will try to insert the rows one by one... most of the time this
- // is caused by duplicate entries - but we also do not want to miss one...
- foreach ($waiting_rows as $waiting_sql)
- {
- if (!$db->sql_query($insert_query . $waiting_sql))
- {
- $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
- }
- }
-
- $db->sql_return_on_error(false);
- }
-
- $waiting_rows = array();
- }
-
- break;
-
- default:
- $insert_sql = $insert_query . '(' . implode(', ', $insert_values) . ')';
-
- $db->sql_return_on_error(true);
-
- if (!$db->sql_query($insert_sql))
- {
- $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
- }
- $db->sql_return_on_error(false);
-
- $waiting_rows = array();
-
- break;
- }
- }
-
- $skip_rows++;
- }
- $src_db->sql_freeresult($___result);
-
- // We might still have some rows waiting
- if (sizeof($waiting_rows))
- {
- $errored = false;
- $db->sql_return_on_error(true);
-
- if (!$db->sql_query($insert_query . implode(', ', $waiting_rows)))
- {
- $errored = true;
- }
- $db->sql_return_on_error(false);
-
- if ($errored)
- {
- $db->sql_return_on_error(true);
-
- // Because it errored out we will try to insert the rows one by one... most of the time this
- // is caused by duplicate entries - but we also do not want to miss one...
- foreach ($waiting_rows as $waiting_sql)
- {
- $db->sql_query($insert_query . $waiting_sql);
- $this->p_master->db_error($user->lang['DB_ERR_INSERT'], htmlspecialchars($insert_query . $waiting_sql) . '<br /><br />' . htmlspecialchars(print_r($db->_sql_error(), true)), __LINE__, __FILE__, true);
- }
-
- $db->sql_return_on_error(false);
- }
-
- $waiting_rows = array();
- }
-
- if (!empty($schema['autoincrement']))
- {
- switch ($db->get_sql_layer())
- {
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
- $db->sql_query('SET IDENTITY_INSERT ' . $schema['target'] . ' OFF');
- break;
-
- case 'postgres':
- $db->sql_query("SELECT SETVAL('" . $schema['target'] . "_seq',(select case when max(" . $schema['autoincrement'] . ")>0 then max(" . $schema['autoincrement'] . ")+1 else 1 end from " . $schema['target'] . '));');
- break;
-
- case 'oracle':
- $result = $db->sql_query('SELECT MAX(' . $schema['autoincrement'] . ') as max_id FROM ' . $schema['target']);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $largest_id = (int) $row['max_id'];
-
- if ($largest_id)
- {
- $db->sql_query('DROP SEQUENCE ' . $schema['target'] . '_seq');
- $db->sql_query('CREATE SEQUENCE ' . $schema['target'] . '_seq START WITH ' . ($largest_id + 1));
- }
- break;
- }
- }
- }
-
- // When we reach this point, either the current table has been processed or we're running out of time.
- if (still_on_time() && $counting < $convert->batch_size/* && !defined('DEBUG')*/)
- {
- $skip_rows = 0;
- $current_table++;
- }
- else
- {/*
- if (still_on_time() && $counting < $convert->batch_size)
- {
- $skip_rows = 0;
- $current_table++;
- }*/
-
- // Looks like we ran out of time.
- $url = $this->save_convert_progress('&amp;current_table=' . $current_table . '&amp;skip_rows=' . $skip_rows);
-
- $current_table++;
-// $percentage = ($skip_rows == 0) ? 0 : floor(100 / ($total_rows / $skip_rows));
-
- $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $current_table, sizeof($convert->convertor['schema']));
-
- $template->assign_vars(array(
- 'L_MESSAGE' => $msg,
- 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
- }
-
- // Process execute_last then we'll be done
- $url = $this->save_convert_progress('&amp;jump=1');
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['FINAL_STEP'],
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
-
- /**
- * Sync function being executed at the middle, some functions need to be executed after a successful sync.
- */
- function sync_forums($sync_batch)
- {
- global $template, $user, $db, $phpbb_root_path, $phpEx, $config, $cache;
- global $convert;
-
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $user->lang['SYNC_TOPICS'],
- ));
-
- $batch_size = $convert->batch_size;
-
- $sql = 'SELECT MIN(topic_id) as min_value, MAX(topic_id) AS max_value
- FROM ' . TOPICS_TABLE;
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // Set values of minimum/maximum primary value for this table.
- $primary_min = $row['min_value'];
- $primary_max = $row['max_value'];
-
- if ($sync_batch == 0)
- {
- $sync_batch = (int) $primary_min;
- }
-
- if ($sync_batch == 0)
- {
- $sync_batch = 1;
- }
-
- // Fetch a batch of rows, process and insert them.
- while ($sync_batch <= $primary_max && still_on_time())
- {
- $end = ($sync_batch + $batch_size - 1);
-
- // Sync all topics in batch mode...
- sync('topic', 'range', 'topic_id BETWEEN ' . $sync_batch . ' AND ' . $end, true, true);
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => sprintf($user->lang['SYNC_TOPIC_ID'], $sync_batch, ($sync_batch + $batch_size)) . ((defined('DEBUG') && function_exists('memory_get_usage')) ? ' [' . ceil(memory_get_usage()/1024) . ' ' . $user->lang['KIB'] . ']' : ''),
- 'RESULT' => $user->lang['DONE'],
- ));
-
- $sync_batch += $batch_size;
- }
-
- if ($sync_batch >= $primary_max)
- {
- $url = $this->save_convert_progress('&amp;final_jump=1');
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
- else
- {
- $sync_batch--;
- }
-
- $url = $this->save_convert_progress('&amp;sync_batch=' . $sync_batch);
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
-
- /**
- * Save the convertor status
- */
- function save_convert_progress($step)
- {
- global $convert, $language;
-
- // Save convertor Status
- set_config('convert_progress', serialize(array(
- 'step' => $step,
- 'table_prefix' => $convert->src_table_prefix,
- 'tag' => $convert->convertor_tag,
- )), true);
-
- set_config('convert_db_server', serialize(array(
- 'dbms' => $convert->src_dbms,
- 'dbhost' => $convert->src_dbhost,
- 'dbport' => $convert->src_dbport,
- 'dbname' => $convert->src_dbname,
- )), true);
-
- set_config('convert_db_user', serialize(array(
- 'dbuser' => $convert->src_dbuser,
- 'dbpasswd' => $convert->src_dbpasswd,
- )), true);
-
- return $this->p_master->module_url . "?mode={$this->mode}&amp;sub=in_progress&amp;tag={$convert->convertor_tag}$step&amp;language=$language";
- }
-
- /**
- * Finish conversion, the last function to be called.
- */
- function finish_conversion()
- {
- global $db, $phpbb_root_path, $phpEx, $convert, $config, $language, $user, $template;
- global $cache, $auth, $phpbb_container, $phpbb_log;
-
- $db->sql_query('DELETE FROM ' . CONFIG_TABLE . "
- WHERE config_name = 'convert_progress'
- OR config_name = 'convert_options'
- OR config_name = 'convert_db_server'
- OR config_name = 'convert_db_user'");
- $db->sql_query('DELETE FROM ' . SESSIONS_TABLE);
-
- @unlink($phpbb_root_path . 'cache/data_global.' . $phpEx);
- phpbb_cache_moderators($db, $cache, $auth);
-
- // And finally, add a note to the log
- $phpbb_log = $phpbb_container->get('log');
- add_log('admin', 'LOG_INSTALL_CONVERTED', $convert->convertor_data['forum_name'], $config['version']);
-
- $url = $this->p_master->module_url . "?mode={$this->mode}&amp;sub=final&amp;language=$language";
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['FINAL_STEP'],
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
-
- /**
- * This function marks the steps after syncing
- */
- function final_jump($final_jump)
- {
- global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
- global $convert;
-
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $user->lang['PROCESS_LAST'],
- ));
-
- if ($final_jump == 1)
- {
- $db->sql_return_on_error(true);
-
- update_topics_posted();
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $user->lang['UPDATE_TOPICS_POSTED'],
- 'RESULT' => $user->lang['DONE'],
- ));
-
- if ($db->get_sql_error_triggered())
- {
- $template->assign_vars(array(
- 'S_ERROR_BOX' => true,
- 'ERROR_TITLE' => $user->lang['UPDATE_TOPICS_POSTED'],
- 'ERROR_MSG' => $user->lang['UPDATE_TOPICS_POSTED_ERR'],
- ));
- }
- $db->sql_return_on_error(false);
-
- $this->finish_conversion();
- return;
- }
- }
-
- /**
- * This function marks the steps before syncing (jump=1)
- */
- function jump($jump, $last_statement)
- {
- global $template, $user, $src_db, $same_db, $db, $phpbb_root_path, $phpEx, $config, $cache;
- global $convert;
-
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $user->lang['PROCESS_LAST'],
- ));
-
- if ($jump == 1)
- {
- // Execute 'last' statements/queries
- if (!empty($convert->convertor['execute_last']))
- {
- if (!is_array($convert->convertor['execute_last']))
- {
- // @codingStandardsIgnoreStart
- eval($convert->convertor['execute_last']);
- // @codingStandardsIgnoreEnd
- }
- else
- {
- while ($last_statement < sizeof($convert->convertor['execute_last']))
- {
- // @codingStandardsIgnoreStart
- eval($convert->convertor['execute_last'][$last_statement]);
- // @codingStandardsIgnoreEnd
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $convert->convertor['execute_last'][$last_statement],
- 'RESULT' => $user->lang['DONE'],
- ));
-
- $last_statement++;
- $url = $this->save_convert_progress('&amp;jump=1&amp;last=' . $last_statement);
-
- $percentage = ($last_statement == 0) ? 0 : floor(100 / (sizeof($convert->convertor['execute_last']) / $last_statement));
- $msg = sprintf($user->lang['STEP_PERCENT_COMPLETED'], $last_statement, sizeof($convert->convertor['execute_last']), $percentage);
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['CONTINUE_LAST'],
- 'L_MESSAGE' => $msg,
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
- }
- }
-
- if (!empty($convert->convertor['query_last']))
- {
- if (!is_array($convert->convertor['query_last']))
- {
- $convert->convertor['query_last'] = array('target', array($convert->convertor['query_last']));
- }
- else if (!is_array($convert->convertor['query_last'][0]))
- {
- $convert->convertor['query_last'] = array(array($convert->convertor['query_last'][0], $convert->convertor['query_last'][1]));
- }
-
- foreach ($convert->convertor['query_last'] as $query_last)
- {
- if ($query_last[0] == 'src')
- {
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'binary'");
- }
-
- $src_db->sql_query($query_last[1]);
-
- if ($convert->mysql_convert && $same_db)
- {
- $src_db->sql_query("SET NAMES 'utf8'");
- }
- }
- else
- {
- $db->sql_query($query_last[1]);
- }
- }
- }
-
- // Sanity check
- $db->sql_return_on_error(false);
- $src_db->sql_return_on_error(false);
-
- fix_empty_primary_groups();
-
- $sql = 'SELECT MIN(user_regdate) AS board_startdate
- FROM ' . USERS_TABLE;
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!isset($config['board_startdate']) || ($row['board_startdate'] < $config['board_startdate'] && $row['board_startdate'] > 0))
- {
- set_config('board_startdate', $row['board_startdate']);
- $db->sql_query('UPDATE ' . USERS_TABLE . ' SET user_regdate = ' . $row['board_startdate'] . ' WHERE user_id = ' . ANONYMOUS);
- }
-
- update_dynamic_config();
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $user->lang['CLEAN_VERIFY'],
- 'RESULT' => $user->lang['DONE'],
- ));
-
- $url = $this->save_convert_progress('&amp;jump=2');
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
-
- if ($jump == 2)
- {
- $db->sql_query('UPDATE ' . USERS_TABLE . " SET user_permissions = ''");
-
- // TODO: sync() is likely going to bomb out on forums with a considerable amount of topics.
- // TODO: the sync function is able to handle FROM-TO values, we should use them here (batch processing)
- sync('forum', '', '', false, true);
- $cache->destroy('sql', FORUMS_TABLE);
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $user->lang['SYNC_FORUMS'],
- 'RESULT' => $user->lang['DONE'],
- ));
-
- // Continue with synchronizing the forums...
- $url = $this->save_convert_progress('&amp;sync_batch=0');
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $user->lang['CONTINUE_CONVERT'],
- 'U_ACTION' => $url,
- ));
-
- $this->meta_refresh($url);
- return;
- }
- }
-
- function build_insert_query(&$schema, &$sql_data, $current_table)
- {
- global $db, $user;
- global $convert;
-
- // Can we use IGNORE with this DBMS?
- $sql_ignore = (strpos($db->get_sql_layer(), 'mysql') === 0 && !defined('DEBUG')) ? 'IGNORE ' : '';
- $insert_query = 'INSERT ' . $sql_ignore . 'INTO ' . $schema['target'] . ' (';
-
- $aliases = array();
-
- $sql_data = array(
- 'source_fields' => array(),
- 'target_fields' => array(),
- 'source_tables' => array(),
- 'select_fields' => array(),
- );
-
- foreach ($schema as $key => $val)
- {
- // Example: array('group_name', 'extension_groups.group_name', 'htmlspecialchars'),
- if (is_int($key))
- {
- if (!empty($val[0]))
- {
- // Target fields
- $sql_data['target_fields'][$val[0]] = $key;
- $insert_query .= $val[0] . ', ';
- }
-
- if (!is_array($val[1]))
- {
- $val[1] = array($val[1]);
- }
-
- foreach ($val[1] as $valkey => $value_1)
- {
- // This should cover about any case:
- //
- // table.field => SELECT table.field FROM table
- // table.field AS alias => SELECT table.field AS alias FROM table
- // table.field AS table2.alias => SELECT table2.field AS alias FROM table table2
- // table.field AS table2.field => SELECT table2.field FROM table table2
- //
- if (preg_match('/^([a-z0-9_]+)\.([a-z0-9_]+)( +AS +(([a-z0-9_]+?)\.)?([a-z0-9_]+))?$/i', $value_1, $m))
- {
- // There is 'AS ...' in the field names
- if (!empty($m[3]))
- {
- $value_1 = ($m[2] == $m[6]) ? $m[1] . '.' . $m[2] : $m[1] . '.' . $m[2] . ' AS ' . $m[6];
-
- // Table alias: store it then replace the source table with it
- if (!empty($m[5]) && $m[5] != $m[1])
- {
- $aliases[$m[5]] = $m[1];
- $value_1 = str_replace($m[1] . '.' . $m[2], $m[5] . '.' . $m[2], $value_1);
- }
- }
- else
- {
- // No table alias
- $sql_data['source_tables'][$m[1]] = (empty($convert->src_table_prefix)) ? $m[1] : $convert->src_table_prefix . $m[1] . ' ' . $m[1];
- }
-
- $sql_data['select_fields'][$value_1] = $value_1;
- $sql_data['source_fields'][$key][$valkey] = (!empty($m[6])) ? $m[6] : $m[2];
- }
- }
- }
- else if ($key == 'where' || $key == 'group_by' || $key == 'order_by' || $key == 'having')
- {
- if (@preg_match_all('/([a-z0-9_]+)\.([a-z0-9_]+)/i', $val, $m))
- {
- foreach ($m[1] as $value)
- {
- $sql_data['source_tables'][$value] = (empty($convert->src_table_prefix)) ? $value : $convert->src_table_prefix . $value . ' ' . $value;
- }
- }
- }
- }
-
- // Add the aliases to the list of tables
- foreach ($aliases as $alias => $table)
- {
- $sql_data['source_tables'][$alias] = $convert->src_table_prefix . $table . ' ' . $alias;
- }
-
- // 'left_join' => 'forums LEFT JOIN forum_prune ON forums.forum_id = forum_prune.forum_id',
- if (!empty($schema['left_join']))
- {
- if (!is_array($schema['left_join']))
- {
- $schema['left_join'] = array($schema['left_join']);
- }
-
- foreach ($schema['left_join'] as $left_join)
- {
- // This won't handle concatened LEFT JOINs
- if (!preg_match('/([a-z0-9_]+) LEFT JOIN ([a-z0-9_]+) A?S? ?([a-z0-9_]*?) ?(ON|USING)(.*)/i', $left_join, $m))
- {
- $this->p_master->error(sprintf($user->lang['NOT_UNDERSTAND'], 'LEFT JOIN', $left_join, $current_table, $schema['target']), __LINE__, __FILE__);
- }
-
- if (!empty($aliases[$m[2]]))
- {
- if (!empty($m[3]))
- {
- $this->p_master->error(sprintf($user->lang['NAMING_CONFLICT'], $m[2], $m[3], $schema['left_join']), __LINE__, __FILE__);
- }
-
- $m[2] = $aliases[$m[2]];
- $m[3] = $m[2];
- }
-
- $right_table = $convert->src_table_prefix . $m[2];
- if (!empty($m[3]))
- {
- unset($sql_data['source_tables'][$m[3]]);
- }
- else if ($m[2] != $m[1])
- {
- unset($sql_data['source_tables'][$m[2]]);
- }
-
- if (strpos($sql_data['source_tables'][$m[1]], "\nLEFT JOIN") !== false)
- {
- $sql_data['source_tables'][$m[1]] = '(' . $sql_data['source_tables'][$m[1]] . ")\nLEFT JOIN $right_table";
- }
- else
- {
- $sql_data['source_tables'][$m[1]] .= "\nLEFT JOIN $right_table";
- }
-
- if (!empty($m[3]))
- {
- unset($sql_data['source_tables'][$m[3]]);
- $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[3];
- }
- else if (!empty($convert->src_table_prefix))
- {
- $sql_data['source_tables'][$m[1]] .= ' AS ' . $m[2];
- }
- $sql_data['source_tables'][$m[1]] .= ' ' . $m[4] . $m[5];
- }
- }
-
- // Remove ", " from the end of the insert query
- $insert_query = substr($insert_query, 0, -2) . ') VALUES ';
-
- return $insert_query;
- }
-
- /**
- * Function for processing the currently handled row
- */
- function process_row(&$schema, &$sql_data, &$insert_values)
- {
- global $template, $user, $phpbb_root_path, $phpEx, $db, $lang, $config, $cache;
- global $convert, $convert_row;
-
- $sql_flag = false;
-
- foreach ($schema as $key => $fields)
- {
- // We are only interested in the lines with:
- // array('comment', 'attachments_desc.comment', 'htmlspecialchars'),
- if (is_int($key))
- {
- if (!is_array($fields[1]))
- {
- $fields[1] = array($fields[1]);
- }
-
- $firstkey_set = false;
- $firstkey = 0;
-
- foreach ($fields[1] as $inner_key => $inner_value)
- {
- if (!$firstkey_set)
- {
- $firstkey = $inner_key;
- $firstkey_set = true;
- }
-
- $src_field = isset($sql_data['source_fields'][$key][$inner_key]) ? $sql_data['source_fields'][$key][$inner_key] : '';
-
- if (!empty($src_field))
- {
- $fields[1][$inner_key] = $convert->row[$src_field];
- }
- }
-
- if (!empty($fields[0]))
- {
- // We have a target field, if we haven't set $sql_flag yet it will be set to TRUE.
- // If a function has already set it to FALSE it won't change it.
- if ($sql_flag === false)
- {
- $sql_flag = true;
- }
-
- // No function assigned?
- if (empty($fields[2]))
- {
- $value = $fields[1][$firstkey];
- }
- else if (is_array($fields[2]) && !is_callable($fields[2]))
- {
- // Execute complex function/eval/typecast
- $value = $fields[1];
-
- foreach ($fields[2] as $type => $execution)
- {
- if (strpos($type, 'typecast') === 0)
- {
- if (!is_array($value))
- {
- $value = array($value);
- }
- $value = $value[0];
- settype($value, $execution);
- }
- else if (strpos($type, 'function') === 0)
- {
- if (!is_array($value))
- {
- $value = array($value);
- }
-
- $value = call_user_func_array($execution, $value);
- }
- else if (strpos($type, 'execute') === 0)
- {
- if (!is_array($value))
- {
- $value = array($value);
- }
-
- $execution = str_replace('{RESULT}', '$value', $execution);
- $execution = str_replace('{VALUE}', '$value', $execution);
- // @codingStandardsIgnoreStart
- eval($execution);
- // @codingStandardsIgnoreEnd
- }
- }
- }
- else
- {
- $value = call_user_func_array($fields[2], $fields[1]);
- }
-
- if (is_null($value))
- {
- $value = '';
- }
-
- $insert_values[] = $db->_sql_validate_value($value);
- }
- else if (!empty($fields[2]))
- {
- if (is_array($fields[2]))
- {
- // Execute complex function/eval/typecast
- $value = '';
-
- foreach ($fields[2] as $type => $execution)
- {
- if (strpos($type, 'typecast') === 0)
- {
- $value = settype($value, $execution);
- }
- else if (strpos($type, 'function') === 0)
- {
- if (!is_array($value))
- {
- $value = array($value);
- }
-
- $value = call_user_func_array($execution, $value);
- }
- else if (strpos($type, 'execute') === 0)
- {
- if (!is_array($value))
- {
- $value = array($value);
- }
-
- $execution = str_replace('{RESULT}', '$value', $execution);
- $execution = str_replace('{VALUE}', '$value', $execution);
- // @codingStandardsIgnoreStart
- eval($execution);
- // @codingStandardsIgnoreEnd
- }
- }
- }
- else
- {
- call_user_func_array($fields[2], $fields[1]);
- }
- }
- }
- }
-
- return $sql_flag;
- }
-
- /**
- * Own meta refresh function to be able to change the global time used
- */
- function meta_refresh($url)
- {
- global $convert, $template;
-
- if ($convert->options['refresh'])
- {
- // Because we should not rely on correct settings, we simply use the relative path here directly.
- $template->assign_vars(array(
- 'S_REFRESH' => true,
- 'META' => '<meta http-equiv="refresh" content="5; url=' . $url . '" />')
- );
- }
- }
-
- /**
- * The information below will be used to build the input fields presented to the user
- */
- var $convert_options = array(
- 'legend1' => 'SPECIFY_OPTIONS',
- 'src_dbms' => array('lang' => 'DBMS', 'type' => 'select', 'options' => 'dbms_select(\'{VALUE}\', true)', 'explain' => false),
- 'src_dbhost' => array('lang' => 'DB_HOST', 'type' => 'text:25:100', 'explain' => true),
- 'src_dbport' => array('lang' => 'DB_PORT', 'type' => 'text:25:100', 'explain' => true),
- 'src_dbname' => array('lang' => 'DB_NAME', 'type' => 'text:25:100', 'explain' => false),
- 'src_dbuser' => array('lang' => 'DB_USERNAME', 'type' => 'text:25:100', 'explain' => false),
- 'src_dbpasswd' => array('lang' => 'DB_PASSWORD', 'type' => 'password:25:100', 'explain' => false),
- 'src_table_prefix' => array('lang' => 'TABLE_PREFIX', 'type' => 'text:25:100', 'explain' => false),
- //'src_url' => array('lang' => 'FORUM_ADDRESS', 'type' => 'text:50:100', 'explain' => true),
- 'forum_path' => array('lang' => 'FORUM_PATH', 'type' => 'text:25:100', 'explain' => true),
- 'refresh' => array('lang' => 'REFRESH_PAGE', 'type' => 'radio:yes_no', 'explain' => true),
- );
-}
diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php
deleted file mode 100644
index 8e57ed3edd..0000000000
--- a/phpBB/install/install_install.php
+++ /dev/null
@@ -1,2331 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-*/
-if (!defined('IN_INSTALL'))
-{
- // Someone has tried to access the file direct. This is not a good idea, so exit
- exit;
-}
-
-if (!empty($setmodules))
-{
- // If phpBB is already installed we do not include this module
- if (phpbb_check_installation_exists($phpbb_root_path, $phpEx) && !file_exists($phpbb_root_path . 'cache/install_lock'))
- {
- return;
- }
-
- $module[] = array(
- 'module_type' => 'install',
- 'module_title' => 'INSTALL',
- 'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
- 'module_order' => 10,
- 'module_subs' => '',
- 'module_stages' => array('INTRO', 'REQUIREMENTS', 'DATABASE', 'ADMINISTRATOR', 'CONFIG_FILE', 'ADVANCED', 'CREATE_TABLE', 'FINAL'),
- 'module_reqs' => ''
- );
-}
-
-/**
-* Installation
-*/
-class install_install extends module
-{
- function install_install(&$p_master)
- {
- $this->p_master = &$p_master;
- }
-
- function main($mode, $sub)
- {
- global $lang, $template, $language, $phpbb_root_path, $phpEx;
- global $phpbb_container, $cache, $phpbb_log, $request, $phpbb_config_php_file;
-
- switch ($sub)
- {
- case 'intro':
- $phpbb_container->get('cache.driver')->purge();
-
- $this->page_title = $lang['SUB_INTRO'];
-
- $template->assign_vars(array(
- 'TITLE' => $lang['INSTALL_INTRO'],
- 'BODY' => $lang['INSTALL_INTRO_BODY'],
- 'L_SUBMIT' => $lang['NEXT_STEP'],
- 'S_LANG_SELECT' => '<select id="language" name="language">' . $this->p_master->inst_language_select($language) . '</select>',
- 'U_ACTION' => $this->p_master->module_url . "?mode=$mode&amp;sub=requirements&amp;language=$language",
- ));
-
- break;
-
- case 'requirements':
- $this->check_server_requirements($mode, $sub);
-
- break;
-
- case 'database':
- $this->obtain_database_settings($mode, $sub);
-
- break;
-
- case 'administrator':
- $this->obtain_admin_settings($mode, $sub);
-
- break;
-
- case 'config_file':
- $this->create_config_file($mode, $sub);
-
- break;
-
- case 'advanced':
- $this->obtain_advanced_settings($mode, $sub);
-
- break;
-
- case 'create_table':
- $this->load_schema($mode, $sub);
- break;
-
- case 'final':
- // Enable super globals to prevent issues with the new \phpbb\request\request object
- $request->enable_super_globals();
-
- // Create a normal container now
- $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
- $phpbb_container = $phpbb_container_builder->get_container();
-
- // Sets the global variables
- $cache = $phpbb_container->get('cache');
- $phpbb_log = $phpbb_container->get('log');
-
- $this->build_search_index($mode, $sub);
- $this->add_modules($mode, $sub);
- $this->add_language($mode, $sub);
- $this->add_bots($mode, $sub);
- $this->email_admin($mode, $sub);
- $this->disable_avatars_if_unwritable();
- $this->populate_migrations($phpbb_container->get('ext.manager'), $phpbb_container->get('migrator'));
-
- // Remove the lock file
- @unlink($phpbb_root_path . 'cache/install_lock');
-
- break;
- }
-
- $this->tpl_name = 'install_install';
- }
-
- /**
- * Checks that the server we are installing on meets the requirements for running phpBB
- */
- function check_server_requirements($mode, $sub)
- {
- global $lang, $template, $phpbb_root_path, $phpEx, $language;
-
- $this->page_title = $lang['STAGE_REQUIREMENTS'];
-
- $template->assign_vars(array(
- 'TITLE' => $lang['REQUIREMENTS_TITLE'],
- 'BODY' => $lang['REQUIREMENTS_EXPLAIN'],
- ));
-
- $passed = array('php' => false, 'db' => false, 'files' => false, 'pcre' => false, 'imagesize' => false, 'json' => false,);
-
- // Test for basic PHP settings
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['PHP_SETTINGS'],
- 'LEGEND_EXPLAIN' => $lang['PHP_SETTINGS_EXPLAIN'],
- ));
-
- // Test the minimum and maximum version of PHP
- $php_version = PHP_VERSION;
-
- if ((version_compare($php_version, '5.3.3') < 0) || (version_compare($php_version, '7.0.0-dev', '>=')))
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- }
- else
- {
- $passed['php'] = true;
-
- // We also give feedback on whether we're running in safe mode
- $result = '<strong style="color:green">' . $lang['YES'];
- if (@ini_get('safe_mode') == '1' || strtolower(@ini_get('safe_mode')) == 'on')
- {
- $result .= ', ' . $lang['PHP_SAFE_MODE'];
- }
- $result .= '</strong>';
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['PHP_VERSION_REQD'],
- 'RESULT' => $result,
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
-
- // Don't check for register_globals on 5.4+
- if (version_compare($php_version, '5.4.0-dev') < 0)
- {
- // Check for register_globals being enabled
- if (@ini_get('register_globals') == '1' || strtolower(@ini_get('register_globals')) == 'on')
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- }
- else
- {
- $result = '<strong style="color:green">' . $lang['YES'] . '</strong>';
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['PHP_REGISTER_GLOBALS'],
- 'TITLE_EXPLAIN' => $lang['PHP_REGISTER_GLOBALS_EXPLAIN'],
- 'RESULT' => $result,
-
- 'S_EXPLAIN' => true,
- 'S_LEGEND' => false,
- ));
- }
-
- // Check for url_fopen
- if (@ini_get('allow_url_fopen') == '1' || strtolower(@ini_get('allow_url_fopen')) == 'on')
- {
- $result = '<strong style="color:green">' . $lang['YES'] . '</strong>';
- }
- else
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['PHP_URL_FOPEN_SUPPORT'],
- 'TITLE_EXPLAIN' => $lang['PHP_URL_FOPEN_SUPPORT_EXPLAIN'],
- 'RESULT' => $result,
-
- 'S_EXPLAIN' => true,
- 'S_LEGEND' => false,
- ));
-
- // Check for getimagesize
- if (@function_exists('getimagesize'))
- {
- $passed['imagesize'] = true;
- $result = '<strong style="color:green">' . $lang['YES'] . '</strong>';
- }
- else
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['PHP_GETIMAGESIZE_SUPPORT'],
- 'TITLE_EXPLAIN' => $lang['PHP_GETIMAGESIZE_SUPPORT_EXPLAIN'],
- 'RESULT' => $result,
-
- 'S_EXPLAIN' => true,
- 'S_LEGEND' => false,
- ));
-
- // Check for PCRE UTF-8 support
- if (@preg_match('//u', ''))
- {
- $passed['pcre'] = true;
- $result = '<strong style="color:green">' . $lang['YES'] . '</strong>';
- }
- else
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['PCRE_UTF_SUPPORT'],
- 'TITLE_EXPLAIN' => $lang['PCRE_UTF_SUPPORT_EXPLAIN'],
- 'RESULT' => $result,
-
- 'S_EXPLAIN' => true,
- 'S_LEGEND' => false,
- ));
-
- // Check for php json support
- if (@extension_loaded('json'))
- {
- $passed['json'] = true;
- $result = '<strong style="color:green">' . $lang['YES'] . '</strong>';
- }
- else
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['PHP_JSON_SUPPORT'],
- 'TITLE_EXPLAIN' => $lang['PHP_JSON_SUPPORT_EXPLAIN'],
- 'RESULT' => $result,
-
- 'S_EXPLAIN' => true,
- 'S_LEGEND' => false,
- ));
-
- $passed['mbstring'] = true;
- if (@extension_loaded('mbstring'))
- {
- // Test for available database modules
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['MBSTRING_CHECK'],
- 'LEGEND_EXPLAIN' => $lang['MBSTRING_CHECK_EXPLAIN'],
- ));
-
- $checks = array(
- array('func_overload', '&', MB_OVERLOAD_MAIL|MB_OVERLOAD_STRING),
- array('encoding_translation', '!=', 0),
- array('http_input', '!=', array('pass', '')),
- array('http_output', '!=', array('pass', ''))
- );
-
- foreach ($checks as $mb_checks)
- {
- $ini_val = @ini_get('mbstring.' . $mb_checks[0]);
- switch ($mb_checks[1])
- {
- case '&':
- if (intval($ini_val) & $mb_checks[2])
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- $passed['mbstring'] = false;
- }
- else
- {
- $result = '<strong style="color:green">' . $lang['YES'] . '</strong>';
- }
- break;
-
- case '!=':
- if (!is_array($mb_checks[2]) && $ini_val != $mb_checks[2] ||
- is_array($mb_checks[2]) && !in_array($ini_val, $mb_checks[2]))
- {
- $result = '<strong style="color:red">' . $lang['NO'] . '</strong>';
- $passed['mbstring'] = false;
- }
- else
- {
- $result = '<strong style="color:green">' . $lang['YES'] . '</strong>';
- }
- break;
- }
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['MBSTRING_' . strtoupper($mb_checks[0])],
- 'TITLE_EXPLAIN' => $lang['MBSTRING_' . strtoupper($mb_checks[0]) . '_EXPLAIN'],
- 'RESULT' => $result,
-
- 'S_EXPLAIN' => true,
- 'S_LEGEND' => false,
- ));
- }
- }
-
- // Test for available database modules
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['PHP_SUPPORTED_DB'],
- 'LEGEND_EXPLAIN' => $lang['PHP_SUPPORTED_DB_EXPLAIN'],
- ));
-
- $available_dbms = get_available_dbms(false, true);
- $passed['db'] = $available_dbms['ANY_DB_SUPPORT'];
- unset($available_dbms['ANY_DB_SUPPORT']);
-
- foreach ($available_dbms as $db_name => $db_ary)
- {
- if (!$db_ary['AVAILABLE'])
- {
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['DLL_' . strtoupper($db_name)],
- 'RESULT' => '<span style="color:red">' . $lang['UNAVAILABLE'] . '</span>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
- else
- {
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['DLL_' . strtoupper($db_name)],
- 'RESULT' => '<strong style="color:green">' . $lang['AVAILABLE'] . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
- }
-
- // Test for other modules
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['PHP_OPTIONAL_MODULE'],
- 'LEGEND_EXPLAIN' => $lang['PHP_OPTIONAL_MODULE_EXPLAIN'],
- ));
-
- foreach ($this->php_dlls_other as $dll)
- {
- if (!@extension_loaded($dll))
- {
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['DLL_' . strtoupper($dll)],
- 'RESULT' => '<strong style="color:red">' . $lang['UNAVAILABLE'] . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- continue;
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['DLL_' . strtoupper($dll)],
- 'RESULT' => '<strong style="color:green">' . $lang['AVAILABLE'] . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
-
- // Can we find ImageMagick anywhere on the system?
- $exe = (DIRECTORY_SEPARATOR == '\\') ? '.exe' : '';
-
- $magic_home = getenv('MAGICK_HOME');
- $img_imagick = '';
- if (empty($magic_home))
- {
- $locations = array('C:/WINDOWS/', 'C:/WINNT/', 'C:/WINDOWS/SYSTEM/', 'C:/WINNT/SYSTEM/', 'C:/WINDOWS/SYSTEM32/', 'C:/WINNT/SYSTEM32/', '/usr/bin/', '/usr/sbin/', '/usr/local/bin/', '/usr/local/sbin/', '/opt/', '/usr/imagemagick/', '/usr/bin/imagemagick/');
- $path_locations = str_replace('\\', '/', (explode(($exe) ? ';' : ':', getenv('PATH'))));
-
- $locations = array_merge($path_locations, $locations);
- foreach ($locations as $location)
- {
- // The path might not end properly, fudge it
- if (substr($location, -1, 1) !== '/')
- {
- $location .= '/';
- }
-
- if (@file_exists($location) && @is_readable($location . 'mogrify' . $exe) && @filesize($location . 'mogrify' . $exe) > 3000)
- {
- $img_imagick = str_replace('\\', '/', $location);
- continue;
- }
- }
- }
- else
- {
- $img_imagick = str_replace('\\', '/', $magic_home);
- }
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['APP_MAGICK'],
- 'RESULT' => ($img_imagick) ? '<strong style="color:green">' . $lang['AVAILABLE'] . ', ' . $img_imagick . '</strong>' : '<strong style="color:blue">' . $lang['NO_LOCATION'] . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
-
- // Check permissions on files/directories we need access to
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['FILES_REQUIRED'],
- 'LEGEND_EXPLAIN' => $lang['FILES_REQUIRED_EXPLAIN'],
- ));
-
- $directories = array('cache/', 'files/', 'store/');
-
- umask(0);
-
- $passed['files'] = true;
- foreach ($directories as $dir)
- {
- $exists = $write = false;
-
- // Try to create the directory if it does not exist
- if (!file_exists($phpbb_root_path . $dir))
- {
- @mkdir($phpbb_root_path . $dir, 0777);
- phpbb_chmod($phpbb_root_path . $dir, CHMOD_READ | CHMOD_WRITE);
- }
-
- // Now really check
- if (file_exists($phpbb_root_path . $dir) && is_dir($phpbb_root_path . $dir))
- {
- phpbb_chmod($phpbb_root_path . $dir, CHMOD_READ | CHMOD_WRITE);
- $exists = true;
- }
-
- // Now check if it is writable by storing a simple file
- $fp = @fopen($phpbb_root_path . $dir . 'test_lock', 'wb');
- if ($fp !== false)
- {
- $write = true;
- }
- @fclose($fp);
-
- @unlink($phpbb_root_path . $dir . 'test_lock');
-
- $passed['files'] = ($exists && $write && $passed['files']) ? true : false;
-
- $exists = ($exists) ? '<strong style="color:green">' . $lang['FOUND'] . '</strong>' : '<strong style="color:red">' . $lang['NOT_FOUND'] . '</strong>';
- $write = ($write) ? ', <strong style="color:green">' . $lang['WRITABLE'] . '</strong>' : (($exists) ? ', <strong style="color:red">' . $lang['UNWRITABLE'] . '</strong>' : '');
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $dir,
- 'RESULT' => $exists . $write,
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
-
- // Check permissions on files/directories it would be useful access to
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['FILES_OPTIONAL'],
- 'LEGEND_EXPLAIN' => $lang['FILES_OPTIONAL_EXPLAIN'],
- ));
-
- $directories = array('config.' . $phpEx, 'images/avatars/upload/');
-
- foreach ($directories as $dir)
- {
- $write = $exists = true;
- if (file_exists($phpbb_root_path . $dir))
- {
- if (!phpbb_is_writable($phpbb_root_path . $dir))
- {
- $write = false;
- }
- }
- else
- {
- $write = $exists = false;
- }
-
- $exists_str = ($exists) ? '<strong style="color:green">' . $lang['FOUND'] . '</strong>' : '<strong style="color:red">' . $lang['NOT_FOUND'] . '</strong>';
- $write_str = ($write) ? ', <strong style="color:green">' . $lang['WRITABLE'] . '</strong>' : (($exists) ? ', <strong style="color:red">' . $lang['UNWRITABLE'] . '</strong>' : '');
-
- $template->assign_block_vars('checks', array(
- 'TITLE' => $dir,
- 'RESULT' => $exists_str . $write_str,
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
-
- // And finally where do we want to go next (well today is taken isn't it :P)
- $s_hidden_fields = ($img_imagick) ? '<input type="hidden" name="img_imagick" value="' . addslashes($img_imagick) . '" />' : '';
-
- $url = (!in_array(false, $passed)) ? $this->p_master->module_url . "?mode=$mode&amp;sub=database&amp;language=$language" : $this->p_master->module_url . "?mode=$mode&amp;sub=requirements&amp;language=$language ";
- $submit = (!in_array(false, $passed)) ? $lang['INSTALL_START'] : $lang['INSTALL_TEST'];
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $submit,
- 'S_HIDDEN' => $s_hidden_fields,
- 'U_ACTION' => $url,
- ));
- }
-
- /**
- * Obtain the information required to connect to the database
- */
- function obtain_database_settings($mode, $sub)
- {
- global $lang, $template, $phpEx;
-
- $this->page_title = $lang['STAGE_DATABASE'];
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
-
- $connect_test = false;
- $error = array();
- $available_dbms = get_available_dbms(false, true);
-
- // Has the user opted to test the connection?
- if (isset($_POST['testdb']))
- {
- if (!isset($available_dbms[$data['dbms']]) || !$available_dbms[$data['dbms']]['AVAILABLE'])
- {
- $error[] = $lang['INST_ERR_NO_DB'];
- $connect_test = false;
- }
- else if (!preg_match(get_preg_expression('table_prefix'), $data['table_prefix']))
- {
- $error[] = $lang['INST_ERR_DB_INVALID_PREFIX'];
- $connect_test = false;
- }
- else
- {
- $connect_test = connect_check_db(true, $error, $available_dbms[$data['dbms']], $data['table_prefix'], $data['dbhost'], $data['dbuser'], htmlspecialchars_decode($data['dbpasswd']), $data['dbname'], $data['dbport']);
- }
-
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['DB_CONNECTION'],
- 'LEGEND_EXPLAIN' => false,
- ));
-
- if ($connect_test)
- {
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['DB_TEST'],
- 'RESULT' => '<strong style="color:green">' . $lang['SUCCESSFUL_CONNECT'] . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
- else
- {
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['DB_TEST'],
- 'RESULT' => '<strong style="color:red">' . implode('<br />', $error) . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
- }
-
- if (!$connect_test)
- {
- // Update the list of available DBMS modules to only contain those which can be used
- $available_dbms_temp = array();
- foreach ($available_dbms as $type => $dbms_ary)
- {
- if (!$dbms_ary['AVAILABLE'])
- {
- continue;
- }
-
- $available_dbms_temp[$type] = $dbms_ary;
- }
-
- $available_dbms = &$available_dbms_temp;
-
- // And now for the main part of this page
- $data['table_prefix'] = (!empty($data['table_prefix']) ? $data['table_prefix'] : 'phpbb_');
-
- foreach ($this->db_config_options as $config_key => $vars)
- {
- if (!is_array($vars) && strpos($config_key, 'legend') === false)
- {
- continue;
- }
-
- if (strpos($config_key, 'legend') !== false)
- {
- $template->assign_block_vars('options', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang[$vars])
- );
-
- continue;
- }
-
- $options = isset($vars['options']) ? $vars['options'] : '';
-
- $template->assign_block_vars('options', array(
- 'KEY' => $config_key,
- 'TITLE' => $lang[$vars['lang']],
- 'S_EXPLAIN' => $vars['explain'],
- 'S_LEGEND' => false,
- 'TITLE_EXPLAIN' => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
- 'CONTENT' => $this->p_master->input_field($config_key, $vars['type'], $data[$config_key], $options),
- )
- );
- }
- }
-
- // And finally where do we want to go next (well today is taken isn't it :P)
- $s_hidden_fields = ($data['img_imagick']) ? '<input type="hidden" name="img_imagick" value="' . addslashes($data['img_imagick']) . '" />' : '';
- $s_hidden_fields .= '<input type="hidden" name="language" value="' . $data['language'] . '" />';
- if ($connect_test)
- {
- foreach ($this->db_config_options as $config_key => $vars)
- {
- if (!is_array($vars))
- {
- continue;
- }
- $s_hidden_fields .= '<input type="hidden" name="' . $config_key . '" value="' . $data[$config_key] . '" />';
- }
- }
-
- $url = ($connect_test) ? $this->p_master->module_url . "?mode=$mode&amp;sub=administrator" : $this->p_master->module_url . "?mode=$mode&amp;sub=database";
- $s_hidden_fields .= ($connect_test) ? '' : '<input type="hidden" name="testdb" value="true" />';
-
- $submit = $lang['NEXT_STEP'];
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $submit,
- 'S_HIDDEN' => $s_hidden_fields,
- 'U_ACTION' => $url,
- ));
- }
-
- /**
- * Obtain the administrator's name, password and email address
- */
- function obtain_admin_settings($mode, $sub)
- {
- global $lang, $template, $phpEx;
-
- $this->page_title = $lang['STAGE_ADMINISTRATOR'];
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
-
- if ($data['dbms'] == '')
- {
- // Someone's been silly and tried calling this page direct
- // So we send them back to the start to do it again properly
- $this->p_master->redirect("index.$phpEx?mode=install");
- }
-
- $s_hidden_fields = ($data['img_imagick']) ? '<input type="hidden" name="img_imagick" value="' . addslashes($data['img_imagick']) . '" />' : '';
- $passed = false;
-
- $data['default_lang'] = ($data['default_lang'] !== '') ? $data['default_lang'] : $data['language'];
-
- if (isset($_POST['check']))
- {
- $error = array();
-
- // Check the entered email address and password
- if ($data['admin_name'] == '' || $data['admin_pass1'] == '' || $data['admin_pass2'] == '' || $data['board_email'] == '')
- {
- $error[] = $lang['INST_ERR_MISSING_DATA'];
- }
-
- if ($data['admin_pass1'] != $data['admin_pass2'] && $data['admin_pass1'] != '')
- {
- $error[] = $lang['INST_ERR_PASSWORD_MISMATCH'];
- }
-
- // Test against the default username rules
- if ($data['admin_name'] != '' && utf8_strlen($data['admin_name']) < 3)
- {
- $error[] = $lang['INST_ERR_USER_TOO_SHORT'];
- }
-
- if ($data['admin_name'] != '' && utf8_strlen($data['admin_name']) > 20)
- {
- $error[] = $lang['INST_ERR_USER_TOO_LONG'];
- }
-
- // Test against the default password rules
- if ($data['admin_pass1'] != '' && utf8_strlen($data['admin_pass1']) < 6)
- {
- $error[] = $lang['INST_ERR_PASSWORD_TOO_SHORT'];
- }
-
- if ($data['admin_pass1'] != '' && utf8_strlen($data['admin_pass1']) > 30)
- {
- $error[] = $lang['INST_ERR_PASSWORD_TOO_LONG'];
- }
-
- if ($data['board_email'] != '' && !preg_match('/^' . get_preg_expression('email') . '$/i', $data['board_email']))
- {
- $error[] = $lang['INST_ERR_EMAIL_INVALID'];
- }
-
- $template->assign_block_vars('checks', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang['STAGE_ADMINISTRATOR'],
- 'LEGEND_EXPLAIN' => false,
- ));
-
- if (!sizeof($error))
- {
- $passed = true;
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['ADMIN_TEST'],
- 'RESULT' => '<strong style="color:green">' . $lang['TESTS_PASSED'] . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
- else
- {
- $template->assign_block_vars('checks', array(
- 'TITLE' => $lang['ADMIN_TEST'],
- 'RESULT' => '<strong style="color:red">' . implode('<br />', $error) . '</strong>',
-
- 'S_EXPLAIN' => false,
- 'S_LEGEND' => false,
- ));
- }
- }
-
- if (!$passed)
- {
- foreach ($this->admin_config_options as $config_key => $vars)
- {
- if (!is_array($vars) && strpos($config_key, 'legend') === false)
- {
- continue;
- }
-
- if (strpos($config_key, 'legend') !== false)
- {
- $template->assign_block_vars('options', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang[$vars])
- );
-
- continue;
- }
-
- $options = isset($vars['options']) ? $vars['options'] : '';
-
- $template->assign_block_vars('options', array(
- 'KEY' => $config_key,
- 'TITLE' => $lang[$vars['lang']],
- 'S_EXPLAIN' => $vars['explain'],
- 'S_LEGEND' => false,
- 'TITLE_EXPLAIN' => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
- 'CONTENT' => $this->p_master->input_field($config_key, $vars['type'], $data[$config_key], $options),
- )
- );
- }
- }
- else
- {
- foreach ($this->admin_config_options as $config_key => $vars)
- {
- if (!is_array($vars))
- {
- continue;
- }
- $s_hidden_fields .= '<input type="hidden" name="' . $config_key . '" value="' . $data[$config_key] . '" />';
- }
- }
-
- $s_hidden_fields .= ($data['img_imagick']) ? '<input type="hidden" name="img_imagick" value="' . addslashes($data['img_imagick']) . '" />' : '';
- $s_hidden_fields .= '<input type="hidden" name="language" value="' . $data['language'] . '" />';
-
- foreach ($this->db_config_options as $config_key => $vars)
- {
- if (!is_array($vars))
- {
- continue;
- }
- $s_hidden_fields .= '<input type="hidden" name="' . $config_key . '" value="' . $data[$config_key] . '" />';
- }
-
- $submit = $lang['NEXT_STEP'];
-
- $url = ($passed) ? $this->p_master->module_url . "?mode=$mode&amp;sub=config_file" : $this->p_master->module_url . "?mode=$mode&amp;sub=administrator";
- $s_hidden_fields .= ($passed) ? '' : '<input type="hidden" name="check" value="true" />';
-
- $template->assign_vars(array(
- 'L_SUBMIT' => $submit,
- 'S_HIDDEN' => $s_hidden_fields,
- 'U_ACTION' => $url,
- ));
- }
-
- /**
- * Writes the config file to disk, or if unable to do so offers alternative methods
- */
- function create_config_file($mode, $sub)
- {
- global $lang, $template, $phpbb_root_path, $phpEx;
-
- $this->page_title = $lang['STAGE_CONFIG_FILE'];
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
-
- if ($data['dbms'] == '')
- {
- // Someone's been silly and tried calling this page direct
- // So we send them back to the start to do it again properly
- $this->p_master->redirect("index.$phpEx?mode=install");
- }
-
- $s_hidden_fields = ($data['img_imagick']) ? '<input type="hidden" name="img_imagick" value="' . addslashes($data['img_imagick']) . '" />' : '';
- $s_hidden_fields .= '<input type="hidden" name="language" value="' . $data['language'] . '" />';
- $written = false;
-
- // Create a list of any PHP modules we wish to have loaded
- $available_dbms = get_available_dbms($data['dbms']);
-
- // Create a lock file to indicate that there is an install in progress
- $fp = @fopen($phpbb_root_path . 'cache/install_lock', 'wb');
- if ($fp === false)
- {
- // We were unable to create the lock file - abort
- $this->p_master->error($lang['UNABLE_WRITE_LOCK'], __LINE__, __FILE__);
- }
- @fclose($fp);
-
- @chmod($phpbb_root_path . 'cache/install_lock', 0777);
-
- // Time to convert the data provided into a config file
- $config_data = phpbb_create_config_file_data($data, $available_dbms[$data['dbms']]['DRIVER']);
-
- // Attempt to write out the config file directly. If it works, this is the easiest way to do it ...
- if ((file_exists($phpbb_root_path . 'config.' . $phpEx) && phpbb_is_writable($phpbb_root_path . 'config.' . $phpEx)) || phpbb_is_writable($phpbb_root_path))
- {
- // Assume it will work ... if nothing goes wrong below
- $written = true;
-
- if (!($fp = @fopen($phpbb_root_path . 'config.' . $phpEx, 'w')))
- {
- // Something went wrong ... so let's try another method
- $written = false;
- }
-
- if (!(@fwrite($fp, $config_data)))
- {
- // Something went wrong ... so let's try another method
- $written = false;
- }
-
- @fclose($fp);
-
- if ($written)
- {
- // We may revert back to chmod() if we see problems with users not able to change their config.php file directly
- phpbb_chmod($phpbb_root_path . 'config.' . $phpEx, CHMOD_READ);
- }
- }
-
- if (isset($_POST['dldone']))
- {
- // Do a basic check to make sure that the file has been uploaded
- // Note that all we check is that the file has _something_ in it
- // We don't compare the contents exactly - if they can't upload
- // a single file correctly, it's likely they will have other problems....
- if (filesize($phpbb_root_path . 'config.' . $phpEx) > 10)
- {
- $written = true;
- }
- }
-
- $config_options = array_merge($this->db_config_options, $this->admin_config_options);
-
- foreach ($config_options as $config_key => $vars)
- {
- if (!is_array($vars))
- {
- continue;
- }
- $s_hidden_fields .= '<input type="hidden" name="' . $config_key . '" value="' . $data[$config_key] . '" />';
- }
-
- if (!$written)
- {
- // OK, so it didn't work let's try the alternatives
-
- if (isset($_POST['dlconfig']))
- {
- // They want a copy of the file to download, so send the relevant headers and dump out the data
- header("Content-Type: text/x-delimtext; name=\"config.$phpEx\"");
- header("Content-disposition: attachment; filename=config.$phpEx");
- echo $config_data;
- exit;
- }
-
- // The option to download the config file is always available, so output it here
- $template->assign_vars(array(
- 'BODY' => $lang['CONFIG_FILE_UNABLE_WRITE'],
- 'L_DL_CONFIG' => $lang['DL_CONFIG'],
- 'L_DL_CONFIG_EXPLAIN' => $lang['DL_CONFIG_EXPLAIN'],
- 'L_DL_DONE' => $lang['DONE'],
- 'L_DL_DOWNLOAD' => $lang['DL_DOWNLOAD'],
- 'S_HIDDEN' => $s_hidden_fields,
- 'S_SHOW_DOWNLOAD' => true,
- 'U_ACTION' => $this->p_master->module_url . "?mode=$mode&amp;sub=config_file",
- ));
- return;
- }
- else
- {
- $template->assign_vars(array(
- 'BODY' => $lang['CONFIG_FILE_WRITTEN'],
- 'L_SUBMIT' => $lang['NEXT_STEP'],
- 'S_HIDDEN' => $s_hidden_fields,
- 'U_ACTION' => $this->p_master->module_url . "?mode=$mode&amp;sub=advanced",
- ));
- return;
- }
- }
-
- /**
- * Provide an opportunity to customise some advanced settings during the install
- * in case it is necessary for them to be set to access later
- */
- function obtain_advanced_settings($mode, $sub)
- {
- global $lang, $template, $phpEx, $request;
-
- $this->page_title = $lang['STAGE_ADVANCED'];
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
-
- if ($data['dbms'] == '')
- {
- // Someone's been silly and tried calling this page direct
- // So we send them back to the start to do it again properly
- $this->p_master->redirect("index.$phpEx?mode=install");
- }
-
- $s_hidden_fields = ($data['img_imagick']) ? '<input type="hidden" name="img_imagick" value="' . addslashes($data['img_imagick']) . '" />' : '';
- $s_hidden_fields .= '<input type="hidden" name="language" value="' . $data['language'] . '" />';
-
- // HTTP_HOST is having the correct browser url in most cases...
- $server_name = strtolower(htmlspecialchars_decode($request->header('Host', $request->server('SERVER_NAME'))));
-
- // HTTP HOST can carry a port number...
- if (strpos($server_name, ':') !== false)
- {
- $server_name = substr($server_name, 0, strpos($server_name, ':'));
- }
-
- $data['email_enable'] = ($data['email_enable'] !== '') ? $data['email_enable'] : true;
- $data['server_name'] = ($data['server_name'] !== '') ? $data['server_name'] : $server_name;
- $data['server_port'] = ($data['server_port'] !== '') ? $data['server_port'] : $request->server('SERVER_PORT', 0);
- $data['server_protocol'] = ($data['server_protocol'] !== '') ? $data['server_protocol'] : ($request->is_secure() ? 'https://' : 'http://');
- $data['cookie_secure'] = ($data['cookie_secure'] !== '') ? $data['cookie_secure'] : $request->is_secure();
-
- if ($data['script_path'] === '')
- {
- $name = htmlspecialchars_decode($request->server('PHP_SELF'));
- if (!$name)
- {
- $name = htmlspecialchars_decode($request->server('REQUEST_URI'));
- }
-
- // Replace backslashes and doubled slashes (could happen on some proxy setups)
- $name = str_replace(array('\\', '//'), '/', $name);
- $data['script_path'] = trim(dirname(dirname($name)));
- }
-
- foreach ($this->advanced_config_options as $config_key => $vars)
- {
- if (!is_array($vars) && strpos($config_key, 'legend') === false)
- {
- continue;
- }
-
- if (strpos($config_key, 'legend') !== false)
- {
- $template->assign_block_vars('options', array(
- 'S_LEGEND' => true,
- 'LEGEND' => $lang[$vars])
- );
-
- continue;
- }
-
- $options = isset($vars['options']) ? $vars['options'] : '';
-
- $template->assign_block_vars('options', array(
- 'KEY' => $config_key,
- 'TITLE' => $lang[$vars['lang']],
- 'S_EXPLAIN' => $vars['explain'],
- 'S_LEGEND' => false,
- 'TITLE_EXPLAIN' => ($vars['explain']) ? $lang[$vars['lang'] . '_EXPLAIN'] : '',
- 'CONTENT' => $this->p_master->input_field($config_key, $vars['type'], $data[$config_key], $options),
- )
- );
- }
-
- $config_options = array_merge($this->db_config_options, $this->admin_config_options);
- foreach ($config_options as $config_key => $vars)
- {
- if (!is_array($vars))
- {
- continue;
- }
- $s_hidden_fields .= '<input type="hidden" name="' . $config_key . '" value="' . $data[$config_key] . '" />';
- }
-
- $submit = $lang['NEXT_STEP'];
-
- $url = $this->p_master->module_url . "?mode=$mode&amp;sub=create_table";
-
- $template->assign_vars(array(
- 'BODY' => $lang['STAGE_ADVANCED_EXPLAIN'],
- 'L_SUBMIT' => $submit,
- 'S_HIDDEN' => $s_hidden_fields,
- 'U_ACTION' => $url,
- ));
- }
-
- /**
- * Load the contents of the schema into the database and then alter it based on what has been input during the installation
- */
- function load_schema($mode, $sub)
- {
- global $db, $lang, $template, $phpbb_root_path, $phpEx, $request;
-
- $this->page_title = $lang['STAGE_CREATE_TABLE'];
- $s_hidden_fields = '';
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
-
- if ($data['dbms'] == '')
- {
- // Someone's been silly and tried calling this page direct
- // So we send them back to the start to do it again properly
- $this->p_master->redirect("index.$phpEx?mode=install");
- }
-
- // HTTP_HOST is having the correct browser url in most cases...
- $server_name = strtolower(htmlspecialchars_decode($request->header('Host', $request->server('SERVER_NAME'))));
- $referer = strtolower($request->header('Referer'));
-
- // HTTP HOST can carry a port number...
- if (strpos($server_name, ':') !== false)
- {
- $server_name = substr($server_name, 0, strpos($server_name, ':'));
- }
-
- $cookie_domain = ($data['server_name'] != '') ? $data['server_name'] : $server_name;
-
- // Try to come up with the best solution for cookie domain...
- if (strpos($cookie_domain, 'www.') === 0)
- {
- $cookie_domain = str_replace('www.', '.', $cookie_domain);
- }
-
- // If we get here and the extension isn't loaded it should be safe to just go ahead and load it
- $available_dbms = get_available_dbms($data['dbms']);
-
- if (!isset($available_dbms[$data['dbms']]))
- {
- // Someone's been silly and tried providing a non-existant dbms
- $this->p_master->redirect("index.$phpEx?mode=install");
- }
-
- $dbms = $available_dbms[$data['dbms']]['DRIVER'];
-
- // Instantiate the database
- $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.
- $db->sql_return_on_error(true);
-
- // If mysql is chosen, we need to adjust the schema filename slightly to reflect the correct version. ;)
- if ($data['dbms'] == 'mysql')
- {
- if (version_compare($db->sql_server_info(true), '4.1.3', '>='))
- {
- $available_dbms[$data['dbms']]['SCHEMA'] .= '_41';
- }
- else
- {
- $available_dbms[$data['dbms']]['SCHEMA'] .= '_40';
- }
- }
-
- // Ok we have the db info go ahead and read in the relevant schema
- // and work on building the table
- $dbms_schema = 'schemas/' . $available_dbms[$data['dbms']]['SCHEMA'] . '_schema.sql';
-
- // How should we treat this schema?
- $delimiter = $available_dbms[$data['dbms']]['DELIM'];
-
- if (file_exists($dbms_schema))
- {
- $sql_query = @file_get_contents($dbms_schema);
- $sql_query = preg_replace('#phpbb_#i', $data['table_prefix'], $sql_query);
- $sql_query = phpbb_remove_comments($sql_query);
- $sql_query = split_sql_file($sql_query, $delimiter);
-
- foreach ($sql_query as $sql)
- {
- // Ignore errors when the functions or types already exist
- // to allow installing phpBB twice in the same database with
- // a different prefix
- $db->sql_query($sql);
- }
- unset($sql_query);
- }
-
- // Ok we have the db info go ahead and work on building the table
- if (file_exists('schemas/schema.json'))
- {
- $db_table_schema = @file_get_contents('schemas/schema.json');
- $db_table_schema = json_decode($db_table_schema, true);
- }
- else
- {
- global $phpbb_root_path, $phpEx, $table_prefix;
- $table_prefix = 'phpbb_';
-
- if (!defined('CONFIG_TABLE'))
- {
- // We need to include the constants file for the table constants
- // when we generate the schema from the migration files.
- include($phpbb_root_path . 'includes/constants.' . $phpEx);
- }
-
- $finder = new \phpbb\finder(new \phpbb\filesystem(), $phpbb_root_path, null, $phpEx);
- $classes = $finder->core_path('phpbb/db/migration/data/')
- ->get_classes();
-
- $sqlite_db = new \phpbb\db\driver\sqlite();
- $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $sqlite_db, new \phpbb\db\tools($sqlite_db, true), $phpbb_root_path, $phpEx, $table_prefix);
- $db_table_schema = $schema_generator->get_schema();
- }
-
- if (!defined('CONFIG_TABLE'))
- {
- // CONFIG_TABLE is required by sql_create_index() to check the
- // length of index names. However table_prefix is not defined
- // here yet, so we need to create the constant ourselves.
- define('CONFIG_TABLE', $data['table_prefix'] . 'config');
- }
-
- $db_tools = new \phpbb\db\tools($db);
- foreach ($db_table_schema as $table_name => $table_data)
- {
- $db_tools->sql_create_table(
- $data['table_prefix'] . substr($table_name, 6),
- $table_data
- );
- }
-
- // Ok tables have been built, let's fill in the basic information
- $sql_query = file_get_contents('schemas/schema_data.sql');
-
- // Deal with any special comments and characters
- switch ($data['dbms'])
- {
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
- $sql_query = preg_replace('#\# MSSQL IDENTITY (phpbb_[a-z_]+) (ON|OFF) \##s', 'SET IDENTITY_INSERT \1 \2;', $sql_query);
- break;
-
- case 'postgres':
- $sql_query = preg_replace('#\# POSTGRES (BEGIN|COMMIT) \##s', '\1; ', $sql_query);
- break;
-
- case 'mysql':
- case 'mysqli':
- $sql_query = str_replace('\\', '\\\\', $sql_query);
- break;
- }
-
- // Change prefix
- $sql_query = preg_replace('# phpbb_([^\s]*) #i', ' ' . $data['table_prefix'] . '\1 ', $sql_query);
-
- // Change language strings...
- $sql_query = preg_replace_callback('#\{L_([A-Z0-9\-_]*)\}#s', 'adjust_language_keys_callback', $sql_query);
-
- $sql_query = phpbb_remove_comments($sql_query);
- $sql_query = split_sql_file($sql_query, ';');
-
- foreach ($sql_query as $sql)
- {
- //$sql = trim(str_replace('|', ';', $sql));
- if (!$db->sql_query($sql))
- {
- $error = $db->sql_error();
- $this->p_master->db_error($error['message'], $sql, __LINE__, __FILE__);
- }
- }
- unset($sql_query);
-
- $current_time = time();
-
- $user_ip = $request->server('REMOTE_ADDR') ? phpbb_ip_normalise($request->server('REMOTE_ADDR')) : '';
-
- if ($data['script_path'] !== '/')
- {
- // Adjust destination path (no trailing slash)
- if (substr($data['script_path'], -1) == '/')
- {
- $data['script_path'] = substr($data['script_path'], 0, -1);
- }
-
- $data['script_path'] = str_replace(array('../', './'), '', $data['script_path']);
-
- if ($data['script_path'][0] != '/')
- {
- $data['script_path'] = '/' . $data['script_path'];
- }
- }
-
- // Set default config and post data, this applies to all DB's
- $sql_ary = array(
- 'INSERT INTO ' . $data['table_prefix'] . "config (config_name, config_value)
- VALUES ('board_startdate', '$current_time')",
-
- 'INSERT INTO ' . $data['table_prefix'] . "config (config_name, config_value)
- VALUES ('default_lang', '" . $db->sql_escape($data['default_lang']) . "')",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['img_imagick']) . "'
- WHERE config_name = 'img_imagick'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['server_name']) . "'
- WHERE config_name = 'server_name'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['server_port']) . "'
- WHERE config_name = 'server_port'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['board_email']) . "'
- WHERE config_name = 'board_email'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['board_email']) . "'
- WHERE config_name = 'board_contact'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($cookie_domain) . "'
- WHERE config_name = 'cookie_domain'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($lang['default_dateformat']) . "'
- WHERE config_name = 'default_dateformat'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['email_enable']) . "'
- WHERE config_name = 'email_enable'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['smtp_delivery']) . "'
- WHERE config_name = 'smtp_delivery'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['smtp_host']) . "'
- WHERE config_name = 'smtp_host'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['smtp_auth']) . "'
- WHERE config_name = 'smtp_auth_method'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['smtp_user']) . "'
- WHERE config_name = 'smtp_username'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['smtp_pass']) . "'
- WHERE config_name = 'smtp_password'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['cookie_secure']) . "'
- WHERE config_name = 'cookie_secure'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['force_server_vars']) . "'
- WHERE config_name = 'force_server_vars'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['script_path']) . "'
- WHERE config_name = 'script_path'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['server_protocol']) . "'
- WHERE config_name = 'server_protocol'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($data['admin_name']) . "'
- WHERE config_name = 'newest_username'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . md5(mt_rand()) . "'
- WHERE config_name = 'avatar_salt'",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . md5(mt_rand()) . "'
- WHERE config_name = 'plupload_salt'",
-
- 'UPDATE ' . $data['table_prefix'] . "users
- SET username = '" . $db->sql_escape($data['admin_name']) . "', user_password='" . $db->sql_escape(md5($data['admin_pass1'])) . "', user_ip = '" . $db->sql_escape($user_ip) . "', user_lang = '" . $db->sql_escape($data['default_lang']) . "', user_email='" . $db->sql_escape($data['board_email']) . "', user_dateformat='" . $db->sql_escape($lang['default_dateformat']) . "', user_email_hash = " . $db->sql_escape(phpbb_email_hash($data['board_email'])) . ", username_clean = '" . $db->sql_escape(utf8_clean_string($data['admin_name'])) . "'
- WHERE username = 'Admin'",
-
- 'UPDATE ' . $data['table_prefix'] . "moderator_cache
- SET username = '" . $db->sql_escape($data['admin_name']) . "'
- WHERE username = 'Admin'",
-
- 'UPDATE ' . $data['table_prefix'] . "forums
- SET forum_last_poster_name = '" . $db->sql_escape($data['admin_name']) . "'
- WHERE forum_last_poster_name = 'Admin'",
-
- 'UPDATE ' . $data['table_prefix'] . "topics
- SET topic_first_poster_name = '" . $db->sql_escape($data['admin_name']) . "', topic_last_poster_name = '" . $db->sql_escape($data['admin_name']) . "'
- WHERE topic_first_poster_name = 'Admin'
- OR topic_last_poster_name = 'Admin'",
-
- 'UPDATE ' . $data['table_prefix'] . "users
- SET user_regdate = $current_time",
-
- 'UPDATE ' . $data['table_prefix'] . "posts
- SET post_time = $current_time, poster_ip = '" . $db->sql_escape($user_ip) . "'",
-
- 'UPDATE ' . $data['table_prefix'] . "topics
- SET topic_time = $current_time, topic_last_post_time = $current_time",
-
- 'UPDATE ' . $data['table_prefix'] . "forums
- SET forum_last_post_time = $current_time",
-
- 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($db->sql_server_info(true)) . "'
- WHERE config_name = 'dbms_version'",
- );
-
- if (@extension_loaded('gd'))
- {
- $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = 'core.captcha.plugins.gd'
- WHERE config_name = 'captcha_plugin'";
-
- $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '1'
- WHERE config_name = 'captcha_gd'";
- }
-
- $ref = substr($referer, strpos($referer, '://') + 3);
-
- if (!(stripos($ref, $server_name) === 0))
- {
- $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '0'
- WHERE config_name = 'referer_validation'";
- }
-
- // We set a (semi-)unique cookie name to bypass login issues related to the cookie name.
- $cookie_name = 'phpbb3_';
- $rand_str = md5(mt_rand());
- $rand_str = str_replace('0', 'z', base_convert($rand_str, 16, 35));
- $rand_str = substr($rand_str, 0, 5);
- $cookie_name .= strtolower($rand_str);
-
- $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config
- SET config_value = '" . $db->sql_escape($cookie_name) . "'
- WHERE config_name = 'cookie_name'";
-
- foreach ($sql_ary as $sql)
- {
- //$sql = trim(str_replace('|', ';', $sql));
-
- if (!$db->sql_query($sql))
- {
- $error = $db->sql_error();
- $this->p_master->db_error($error['message'], $sql, __LINE__, __FILE__);
- }
- }
-
- $submit = $lang['NEXT_STEP'];
-
- $url = $this->p_master->module_url . "?mode=$mode&amp;sub=final";
-
- $template->assign_vars(array(
- 'BODY' => $lang['STAGE_CREATE_TABLE_EXPLAIN'],
- 'L_SUBMIT' => $submit,
- 'S_HIDDEN' => build_hidden_fields($data),
- 'U_ACTION' => $url,
- ));
- }
-
- /**
- * Build the search index...
- */
- function build_search_index($mode, $sub)
- {
- global $db, $lang, $phpbb_root_path, $phpbb_dispatcher, $phpEx, $config, $auth, $user;
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
- $table_prefix = $data['table_prefix'];
-
- // If we get here and the extension isn't loaded it should be safe to just go ahead and load it
- $available_dbms = get_available_dbms($data['dbms']);
-
- if (!isset($available_dbms[$data['dbms']]))
- {
- // Someone's been silly and tried providing a non-existant dbms
- $this->p_master->redirect("index.$phpEx?mode=install");
- }
-
- $dbms = $available_dbms[$data['dbms']]['DRIVER'];
-
- // Instantiate the database
- $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.
- $db->sql_return_on_error(true);
-
- include_once($phpbb_root_path . 'includes/constants.' . $phpEx);
- include_once($phpbb_root_path . 'phpbb/search/fulltext_native.' . $phpEx);
-
- // We need to fill the config to let internal functions correctly work
- $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
-
- $error = false;
- $search = new \phpbb\search\fulltext_native($error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user, $phpbb_dispatcher);
-
- $sql = 'SELECT post_id, post_subject, post_text, poster_id, forum_id
- FROM ' . POSTS_TABLE;
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']);
- }
- $db->sql_freeresult($result);
- }
-
- /**
- * Populate the module tables
- */
- function add_modules($mode, $sub)
- {
- global $db, $lang, $phpbb_root_path, $phpEx, $phpbb_extension_manager, $config, $phpbb_container;
-
- // modules require an extension manager
- if (empty($phpbb_extension_manager))
- {
- $phpbb_extension_manager = $phpbb_container->get('ext.manager');
- }
-
- include_once($phpbb_root_path . 'includes/acp/acp_modules.' . $phpEx);
-
- $_module = new acp_modules();
- $module_classes = array('acp', 'mcp', 'ucp');
-
- // Add categories
- foreach ($module_classes as $module_class)
- {
- $categories = array();
-
- // Set the module class
- $_module->module_class = $module_class;
-
- foreach ($this->module_categories[$module_class] as $cat_name => $subs)
- {
- $basename = '';
- // Check if this sub-category has a basename. If it has, use it.
- if (isset($this->module_categories_basenames[$cat_name]))
- {
- $basename = $this->module_categories_basenames[$cat_name];
- }
- $module_data = array(
- 'module_basename' => $basename,
- 'module_enabled' => 1,
- 'module_display' => 1,
- 'parent_id' => 0,
- 'module_class' => $module_class,
- 'module_langname' => $cat_name,
- 'module_mode' => '',
- 'module_auth' => '',
- );
-
- // Add category
- $_module->update_module_data($module_data, true);
-
- // Check for last sql error happened
- if ($db->get_sql_error_triggered())
- {
- $error = $db->sql_error($db->get_sql_error_sql());
- $this->p_master->db_error($error['message'], $db->get_sql_error_sql(), __LINE__, __FILE__);
- }
-
- $categories[$cat_name]['id'] = (int) $module_data['module_id'];
- $categories[$cat_name]['parent_id'] = 0;
-
- // Create sub-categories...
- if (is_array($subs))
- {
- foreach ($subs as $level2_name)
- {
- $basename = '';
- // Check if this sub-category has a basename. If it has, use it.
- if (isset($this->module_categories_basenames[$level2_name]))
- {
- $basename = $this->module_categories_basenames[$level2_name];
- }
- $module_data = array(
- 'module_basename' => $basename,
- 'module_enabled' => 1,
- 'module_display' => 1,
- 'parent_id' => (int) $categories[$cat_name]['id'],
- 'module_class' => $module_class,
- 'module_langname' => $level2_name,
- 'module_mode' => '',
- 'module_auth' => '',
- );
-
- $_module->update_module_data($module_data, true);
-
- // Check for last sql error happened
- if ($db->get_sql_error_triggered())
- {
- $error = $db->sql_error($db->get_sql_error_sql());
- $this->p_master->db_error($error['message'], $db->get_sql_error_sql(), __LINE__, __FILE__);
- }
-
- $categories[$level2_name]['id'] = (int) $module_data['module_id'];
- $categories[$level2_name]['parent_id'] = (int) $categories[$cat_name]['id'];
- }
- }
- }
-
- // Get the modules we want to add... returned sorted by name
- $module_info = $_module->get_module_infos('', $module_class);
-
- foreach ($module_info as $module_basename => $fileinfo)
- {
- foreach ($fileinfo['modes'] as $module_mode => $row)
- {
- foreach ($row['cat'] as $cat_name)
- {
- if (!isset($categories[$cat_name]))
- {
- continue;
- }
-
- $module_data = array(
- 'module_basename' => $module_basename,
- 'module_enabled' => 1,
- 'module_display' => (isset($row['display'])) ? (int) $row['display'] : 1,
- 'parent_id' => (int) $categories[$cat_name]['id'],
- 'module_class' => $module_class,
- 'module_langname' => $row['title'],
- 'module_mode' => $module_mode,
- 'module_auth' => $row['auth'],
- );
-
- $_module->update_module_data($module_data, true);
-
- // Check for last sql error happened
- if ($db->get_sql_error_triggered())
- {
- $error = $db->sql_error($db->get_sql_error_sql());
- $this->p_master->db_error($error['message'], $db->get_sql_error_sql(), __LINE__, __FILE__);
- }
- }
- }
- }
-
- // Move some of the modules around since the code above will put them in the wrong place
- if ($module_class == 'acp')
- {
- // Move main module 4 up...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'acp_main'
- AND module_class = 'acp'
- AND module_mode = 'main'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_up', 4);
-
- // Move permissions intro screen module 4 up...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'acp_permissions'
- AND module_class = 'acp'
- AND module_mode = 'intro'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_up', 4);
-
- // Move manage users screen module 5 up...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'acp_users'
- AND module_class = 'acp'
- AND module_mode = 'overview'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_up', 5);
-
- // Move extension management module 1 up...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_langname = 'ACP_EXTENSION_MANAGEMENT'
- AND module_class = 'acp'
- AND module_mode = ''
- AND module_basename = ''";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_up', 1);
- }
-
- if ($module_class == 'mcp')
- {
- // Move pm report details module 3 down...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'mcp_pm_reports'
- AND module_class = 'mcp'
- AND module_mode = 'pm_report_details'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_down', 3);
-
- // Move closed pm reports module 3 down...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'mcp_pm_reports'
- AND module_class = 'mcp'
- AND module_mode = 'pm_reports_closed'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_down', 3);
-
- // Move open pm reports module 3 down...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'mcp_pm_reports'
- AND module_class = 'mcp'
- AND module_mode = 'pm_reports'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_down', 3);
- }
-
- if ($module_class == 'ucp')
- {
- // Move attachment module 4 down...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'ucp_attachments'
- AND module_class = 'ucp'
- AND module_mode = 'attachments'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_down', 4);
-
- // Move notification options module 4 down...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'ucp_notifications'
- AND module_class = 'ucp'
- AND module_mode = 'notification_options'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_down', 4);
-
- // Move OAuth module 5 down...
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_basename = 'ucp_auth_link'
- AND module_class = 'ucp'
- AND module_mode = 'auth_link'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $_module->move_module_by($row, 'move_down', 5);
- }
-
- // And now for the special ones
- // (these are modules which appear in multiple categories and thus get added manually to some for more control)
- if (isset($this->module_extras[$module_class]))
- {
- foreach ($this->module_extras[$module_class] as $cat_name => $mods)
- {
- $sql = 'SELECT module_id, left_id, right_id
- FROM ' . MODULES_TABLE . "
- WHERE module_langname = '" . $db->sql_escape($cat_name) . "'
- AND module_class = '" . $db->sql_escape($module_class) . "'";
- $result = $db->sql_query_limit($sql, 1);
- $row2 = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- foreach ($mods as $mod_name)
- {
- $sql = 'SELECT *
- FROM ' . MODULES_TABLE . "
- WHERE module_langname = '" . $db->sql_escape($mod_name) . "'
- AND module_class = '" . $db->sql_escape($module_class) . "'
- AND module_basename <> ''";
- $result = $db->sql_query_limit($sql, 1);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- $module_data = array(
- 'module_basename' => $row['module_basename'],
- 'module_enabled' => (int) $row['module_enabled'],
- 'module_display' => (int) $row['module_display'],
- 'parent_id' => (int) $row2['module_id'],
- 'module_class' => $row['module_class'],
- 'module_langname' => $row['module_langname'],
- 'module_mode' => $row['module_mode'],
- 'module_auth' => $row['module_auth'],
- );
-
- $_module->update_module_data($module_data, true);
-
- // Check for last sql error happened
- if ($db->get_sql_error_triggered())
- {
- $error = $db->sql_error($db->get_sql_error_sql());
- $this->p_master->db_error($error['message'], $db->get_sql_error_sql(), __LINE__, __FILE__);
- }
- }
- }
- }
-
- $_module->remove_cache_file();
- }
- }
-
- /**
- * Populate the language tables
- */
- function add_language($mode, $sub)
- {
- global $db, $lang, $phpbb_root_path, $phpEx;
-
- $dir = @opendir($phpbb_root_path . 'language');
-
- if (!$dir)
- {
- $this->error('Unable to access the language directory', __LINE__, __FILE__);
- }
-
- $installed_languages = array();
- while (($file = readdir($dir)) !== false)
- {
- $path = $phpbb_root_path . 'language/' . $file;
-
- if ($file == '.' || $file == '..' || is_link($path) || is_file($path) || $file == 'CVS')
- {
- continue;
- }
-
- if (is_dir($path) && file_exists($path . '/iso.txt'))
- {
- $lang_file = file("$path/iso.txt");
-
- $lang_pack = array(
- 'lang_iso' => basename($path),
- 'lang_dir' => basename($path),
- 'lang_english_name' => trim(htmlspecialchars($lang_file[0])),
- 'lang_local_name' => trim(htmlspecialchars($lang_file[1], ENT_COMPAT, 'UTF-8')),
- 'lang_author' => trim(htmlspecialchars($lang_file[2], ENT_COMPAT, 'UTF-8')),
- );
-
- $db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $lang_pack));
-
- $installed_languages[] = (int) $db->sql_nextid();
- if ($db->get_sql_error_triggered())
- {
- $error = $db->sql_error($db->get_sql_error_sql());
- $this->p_master->db_error($error['message'], $db->get_sql_error_sql(), __LINE__, __FILE__);
- }
- }
- }
- closedir($dir);
-
- $sql = 'SELECT *
- FROM ' . PROFILE_FIELDS_TABLE;
- $result = $db->sql_query($sql);
-
- $profile_fields = array();
- $insert_buffer = new \phpbb\db\sql_insert_buffer($db, PROFILE_LANG_TABLE);
- while ($row = $db->sql_fetchrow($result))
- {
- foreach ($installed_languages as $lang_id)
- {
- $insert_buffer->insert(array(
- 'field_id' => $row['field_id'],
- 'lang_id' => $lang_id,
- 'lang_name' => strtoupper(substr($row['field_name'], 6)),// Remove phpbb_ from field name
- 'lang_explain' => '',
- 'lang_default_value' => '',
- ));
- }
- }
- $db->sql_freeresult($result);
-
- $insert_buffer->flush();
- }
-
- /**
- * Add search robots to the database
- */
- function add_bots($mode, $sub)
- {
- global $db, $lang, $phpbb_root_path, $phpEx, $config;
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
-
- // We need to fill the config to let internal functions correctly work
- $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
-
- $sql = 'SELECT group_id
- FROM ' . GROUPS_TABLE . "
- WHERE group_name = 'BOTS'";
- $result = $db->sql_query($sql);
- $group_id = (int) $db->sql_fetchfield('group_id');
- $db->sql_freeresult($result);
-
- if (!$group_id)
- {
- // If we reach this point then something has gone very wrong
- $this->p_master->error($lang['NO_GROUP'], __LINE__, __FILE__);
- }
-
- if (!function_exists('user_add'))
- {
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- }
-
- foreach ($this->bot_list as $bot_name => $bot_ary)
- {
- $user_row = array(
- 'user_type' => USER_IGNORE,
- 'group_id' => $group_id,
- 'username' => $bot_name,
- 'user_regdate' => time(),
- 'user_password' => '',
- 'user_colour' => '9E8DA7',
- 'user_email' => '',
- 'user_lang' => $data['default_lang'],
- 'user_style' => 1,
- 'user_timezone' => 'UTC',
- 'user_dateformat' => $lang['default_dateformat'],
- 'user_allow_massemail' => 0,
- 'user_allow_pm' => 0,
- );
-
- $user_id = user_add($user_row);
-
- if (!$user_id)
- {
- // If we can't insert this user then continue to the next one to avoid inconsistent data
- $this->p_master->db_error('Unable to insert bot into users table', $db->get_sql_error_sql(), __LINE__, __FILE__, true);
- continue;
- }
-
- $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
- 'bot_active' => 1,
- 'bot_name' => (string) $bot_name,
- 'user_id' => (int) $user_id,
- 'bot_agent' => (string) $bot_ary[0],
- 'bot_ip' => (string) $bot_ary[1],
- ));
-
- $db->sql_query($sql);
- }
- }
-
- /**
- * Sends an email to the board administrator with their password and some useful links
- */
- function email_admin($mode, $sub)
- {
- global $auth, $config, $db, $lang, $template, $user, $phpbb_root_path, $phpbb_admin_path, $phpEx;
-
- $this->page_title = $lang['STAGE_FINAL'];
-
- // Obtain any submitted data
- $data = $this->get_submitted_data();
-
- // We need to fill the config to let internal functions correctly work
- $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
-
- $user->session_begin();
- $auth->login($data['admin_name'], $data['admin_pass1'], false, true, true);
-
- // OK, Now that we've reached this point we can be confident that everything
- // is installed and working......I hope :)
- // So it's time to send an email to the administrator confirming the details
- // they entered
-
- if ($config['email_enable'])
- {
- include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
-
- $messenger = new messenger(false);
-
- $messenger->template('installed', $data['language']);
-
- $messenger->to($data['board_email'], $data['admin_name']);
-
- $messenger->anti_abuse_headers($config, $user);
-
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($data['admin_name']),
- 'PASSWORD' => htmlspecialchars_decode($data['admin_pass1']))
- );
-
- $messenger->send(NOTIFY_EMAIL);
- }
-
- // And finally, add a note to the log
- add_log('admin', 'LOG_INSTALL_INSTALLED', $config['version']);
-
- $template->assign_vars(array(
- 'TITLE' => $lang['INSTALL_CONGRATS'],
- 'BODY' => sprintf($lang['INSTALL_CONGRATS_EXPLAIN'], $config['version'], append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=convert&amp;language=' . $data['language']), '../docs/README.html'),
- 'L_SUBMIT' => $lang['INSTALL_LOGIN'],
- 'U_ACTION' => append_sid($phpbb_admin_path . 'index.' . $phpEx, 'i=send_statistics&amp;mode=send_statistics'),
- ));
- }
-
- /**
- * Check if the avatar directory is writable and disable avatars
- * if it isn't writable.
- */
- function disable_avatars_if_unwritable()
- {
- global $phpbb_root_path;
-
- if (!phpbb_is_writable($phpbb_root_path . 'images/avatars/upload/'))
- {
- set_config('allow_avatar', 0);
- set_config('allow_avatar_upload', 0);
- }
- }
-
- /**
- * Populate migrations for the installation
- *
- * This "installs" all migrations from (root path)/phpbb/db/migrations/data.
- * "installs" means it adds all migrations to the migrations table, but does not
- * perform any of the actions in the migrations.
- *
- * @param \phpbb\extension\manager $extension_manager
- * @param \phpbb\db\migrator $migrator
- */
- function populate_migrations($extension_manager, $migrator)
- {
- $finder = $extension_manager->get_finder();
-
- $migrations = $finder
- ->core_path('phpbb/db/migration/data/')
- ->get_classes();
- $migrator->populate_migrations($migrations);
- }
-
- /**
- * Generate a list of available mail server authentication methods
- */
- function mail_auth_select($selected_method)
- {
- global $lang;
-
- $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5', 'POP-BEFORE-SMTP');
- $s_smtp_auth_options = '';
-
- foreach ($auth_methods as $method)
- {
- $s_smtp_auth_options .= '<option value="' . $method . '"' . (($selected_method == $method) ? ' selected="selected"' : '') . '>' . $lang['SMTP_' . str_replace('-', '_', $method)] . '</option>';
- }
-
- return $s_smtp_auth_options;
- }
-
- /**
- * Get submitted data
- */
- function get_submitted_data()
- {
- return array(
- 'language' => basename(request_var('language', '')),
- 'dbms' => request_var('dbms', ''),
- 'dbhost' => request_var('dbhost', '', true),
- 'dbport' => request_var('dbport', ''),
- 'dbuser' => request_var('dbuser', ''),
- 'dbpasswd' => request_var('dbpasswd', '', true),
- 'dbname' => request_var('dbname', ''),
- 'table_prefix' => request_var('table_prefix', ''),
- 'default_lang' => basename(request_var('default_lang', '')),
- 'admin_name' => utf8_normalize_nfc(request_var('admin_name', '', true)),
- 'admin_pass1' => request_var('admin_pass1', '', true),
- 'admin_pass2' => request_var('admin_pass2', '', true),
- 'board_email' => strtolower(request_var('board_email', '')),
- 'img_imagick' => request_var('img_imagick', ''),
- 'ftp_path' => request_var('ftp_path', ''),
- 'ftp_user' => request_var('ftp_user', ''),
- 'ftp_pass' => request_var('ftp_pass', ''),
- 'email_enable' => request_var('email_enable', ''),
- 'smtp_delivery' => request_var('smtp_delivery', ''),
- 'smtp_host' => request_var('smtp_host', ''),
- 'smtp_auth' => request_var('smtp_auth', ''),
- 'smtp_user' => request_var('smtp_user', ''),
- 'smtp_pass' => request_var('smtp_pass', ''),
- 'cookie_secure' => request_var('cookie_secure', ''),
- 'force_server_vars' => request_var('force_server_vars', ''),
- 'server_protocol' => request_var('server_protocol', ''),
- 'server_name' => request_var('server_name', ''),
- 'server_port' => request_var('server_port', ''),
- 'script_path' => request_var('script_path', ''),
- );
- }
-
- /**
- * The information below will be used to build the input fields presented to the user
- */
- var $db_config_options = array(
- 'legend1' => 'DB_CONFIG',
- 'dbms' => array('lang' => 'DBMS', 'type' => 'select', 'options' => 'dbms_select(\'{VALUE}\')', 'explain' => false),
- 'dbhost' => array('lang' => 'DB_HOST', 'type' => 'text:25:100', 'explain' => true),
- 'dbport' => array('lang' => 'DB_PORT', 'type' => 'text:25:100', 'explain' => true),
- 'dbname' => array('lang' => 'DB_NAME', 'type' => 'text:25:100', 'explain' => false),
- 'dbuser' => array('lang' => 'DB_USERNAME', 'type' => 'text:25:100', 'explain' => false),
- 'dbpasswd' => array('lang' => 'DB_PASSWORD', 'type' => 'password:25:100', 'explain' => false),
- 'table_prefix' => array('lang' => 'TABLE_PREFIX', 'type' => 'text:25:100', 'explain' => true),
- );
- var $admin_config_options = array(
- 'legend1' => 'ADMIN_CONFIG',
- 'default_lang' => array('lang' => 'DEFAULT_LANG', 'type' => 'select', 'options' => '$this->module->inst_language_select(\'{VALUE}\')', 'explain' => false),
- 'admin_name' => array('lang' => 'ADMIN_USERNAME', 'type' => 'text:25:100', 'explain' => true),
- 'admin_pass1' => array('lang' => 'ADMIN_PASSWORD', 'type' => 'password:25:100', 'explain' => true),
- 'admin_pass2' => array('lang' => 'ADMIN_PASSWORD_CONFIRM', 'type' => 'password:25:100', 'explain' => false),
- 'board_email' => array('lang' => 'CONTACT_EMAIL', 'type' => 'email:25:100', 'explain' => false),
- );
- var $advanced_config_options = array(
- 'legend1' => 'ACP_EMAIL_SETTINGS',
- 'email_enable' => array('lang' => 'ENABLE_EMAIL', 'type' => 'radio:enabled_disabled', 'explain' => true),
- 'smtp_delivery' => array('lang' => 'USE_SMTP', 'type' => 'radio:yes_no', 'explain' => true),
- 'smtp_host' => array('lang' => 'SMTP_SERVER', 'type' => 'text:25:50', 'explain' => false),
- 'smtp_auth' => array('lang' => 'SMTP_AUTH_METHOD', 'type' => 'select', 'options' => '$this->module->mail_auth_select(\'{VALUE}\')', 'explain' => true),
- 'smtp_user' => array('lang' => 'SMTP_USERNAME', 'type' => 'text:25:255', 'explain' => true, 'options' => array('autocomplete' => 'off')),
- 'smtp_pass' => array('lang' => 'SMTP_PASSWORD', 'type' => 'password:25:255', 'explain' => true, 'options' => array('autocomplete' => 'off')),
-
- 'legend2' => 'SERVER_URL_SETTINGS',
- 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'type' => 'radio:enabled_disabled', 'explain' => true),
- 'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'type' => 'radio:yes_no', 'explain' => true),
- 'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'type' => 'text:10:10', 'explain' => true),
- 'server_name' => array('lang' => 'SERVER_NAME', 'type' => 'text:40:255', 'explain' => true),
- 'server_port' => array('lang' => 'SERVER_PORT', 'type' => 'text:5:5', 'explain' => true),
- 'script_path' => array('lang' => 'SCRIPT_PATH', 'type' => 'text::255', 'explain' => true),
- );
-
- /**
- * Specific PHP modules we may require for certain optional or extended features
- */
- var $php_dlls_other = array('zlib', 'ftp', 'gd', 'xml');
-
- /**
- * A list of the web-crawlers/bots we recognise by default
- *
- * Candidates but not included:
- * 'Accoona [Bot]' 'Accoona-AI-Agent/'
- * 'ASPseek [Crawler]' 'ASPseek/'
- * 'Boitho [Crawler]' 'boitho.com-dc/'
- * 'Bunnybot [Bot]' 'powered by www.buncat.de'
- * 'Cosmix [Bot]' 'cfetch/'
- * 'Crawler Search [Crawler]' '.Crawler-Search.de'
- * 'Findexa [Crawler]' 'Findexa Crawler ('
- * 'GBSpider [Spider]' 'GBSpider v'
- * 'genie [Bot]' 'genieBot ('
- * 'Hogsearch [Bot]' 'oegp v. 1.3.0'
- * 'Insuranco [Bot]' 'InsurancoBot'
- * 'IRLbot [Bot]' 'http://irl.cs.tamu.edu/crawler'
- * 'ISC Systems [Bot]' 'ISC Systems iRc Search'
- * 'Jyxobot [Bot]' 'Jyxobot/'
- * 'Kraehe [Metasuche]' '-DIE-KRAEHE- META-SEARCH-ENGINE/'
- * 'LinkWalker' 'LinkWalker'
- * 'MMSBot [Bot]' 'http://www.mmsweb.at/bot.html'
- * 'Naver [Bot]' 'nhnbot@naver.com)'
- * 'NetResearchServer' 'NetResearchServer/'
- * 'Nimble [Crawler]' 'NimbleCrawler'
- * 'Ocelli [Bot]' 'Ocelli/'
- * 'Onsearch [Bot]' 'onCHECK-Robot'
- * 'Orange [Spider]' 'OrangeSpider'
- * 'Sproose [Bot]' 'http://www.sproose.com/bot'
- * 'Susie [Sync]' '!Susie (http://www.sync2it.com/susie)'
- * 'Tbot [Bot]' 'Tbot/'
- * 'Thumbshots [Capture]' 'thumbshots-de-Bot'
- * 'Vagabondo [Crawler]' 'http://webagent.wise-guys.nl/'
- * 'Walhello [Bot]' 'appie 1.1 (www.walhello.com)'
- * 'WissenOnline [Bot]' 'WissenOnline-Bot'
- * 'WWWeasel [Bot]' 'WWWeasel Robot v'
- * 'Xaldon [Spider]' 'Xaldon WebSpider'
- */
- var $bot_list = array(
- 'AdsBot [Google]' => array('AdsBot-Google', ''),
- 'Alexa [Bot]' => array('ia_archiver', ''),
- 'Alta Vista [Bot]' => array('Scooter/', ''),
- 'Ask Jeeves [Bot]' => array('Ask Jeeves', ''),
- 'Baidu [Spider]' => array('Baiduspider', ''),
- 'Bing [Bot]' => array('bingbot/', ''),
- 'Exabot [Bot]' => array('Exabot', ''),
- 'FAST Enterprise [Crawler]' => array('FAST Enterprise Crawler', ''),
- 'FAST WebCrawler [Crawler]' => array('FAST-WebCrawler/', ''),
- 'Francis [Bot]' => array('http://www.neomo.de/', ''),
- 'Gigabot [Bot]' => array('Gigabot/', ''),
- 'Google Adsense [Bot]' => array('Mediapartners-Google', ''),
- 'Google Desktop' => array('Google Desktop', ''),
- 'Google Feedfetcher' => array('Feedfetcher-Google', ''),
- 'Google [Bot]' => array('Googlebot', ''),
- 'Heise IT-Markt [Crawler]' => array('heise-IT-Markt-Crawler', ''),
- 'Heritrix [Crawler]' => array('heritrix/1.', ''),
- 'IBM Research [Bot]' => array('ibm.com/cs/crawler', ''),
- 'ICCrawler - ICjobs' => array('ICCrawler - ICjobs', ''),
- 'ichiro [Crawler]' => array('ichiro/', ''),
- 'Majestic-12 [Bot]' => array('MJ12bot/', ''),
- 'Metager [Bot]' => array('MetagerBot/', ''),
- 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''),
- 'MSN [Bot]' => array('msnbot/', ''),
- 'MSNbot Media' => array('msnbot-media/', ''),
- 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''),
- 'Online link [Validator]' => array('online link validator', ''),
- 'psbot [Picsearch]' => array('psbot/0', ''),
- 'Sensis [Crawler]' => array('Sensis Web Crawler', ''),
- 'SEO Crawler' => array('SEO search Crawler/', ''),
- 'Seoma [Crawler]' => array('Seoma [SEO Crawler]', ''),
- 'SEOSearch [Crawler]' => array('SEOsearch/', ''),
- 'Snappy [Bot]' => array('Snappy/1.1 ( http://www.urltrends.com/ )', ''),
- 'Steeler [Crawler]' => array('http://www.tkl.iis.u-tokyo.ac.jp/~crawler/', ''),
- 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''),
- 'TurnitinBot [Bot]' => array('TurnitinBot/', ''),
- 'Voyager [Bot]' => array('voyager/', ''),
- 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''),
- 'W3C [Linkcheck]' => array('W3C-checklink/', ''),
- 'W3C [Validator]' => array('W3C_Validator', ''),
- 'YaCy [Bot]' => array('yacybot', ''),
- 'Yahoo MMCrawler [Bot]' => array('Yahoo-MMCrawler/', ''),
- 'Yahoo Slurp [Bot]' => array('Yahoo! DE Slurp', ''),
- 'Yahoo [Bot]' => array('Yahoo! Slurp', ''),
- 'YahooSeeker [Bot]' => array('YahooSeeker/', ''),
- );
-
- /**
- * Define the module structure so that we can populate the database without
- * needing to hard-code module_id values
- */
- var $module_categories = array(
- 'acp' => array(
- 'ACP_CAT_GENERAL' => array(
- 'ACP_QUICK_ACCESS',
- 'ACP_BOARD_CONFIGURATION',
- 'ACP_CLIENT_COMMUNICATION',
- 'ACP_SERVER_CONFIGURATION',
- ),
- 'ACP_CAT_FORUMS' => array(
- 'ACP_MANAGE_FORUMS',
- 'ACP_FORUM_BASED_PERMISSIONS',
- ),
- 'ACP_CAT_POSTING' => array(
- 'ACP_MESSAGES',
- 'ACP_ATTACHMENTS',
- ),
- 'ACP_CAT_USERGROUP' => array(
- 'ACP_CAT_USERS',
- 'ACP_GROUPS',
- 'ACP_USER_SECURITY',
- ),
- 'ACP_CAT_PERMISSIONS' => array(
- 'ACP_GLOBAL_PERMISSIONS',
- 'ACP_FORUM_BASED_PERMISSIONS',
- 'ACP_PERMISSION_ROLES',
- 'ACP_PERMISSION_MASKS',
- ),
- 'ACP_CAT_CUSTOMISE' => array(
- 'ACP_STYLE_MANAGEMENT',
- 'ACP_EXTENSION_MANAGEMENT',
- 'ACP_LANGUAGE',
- ),
- 'ACP_CAT_MAINTENANCE' => array(
- 'ACP_FORUM_LOGS',
- 'ACP_CAT_DATABASE',
- ),
- 'ACP_CAT_SYSTEM' => array(
- 'ACP_AUTOMATION',
- 'ACP_GENERAL_TASKS',
- 'ACP_MODULE_MANAGEMENT',
- ),
- 'ACP_CAT_DOT_MODS' => null,
- ),
- 'mcp' => array(
- 'MCP_MAIN' => null,
- 'MCP_QUEUE' => null,
- 'MCP_REPORTS' => null,
- 'MCP_NOTES' => null,
- 'MCP_WARN' => null,
- 'MCP_LOGS' => null,
- 'MCP_BAN' => null,
- ),
- 'ucp' => array(
- 'UCP_MAIN' => null,
- 'UCP_PROFILE' => null,
- 'UCP_PREFS' => null,
- 'UCP_PM' => null,
- 'UCP_USERGROUPS' => null,
- 'UCP_ZEBRA' => null,
- ),
- );
- var $module_categories_basenames = array(
- 'UCP_PM' => 'ucp_pm',
- );
-
- var $module_extras = array(
- 'acp' => array(
- 'ACP_QUICK_ACCESS' => array(
- 'ACP_MANAGE_USERS',
- 'ACP_GROUPS_MANAGE',
- 'ACP_MANAGE_FORUMS',
- 'ACP_MOD_LOGS',
- 'ACP_BOTS',
- 'ACP_PHP_INFO',
- ),
- 'ACP_FORUM_BASED_PERMISSIONS' => array(
- 'ACP_FORUM_PERMISSIONS',
- 'ACP_FORUM_PERMISSIONS_COPY',
- 'ACP_FORUM_MODERATORS',
- 'ACP_USERS_FORUM_PERMISSIONS',
- 'ACP_GROUPS_FORUM_PERMISSIONS',
- ),
- ),
- );
-}
diff --git a/phpBB/install/install_main.php b/phpBB/install/install_main.php
deleted file mode 100644
index d5874dac83..0000000000
--- a/phpBB/install/install_main.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-*/
-
-if ( !defined('IN_INSTALL') )
-{
- // Someone has tried to access the file direct. This is not a good idea, so exit
- exit;
-}
-
-if (!empty($setmodules))
-{
- $module[] = array(
- 'module_type' => 'install',
- 'module_title' => 'OVERVIEW',
- 'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
- 'module_order' => 0,
- 'module_subs' => array('INTRO', 'LICENSE', 'SUPPORT'),
- 'module_stages' => '',
- 'module_reqs' => ''
- );
-}
-
-/**
-* Main Tab - Installation
-*/
-class install_main extends module
-{
- function install_main(&$p_master)
- {
- $this->p_master = &$p_master;
- }
-
- function main($mode, $sub)
- {
- global $lang, $template, $language;
-
- switch ($sub)
- {
- case 'intro' :
- $title = $lang['SUB_INTRO'];
- $body = $lang['OVERVIEW_BODY'];
- break;
-
- case 'license' :
- $title = $lang['GPL'];
- $body = implode("<br/>\n", file(__DIR__ . '/../docs/LICENSE.txt'));
- break;
-
- case 'support' :
- $title = $lang['SUB_SUPPORT'];
- $body = $lang['SUPPORT_BODY'];
- break;
- }
-
- $this->tpl_name = 'install_main';
- $this->page_title = $title;
-
- $template->assign_vars(array(
- 'TITLE' => $title,
- 'BODY' => $body,
-
- 'S_LANG_SELECT' => '<select id="language" name="language">' . $this->p_master->inst_language_select($language) . '</select>',
- ));
- }
-}
diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php
deleted file mode 100644
index a00280a925..0000000000
--- a/phpBB/install/install_update.php
+++ /dev/null
@@ -1,1782 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-* @todo check for writable cache/store/files directory
-*/
-
-if (!defined('IN_INSTALL'))
-{
- // Someone has tried to access the file directly. This is not a good idea, so exit
- exit;
-}
-
-if (!empty($setmodules))
-{
- // If phpBB is not installed we do not include this module
- if (!phpbb_check_installation_exists($phpbb_root_path, $phpEx) || file_exists($phpbb_root_path . 'cache/install_lock'))
- {
- return;
- }
-
- $module[] = array(
- 'module_type' => 'update',
- 'module_title' => 'UPDATE',
- 'module_filename' => substr(basename(__FILE__), 0, -strlen($phpEx)-1),
- 'module_order' => 30,
- 'module_subs' => '',
- 'module_stages' => array('INTRO', 'VERSION_CHECK', 'FILE_CHECK', 'UPDATE_FILES', 'UPDATE_DB'),
- 'module_reqs' => ''
- );
-}
-
-/**
-* Update Installation
-*/
-class install_update extends module
-{
- var $p_master;
- var $update_info;
-
- var $old_location;
- var $new_location;
- var $latest_version;
- var $current_version;
-
- var $update_to_version;
-
- // Set to false
- var $test_update = false;
-
- function install_update(&$p_master)
- {
- $this->p_master = &$p_master;
- }
-
- function main($mode, $sub)
- {
- global $template, $phpEx, $phpbb_root_path, $user, $db, $config, $cache, $auth, $language;
- global $request, $phpbb_admin_path, $phpbb_adm_relative_path, $phpbb_container, $phpbb_config_php_file;
-
- // We must enable super globals, otherwise creating a new instance of the request class,
- // using the new container with a dbal connection will fail with the following PHP Notice:
- // Object of class phpbb_request_deactivated_super_global could not be converted to int
- $request->enable_super_globals();
-
- // Create a normal container now
- $phpbb_container_builder = new \phpbb\di\container_builder($phpbb_config_php_file, $phpbb_root_path, $phpEx);
- $phpbb_container_builder->set_dump_container(false);
- $phpbb_container_builder->set_use_extensions(false);
- if (file_exists($phpbb_root_path . 'install/update/new/config'))
- {
- $phpbb_container_builder->set_config_path($phpbb_root_path . 'install/update/new/config');
- }
- $phpbb_container = $phpbb_container_builder->get_container();
-
- // Writes into global $cache
- $cache = $phpbb_container->get('cache');
-
- $this->tpl_name = 'install_update';
- $this->page_title = 'UPDATE_INSTALLATION';
-
- $this->old_location = $phpbb_root_path . 'install/update/old/';
- $this->new_location = $phpbb_root_path . 'install/update/new/';
-
- // Init DB
- extract($phpbb_config_php_file->get_all());
- require($phpbb_root_path . 'includes/constants.' . $phpEx);
-
- // Special options for conflicts/modified files
- define('MERGE_NO_MERGE_NEW', 1);
- define('MERGE_NO_MERGE_MOD', 2);
- define('MERGE_NEW_FILE', 3);
- define('MERGE_MOD_FILE', 4);
-
- $dbms = $phpbb_config_php_file->convert_30_dbms_to_31($dbms);
-
- $db = new $dbms();
-
- // Connect to DB
- $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false);
-
- // We do not need this any longer, unset for safety purposes
- unset($dbpasswd);
-
- // We need to fill the config to let internal functions correctly work
- $config = new \phpbb\config\db($db, new \phpbb\cache\driver\null, CONFIG_TABLE);
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
-
- // Force template recompile
- $config['load_tplcompile'] = 1;
-
- // First of all, init the user session
- $user->session_begin();
- $auth->acl($user->data);
-
- // Overwrite user's language with the selected one.
- // Config needs to be changed to ensure that guests also get the selected language.
- $config_default_lang = $config['default_lang'];
- $config['default_lang'] = $language;
- $user->data['user_lang'] = $language;
-
- $user->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
-
- // Reset the default_lang
- $config['default_lang'] = $config_default_lang;
- unset($config_default_lang);
-
- // If we are within the intro page we need to make sure we get up-to-date version info
- if ($sub == 'intro')
- {
- $cache->destroy('_version_info');
- }
-
- // Set custom template again. ;)
- $paths = array($phpbb_root_path . 'install/update/new/adm/style', $phpbb_admin_path . 'style');
- $paths = array_filter($paths, 'is_dir');
- $template->set_custom_style(array(
- array(
- 'name' => 'adm',
- 'ext_path' => 'adm/style/',
- ),
- ), $paths);
-
- $template->assign_vars(array(
- 'S_USER_LANG' => $user->lang['USER_LANG'],
- 'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'],
- 'S_CONTENT_ENCODING' => 'UTF-8',
- 'S_CONTENT_FLOW_BEGIN' => ($user->lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
- 'S_CONTENT_FLOW_END' => ($user->lang['DIRECTION'] == 'ltr') ? 'right' : 'left',
- ));
-
- // Get current and latest version
- $version_helper = $phpbb_container->get('version_helper');
- try
- {
- $this->latest_version = $version_helper->get_latest_on_current_branch(true);
- }
- catch (\RuntimeException $e)
- {
- $this->latest_version = false;
-
- $update_info = array();
- include($phpbb_root_path . 'install/update/index.' . $phpEx);
- $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
-
- if ($info !== false)
- {
- $this->latest_version = (!empty($info['version']['to'])) ? trim($info['version']['to']) : false;
- }
- }
-
- // For the current version we trick a bit. ;)
- $this->current_version = (!empty($config['version_update_from'])) ? $config['version_update_from'] : $config['version'];
-
- $up_to_date = (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->latest_version)), '<')) ? false : true;
-
- // Check for a valid update directory, else point the user to the phpbb.com website
- if (!file_exists($phpbb_root_path . 'install/update') || !file_exists($phpbb_root_path . 'install/update/index.' . $phpEx) || !file_exists($this->old_location) || !file_exists($this->new_location))
- {
- $template->assign_vars(array(
- 'S_ERROR' => true,
- 'ERROR_MSG' => ($up_to_date) ? $user->lang['NO_UPDATE_FILES_UP_TO_DATE'] : sprintf($user->lang['NO_UPDATE_FILES_OUTDATED'], $config['version'], $this->current_version, $this->latest_version))
- );
-
- return;
- }
-
- $this->update_info = $this->get_file('update_info');
-
- // Make sure the update directory holds the correct information
- // Since admins are able to run the update/checks more than once we only check if the current version is lower or equal than the version to which we update to.
- if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '>'))
- {
- $template->assign_vars(array(
- 'S_ERROR' => true,
- 'ERROR_MSG' => sprintf($user->lang['INCOMPATIBLE_UPDATE_FILES'], $config['version'], $this->update_info['version']['from'], $this->update_info['version']['to']))
- );
-
- return;
- }
-
- // Check if the update files are actually meant to update from the current version
- if ($this->current_version != $this->update_info['version']['from'])
- {
- $template->assign_vars(array(
- 'S_ERROR' => true,
- 'ERROR_MSG' => sprintf($user->lang['INCOMPATIBLE_UPDATE_FILES'], $this->current_version, $this->update_info['version']['from'], $this->update_info['version']['to']),
- ));
- }
-
- // Check if the update files stored are for the latest version...
- if (version_compare(strtolower($this->latest_version), strtolower($this->update_info['version']['to']), '>'))
- {
- $template->assign_vars(array(
- 'S_WARNING' => true,
- 'WARNING_MSG' => sprintf($user->lang['OLD_UPDATE_FILES'], $this->update_info['version']['from'], $this->update_info['version']['to'], $this->latest_version))
- );
- }
-
- // We store the "update to" version, because it is not always the latest. ;)
- $this->update_to_version = $this->update_info['version']['to'];
-
- // Fill DB version
- if (empty($config['dbms_version']))
- {
- set_config('dbms_version', $db->sql_server_info(true));
- }
-
- if ($this->test_update === false)
- {
- // What about the language file? Got it updated?
- if (in_array('language/' . $language . '/install.' . $phpEx, $this->update_info['files']))
- {
- $lang = array();
- include($this->new_location . 'language/' . $language . '/install.' . $phpEx);
- // this is the user's language.. just merge it
- $user->lang = array_merge($user->lang, $lang);
- }
- if ($language != 'en' && in_array('language/en/install.' . $phpEx, $this->update_info['files']))
- {
- $lang = array();
- include($this->new_location . 'language/en/install.' . $phpEx);
- // only add new keys to user's language in english
- $new_keys = array_diff(array_keys($lang), array_keys($user->lang));
- foreach ($new_keys as $i => $new_key)
- {
- $user->lang[$new_key] = $lang[$new_key];
- }
- }
- }
-
- // Include renderer and engine
- $this->include_file('includes/diff/diff.' . $phpEx);
- $this->include_file('includes/diff/engine.' . $phpEx);
- $this->include_file('includes/diff/renderer.' . $phpEx);
-
- // Make sure we stay at the file check if checking the files again
- if ($request->variable('check_again', false, false, \phpbb\request\request_interface::POST))
- {
- $sub = $this->p_master->sub = 'file_check';
- }
-
- switch ($sub)
- {
- case 'intro':
- $this->page_title = 'UPDATE_INSTALLATION';
-
- $template->assign_vars(array(
- 'S_INTRO' => true,
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=version_check"),
- ));
-
- // Make sure the update list is destroyed.
- $cache->destroy('_update_list');
- $cache->destroy('_update_list_time');
- $cache->destroy('_diff_files');
- $cache->destroy('_expected_files');
- break;
-
- case 'version_check':
- $this->page_title = 'STAGE_VERSION_CHECK';
-
- $template->assign_vars(array(
- 'S_VERSION_CHECK' => true,
-
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
-
- 'S_UP_TO_DATE' => $up_to_date,
- 'LATEST_VERSION' => $this->latest_version,
- 'CURRENT_VERSION' => $this->current_version,
- ));
-
- // Print out version the update package updates to
- if ($this->latest_version != $this->update_info['version']['to'])
- {
- $template->assign_var('PACKAGE_VERSION', $this->update_info['version']['to']);
- }
-
- // Since some people try to update to RC releases, but phpBB.com tells them the last version is the version they currently run
- // we are faced with the updater thinking the database schema is up-to-date; which it is, but should be updated none-the-less
- // We now try to cope with this by triggering the update process
- if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '<'))
- {
- $template->assign_vars(array(
- 'S_UP_TO_DATE' => false,
- ));
- }
-
- break;
-
- case 'update_db':
- // Redirect the user to the database update script with some explanations...
- $template->assign_vars(array(
- 'S_DB_UPDATE' => true,
- 'S_DB_UPDATE_FINISHED' => ($config['version'] == $this->update_info['version']['to']) ? true : false,
- 'U_DB_UPDATE' => append_sid($phpbb_root_path . 'install/database_update.' . $phpEx, 'type=1&amp;language=' . $user->data['user_lang']),
- 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
- 'L_EVERYTHING_UP_TO_DATE' => $user->lang('EVERYTHING_UP_TO_DATE', append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login'), append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login&amp;redirect=' . $phpbb_adm_relative_path . 'index.php%3Fi=send_statistics%26mode=send_statistics')),
- ));
-
- // Do not display incompatible package note after successful update
- if ($config['version'] == $this->update_info['version']['to'])
- {
- $template->assign_var('S_ERROR', false);
- }
- break;
-
- case 'file_check':
-
- // retrieve info on what changes should have already been made to the files.
- $expected_files = $cache->get('_expected_files');
- if (!$expected_files)
- {
- $expected_files = array();
- }
-
- // Now make sure the previous file collection is no longer valid...
- $cache->destroy('_diff_files');
-
- $this->page_title = 'STAGE_FILE_CHECK';
-
- // Now make sure our update list is correct if the admin refreshes
- $action = request_var('action', '');
-
- // We are directly within an update. To make sure our update list is correct we check its status.
- $update_list = ($request->variable('check_again', false, false, \phpbb\request\request_interface::POST)) ? false : $cache->get('_update_list');
- $modified = ($update_list !== false) ? $cache->get('_update_list_time') : 0;
-
- // Make sure the list is up-to-date
- if ($update_list !== false)
- {
- $get_new_list = false;
- foreach ($this->update_info['files'] as $file)
- {
- if (file_exists($phpbb_root_path . $file) && filemtime($phpbb_root_path . $file) > $modified)
- {
- $get_new_list = true;
- break;
- }
- }
- }
- else
- {
- $get_new_list = true;
- }
-
- if (!$get_new_list && $update_list['status'] != -1)
- {
- $get_new_list = true;
- }
-
- if ($get_new_list)
- {
- $this->get_update_structure($update_list, $expected_files);
- $cache->put('_update_list', $update_list);
- $cache->put('_update_list_time', time());
-
- // Refresh the page if we are still not finished...
- if ($update_list['status'] != -1)
- {
- $refresh_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check");
- meta_refresh(2, $refresh_url);
-
- $template->assign_vars(array(
- 'S_IN_PROGRESS' => true,
- 'S_COLLECTED' => (int) $update_list['status'],
- 'S_TO_COLLECT' => sizeof($this->update_info['files']),
- 'L_IN_PROGRESS' => $user->lang['COLLECTING_FILE_DIFFS'],
- 'L_IN_PROGRESS_EXPLAIN' => sprintf($user->lang['NUMBER_OF_FILES_COLLECTED'], (int) $update_list['status'], sizeof($this->update_info['files']) + sizeof($this->update_info['deleted'])),
- ));
-
- return;
- }
- }
-
- if ($action == 'diff')
- {
- $this->show_diff($update_list);
- return;
- }
-
- if (sizeof($update_list['no_update']))
- {
- $template->assign_vars(array(
- 'S_NO_UPDATE_FILES' => true,
- 'NO_UPDATE_FILES' => implode(', ', array_map('htmlspecialchars', $update_list['no_update'])))
- );
- }
-
- $new_expected_files = array();
-
- // Now assign the list to the template
- foreach ($update_list as $status => $filelist)
- {
- if ($status == 'no_update' || !sizeof($filelist) || $status == 'status' || $status == 'status_deleted')
- {
- continue;
- }
-
-/* $template->assign_block_vars('files', array(
- 'S_STATUS' => true,
- 'STATUS' => $status,
- 'L_STATUS' => $user->lang['STATUS_' . strtoupper($status)],
- 'TITLE' => $user->lang['FILES_' . strtoupper($status)],
- 'EXPLAIN' => $user->lang['FILES_' . strtoupper($status) . '_EXPLAIN'],
- )
- );*/
-
- foreach ($filelist as $file_struct)
- {
- $s_binary = (!empty($this->update_info['binary']) && in_array($file_struct['filename'], $this->update_info['binary'])) ? true : false;
-
- $filename = htmlspecialchars($file_struct['filename']);
- if (strrpos($filename, '/') !== false)
- {
- $dir_part = substr($filename, 0, strrpos($filename, '/') + 1);
- $file_part = substr($filename, strrpos($filename, '/') + 1);
- }
- else
- {
- $dir_part = '';
- $file_part = $filename;
- }
-
- $diff_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check&amp;action=diff&amp;status=$status&amp;file=" . urlencode($file_struct['filename']));
-
- if (isset($file_struct['as_expected']) && $file_struct['as_expected'])
- {
- $new_expected_files[$file_struct['filename']] = $expected_files[$file_struct['filename']];
- }
- else
- {
- $template->assign_block_vars($status, array(
- 'STATUS' => $status,
-
- 'FILENAME' => $filename,
- 'DIR_PART' => $dir_part,
- 'FILE_PART' => $file_part,
- 'NUM_CONFLICTS' => (isset($file_struct['conflicts'])) ? $file_struct['conflicts'] : 0,
-
- 'S_CUSTOM' => ($file_struct['custom']) ? true : false,
- 'S_BINARY' => $s_binary,
- 'CUSTOM_ORIGINAL' => ($file_struct['custom']) ? $file_struct['original'] : '',
-
- 'U_SHOW_DIFF' => $diff_url,
- 'L_SHOW_DIFF' => ($status != 'up_to_date') ? $user->lang['SHOW_DIFF_' . strtoupper($status)] : '',
-
- 'U_VIEW_MOD_FILE' => $diff_url . '&amp;op=' . MERGE_MOD_FILE,
- 'U_VIEW_NEW_FILE' => $diff_url . '&amp;op=' . MERGE_NEW_FILE,
- 'U_VIEW_NO_MERGE_MOD' => $diff_url . '&amp;op=' . MERGE_NO_MERGE_MOD,
- 'U_VIEW_NO_MERGE_NEW' => $diff_url . '&amp;op=' . MERGE_NO_MERGE_NEW,
- ));
- }
- }
- }
-
- $cache->put('_expected_files', $new_expected_files);
-
- $all_up_to_date = true;
- foreach ($update_list as $status => $filelist)
- {
- if ($status != 'up_to_date' && $status != 'custom' && $status != 'status' && $status != 'status_deleted' && sizeof($filelist))
- {
- $all_up_to_date = false;
- break;
- }
- }
-
- $template->assign_vars(array(
- 'S_FILE_CHECK' => true,
- 'S_ALL_UP_TO_DATE' => $all_up_to_date,
- 'S_VERSION_UP_TO_DATE' => $up_to_date,
- 'S_UP_TO_DATE' => $up_to_date,
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"),
- 'U_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
- 'U_DB_UPDATE_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_db"),
- ));
-
- // Since some people try to update to RC releases, but phpBB.com tells them the last version is the version they currently run
- // we are faced with the updater thinking the database schema is up-to-date; which it is, but should be updated none-the-less
- // We now try to cope with this by triggering the update process
- if (version_compare(str_replace('rc', 'RC', strtolower($this->current_version)), str_replace('rc', 'RC', strtolower($this->update_info['version']['to'])), '<'))
- {
- $template->assign_vars(array(
- 'S_UP_TO_DATE' => false,
- ));
- }
-
- if ($all_up_to_date)
- {
- global $phpbb_container;
- $phpbb_log = $phpbb_container->get('log');
-
- // Add database update to log
- $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_UPDATE_PHPBB', time(), array($this->current_version, $this->update_to_version));
-
- $db->sql_return_on_error(true);
- $db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'version_update_from'");
- $db->sql_return_on_error(false);
-
- $cache->purge();
- }
-
- break;
-
- case 'update_files':
-
- $this->page_title = 'STAGE_UPDATE_FILES';
-
- $s_hidden_fields = '';
- $params = array();
- $conflicts = request_var('conflict', array('' => 0));
- $modified = request_var('modified', array('' => 0));
-
- foreach ($conflicts as $filename => $merge_option)
- {
- $s_hidden_fields .= '<input type="hidden" name="conflict[' . htmlspecialchars($filename) . ']" value="' . $merge_option . '" />';
- $params[] = 'conflict[' . urlencode($filename) . ']=' . urlencode($merge_option);
- }
-
- foreach ($modified as $filename => $merge_option)
- {
- if (!$merge_option)
- {
- continue;
- }
- $s_hidden_fields .= '<input type="hidden" name="modified[' . htmlspecialchars($filename) . ']" value="' . $merge_option . '" />';
- $params[] = 'modified[' . urlencode($filename) . ']=' . urlencode($merge_option);
- }
-
- $no_update = request_var('no_update', array(0 => ''));
-
- foreach ($no_update as $index => $filename)
- {
- $s_hidden_fields .= '<input type="hidden" name="no_update[]" value="' . htmlspecialchars($filename) . '" />';
- $params[] = 'no_update[]=' . urlencode($filename);
- }
-
- // Before the user is choosing his preferred method, let's create the content list...
- $update_list = $cache->get('_update_list');
-
- if ($update_list === false)
- {
- trigger_error($user->lang['NO_UPDATE_INFO'], E_USER_ERROR);
- }
-
- // Check if the conflicts data is valid
- if (sizeof($conflicts))
- {
- $conflict_filenames = array();
- foreach ($update_list['conflict'] as $files)
- {
- $conflict_filenames[] = $files['filename'];
- }
-
- $new_conflicts = array();
- foreach ($conflicts as $filename => $diff_method)
- {
- if (in_array($filename, $conflict_filenames))
- {
- $new_conflicts[$filename] = $diff_method;
- }
- }
-
- $conflicts = $new_conflicts;
- }
-
- // Build list for modifications
- if (sizeof($modified))
- {
- $modified_filenames = array();
- foreach ($update_list['modified'] as $files)
- {
- $modified_filenames[] = $files['filename'];
- }
-
- $new_modified = array();
- foreach ($modified as $filename => $diff_method)
- {
- if (in_array($filename, $modified_filenames))
- {
- $new_modified[$filename] = $diff_method;
- }
- }
-
- $modified = $new_modified;
- }
-
- // Check number of conflicting files, they need to be equal. For modified files the number can differ
- if (sizeof($update_list['conflict']) != sizeof($conflicts))
- {
- trigger_error($user->lang['MERGE_SELECT_ERROR'], E_USER_ERROR);
- }
-
- // Before we do anything, let us diff the files and store the raw file information "somewhere"
- $get_files = false;
- $file_list = $cache->get('_diff_files');
- $expected_files = $cache->get('_expected_files');
-
- if ($file_list === false || $file_list['status'] != -1)
- {
- $get_files = true;
- }
-
- if ($get_files)
- {
- if ($file_list === false)
- {
- $file_list = array(
- 'status' => 0,
- );
- }
-
- if (!isset($expected_files) || $expected_files === false)
- {
- $expected_files = array();
- }
-
- $processed = 0;
- foreach ($update_list as $status => $files)
- {
- if (!is_array($files))
- {
- continue;
- }
-
- foreach ($files as $file_struct)
- {
- // Skip this file if the user selected to not update it
- if (in_array($file_struct['filename'], $no_update))
- {
- $expected_files[$file_struct['filename']] = false;
- continue;
- }
-
- // Already handled... then skip of course...
- if (isset($file_list[$file_struct['filename']]))
- {
- continue;
- }
-
- // Refresh if we reach 5 diffs...
- if ($processed >= 5)
- {
- $cache->put('_diff_files', $file_list);
-
- if ($request->variable('download', false))
- {
- $params[] = 'download=1';
- }
-
- $redirect_url = append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files&amp;" . implode('&amp;', $params));
- meta_refresh(3, $redirect_url);
-
- $template->assign_vars(array(
- 'S_IN_PROGRESS' => true,
- 'L_IN_PROGRESS' => $user->lang['MERGING_FILES'],
- 'L_IN_PROGRESS_EXPLAIN' => $user->lang['MERGING_FILES_EXPLAIN'],
- ));
-
- return;
- }
-
- if (file_exists($phpbb_root_path . $file_struct['filename']))
- {
- $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
- if (isset($expected_files[$file_struct['filename']]) && md5($contents) == $expected_files[$file_struct['filename']])
- {
- continue;
- }
- }
-
- $original_filename = ($file_struct['custom']) ? $file_struct['original'] : $file_struct['filename'];
-
- switch ($status)
- {
- case 'modified':
-
- $option = (isset($modified[$file_struct['filename']])) ? $modified[$file_struct['filename']] : 0;
-
- switch ($option)
- {
- case MERGE_NO_MERGE_NEW:
- $contents = file_get_contents($this->new_location . $original_filename);
- break;
-
- case MERGE_NO_MERGE_MOD:
- $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
- break;
-
- default:
- $diff = $this->return_diff($this->old_location . $original_filename, $phpbb_root_path . $file_struct['filename'], $this->new_location . $original_filename);
-
- $contents = implode("\n", $diff->merged_output());
- unset($diff);
- break;
- }
-
- $expected_files[$file_struct['filename']] = md5($contents);
- $file_list[$file_struct['filename']] = '_file_' . md5($file_struct['filename']);
- $cache->put($file_list[$file_struct['filename']], base64_encode($contents));
-
- $file_list['status']++;
- $processed++;
-
- break;
-
- case 'conflict':
-
- $option = $conflicts[$file_struct['filename']];
- $contents = '';
-
- switch ($option)
- {
- case MERGE_NO_MERGE_NEW:
- $contents = file_get_contents($this->new_location . $original_filename);
- break;
-
- case MERGE_NO_MERGE_MOD:
- $contents = file_get_contents($phpbb_root_path . $file_struct['filename']);
- break;
-
- default:
-
- $diff = $this->return_diff($this->old_location . $original_filename, $phpbb_root_path . $file_struct['filename'], $this->new_location . $original_filename);
-
- if ($option == MERGE_NEW_FILE)
- {
- $contents = implode("\n", $diff->merged_new_output());
- }
- else if ($option == MERGE_MOD_FILE)
- {
- $contents = implode("\n", $diff->merged_orig_output());
- }
- else
- {
- unset($diff);
- break 2;
- }
-
- unset($diff);
- break;
- }
-
- $expected_files[$file_struct['filename']] = md5($contents);
- $file_list[$file_struct['filename']] = '_file_' . md5($file_struct['filename']);
- $cache->put($file_list[$file_struct['filename']], base64_encode($contents));
-
- $file_list['status']++;
- $processed++;
-
- break;
- }
- }
- }
- $cache->put('_expected_files', $expected_files);
- }
-
- $file_list['status'] = -1;
- $cache->put('_diff_files', $file_list);
-
- if ($request->variable('download', false))
- {
- $this->include_file('includes/functions_compress.' . $phpEx);
-
- $use_method = request_var('use_method', '');
- $methods = array('.tar');
-
- $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
- foreach ($available_methods as $type => $module)
- {
- if (!@extension_loaded($module))
- {
- continue;
- }
-
- $methods[] = $type;
- }
-
- // Let the user decide in which format he wants to have the pack
- if (!$use_method)
- {
- $this->page_title = 'SELECT_DOWNLOAD_FORMAT';
-
- $radio_buttons = '';
- foreach ($methods as $method)
- {
- $radio_buttons .= '<label><input type="radio"' . ((!$radio_buttons) ? ' id="use_method"' : '') . ' class="radio" value="' . $method . '" name="use_method" /> ' . $method . '</label>';
- }
-
- $template->assign_vars(array(
- 'S_DOWNLOAD_FILES' => true,
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
- 'RADIO_BUTTONS' => $radio_buttons,
- 'S_HIDDEN_FIELDS' => $s_hidden_fields)
- );
-
- // To ease the update process create a file location map
- $update_list = $cache->get('_update_list');
- $script_path = ($config['force_server_vars']) ? (($config['script_path'] == '/') ? '/' : $config['script_path'] . '/') : $user->page['root_script_path'];
-
- foreach ($update_list as $status => $files)
- {
- if ($status == 'up_to_date' || $status == 'no_update' || $status == 'status' || $status == 'status_deleted')
- {
- continue;
- }
-
- foreach ($files as $file_struct)
- {
- if (in_array($file_struct['filename'], $no_update))
- {
- continue;
- }
-
- $template->assign_block_vars('location', array(
- 'SOURCE' => htmlspecialchars($file_struct['filename']),
- 'DESTINATION' => $script_path . htmlspecialchars($file_struct['filename']),
- ));
- }
- }
- return;
- }
-
- if (!in_array($use_method, $methods))
- {
- $use_method = '.tar';
- }
-
- $update_mode = 'download';
- }
- else
- {
- $this->include_file('includes/functions_transfer.' . $phpEx);
-
- // Choose FTP, if not available use fsock...
- $method = basename(request_var('method', ''));
- $submit = (isset($_POST['submit'])) ? true : false;
- $test_ftp_connection = request_var('test_connection', '');
-
- if (!$method || !class_exists($method))
- {
- $method = 'ftp';
- $methods = transfer::methods();
-
- if (!in_array('ftp', $methods))
- {
- $method = $methods[0];
- }
- }
-
- $test_connection = false;
- if ($test_ftp_connection || $submit)
- {
- $transfer = new $method(
- request_var('host', ''),
- request_var('username', ''),
- htmlspecialchars_decode($request->untrimmed_variable('password', '')),
- request_var('root_path', ''),
- request_var('port', ''),
- request_var('timeout', '')
- );
- $test_connection = $transfer->open_session();
-
- // Make sure that the directory is correct by checking for the existence of common.php
- if ($test_connection === true)
- {
- // Check for common.php file
- if (!$transfer->file_exists($phpbb_root_path, 'common.' . $phpEx))
- {
- $test_connection = 'ERR_WRONG_PATH_TO_PHPBB';
- }
- }
-
- $transfer->close_session();
-
- // Make sure the login details are correct before continuing
- if ($submit && $test_connection !== true)
- {
- $submit = false;
- $test_ftp_connection = true;
- }
- }
-
- $s_hidden_fields .= build_hidden_fields(array('method' => $method));
-
- if (!$submit)
- {
- $this->page_title = 'SELECT_FTP_SETTINGS';
-
- if (!class_exists($method))
- {
- trigger_error('Method does not exist.', E_USER_ERROR);
- }
-
- $requested_data = call_user_func(array($method, 'data'));
- foreach ($requested_data as $data => $default)
- {
- $template->assign_block_vars('data', array(
- 'DATA' => $data,
- 'NAME' => $user->lang[strtoupper($method . '_' . $data)],
- 'EXPLAIN' => $user->lang[strtoupper($method . '_' . $data) . '_EXPLAIN'],
- 'DEFAULT' => $request->variable($data, (string) $default),
- ));
- }
-
- $template->assign_vars(array(
- 'S_CONNECTION_SUCCESS' => ($test_ftp_connection && $test_connection === true) ? true : false,
- 'S_CONNECTION_FAILED' => ($test_ftp_connection && $test_connection !== true) ? true : false,
- 'ERROR_MSG' => ($test_ftp_connection && $test_connection !== true) ? $user->lang[$test_connection] : '',
-
- 'S_FTP_UPLOAD' => true,
- 'UPLOAD_METHOD' => $method,
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files"),
- 'U_DOWNLOAD_METHOD' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=update_files&amp;download=1"),
- 'S_HIDDEN_FIELDS' => $s_hidden_fields,
- ));
-
- return;
- }
-
- $update_mode = 'upload';
- }
-
- // Now update the installation or download the archive...
- $download_filename = 'update_' . $this->update_info['version']['from'] . '_to_' . $this->update_info['version']['to'];
- $archive_filename = $download_filename . '_' . time() . '_' . unique_id();
-
- // Now init the connection
- if ($update_mode == 'download')
- {
- if (function_exists('phpbb_is_writable') && !phpbb_is_writable($phpbb_root_path . 'store/'))
- {
- trigger_error(sprintf('The directory “%s†is not writable.', $phpbb_root_path . 'store/'), E_USER_ERROR);
- }
-
- if ($use_method == '.zip')
- {
- $compress = new compress_zip('w', $phpbb_root_path . 'store/' . $archive_filename . $use_method);
- }
- else
- {
- $compress = new compress_tar('w', $phpbb_root_path . 'store/' . $archive_filename . $use_method, $use_method);
- }
- }
- else
- {
- $transfer = new $method(
- request_var('host', ''),
- request_var('username', ''),
- htmlspecialchars_decode($request->untrimmed_variable('password', '')),
- request_var('root_path', ''),
- request_var('port', ''),
- request_var('timeout', '')
- );
- $transfer->open_session();
- }
-
- // Ok, go through the update list and do the operations based on their status
- foreach ($update_list as $status => $files)
- {
- if (!is_array($files))
- {
- continue;
- }
-
- foreach ($files as $file_struct)
- {
- // Skip this file if the user selected to not update it
- if (in_array($file_struct['filename'], $no_update))
- {
- continue;
- }
-
- $original_filename = ($file_struct['custom']) ? $file_struct['original'] : $file_struct['filename'];
-
- switch ($status)
- {
- case 'new':
- case 'new_conflict':
- case 'not_modified':
-
- if ($update_mode == 'download')
- {
- $compress->add_custom_file($this->new_location . $original_filename, $file_struct['filename']);
- }
- else
- {
- if ($status != 'new')
- {
- $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
- }
-
- // New directory too?
- $dirname = dirname($file_struct['filename']);
-
- if ($dirname && !file_exists($phpbb_root_path . $dirname))
- {
- $transfer->make_dir($dirname);
- }
-
- $transfer->copy_file($this->new_location . $original_filename, $file_struct['filename']);
- }
- break;
-
- case 'modified':
-
- $contents = base64_decode($cache->get($file_list[$file_struct['filename']]));
-
- if ($update_mode == 'download')
- {
- $compress->add_data($contents, $file_struct['filename']);
- }
- else
- {
- // @todo add option to specify if a backup file should be created?
- $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
- $transfer->write_file($file_struct['filename'], $contents);
- }
- break;
-
- case 'conflict':
-
- $contents = base64_decode($cache->get($file_list[$file_struct['filename']]));
-
- if ($update_mode == 'download')
- {
- $compress->add_data($contents, $file_struct['filename']);
- }
- else
- {
- $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
- $transfer->write_file($file_struct['filename'], $contents);
- }
- break;
-
- case 'deleted':
-
- if ($update_mode != 'download')
- {
- $transfer->rename($file_struct['filename'], $file_struct['filename'] . '.bak');
- }
- break;
- }
- }
- }
-
- if ($update_mode == 'download')
- {
- $compress->close();
-
- $compress->download($archive_filename, $download_filename);
- @unlink($phpbb_root_path . 'store/' . $archive_filename . $use_method);
-
- exit;
- }
- else
- {
- $transfer->close_session();
-
- $template->assign_vars(array(
- 'S_UPLOAD_SUCCESS' => true,
- 'U_ACTION' => append_sid($this->p_master->module_url, "language=$language&amp;mode=$mode&amp;sub=file_check"))
- );
- return;
- }
-
- break;
-
- }
- }
-
- /**
- * Show file diff
- */
- function show_diff(&$update_list)
- {
- global $phpbb_root_path, $template, $user, $phpbb_adm_relative_path;
-
- $this->tpl_name = 'install_update_diff';
-
- $this->page_title = 'VIEWING_FILE_DIFF';
-
- $status = request_var('status', '');
- $file = request_var('file', '');
- $diff_mode = request_var('diff_mode', 'inline');
-
- // First of all make sure the file is within our file update list with the correct status
- $found_entry = array();
- foreach ($update_list[$status] as $index => $file_struct)
- {
- if ($file_struct['filename'] === $file)
- {
- $found_entry = $update_list[$status][$index];
- }
- }
-
- if (empty($found_entry))
- {
- trigger_error($user->lang['FILE_DIFF_NOT_ALLOWED'], E_USER_ERROR);
- }
-
- // If the status is 'up_to_date' then we do not need to show a diff
- if ($status == 'up_to_date')
- {
- trigger_error($user->lang['FILE_ALREADY_UP_TO_DATE'], E_USER_ERROR);
- }
-
- $original_file = ($found_entry['custom']) ? $found_entry['original'] : $file;
-
- // Get the correct diff
- switch ($status)
- {
- case 'conflict':
- $option = request_var('op', 0);
-
- switch ($option)
- {
- case MERGE_NO_MERGE_NEW:
- case MERGE_NO_MERGE_MOD:
-
- $diff = $this->return_diff(array(), ($option == MERGE_NO_MERGE_NEW) ? $this->new_location . $original_file : $phpbb_root_path . $file);
-
- $template->assign_var('S_DIFF_NEW_FILE', true);
- $diff_mode = 'inline';
- $this->page_title = 'VIEWING_FILE_CONTENTS';
-
- break;
-
- // Merge differences and use new phpBB code for conflicted blocks
- case MERGE_NEW_FILE:
- case MERGE_MOD_FILE:
-
- $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $file, $this->new_location . $original_file);
-
- $template->assign_vars(array(
- 'S_DIFF_CONFLICT_FILE' => true,
- 'NUM_CONFLICTS' => $diff->get_num_conflicts())
- );
-
- $diff = $this->return_diff($phpbb_root_path . $file, ($option == MERGE_NEW_FILE) ? $diff->merged_new_output() : $diff->merged_orig_output());
- break;
-
- // Download conflict file
- default:
-
- $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $file, $this->new_location . $original_file);
-
- header('Pragma: no-cache');
- header("Content-Type: application/octetstream; name=\"$file\"");
- header("Content-disposition: attachment; filename=$file");
-
- @set_time_limit(0);
-
- echo implode("\n", $diff->get_conflicts_content());
-
- flush();
- exit;
-
- break;
- }
-
- break;
-
- case 'modified':
- $option = request_var('op', 0);
-
- switch ($option)
- {
- case MERGE_NO_MERGE_NEW:
- case MERGE_NO_MERGE_MOD:
-
- $diff = $this->return_diff(array(), ($option == MERGE_NO_MERGE_NEW) ? $this->new_location . $original_file : $phpbb_root_path . $file);
-
- $template->assign_var('S_DIFF_NEW_FILE', true);
- $diff_mode = 'inline';
- $this->page_title = 'VIEWING_FILE_CONTENTS';
-
- break;
-
- default:
- $diff = $this->return_diff($this->old_location . $original_file, $phpbb_root_path . $original_file, $this->new_location . $file);
- $diff = $this->return_diff($phpbb_root_path . $file, $diff->merged_output());
- break;
- }
- break;
-
- case 'not_modified':
- case 'new_conflict':
- $diff = $this->return_diff($phpbb_root_path . $file, $this->new_location . $original_file);
- break;
-
- case 'new':
-
- $diff = $this->return_diff(array(), $this->new_location . $original_file);
-
- $template->assign_var('S_DIFF_NEW_FILE', true);
- $diff_mode = 'inline';
- $this->page_title = 'VIEWING_FILE_CONTENTS';
-
- break;
-
- case 'deleted':
-
- $diff = $this->return_diff(array(), $phpbb_root_path . $original_file);
-
- $template->assign_var('S_DIFF_NEW_FILE', true);
- $diff_mode = 'inline';
- $this->page_title = 'VIEWING_FILE_CONTENTS';
-
- break;
- }
-
- $diff_mode_options = '';
- foreach (array('side_by_side', 'inline', 'unified', 'raw') as $option)
- {
- $diff_mode_options .= '<option value="' . $option . '"' . (($diff_mode == $option) ? ' selected="selected"' : '') . '>' . $user->lang['DIFF_' . strtoupper($option)] . '</option>';
- }
-
- // Now the correct renderer
- $render_class = 'diff_renderer_' . $diff_mode;
-
- if (!class_exists($render_class))
- {
- trigger_error('Chosen diff mode is not supported', E_USER_ERROR);
- }
-
- $renderer = new $render_class();
-
- $template->assign_vars(array(
- 'DIFF_CONTENT' => $renderer->get_diff_content($diff),
- 'DIFF_MODE' => $diff_mode,
- 'S_DIFF_MODE_OPTIONS' => $diff_mode_options,
- 'S_SHOW_DIFF' => true,
- ));
-
- unset($diff, $renderer);
- }
-
- /**
- * Collect all file status infos we need for the update by diffing all files
- */
- function get_update_structure(&$update_list, $expected_files)
- {
- global $phpbb_root_path, $phpEx, $user;
-
- if ($update_list === false)
- {
- $update_list = array(
- 'up_to_date' => array(),
- 'new' => array(),
- 'not_modified' => array(),
- 'modified' => array(),
- 'new_conflict' => array(),
- 'conflict' => array(),
- 'no_update' => array(),
- 'deleted' => array(),
- 'status' => 0,
- 'status_deleted'=> 0,
- );
- }
-
- /* if (!empty($this->update_info['custom']))
- {
- foreach ($this->update_info['custom'] as $original_file => $file_ary)
- {
- foreach ($file_ary as $index => $file)
- {
- $this->make_update_diff($update_list, $original_file, $file, true);
- }
- }
- } */
-
- // Get a list of those files which are completely new by checking with file_exists...
- $num_bytes_processed = 0;
-
- foreach ($this->update_info['files'] as $index => $file)
- {
- if (is_int($update_list['status']) && $index < $update_list['status'])
- {
- continue;
- }
-
- if ($num_bytes_processed >= 500 * 1024)
- {
- return;
- }
-
- if (!file_exists($phpbb_root_path . $file))
- {
- // Make sure the update files are consistent by checking if the file is in new_files...
- if (!file_exists($this->new_location . $file))
- {
- trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR);
- }
-
- // If the file exists within the old directory the file got removed and we will write it back
- // not a biggie, but we might want to state this circumstance separately later.
- // if (file_exists($this->old_location . $file))
- // {
- // $update_list['removed'][] = $file;
- // }
-
- /* Only include a new file as new if the underlying path exist
- // The path normally do not exist if the original style or language has been removed
- if (file_exists($phpbb_root_path . dirname($file)))
- {
- $this->get_custom_info($update_list['new'], $file);
- $update_list['new'][] = array('filename' => $file, 'custom' => false);
- }
- else
- {
- // Do not include style-related or language-related content
- if (strpos($file, 'styles/') !== 0 && strpos($file, 'language/') !== 0)
- {
- $update_list['no_update'][] = $file;
- }
- }*/
-
- if (!phpbb_ignore_new_file_on_update($phpbb_root_path, $file))
- {
- $this->get_custom_info($update_list['new'], $file);
- $update_list['new'][] = array('filename' => $file, 'custom' => false);
- }
-
- // unset($this->update_info['files'][$index]);
- }
- else
- {
- // not modified?
- $this->make_update_diff($update_list, $file, $file, $expected_files);
- }
-
- $num_bytes_processed += (file_exists($this->new_location . $file)) ? filesize($this->new_location . $file) : 100 * 1024;
- $update_list['status']++;
- }
-
- foreach ($this->update_info['deleted'] as $index => $file)
- {
- if (is_int($update_list['status_deleted']) && $index < $update_list['status_deleted'])
- {
- continue;
- }
-
- if ($num_bytes_processed >= 500 * 1024)
- {
- return;
- }
-
- if (file_exists($phpbb_root_path . $file))
- {
- $update_list['deleted'][] = array('filename' => $file, 'custom' => false, 'as_expected' => false);
- $num_bytes_processed += filesize($phpbb_root_path . $file);
- }
-
- $update_list['status_deleted']++;
- $update_list['status']++;
- }
-
- $update_list['status_deleted'] = -1;
- $update_list['status'] = -1;
-
-/* if (!sizeof($this->update_info['files']))
- {
- return $update_list;
- }
-
- // Now diff the remaining files to get information about their status (not modified/modified/up-to-date)
-
- // not modified?
- foreach ($this->update_info['files'] as $index => $file)
- {
- $this->make_update_diff($update_list, $file, $file);
- }
-
- // Now to the styles...
- if (empty($this->update_info['custom']))
- {
- return $update_list;
- }
-
- foreach ($this->update_info['custom'] as $original_file => $file_ary)
- {
- foreach ($file_ary as $index => $file)
- {
- $this->make_update_diff($update_list, $original_file, $file, true);
- }
- }
-
- return $update_list;*/
- }
-
- /**
- * Compare files for storage in update_list
- */
- function make_update_diff(&$update_list, $original_file, $file, $expected_files, $custom = false)
- {
- global $phpbb_root_path, $user;
-
- $update_ary = array('filename' => $file, 'custom' => $custom, 'as_expected' => false);
-
- if ($custom)
- {
- $update_ary['original'] = $original_file;
- }
-
- if (file_exists($phpbb_root_path . $file))
- {
- $content = file_get_contents($phpbb_root_path . $file);
-
- if (isset($expected_files[$file]) && // the user already selected what to do with this file
- ($expected_files[$file] === false || // the user wanted this file to stay the same, so just assume it's alright
- $expected_files[$file] === md5($content)))
- {
- // the file contains what it was supposed to contain after the merge
- $update_ary['as_expected'] = true;
- $update_ary['was_ignored'] = ($expected_files[$file] === false);
- $update_list['up_to_date'][] = $update_ary;
-
- return;
- }
- }
-
- // we only want to know if the files are successfully merged and newlines could result in errors (duplicate addition of lines and such things)
- // Therefore we check for empty diffs with two methods, preserving newlines and not preserving them (which mostly works best, therefore the first option)
-
- // On a successfull update the new location file exists but the old one does not exist.
- // Check for this circumstance, the new file need to be up-to-date with the current file then...
- if (!file_exists($this->old_location . $original_file) && file_exists($this->new_location . $original_file) && file_exists($phpbb_root_path . $file))
- {
- $tmp = array(
- 'file1' => file_get_contents($this->new_location . $original_file),
- 'file2' => $content,
- );
-
- // We need to diff the contents here to make sure the file is really the one we expect
- $diff = new diff($tmp['file1'], $tmp['file2'], false);
- $empty = $diff->is_empty();
-
- unset($tmp, $diff);
-
- // if there are no differences we have an up-to-date file...
- if ($empty)
- {
- $update_list['up_to_date'][] = $update_ary;
- return;
- }
-
- // If no other status matches we have another file in the way...
- $update_list['new_conflict'][] = $update_ary;
- return;
- }
-
- // Old file removed?
- if (file_exists($this->old_location . $original_file) && !file_exists($this->new_location . $original_file))
- {
- return;
- }
-
- // Check for existance, else abort immediately
- if (!file_exists($this->old_location . $original_file) || !file_exists($this->new_location . $original_file))
- {
- trigger_error($user->lang['INCOMPLETE_UPDATE_FILES'], E_USER_ERROR);
- }
-
- $preserve_cr_ary = array(false, true);
-
- foreach ($preserve_cr_ary as $preserve_cr)
- {
- $tmp = array(
- 'file1' => file_get_contents($this->old_location . $original_file),
- 'file2' => $content,
- );
-
- // We need to diff the contents here to make sure the file is really the one we expect
- $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
- $empty_1 = $diff->is_empty();
-
- unset($tmp, $diff);
-
- $tmp = array(
- 'file1' => file_get_contents($this->new_location . $original_file),
- 'file2' => $content,
- );
-
- $diff = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
- $empty_2 = $diff->is_empty();
-
- unset($tmp, $diff);
-
- // If the file is not modified we are finished here...
- if ($empty_1)
- {
- // Further check if it is already up to date - it could happen that non-modified files
- // slip through
- if ($empty_2)
- {
- $update_list['up_to_date'][] = $update_ary;
- return;
- }
-
- $update_list['not_modified'][] = $update_ary;
- return;
- }
-
- // If the file had been modified then we need to check if it is already up to date
-
- // if there are no differences we have an up-to-date file...
- if ($empty_2)
- {
- $update_list['up_to_date'][] = $update_ary;
- return;
- }
- }
-
- $conflicts = false;
-
- foreach ($preserve_cr_ary as $preserve_cr)
- {
- // if the file is modified we try to make sure a merge succeed
- $tmp = array(
- 'orig' => file_get_contents($this->old_location . $original_file),
- 'final1' => file_get_contents($phpbb_root_path . $file),
- 'final2' => file_get_contents($this->new_location . $original_file),
- );
-
- $diff = new diff3($tmp['orig'], $tmp['final1'], $tmp['final2'], $preserve_cr);
- unset($tmp);
-
- if (!$diff->get_num_conflicts())
- {
- $tmp = array(
- 'file1' => file_get_contents($phpbb_root_path . $file),
- 'file2' => implode("\n", $diff->merged_output()),
- );
-
- // now compare the merged output with the original file to see if the modified file is up to date
- $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
- $empty = $diff2->is_empty();
-
- unset($diff, $diff2);
-
- if ($empty)
- {
- $update_list['up_to_date'][] = $update_ary;
- return;
- }
-
- // If we preserve cr tag it as modified because the conflict would not show in this mode anyway
- if ($preserve_cr)
- {
- $update_list['modified'][] = $update_ary;
- return;
- }
- }
- else
- {
- // There is one special case... users having merged with a conflicting file... we need to check this
- $tmp = array(
- 'file1' => file_get_contents($phpbb_root_path . $file),
- 'file2' => implode("\n", $diff->merged_new_output()),
- );
-
- $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
- $empty = $diff2->is_empty();
-
- if (!$empty)
- {
- unset($tmp, $diff2);
-
- // We check if the user merged with his output
- $tmp = array(
- 'file1' => file_get_contents($phpbb_root_path . $file),
- 'file2' => implode("\n", $diff->merged_orig_output()),
- );
-
- $diff2 = new diff($tmp['file1'], $tmp['file2'], $preserve_cr);
- $empty = $diff2->is_empty();
- }
-
- if (!$empty)
- {
- $conflicts = $diff->get_num_conflicts();
- }
-
- unset($diff, $diff2);
-
- if ($empty)
- {
- // A conflict got resolved...
- $update_list['up_to_date'][] = $update_ary;
- return;
- }
- }
- }
-
- if ($conflicts !== false)
- {
- $update_ary['conflicts'] = $conflicts;
- $update_list['conflict'][] = $update_ary;
- return;
- }
-
- // If no other status matches we have a modified file...
- $update_list['modified'][] = $update_ary;
- }
-
- /**
- * Update update_list with custom new files
- */
- function get_custom_info(&$update_list, $file)
- {
- if (empty($this->update_info['custom']))
- {
- return;
- }
-
- if (isset($this->update_info['custom'][$file]))
- {
- foreach ($this->update_info['custom'][$file] as $_file)
- {
- $update_list[] = array('filename' => $_file, 'custom' => true, 'original' => $file);
- }
- }
- }
-
- /**
- * Get remote file
- */
- function get_file($mode)
- {
- global $user, $db;
-
- $errstr = '';
- $errno = 0;
-
- switch ($mode)
- {
- case 'update_info':
- global $phpbb_root_path, $phpEx;
-
- $update_info = array();
- include($phpbb_root_path . 'install/update/index.' . $phpEx);
-
- $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
- $errstr = ($info === false) ? $user->lang['WRONG_INFO_FILE_FORMAT'] : '';
-
- if ($info !== false)
- {
- // We assume that all file extensions have been renamed to .$phpEx,
- // if someone is using a non .php file extension for php files.
- // However, in $update_info['files'] we use hardcoded .php.
- // We therefore replace .php with .$phpEx.
- $info['files'] = preg_replace('/\.php$/i', ".$phpEx", $info['files']);
-
- // Adjust the update info file to hold some specific style-related information
- $info['custom'] = array();
-/*
- // Get custom installed styles...
- $sql = 'SELECT style_name, style_path
- FROM ' . STYLES_TABLE . "
- WHERE LOWER(style_name) NOT IN ('subsilver2', 'prosilver')";
- $result = $db->sql_query($sql);
-
- $templates = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $templates[] = $row;
- }
- $db->sql_freeresult($result);
-
- if (sizeof($templates))
- {
- foreach ($info['files'] as $filename)
- {
- // Template update?
- if (strpos(strtolower($filename), 'styles/prosilver/template/') === 0)
- {
- foreach ($templates as $row)
- {
- $info['custom'][$filename][] = str_replace('/prosilver/', '/' . $row['style_path'] . '/', $filename);
- }
- }
- }
- }
-*/
- }
- break;
-
- default:
- trigger_error('Mode for getting remote file not specified', E_USER_ERROR);
- break;
- }
-
- if ($info === false)
- {
- trigger_error($errstr, E_USER_ERROR);
- }
-
- return $info;
- }
-
- /**
- * Function for including files...
- */
- function include_file($filename)
- {
- global $phpbb_root_path, $phpEx;
-
- if (!empty($this->update_info['files']) && in_array($filename, $this->update_info['files']))
- {
- include_once($this->new_location . $filename);
- }
- else
- {
- include_once($phpbb_root_path . $filename);
- }
- }
-
- /**
- * Wrapper for returning a diff object
- */
- function return_diff()
- {
- $args = func_get_args();
- $three_way_diff = (func_num_args() > 2) ? true : false;
-
- $file1 = array_shift($args);
- $file2 = array_shift($args);
-
- $tmp['file1'] = (!empty($file1) && is_string($file1)) ? file_get_contents($file1) : $file1;
- $tmp['file2'] = (!empty($file2) && is_string($file2)) ? file_get_contents($file2) : $file2;
-
- if ($three_way_diff)
- {
- $file3 = array_shift($args);
- $tmp['file3'] = (!empty($file3) && is_string($file3)) ? file_get_contents($file3) : $file3;
-
- $diff = new diff3($tmp['file1'], $tmp['file2'], $tmp['file3']);
- }
- else
- {
- $diff = new diff($tmp['file1'], $tmp['file2']);
- }
-
- unset($tmp);
-
- return $diff;
- }
-}
diff --git a/phpBB/install/phpbbcli.php b/phpBB/install/phpbbcli.php
new file mode 100755
index 0000000000..86ec87b38f
--- /dev/null
+++ b/phpBB/install/phpbbcli.php
@@ -0,0 +1,52 @@
+#!/usr/bin/env php
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use Symfony\Component\Console\Input\ArgvInput;
+
+if (php_sapi_name() !== 'cli')
+{
+ echo 'This program must be run from the command line.' . PHP_EOL;
+ exit(1);
+}
+
+define('IN_PHPBB', true);
+define('IN_INSTALL', true);
+define('PHPBB_ENVIRONMENT', 'production');
+define('PHPBB_VERSION', '3.2.9');
+$phpbb_root_path = __DIR__ . '/../';
+$phpEx = substr(strrchr(__FILE__, '.'), 1);
+
+//
+// Let's do the common.php logic
+//
+$startup_new_path = $phpbb_root_path . 'install/update/update/new/install/startup.' . $phpEx;
+$startup_path = (file_exists($startup_new_path)) ? $startup_new_path : $phpbb_root_path . 'install/startup.' . $phpEx;
+require($startup_path);
+
+$input = new ArgvInput();
+
+// Enable superglobals for cli support
+$phpbb_installer_container->get('request')->enable_super_globals();
+
+/** @var \phpbb\filesystem\filesystem $phpbb_filesystem */
+$phpbb_filesystem = $phpbb_installer_container->get('filesystem');
+
+/** @var \phpbb\language\language $language */
+$language = $phpbb_installer_container->get('language');
+$language->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting', 'cli'));
+
+$application = new \phpbb\console\application('phpBB Installer', PHPBB_VERSION, $language);
+$application->setDispatcher($phpbb_installer_container->get('dispatcher'));
+$application->register_container_commands($phpbb_installer_container->get('console.installer.command_collection'));
+$application->run($input);
diff --git a/phpBB/install/phpinfo.php b/phpBB/install/phpinfo.php
index 1512b00563..28c3b9ff04 100644
--- a/phpBB/install/phpinfo.php
+++ b/phpBB/install/phpinfo.php
@@ -1,14 +1,14 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
phpinfo();
diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql
index 1a62ea6f84..45685051f2 100644
--- a/phpBB/install/schemas/schema_data.sql
+++ b/phpBB/install/schemas/schema_data.sql
@@ -41,6 +41,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_sig_pm', '1'
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_sig_smilies', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_smilies', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_topic_notify', '1');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('allowed_schemes_links', 'http,https,ftp');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('assets_version', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('attachment_quota', '52428800');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('auth_bbcode_pm', '1');
@@ -102,11 +103,13 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('extension_force_un
INSERT INTO phpbb_config (config_name, config_value) VALUES ('delete_time', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_check_mx', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_enable', '1');
-INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_function_name', 'mail');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_force_sender', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_max_chunk_size', '50');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_package_size', '20');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_accurate_pm_button', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_confirm', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_mod_rewrite', '0');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_board_notifications', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_pm_icons', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_post_confirm', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_enable', '1');
@@ -140,11 +143,12 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_postgres_
INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_sphinx_indexer_mem_limit', '512');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('fulltext_sphinx_stopwords', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('gzip_compress', '0');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('help_send_statistics', '1');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('help_send_statistics_time', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('hot_threshold', '25');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('icons_path', 'images/icons');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_create_thumbnail', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_display_inlined', '1');
-INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_imagick', '');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_link_height', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_link_width', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('img_max_height', '0');
@@ -181,7 +185,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_cpf_viewprofi
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_cpf_viewtopic', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_db_lastread', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_db_track', '1');
-INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jumpbox', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_moderators', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_notifications', '1');
@@ -193,6 +197,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_search', '1')
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_tplcompile', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_unreads_search', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_user_activity', '1');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_user_activity_limit', '5000');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_attachments', '3');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_attachments_pm', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_autologin_time', '0');
@@ -237,6 +242,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('queue_interval', '
INSERT INTO phpbb_config (config_name, config_value) VALUES ('ranks_path', 'images/ranks');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('read_notification_expire_days', '30');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('read_notification_gc', '86400');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('remote_upload_verify', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('require_activation', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('referer_validation', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('script_path', '');
@@ -263,9 +269,9 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('smilies_per_page',
INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_auth_method', 'PLAIN');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_delivery', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_host', '');
-INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_password', '');
+INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('smtp_password', '', 1);
INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_port', '25');
-INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_username', '');
+INSERT INTO phpbb_config (config_name, config_value, is_dynamic) VALUES ('smtp_username', '', 1);
INSERT INTO phpbb_config (config_name, config_value) VALUES ('teampage_memberships', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('teampage_forums', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('topics_per_page', '25');
@@ -273,7 +279,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('tpl_allow_php', '0
INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_icons_path', 'images/upload_icons');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_path', 'files');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('use_system_cron', '0');
-INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.1.11');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.2.9');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_expire_days', '90');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_gc', '14400');
@@ -309,6 +315,7 @@ INSERT INTO phpbb_config_text (config_name, config_value) VALUES ('contact_admin
# -- Forum related auth options
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_announce', 1);
+INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_announce_global', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_attach', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_bbcode', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_bump', 1);
@@ -321,6 +328,7 @@ INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_icons', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_ignoreflood', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_img', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_list', 1);
+INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_list_topics', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_noapprove', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_poll', 1);
INSERT INTO phpbb_acl_options (auth_option, is_local) VALUES ('f_post', 1);
@@ -413,6 +421,7 @@ INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chgname', 1);
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chgpasswd', 1);
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_chgprofileinfo', 1);
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_download', 1);
+INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_emoji', 1);
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_hideonline', 1);
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_ignoreflood', 1);
INSERT INTO phpbb_acl_options (auth_option, is_global) VALUES ('u_masspm', 1);
@@ -470,7 +479,7 @@ INSERT INTO phpbb_acl_roles (role_name, role_description, role_type, role_order)
INSERT INTO phpbb_acl_roles (role_name, role_description, role_type, role_order) VALUES ('ROLE_FORUM_NEW_MEMBER', 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER', 'f_', 10);
# -- phpbb_styles
-INSERT INTO phpbb_styles (style_name, style_copyright, style_active, style_path, bbcode_bitfield, style_parent_id, style_parent_tree) VALUES ('prosilver', '&copy; phpBB Limited', 1, 'prosilver', 'kNg=', 0, '');
+INSERT INTO phpbb_styles (style_name, style_copyright, style_active, style_path, bbcode_bitfield, style_parent_id, style_parent_tree) VALUES ('prosilver', '&copy; phpBB Limited', 1, 'prosilver', '//g=', 0, '');
# -- Forums
INSERT INTO phpbb_forums (forum_name, forum_desc, left_id, right_id, parent_id, forum_type, forum_posts_approved, forum_posts_unapproved, forum_posts_softdeleted, forum_topics_approved, forum_topics_unapproved, forum_topics_softdeleted, forum_last_post_id, forum_last_poster_id, forum_last_poster_name, forum_last_poster_colour, forum_last_post_time, forum_link, forum_password, forum_image, forum_rules, forum_rules_link, forum_rules_uid, forum_desc_uid, prune_days, prune_viewed, forum_parents) VALUES ('{L_FORUMS_FIRST_CATEGORY}', '', 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 'Admin', 'AA0000', 972086460, '', '', '', '', '', '', '', 0, 0, '');
@@ -552,29 +561,29 @@ INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 14, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%';
# Standard Access (f_)
-INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 15, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_flash', 'f_ignoreflood', 'f_poll', 'f_sticky', 'f_user_lock');
+INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 15, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_announce_global', 'f_flash', 'f_ignoreflood', 'f_poll', 'f_sticky', 'f_user_lock');
# No Access (f_)
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 16, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option = 'f_';
# Read Only Access (f_)
-INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 17, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_', 'f_download', 'f_list', 'f_read', 'f_search', 'f_subscribe', 'f_print');
+INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 17, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_', 'f_download', 'f_list', 'f_list_topics', 'f_read', 'f_search', 'f_subscribe', 'f_print');
# Limited Access (f_)
-INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 18, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_attach', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_poll', 'f_sticky', 'f_user_lock', 'f_votechg');
+INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 18, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_announce_global', 'f_attach', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_poll', 'f_sticky', 'f_user_lock', 'f_votechg');
# Bot Access (f_)
-INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 19, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_', 'f_download', 'f_list', 'f_read', 'f_print');
+INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 19, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_', 'f_download', 'f_list', 'f_list_topics', 'f_read', 'f_print');
# On Moderation Queue (f_)
-INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 20, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_poll', 'f_sticky', 'f_user_lock', 'f_votechg', 'f_noapprove');
+INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 20, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_announce_global', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_poll', 'f_sticky', 'f_user_lock', 'f_votechg', 'f_noapprove');
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 20, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_noapprove');
# Standard Access + Polls (f_)
-INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 21, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_flash', 'f_ignoreflood', 'f_sticky', 'f_user_lock');
+INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 21, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_announce_global', 'f_flash', 'f_ignoreflood', 'f_sticky', 'f_user_lock');
# Limited Access + Polls (f_)
-INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 22, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_attach', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_sticky', 'f_user_lock', 'f_votechg');
+INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 22, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_announce_global', 'f_attach', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_sticky', 'f_user_lock', 'f_votechg');
# New Member (u_)
INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 23, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group', 'u_chgprofileinfo');
@@ -716,10 +725,7 @@ INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mo
INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('ARCHIVES', 0, 1, 1, '', 0, '');
INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('PLAIN_TEXT', 0, 0, 1, '', 0, '');
INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('DOCUMENTS', 0, 0, 1, '', 0, '');
-INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('REAL_MEDIA', 3, 0, 1, '', 0, '');
-INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('WINDOWS_MEDIA', 2, 0, 1, '', 0, '');
INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('FLASH_FILES', 5, 0, 1, '', 0, '');
-INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('QUICKTIME_MEDIA', 6, 0, 1, '', 0, '');
INSERT INTO phpbb_extension_groups (group_name, cat_id, allow_group, download_mode, upload_icon, max_filesize, allowed_forums) VALUES ('DOWNLOADABLE_FILES', 0, 0, 1, '', 0, '');
# -- extensions
@@ -776,27 +782,13 @@ INSERT INTO phpbb_extensions (group_id, extension) VALUES (4, 'ods');
INSERT INTO phpbb_extensions (group_id, extension) VALUES (4, 'odt');
INSERT INTO phpbb_extensions (group_id, extension) VALUES (4, 'rtf');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (5, 'rm');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (5, 'ram');
+INSERT INTO phpbb_extensions (group_id, extension) VALUES (5, 'swf');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (6, 'wma');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (6, 'wmv');
-
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (7, 'swf');
-
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (8, 'mov');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (8, 'm4v');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (8, 'm4a');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (8, 'mp4');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (8, '3gp');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (8, '3g2');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (8, 'qt');
-
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'mpeg');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'mpg');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'mp3');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'ogg');
-INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'ogm');
+INSERT INTO phpbb_extensions (group_id, extension) VALUES (6, 'mp3');
+INSERT INTO phpbb_extensions (group_id, extension) VALUES (6, 'mpeg');
+INSERT INTO phpbb_extensions (group_id, extension) VALUES (6, 'mpg');
+INSERT INTO phpbb_extensions (group_id, extension) VALUES (6, 'ogg');
+INSERT INTO phpbb_extensions (group_id, extension) VALUES (6, 'ogm');
# Add default profile fields
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_location', 'profilefields.type.string', 'phpbb_location', '20', '2', '100', '', '', '.*', 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, '', '');
@@ -805,7 +797,6 @@ INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_len
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_occupation', 'profilefields.type.text', 'phpbb_occupation', '3|30', '2', '500', '', '', '.*', 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, '', '');
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_aol', 'profilefields.type.string', 'phpbb_aol', '40', '5', '255', '', '', '.*', 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 5, 1, '', '');
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_icq', 'profilefields.type.string', 'phpbb_icq', '20', '3', '15', '', '', '[0-9]+', 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 6, 1, 'SEND_ICQ_MESSAGE', 'https://www.icq.com/people/%s/');
-INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_wlm', 'profilefields.type.string', 'phpbb_wlm', '40', '5', '255', '', '', '.*', 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 7, 1, '', '');
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_yahoo', 'profilefields.type.string', 'phpbb_yahoo', '40', '5', '255', '', '', '.*', 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 8, 1, 'SEND_YIM_MESSAGE', 'ymsgr:sendim?%s');
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_facebook', 'profilefields.type.string', 'phpbb_facebook', '20', '5', '50', '', '', '[\w.]+', 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 9, 1, 'VIEW_FACEBOOK_PROFILE', 'http://facebook.com/%s/');
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_twitter', 'profilefields.type.string', 'phpbb_twitter', '20', '1', '15', '', '', '[\w_]+', 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 10, 1, 'VIEW_TWITTER_PROFILE', 'http://twitter.com/%s');
@@ -814,9 +805,9 @@ INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_len
INSERT INTO phpbb_profile_fields (field_name, field_type, field_ident, field_length, field_minlen, field_maxlen, field_novalue, field_default_value, field_validation, field_required, field_show_novalue, field_show_on_reg, field_show_on_pm, field_show_on_vt, field_show_on_ml, field_show_profile, field_hide, field_no_view, field_active, field_order, field_is_contact, field_contact_desc, field_contact_url) VALUES ('phpbb_googleplus', 'profilefields.type.googleplus', 'phpbb_googleplus', '20', '3', '255', '', '', '[\w]+', 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 13, 1, 'VIEW_GOOGLEPLUS_PROFILE', 'http://plus.google.com/%s');
# User Notification Options (for first user)
-INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('notification.type.post', 0, 2, '');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('notification.type.post', 0, 2, 'notification.method.board');
INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('notification.type.post', 0, 2, 'notification.method.email');
-INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('notification.type.topic', 0, 2, '');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('notification.type.topic', 0, 2, 'notification.method.board');
INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('notification.type.topic', 0, 2, 'notification.method.email');
# POSTGRES COMMIT #
diff --git a/phpBB/install/startup.php b/phpBB/install/startup.php
new file mode 100644
index 0000000000..9a4f9bfe39
--- /dev/null
+++ b/phpBB/install/startup.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/** @ignore */
+if (!defined('IN_PHPBB') || !defined('IN_INSTALL'))
+{
+ exit;
+}
+
+function phpbb_require_updated($path, $phpbb_root_path, $optional = false)
+{
+ $new_path = $phpbb_root_path . 'install/update/new/' . $path;
+ $old_path = $phpbb_root_path . $path;
+
+ if (file_exists($new_path))
+ {
+ require($new_path);
+ }
+ else if (!$optional || file_exists($old_path))
+ {
+ require($old_path);
+ }
+}
+
+function phpbb_include_updated($path, $phpbb_root_path, $optional = false)
+{
+ $new_path = $phpbb_root_path . 'install/update/new/' . $path;
+ $old_path = $phpbb_root_path . $path;
+
+ if (file_exists($new_path))
+ {
+ include($new_path);
+ }
+ else if (!$optional || file_exists($old_path))
+ {
+ include($old_path);
+ }
+}
+
+function installer_msg_handler($errno, $msg_text, $errfile, $errline)
+{
+ global $phpbb_installer_container;
+
+ if (error_reporting() == 0)
+ {
+ return true;
+ }
+
+ switch ($errno)
+ {
+ case E_NOTICE:
+ case E_WARNING:
+ case E_USER_WARNING:
+ case E_USER_NOTICE:
+ $msg = '[phpBB Debug] "' . $msg_text . '" in file ' . $errfile . ' on line ' . $errline;
+
+ if (!empty($phpbb_installer_container))
+ {
+ try
+ {
+ /** @var \phpbb\install\helper\iohandler\iohandler_interface $iohandler */
+ $iohandler = $phpbb_installer_container->get('installer.helper.iohandler');
+ $iohandler->add_warning_message($msg);
+ }
+ catch (\phpbb\install\helper\iohandler\exception\iohandler_not_implemented_exception $e)
+ {
+ print($msg);
+ }
+ }
+ else
+ {
+ print($msg);
+ }
+
+ return;
+ break;
+ case E_USER_ERROR:
+ $msg = '<b>General Error:</b><br />' . $msg_text . '<br /> in file ' . $errfile . ' on line ' . $errline;
+
+ $backtrace = get_backtrace();
+ if ($backtrace)
+ {
+ $msg .= '<br /><br />BACKTRACE<br />' . $backtrace;
+ }
+
+ throw new \phpbb\exception\runtime_exception($msg);
+ break;
+ case E_DEPRECATED:
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+phpbb_require_updated('includes/startup.' . $phpEx, $phpbb_root_path);
+phpbb_require_updated('phpbb/class_loader.' . $phpEx, $phpbb_root_path);
+
+$phpbb_class_loader_new = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}install/update/new/phpbb/", $phpEx);
+$phpbb_class_loader_new->register();
+$phpbb_class_loader = new \phpbb\class_loader('phpbb\\', "{$phpbb_root_path}phpbb/", $phpEx);
+$phpbb_class_loader->register();
+$phpbb_class_loader = new \phpbb\class_loader('phpbb\\convert\\', "{$phpbb_root_path}install/convert/", $phpEx);
+$phpbb_class_loader->register();
+$phpbb_class_loader_ext = new \phpbb\class_loader('\\', "{$phpbb_root_path}ext/", $phpEx);
+$phpbb_class_loader_ext->register();
+
+// In case $phpbb_adm_relative_path is not set (in case of an update), use the default.
+$phpbb_adm_relative_path = (isset($phpbb_adm_relative_path)) ? $phpbb_adm_relative_path : 'adm/';
+$phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : $phpbb_root_path . $phpbb_adm_relative_path;
+
+// Include files
+phpbb_require_updated('includes/functions.' . $phpEx, $phpbb_root_path);
+phpbb_require_updated('includes/functions_content.' . $phpEx, $phpbb_root_path);
+phpbb_include_updated('includes/functions_compatibility.' . $phpEx, $phpbb_root_path);
+phpbb_require_updated('includes/functions_user.' . $phpEx, $phpbb_root_path);
+phpbb_require_updated('includes/utf/utf_tools.' . $phpEx, $phpbb_root_path);
+
+// Set PHP error handler to ours
+set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'installer_msg_handler');
+
+$phpbb_installer_container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+$phpbb_installer_container_builder
+ ->with_environment('installer')
+ ->without_extensions();
+
+$other_config_path = $phpbb_root_path . 'install/update/new/config';
+$config_path = (file_exists($other_config_path . '/installer/config.yml')) ? $other_config_path : $phpbb_root_path . 'config';
+
+$phpbb_installer_container = $phpbb_installer_container_builder
+ ->with_config_path($config_path)
+ ->with_custom_parameters(array('cache.driver.class' => 'phpbb\cache\driver\file'))
+ ->get_container();
diff --git a/phpBB/language/en/acp/attachments.php b/phpBB/language/en/acp/attachments.php
index 750f2f8d61..86430f46bd 100644
--- a/phpBB/language/en/acp/attachments.php
+++ b/phpBB/language/en/acp/attachments.php
@@ -70,9 +70,6 @@ $lang = array_merge($lang, array(
'CAT_FLASH_FILES' => 'Flash files',
'CAT_IMAGES' => 'Images',
- 'CAT_QUICKTIME_FILES' => 'Quicktime media files',
- 'CAT_RM_FILES' => 'RealMedia media files',
- 'CAT_WM_FILES' => 'Windows Media media files',
'CHECK_CONTENT' => 'Check attachment files',
'CHECK_CONTENT_EXPLAIN' => 'Some browsers can be tricked to assume an incorrect mimetype for uploaded files. This option ensures that such files likely to cause this are rejected.',
'CREATE_GROUP' => 'Create new group',
@@ -105,9 +102,6 @@ $lang = array_merge($lang, array(
'EXT_GROUP_FLASH_FILES' => 'Flash Files',
'EXT_GROUP_IMAGES' => 'Images',
'EXT_GROUP_PLAIN_TEXT' => 'Plain Text',
- 'EXT_GROUP_QUICKTIME_MEDIA' => 'Quicktime Media',
- 'EXT_GROUP_REAL_MEDIA' => 'Real Media',
- 'EXT_GROUP_WINDOWS_MEDIA' => 'Windows Media',
'FILES_GONE' => 'Some of the attachments you selected for deletion do not exist. They may have been already deleted. Attachments that did exist were deleted.',
'FILES_STATS_WRONG' => 'Your file statistics are likely inaccurate and need to be resynchronised. Actual values: number of attachments = %1$d, total size of attachments = %2$s.<br />Click %3$shere%4$s to resynchronise them.',
@@ -117,8 +111,6 @@ $lang = array_merge($lang, array(
'IMAGE_LINK_SIZE' => 'Image link dimensions',
'IMAGE_LINK_SIZE_EXPLAIN' => 'Display image attachment as an inline text link if image is larger than this. To disable this behaviour, set the values to 0px by 0px.',
- 'IMAGICK_PATH' => 'ImageMagick path',
- 'IMAGICK_PATH_EXPLAIN' => 'Full path to the imagemagick convert application, e.g. <samp>/usr/bin/</samp>.',
'MAX_ATTACHMENTS' => 'Maximum number of attachments per post',
'MAX_ATTACHMENTS_PM' => 'Maximum number of attachments per private message',
@@ -141,7 +133,6 @@ $lang = array_merge($lang, array(
'NO_EXT_GROUP_SPECIFIED' => 'No extension group specified.',
'NO_FILE_CAT' => 'None',
'NO_IMAGE' => 'No image',
- 'NO_THUMBNAIL_SUPPORT' => 'Thumbnail support has been disabled. For proper functionality either the GD extension need to be available or imagemagick being installed. Both were not found.',
'NO_UPLOAD_DIR' => 'The upload directory you specified does not exist.',
'NO_WRITE_UPLOAD' => 'The upload directory you specified cannot be written to. Please alter the permissions to allow the webserver to write to it.',
@@ -153,7 +144,6 @@ $lang = array_merge($lang, array(
'REMOVE_DISALLOWED_IPS' => 'Remove or un-exclude <em>disallowed</em> IPs/hostnames',
'RESYNC_FILES_STATS_CONFIRM' => 'Are you sure you wish to resynchronise file statistics?',
- 'SEARCH_IMAGICK' => 'Search for ImageMagick',
'SECURE_ALLOW_DENY' => 'Allow/Deny list',
'SECURE_ALLOW_DENY_EXPLAIN' => 'Change the default behaviour when secure downloads are enabled of the Allow/Deny list to that of a <strong>whitelist</strong> (Allow) or a <strong>blacklist</strong> (Deny).',
'SECURE_DOWNLOADS' => 'Enable secure downloads',
diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php
index 8bb5327028..e237446dde 100644
--- a/phpBB/language/en/acp/board.php
+++ b/phpBB/language/en/acp/board.php
@@ -44,7 +44,7 @@ $lang = array_merge($lang, array(
'BOARD_STYLE' => 'Board style',
'CUSTOM_DATEFORMAT' => 'Custom…',
'DEFAULT_DATE_FORMAT' => 'Date format',
- 'DEFAULT_DATE_FORMAT_EXPLAIN' => 'The date format is the same as the PHP <code>date</code> function.',
+ 'DEFAULT_DATE_FORMAT_EXPLAIN' => 'The date format is the same as the PHP <code><a href="https://secure.php.net/manual/function.date.php">date()</a></code> function.',
'DEFAULT_LANGUAGE' => 'Default language',
'DEFAULT_STYLE' => 'Default style',
'DEFAULT_STYLE_EXPLAIN' => 'The default style for new users.',
@@ -99,6 +99,7 @@ $lang = array_merge($lang, array(
'ALLOW_TOPIC_NOTIFY' => 'Allow subscribing to topics',
'BOARD_PM' => 'Private messaging',
'BOARD_PM_EXPLAIN' => 'Enable private messaging for all users.',
+ 'ALLOW_BOARD_NOTIFICATIONS' => 'Allow board notifications',
));
// Avatar Settings
@@ -106,18 +107,18 @@ $lang = array_merge($lang, array(
'ACP_AVATAR_SETTINGS_EXPLAIN' => 'Avatars are generally small, unique images a user can associate with themselves. Depending on the style they are usually displayed below the username when viewing topics. Here you can determine how users can define their avatars. Please note that in order to upload avatars you need to have created the directory you name below and ensure it can be written to by the web server. Please also note that file size limits are only imposed on uploaded avatars, they do not apply to remotely linked images.',
'ALLOW_AVATARS' => 'Enable avatars',
- 'ALLOW_AVATARS_EXPLAIN' => 'Allow general usage of avatars;<br />If you disable avatars in general or avatars of a certain mode, the disabled avatars will no longer be shown on the board, but users will still be able to download their own avatars in the User Control Panel.',
+ 'ALLOW_AVATARS_EXPLAIN' => 'Allow general usage of avatars;<br>If you disable avatars in general or avatars of a certain mode, the disabled avatars will no longer be shown on the board, but users will still be able to download their own avatars in the User Control Panel.',
'ALLOW_GRAVATAR' => 'Enable gravatar avatars',
'ALLOW_LOCAL' => 'Enable gallery avatars',
'ALLOW_REMOTE' => 'Enable remote avatars',
- 'ALLOW_REMOTE_EXPLAIN' => 'Avatars linked to from another website.',
+ 'ALLOW_REMOTE_EXPLAIN' => 'Avatars linked to from another website.<br><em><strong class="error">Warning:</strong> Enabling this feature might allow users to check for the existence of files and services that are only accessible on the local network.</em>',
'ALLOW_REMOTE_UPLOAD' => 'Enable remote avatar uploading',
- 'ALLOW_REMOTE_UPLOAD_EXPLAIN' => 'Allow uploading of avatars from another website.',
+ 'ALLOW_REMOTE_UPLOAD_EXPLAIN' => 'Allow uploading of avatars from another website.<br><em><strong class="error">Warning:</strong> Enabling this feature might allow users to check for the existence of files and services that are only accessible on the local network.</em>',
'ALLOW_UPLOAD' => 'Enable avatar uploading',
'AVATAR_GALLERY_PATH' => 'Avatar gallery path',
- 'AVATAR_GALLERY_PATH_EXPLAIN' => 'Path under your phpBB root directory for pre-loaded images, e.g. <samp>images/avatars/gallery</samp>.<br />Double dots like <samp>../</samp> will be stripped from the path for security reasons.',
+ 'AVATAR_GALLERY_PATH_EXPLAIN' => 'Path under your phpBB root directory for pre-loaded images, e.g. <samp>images/avatars/gallery</samp>.<br>Double dots like <samp>../</samp> will be stripped from the path for security reasons.',
'AVATAR_STORAGE_PATH' => 'Avatar storage path',
- 'AVATAR_STORAGE_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. <samp>images/avatars/upload</samp>.<br />Avatar uploading <strong>will not be available</strong> if this path is not writable.<br />Double dots like <samp>../</samp> will be stripped from the path for security reasons.',
+ 'AVATAR_STORAGE_PATH_EXPLAIN' => 'Path under your phpBB root directory, e.g. <samp>images/avatars/upload</samp>.<br>Avatar uploading <strong>will not be available</strong> if this path is not writable.<br>Double dots like <samp>../</samp> will be stripped from the path for security reasons.',
'MAX_AVATAR_SIZE' => 'Maximum avatar dimensions',
'MAX_AVATAR_SIZE_EXPLAIN' => 'Width x Height in pixels.',
'MAX_FILESIZE' => 'Maximum avatar file size',
@@ -160,6 +161,8 @@ $lang = array_merge($lang, array(
'ACP_POST_SETTINGS_EXPLAIN' => 'Here you can set all default settings for posting.',
'ALLOW_POST_LINKS' => 'Allow links in posts/private messages',
'ALLOW_POST_LINKS_EXPLAIN' => 'If disallowed the <code>[URL]</code> BBCode tag and automatic/magic URLs are disabled.',
+ 'ALLOWED_SCHEMES_LINKS' => 'Allowed schemes in links',
+ 'ALLOWED_SCHEMES_LINKS_EXPLAIN' => 'Users can only post schemeless URLs or one of the comma-separated list of allowed schemes.',
'ALLOW_POST_FLASH' => 'Allow use of <code>[FLASH]</code> BBCode tag in posts',
'ALLOW_POST_FLASH_EXPLAIN' => 'If disallowed the <code>[FLASH]</code> BBCode tag is disabled in posts. Otherwise the permission system controls which users can use the <code>[FLASH]</code> BBCode tag.',
@@ -271,7 +274,7 @@ $lang = array_merge($lang, array(
'ACP_FEED_SETTINGS_OTHER' => 'Other feeds and settings',
'ACP_FEED_ENABLE' => 'Enable feeds',
- 'ACP_FEED_ENABLE_EXPLAIN' => 'Turns on or off ATOM feeds for the entire board.<br />Disabling this switches off all feeds, no matter how the options below are set.',
+ 'ACP_FEED_ENABLE_EXPLAIN' => 'Turns on or off ATOM feeds for the entire board.<br>Disabling this switches off all feeds, no matter how the options below are set.',
'ACP_FEED_LIMIT' => 'Number of items',
'ACP_FEED_LIMIT_EXPLAIN' => 'The maximum number of feed items to display.',
@@ -287,7 +290,7 @@ $lang = array_merge($lang, array(
'ACP_FEED_TOPICS_ACTIVE' => 'Enable active topics feed',
'ACP_FEED_TOPICS_ACTIVE_EXPLAIN' => 'Enables the “Active Topics†feed, which displays the last active topics including the last post.',
'ACP_FEED_NEWS' => 'News feed',
- 'ACP_FEED_NEWS_EXPLAIN' => 'Pull the first post from these forums. Select no forums to disable news feed.<br />Select multiple forums by holding <samp>CTRL</samp> and clicking.',
+ 'ACP_FEED_NEWS_EXPLAIN' => 'Pull the first post from these forums. Select no forums to disable news feed.<br>Select multiple forums by holding <samp>CTRL</samp> and clicking.',
'ACP_FEED_OVERALL_FORUMS' => 'Enable forums feed',
'ACP_FEED_OVERALL_FORUMS_EXPLAIN' => 'Enables the “All forums†feed, which displays a list of forums.',
@@ -295,9 +298,9 @@ $lang = array_merge($lang, array(
'ACP_FEED_HTTP_AUTH' => 'Allow HTTP Authentication',
'ACP_FEED_HTTP_AUTH_EXPLAIN' => 'Enables HTTP authentication, which allows users to receive content that is hidden to guest users by adding the <samp>auth=http</samp> parameter to the feed URL. Please note that some PHP setups require additional changes to the .htaccess file. Instructions can be found in that file.',
'ACP_FEED_ITEM_STATISTICS' => 'Item statistics',
- 'ACP_FEED_ITEM_STATISTICS_EXPLAIN' => 'Display individual statistics underneath feed items<br />(e.g. posted by, date and time, replies, views)',
+ 'ACP_FEED_ITEM_STATISTICS_EXPLAIN' => 'Display individual statistics underneath feed items<br>(e.g. posted by, date and time, replies, views)',
'ACP_FEED_EXCLUDE_ID' => 'Exclude these forums',
- 'ACP_FEED_EXCLUDE_ID_EXPLAIN' => 'Content from these will be <strong>not included in feeds</strong>. Select no forum to pull data from all forums.<br />Select/Deselect multiple forums by holding <samp>CTRL</samp> and clicking.',
+ 'ACP_FEED_EXCLUDE_ID_EXPLAIN' => 'Content from these will be <strong>not included in feeds</strong>. Select no forum to pull data from all forums.<br>Select/Deselect multiple forums by holding <samp>CTRL</samp> and clicking.',
));
// Visual Confirmation Settings
@@ -345,14 +348,16 @@ $lang = array_merge($lang, array(
// Cookie Settings
$lang = array_merge($lang, array(
- 'ACP_COOKIE_SETTINGS_EXPLAIN' => 'These details define the data used to send cookies to your users browsers. In most cases the default values for the cookie settings should be sufficient. If you do need to change any do so with care, incorrect settings can prevent users logging in. If you have problems with users staying logging in to your board, visit the <b><a href="https://www.phpbb.com/support/go/cookie-settings/">phpBB.com Knowledge Base - Fixing incorrect cookie settings</a></b>.',
+ 'ACP_COOKIE_SETTINGS_EXPLAIN' => 'These details define the data used to send cookies to your users browsers. In most cases the default values for the cookie settings should be sufficient. If you do need to change any do so with care, incorrect settings can prevent users logging in. If you have problems with users staying logging in to your board, visit the <strong><a href="https://www.phpbb.com/support/go/cookie-settings">phpBB.com Knowledge Base - Fixing incorrect cookie settings</a></strong>.',
'COOKIE_DOMAIN' => 'Cookie domain',
- 'COOKIE_DOMAIN_EXPLAIN' => 'In most cases the cookie domain is optional. Leave it blank if you are unsure.<br /><br /> In the case where you have a board integrated with other software or have multiple domains, then to determine the cookie domain you need to do the following. If you have something like <i>example.com</i> and <i>forums.example.com</i>, or perhaps <i>forums.example.com</i> and <i>blog.example.com</i>. Remove the subdomains until you find the common domain, <i>example.com</i>. Now add a dot in front of the common domain and you would enter .example.com (note the dot at the beginning).',
+ 'COOKIE_DOMAIN_EXPLAIN' => 'In most cases the cookie domain is optional. Leave it blank if you are unsure.<br><br> In the case where you have a board integrated with other software or have multiple domains, then to determine the cookie domain you need to do the following. If you have something like <i>example.com</i> and <i>forums.example.com</i>, or perhaps <i>forums.example.com</i> and <i>blog.example.com</i>. Remove the subdomains until you find the common domain, <i>example.com</i>. Now add a dot in front of the common domain and you would enter .example.com (note the dot at the beginning).',
'COOKIE_NAME' => 'Cookie name',
'COOKIE_NAME_EXPLAIN' => 'This can be anything what you want, make it original. Whenever the cookie settings are changed the name of the cookie should be changed.',
+ 'COOKIE_NOTICE' => 'Cookie notice',
+ 'COOKIE_NOTICE_EXPLAIN' => 'If enabled a cookie notice will be displayed to users when visiting your board. This might be required by law depending on the content of your board and enabled extensions.',
'COOKIE_PATH' => 'Cookie path',
- 'COOKIE_PATH_EXPLAIN' => 'Note that this is always a slash, it does not matter what your board URL is.',
+ 'COOKIE_PATH_EXPLAIN' => 'This will usually be the same as your script path or simply a slash to make the cookie accessible across the site domain.',
'COOKIE_SECURE' => 'Cookie secure',
'COOKIE_SECURE_EXPLAIN' => 'If your server is running via SSL set this to enabled else leave as disabled. Having this enabled and not running via SSL will result in server errors during redirects.',
'ONLINE_LENGTH' => 'View online time span',
@@ -366,7 +371,7 @@ $lang = array_merge($lang, array(
'ACP_CONTACT_SETTINGS_EXPLAIN' => 'Here you can enable and disable the contact page and also add a text that is displayed on the page.',
'CONTACT_US_ENABLE' => 'Enable contact page',
- 'CONTACT_US_ENABLE_EXPLAIN' => 'This page allows users to send emails to board administrators',
+ 'CONTACT_US_ENABLE_EXPLAIN' => 'This page allows users to send emails to board administrators. Please note that board-wide emails option must be enabled as well. You can find this option in General &gt; Client Communication &gt; Email settings.',
'CONTACT_US_INFO' => 'Contact information',
'CONTACT_US_INFO_EXPLAIN' => 'The message is displayed on the contact page',
@@ -393,10 +398,14 @@ $lang = array_merge($lang, array(
'LOAD_CPF_VIEWTOPIC' => 'Display custom profile fields on topic pages',
'LOAD_USER_ACTIVITY' => 'Show user’s activity',
'LOAD_USER_ACTIVITY_EXPLAIN' => 'Displays active topic/forum in user profiles and user control panel. It is recommended to disable this on boards with more than one million posts.',
+ 'LOAD_USER_ACTIVITY_LIMIT' => 'User’s activity post limit',
+ 'LOAD_USER_ACTIVITY_LIMIT_EXPLAIN' => 'The active topic/forum won’t be shown for users having more than this number of posts. Set to 0 to disable the limit.',
'READ_NOTIFICATION_EXPIRE_DAYS' => 'Read Notification Expiration',
'READ_NOTIFICATION_EXPIRE_DAYS_EXPLAIN' => 'Number of days that will elapse before a read notification will automatically be deleted. Set this value to 0 to make notifications permanent.',
'RECOMPILE_STYLES' => 'Recompile stale style components',
'RECOMPILE_STYLES_EXPLAIN' => 'Check for updated style components on filesystem and recompile.',
+ 'YES_ACCURATE_PM_BUTTON' => 'Enable permission specific PM button in topic pages',
+ 'YES_ACCURATE_PM_BUTTON_EXPLAIN' => 'If this setting is enabled, only post profiles of users who are permitted to read private messages will have a private message button.',
'YES_ANON_READ_MARKING' => 'Enable topic marking for guests',
'YES_ANON_READ_MARKING_EXPLAIN' => 'Stores read/unread status information for guests. If disabled, posts are always marked read for guests.',
'YES_BIRTHDAYS' => 'Enable birthday listing',
@@ -423,7 +432,7 @@ $lang = array_merge($lang, array(
'AUTH_METHOD' => 'Select an authentication method',
'AUTH_PROVIDER_OAUTH_ERROR_ELEMENT_MISSING' => 'Both the key and secret of each enabled OAuth service provider must be provided. Only one was provided for an OAuth service provider.',
- 'AUTH_PROVIDER_OAUTH_EXPLAIN' => 'Each OAuth provider requires a unique secret and key in order to authenticate with the external server. These should be supplied by the OAuth service when you register your website with them and should be entered exactly as provided to you.<br />Any service that does not have both a key and a secret entered here will not be available for use by the forum users. Also note, that user can still register and login using the DB authentication plug-in.',
+ 'AUTH_PROVIDER_OAUTH_EXPLAIN' => 'Each OAuth provider requires a unique secret and key in order to authenticate with the external server. These should be supplied by the OAuth service when you register your website with them and should be entered exactly as provided to you.<br>Any service that does not have both a key and a secret entered here will not be available for use by the forum users. Also note, that user can still register and login using the DB authentication plug-in.',
'AUTH_PROVIDER_OAUTH_KEY' => 'Key',
'AUTH_PROVIDER_OAUTH_TITLE' => 'OAuth',
'AUTH_PROVIDER_OAUTH_SECRET' => 'Secret',
@@ -439,7 +448,7 @@ $lang = array_merge($lang, array(
'LDAP_NO_EMAIL' => 'The specified email attribute does not exist.',
'LDAP_NO_IDENTITY' => 'Could not find a login identity for %s.',
'LDAP_PASSWORD' => 'LDAP password',
- 'LDAP_PASSWORD_EXPLAIN' => 'Leave blank to use anonymous binding, otherwise fill in the password for the above user. Required for Active Directory Servers.<br /><em><strong>Warning:</strong> This password will be stored as plain text in the database, visible to everybody who can access your database or who can view this configuration page.</em>',
+ 'LDAP_PASSWORD_EXPLAIN' => 'Leave blank to use anonymous binding, otherwise fill in the password for the above user. Required for Active Directory Servers.<br><em><strong>Warning:</strong> This password will be stored as plain text in the database, visible to everybody who can access your database or who can view this configuration page.</em>',
'LDAP_PORT' => 'LDAP server port',
'LDAP_PORT_EXPLAIN' => 'Optionally you can specify a port which should be used to connect to the LDAP server instead of the default port 389.',
'LDAP_SERVER' => 'LDAP server name',
@@ -520,7 +529,7 @@ $lang = array_merge($lang, array(
'IP_LOGIN_LIMIT_TIME' => 'IP address login attempt expiration time',
'IP_LOGIN_LIMIT_TIME_EXPLAIN' => 'Login attempts expire after this period.',
'IP_LOGIN_LIMIT_USE_FORWARDED' => 'Limit login attempts by <var>X_FORWARDED_FOR</var> header',
- 'IP_LOGIN_LIMIT_USE_FORWARDED_EXPLAIN' => 'Instead of limiting login attempts by IP address they are limited by <var>X_FORWARDED_FOR</var> values. <br /><em><strong>Warning:</strong> Only enable this if you are operating a proxy server that sets <var>X_FORWARDED_FOR</var> to trustworthy values.</em>',
+ 'IP_LOGIN_LIMIT_USE_FORWARDED_EXPLAIN' => 'Instead of limiting login attempts by IP address they are limited by <var>X_FORWARDED_FOR</var> values. <br><em><strong>Warning:</strong> Only enable this if you are operating a proxy server that sets <var>X_FORWARDED_FOR</var> to trustworthy values.</em>',
'MAX_LOGIN_ATTEMPTS' => 'Maximum number of login attempts per username',
'MAX_LOGIN_ATTEMPTS_EXPLAIN' => 'The number of login attempts allowed for a single account before the anti-spambot task is triggered. Enter 0 to prevent the anti-spambot task from being triggered for distinct user accounts.',
'NO_IP_VALIDATION' => 'None',
@@ -537,14 +546,16 @@ $lang = array_merge($lang, array(
'REFERRER_VALID_EXPLAIN' => 'If enabled, the referrer of POST requests will be checked against the host/script path settings. This may cause issues with boards using several domains and or external logins.',
'TPL_ALLOW_PHP' => 'Allow php in templates',
'TPL_ALLOW_PHP_EXPLAIN' => 'If this option is enabled, <code>PHP</code> and <code>INCLUDEPHP</code> statements will be recognised and parsed in templates.',
+ 'UPLOAD_CERT_VALID' => 'Validate upload certificate',
+ 'UPLOAD_CERT_VALID_EXPLAIN' => 'If enabled, certificates of remote uploads will be validated. This requires the CA bundle to be defined by the <samp>openssl.cafile</samp> or <samp>curl.cainfo</samp> setting in your php.ini.',
));
// Email Settings
$lang = array_merge($lang, array(
'ACP_EMAIL_SETTINGS_EXPLAIN' => 'This information is used when the board sends emails to your users. Please ensure the email address you specify is valid, any bounced or undeliverable messages will likely be sent to that address. If your host does not provide a native (PHP based) email service you can instead send messages directly using SMTP. This requires the address of an appropriate server (ask your provider if necessary). If the server requires authentication (and only if it does) enter the necessary username, password and authentication method.',
- 'ADMIN_EMAIL' => 'Return email address',
- 'ADMIN_EMAIL_EXPLAIN' => 'This will be used as the return address on all emails, the technical contact email address. It will always be used as the <samp>Return-Path</samp> and <samp>Sender</samp> address in emails.',
+ 'ADMIN_EMAIL' => 'From email address',
+ 'ADMIN_EMAIL_EXPLAIN' => 'This will be used as the from address on all emails, the technical contact email address. It will always be used as the <samp>Sender</samp> address in emails.',
'BOARD_EMAIL_FORM' => 'Users send email via board',
'BOARD_EMAIL_FORM_EXPLAIN' => 'Instead of showing the users email address users are able to send emails via the board.',
'BOARD_HIDE_EMAILS' => 'Hide email addresses',
@@ -553,36 +564,41 @@ $lang = array_merge($lang, array(
'CONTACT_EMAIL_EXPLAIN' => 'This address will be used whenever a specific contact point is needed, e.g. spam, error output, etc. It will always be used as the <samp>From</samp> and <samp>Reply-To</samp> address in emails.',
'CONTACT_EMAIL_NAME' => 'Contact name',
'CONTACT_EMAIL_NAME_EXPLAIN' => 'This is the contact name that e-mail recipients will see. If you don’t want to have a contact name, leave this field empty.',
- 'EMAIL_FUNCTION_NAME' => 'Email function name',
- 'EMAIL_FUNCTION_NAME_EXPLAIN' => 'The email function used to send mails through PHP.',
+ 'EMAIL_FORCE_SENDER' => 'Force from email address',
+ 'EMAIL_FORCE_SENDER_EXPLAIN' => 'This will set the <samp>Return-Path</samp> to the from email address instead of using the local user and hostname of the server. This setting does not apply when using SMTP.<br><em><strong>Warning:</strong> Requires the user that the webserver runs as to be added as trusted user to the sendmail configuration.</em>',
'EMAIL_PACKAGE_SIZE' => 'Email package size',
'EMAIL_PACKAGE_SIZE_EXPLAIN' => 'This is the number of maximum emails sent out in one package. This setting is applied to the internal message queue; set this value to 0 if you have problems with non-delivered notification emails.',
+ 'EMAIL_MAX_CHUNK_SIZE' => 'Maximum allowed email recipients',
+ 'EMAIL_MAX_CHUNK_SIZE_EXPLAIN' => 'If necessary, set this to not exceed the maximum number of recipients that your email server will allow in one email message.',
'EMAIL_SIG' => 'Email signature',
'EMAIL_SIG_EXPLAIN' => 'This text will be attached to all emails the board sends.',
'ENABLE_EMAIL' => 'Enable board-wide emails',
'ENABLE_EMAIL_EXPLAIN' => 'If this is set to disabled no emails will be sent by the board at all. <em>Note the user and admin account activation settings require this setting to be enabled. If currently using “user†or “admin†activation in the activation settings, disabling this setting will disable registration.</em>',
+ 'SEND_TEST_EMAIL' => 'Send a test email',
+ 'SEND_TEST_EMAIL_EXPLAIN' => 'This will send a test email to the address defined in your account.',
'SMTP_ALLOW_SELF_SIGNED' => 'Allow self-signed SSL certificates',
- 'SMTP_ALLOW_SELF_SIGNED_EXPLAIN'=> 'Allow connections to SMTP server with self-signed SSL certificate.<em><strong>Warning:</strong> Allowing self-signed SSL certificates may cause security implications.</em>',
+ 'SMTP_ALLOW_SELF_SIGNED_EXPLAIN'=> 'Allow connections to SMTP server with self-signed SSL certificate. <br><em><strong>Warning:</strong> Allowing self-signed SSL certificates may cause security implications.</em>',
'SMTP_AUTH_METHOD' => 'Authentication method for SMTP',
'SMTP_AUTH_METHOD_EXPLAIN' => 'Only used if a username/password is set, ask your provider if you are unsure which method to use.',
'SMTP_CRAM_MD5' => 'CRAM-MD5',
'SMTP_DIGEST_MD5' => 'DIGEST-MD5',
'SMTP_LOGIN' => 'LOGIN',
'SMTP_PASSWORD' => 'SMTP password',
- 'SMTP_PASSWORD_EXPLAIN' => 'Only enter a password if your SMTP server requires it.<br /><em><strong>Warning:</strong> This password will be stored as plain text in the database, visible to everybody who can access your database or who can view this configuration page.</em>',
+ 'SMTP_PASSWORD_EXPLAIN' => 'Only enter a password if your SMTP server requires it.<br><em><strong>Warning:</strong> This password will be stored as plain text in the database, visible to everybody who can access your database or who can view this configuration page.</em>',
'SMTP_PLAIN' => 'PLAIN',
'SMTP_POP_BEFORE_SMTP' => 'POP-BEFORE-SMTP',
'SMTP_PORT' => 'SMTP server port',
'SMTP_PORT_EXPLAIN' => 'Only change this if you know your SMTP server is on a different port.',
'SMTP_SERVER' => 'SMTP server address',
- 'SMTP_SERVER_EXPLAIN' => 'Note that you have to provide the protocol that your server uses. If you are using SSL, this has to be "ssl://your.mailserver.com"',
+ 'SMTP_SERVER_EXPLAIN' => 'Do not provide a protocol (<samp>ssl://</samp> or <samp>tls://</samp>) unless your mail host tells you to do so.',
'SMTP_SETTINGS' => 'SMTP settings',
'SMTP_USERNAME' => 'SMTP username',
'SMTP_USERNAME_EXPLAIN' => 'Only enter a username if your SMTP server requires it.',
'SMTP_VERIFY_PEER' => 'Verify SSL certificate',
- 'SMTP_VERIFY_PEER_EXPLAIN' => 'Require verification of SSL certificate used by SMTP server.<em><strong>Warning:</strong> Connecting peers with unverified SSL certificates may cause security implications.</em>',
+ 'SMTP_VERIFY_PEER_EXPLAIN' => 'Require verification of SSL certificate used by SMTP server. <br><em><strong>Warning:</strong> Connecting peers with unverified SSL certificates may cause security implications.</em>',
'SMTP_VERIFY_PEER_NAME' => 'Verify SMTP peer name',
- 'SMTP_VERIFY_PEER_NAME_EXPLAIN' => 'Require verification of peer name for SMTP servers using SSL / TLS connections.<em><strong>Warning:</strong> Connecting to unverified peers may cause security implications.</em>',
+ 'SMTP_VERIFY_PEER_NAME_EXPLAIN' => 'Require verification of peer name for SMTP servers using SSL / TLS connections. <br><em><strong>Warning:</strong> Connecting to unverified peers may cause security implications.</em>',
+ 'TEST_EMAIL_SENT' => 'The test email has been sent.<br>If you don’t receive it, please check your emails configuration.<br><br>If you require assistance, please visit the <a href="https://www.phpbb.com/community/">phpBB support forums</a>.',
'USE_SMTP' => 'Use SMTP server for email',
'USE_SMTP_EXPLAIN' => 'Select “Yes†if you want or have to send email via a named server instead of the local mail function.',
@@ -593,7 +609,7 @@ $lang = array_merge($lang, array(
'ACP_JABBER_SETTINGS_EXPLAIN' => 'Here you can enable and control the use of Jabber for instant messaging and board notifications. Jabber is an open source protocol and therefore available for use by anyone. Some Jabber servers include gateways or transports which allow you to contact users on other networks. Not all servers offer all transports and changes in protocols can prevent transports from operating. Please be sure to enter already registered account details - phpBB will use the details you enter here as is.',
'JAB_ALLOW_SELF_SIGNED' => 'Allow self-signed SSL certificates',
- 'JAB_ALLOW_SELF_SIGNED_EXPLAIN' => 'Allow connections to Jabber server with self-signed SSL certificate.<em><strong>Warning:</strong> Allowing self-signed SSL certificates may cause security implications.</em>',
+ 'JAB_ALLOW_SELF_SIGNED_EXPLAIN' => 'Allow connections to Jabber server with self-signed SSL certificate. <br><em><strong>Warning:</strong> Allowing self-signed SSL certificates may cause security implications.</em>',
'JAB_ENABLE' => 'Enable Jabber',
'JAB_ENABLE_EXPLAIN' => 'Enables use of Jabber messaging and notifications.',
'JAB_GTALK_NOTE' => 'Please note that GTalk will not work because the <samp>dns_get_record</samp> function could not be found. This function is not available in PHP4, and is not implemented on Windows platforms. It currently does not work on BSD-based systems, including Mac OS.',
@@ -611,7 +627,7 @@ $lang = array_merge($lang, array(
'JAB_USERNAME' => 'Jabber username or JID',
'JAB_USERNAME_EXPLAIN' => 'Specify a registered username or a valid JID. The username will not be checked for validity. If you only specify a username, then your JID will be the username and the server you specified above. Else, specify a valid JID, for example user@jabber.org.',
'JAB_VERIFY_PEER' => 'Verify SSL certificate',
- 'JAB_VERIFY_PEER_EXPLAIN' => 'Require verification of SSL certificate used by Jabber server.<em><strong>Warning:</strong> Connecting peers with unverified SSL certificates may cause security implications.</em>',
+ 'JAB_VERIFY_PEER_EXPLAIN' => 'Require verification of SSL certificate used by Jabber server. <br><em><strong>Warning:</strong> Connecting peers with unverified SSL certificates may cause security implications.</em>',
'JAB_VERIFY_PEER_NAME' => 'Verify Jabber peer name',
- 'JAB_VERIFY_PEER_NAME_EXPLAIN' => 'Require verification of peer name for Jabber servers using SSL / TLS connections.<em><strong>Warning:</strong> Connecting to unverified peers may cause security implications.</em>',
+ 'JAB_VERIFY_PEER_NAME_EXPLAIN' => 'Require verification of peer name for Jabber servers using SSL / TLS connections. <br><em><strong>Warning:</strong> Connecting to unverified peers may cause security implications.</em>',
));
diff --git a/phpBB/language/en/acp/common.php b/phpBB/language/en/acp/common.php
index f5591e7b1e..1c2253542c 100644
--- a/phpBB/language/en/acp/common.php
+++ b/phpBB/language/en/acp/common.php
@@ -108,6 +108,8 @@ $lang = array_merge($lang, array(
'ACP_GROUPS_PERMISSIONS' => 'Group permissions',
'ACP_GROUPS_POSITION' => 'Manage group positions',
+ 'ACP_HELP_PHPBB' => 'Help support phpBB',
+
'ACP_ICONS' => 'Topic icons',
'ACP_ICONS_SMILIES' => 'Topic icons/smilies',
'ACP_INACTIVE_USERS' => 'Inactive users',
@@ -167,7 +169,6 @@ $lang = array_merge($lang, array(
'ACP_SEARCH_SETTINGS' => 'Search settings',
'ACP_SECURITY_SETTINGS' => 'Security settings',
- 'ACP_SEND_STATISTICS' => 'Send statistical information',
'ACP_SERVER_CONFIGURATION' => 'Server configuration',
'ACP_SERVER_SETTINGS' => 'Server settings',
'ACP_SIGNATURE_SETTINGS' => 'Signature settings',
@@ -225,12 +226,26 @@ $lang = array_merge($lang, array(
'BACK' => 'Back',
+ 'CANNOT_CHANGE_FILE_GROUP' => 'Unable to change file group',
+ 'CANNOT_CHANGE_FILE_PERMISSIONS' => 'Unable to change file permissions',
+ 'CANNOT_COPY_FILES' => 'Unable to copy files',
+ 'CANNOT_CREATE_SYMLINK' => 'Unable to create a symlink',
+ 'CANNOT_DELETE_FILES' => 'Unable to delete files from the system',
+ 'CANNOT_DUMP_FILE' => 'Unable to dump file',
+ 'CANNOT_MIRROR_DIRECTORY' => 'Unable to mirror directory',
+ 'CANNOT_RENAME_FILE' => 'Unable to rename a file from the system',
+ 'CANNOT_TOUCH_FILES' => 'Unable to determine if the file exists',
+
+ 'CONTAINER_EXCEPTION' => 'phpBB encountered an error building the container due to an installed extension. For this reason, all extensions have been temporarily disabled. Please try purging your forum cache. All extensions will automatically be re-enabled once the container error is resolved. If this error continues, please visit <a href="https://www.phpbb.com/support">phpBB.com</a> for support.',
+ 'EXCEPTION' => 'Exception',
+
'COLOUR_SWATCH' => 'Web-safe colour swatch',
'CONFIG_UPDATED' => 'Configuration updated successfully.',
'CRON_LOCK_ERROR' => 'Could not obtain cron lock.',
'CRON_NO_SUCH_TASK' => 'Could not find cron task “%sâ€.',
'CRON_NO_TASK' => 'No cron tasks need to be run right now.',
'CRON_NO_TASKS' => 'No cron tasks could be found.',
+ 'CURRENT_VERSION' => 'Current version',
'DEACTIVATE' => 'Deactivate',
'DIRECTORY_DOES_NOT_EXIST' => 'The entered path “%s†does not exist.',
@@ -256,6 +271,7 @@ $lang = array_merge($lang, array(
'IP' => 'User IP',
'IP_HOSTNAME' => 'IP addresses or hostnames',
+ 'LATEST_VERSION' => 'Latest version',
'LOAD_NOTIFICATIONS' => 'Display Notifications',
'LOAD_NOTIFICATIONS_EXPLAIN' => 'Display the notifications list on every page (typically in the header).',
'LOGGED_IN_AS' => 'You are logged in as:',
@@ -288,7 +304,9 @@ $lang = array_merge($lang, array(
'PERMISSIONS_TRANSFERRED_EXPLAIN' => 'You currently have the permissions from %1$s. You are able to browse the board with this user’s permissions, but not access the administration control panel since admin permissions were not transferred. You can <a href="%2$s"><strong>revert to your permission set</strong></a> at any time.',
'PROCEED_TO_ACP' => '%sProceed to the ACP%s',
+ 'RELEASE_ANNOUNCEMENT' => 'Announcement',
'REMIND' => 'Remind',
+ 'REPARSE_LOCK_ERROR' => 'Reparsing is already in progress by another process.',
'RESYNC' => 'Resynchronise',
'RUNNING_TASK' => 'Running task: %s.',
@@ -307,9 +325,14 @@ $lang = array_merge($lang, array(
'TOTAL_SIZE' => 'Total size',
'UCP' => 'User Control Panel',
+ 'URL_INVALID' => 'The provided URL for the setting “%1$s†is invalid.',
'USERNAMES_EXPLAIN' => 'Place each username on a separate line.',
'USER_CONTROL_PANEL' => 'User Control Panel',
+ 'UPDATE_NEEDED' => 'The board is not up to date.',
+ 'UPDATE_NOT_NEEDED' => 'The board is up to date.',
+ 'UPDATES_AVAILABLE' => 'Updates available:',
+
'WARNING' => 'Warning',
));
@@ -373,6 +396,7 @@ $lang = array_merge($lang, array(
'NUMBER_USERS' => 'Number of users',
'NUMBER_ORPHAN' => 'Orphan attachments',
+ 'PHP_VERSION' => 'PHP version',
'PHP_VERSION_OLD' => 'The version of PHP on this server (%1$s) will no longer be supported by future versions of phpBB. The minimum required version will be PHP %2$s. %3$sDetails%4$s',
'POSTS_PER_DAY' => 'Posts per day',
@@ -420,9 +444,14 @@ $lang = array_merge($lang, array(
'VALUE' => 'Value',
'VERSIONCHECK_FAIL' => 'Failed to obtain latest version information.',
'VERSIONCHECK_FORCE_UPDATE' => 'Re-Check version',
+ 'VERSION_CHECK' => 'Version check',
+ 'VERSION_CHECK_EXPLAIN' => 'Checks to see if your phpBB installation is up to date.',
'VERSIONCHECK_INVALID_ENTRY' => 'Latest version information contains an unsupported entry.',
'VERSIONCHECK_INVALID_URL' => 'Latest version information contains invalid URL.',
'VERSIONCHECK_INVALID_VERSION' => 'Latest version information contains an invalid version.',
+ 'VERSION_NOT_UP_TO_DATE_ACP' => 'Your phpBB installation is not up to date.<br />Below is a link to the release announcement, which contains more information as well as instructions on updating.',
+ 'VERSION_NOT_UP_TO_DATE_TITLE' => 'Your phpBB installation is not up to date.',
+ 'VERSION_UP_TO_DATE_ACP' => 'Your phpBB installation is up to date. There are no updates available at this time.',
'VIEW_ADMIN_LOG' => 'View administrator log',
'VIEW_INACTIVE_USERS' => 'View inactive users',
@@ -455,16 +484,18 @@ $lang = array_merge($lang, array(
'USER_IS_INACTIVE' => 'User is inactive',
));
-// Send statistics page
+// Help support phpBB page
$lang = array_merge($lang, array(
'EXPLAIN_SEND_STATISTICS' => 'Please send information about your server and board configurations to phpBB for statistical analysis. All information that could identify you or your website has been removed - the data is entirely <strong>anonymous</strong>. We base decisions about future phpBB versions on this information. The statistics are made available publically. We also share this data with the PHP project, the programming language phpBB is made with.',
'EXPLAIN_SHOW_STATISTICS' => 'Using the button below you can preview all variables that will be transmitted.',
'DONT_SEND_STATISTICS' => 'Return to the ACP if you do not wish to send statistical information to phpBB.',
'GO_ACP_MAIN' => 'Go to the ACP start page',
'HIDE_STATISTICS' => 'Hide details',
- 'SEND_STATISTICS' => 'Send statistical information',
+ 'SEND_STATISTICS' => 'Send statistics',
+ 'SEND_STATISTICS_LONG' => 'Send statistical information',
'SHOW_STATISTICS' => 'Show details',
'THANKS_SEND_STATISTICS' => 'Thank you for submitting your information.',
+ 'FAIL_SEND_STATISTICS' => 'phpBB was unable to send statistics',
));
// Log Entries
@@ -522,6 +553,7 @@ $lang = array_merge($lang, array(
'LOG_BBCODE_ADD' => '<strong>Added new BBCode</strong><br />» %s',
'LOG_BBCODE_EDIT' => '<strong>Edited BBCode</strong><br />» %s',
'LOG_BBCODE_DELETE' => '<strong>Deleted BBCode</strong><br />» %s',
+ 'LOG_BBCODE_CONFIGURATION_ERROR' => '<strong>Error while configuring BBCode</strong>: %1$s<br />» %2$s',
'LOG_BOT_ADDED' => '<strong>New bot added</strong><br />» %s',
'LOG_BOT_DELETE' => '<strong>Deleted bot</strong><br />» %s',
@@ -797,4 +829,5 @@ $lang = array_merge($lang, array(
'LOG_EXT_ENABLE' => '<strong>Extension enabled</strong><br />» %s',
'LOG_EXT_DISABLE' => '<strong>Extension disabled</strong><br />» %s',
'LOG_EXT_PURGE' => '<strong>Extension’s data deleted</strong><br />» %s',
+ 'LOG_EXT_UPDATE' => '<strong>Extension updated</strong><br />» %s',
));
diff --git a/phpBB/language/en/acp/database.php b/phpBB/language/en/acp/database.php
index ab85701eaa..302aaee570 100644
--- a/phpBB/language/en/acp/database.php
+++ b/phpBB/language/en/acp/database.php
@@ -38,14 +38,15 @@ if (empty($lang) || !is_array($lang))
// Database Backup/Restore
$lang = array_merge($lang, array(
- 'ACP_BACKUP_EXPLAIN' => 'Here you can backup all your phpBB related data. You may store the resulting archive in your <samp>store/</samp> folder or download it directly. Depending on your server configuration you may be able to compress the file in a number of formats.',
+ 'ACP_BACKUP_EXPLAIN' => 'Here you can backup all your phpBB related data. The resulting archive will be stored in your <samp>store/</samp> folder. Depending on your server configuration you may be able to compress the file in a number of formats.',
'ACP_RESTORE_EXPLAIN' => 'This will perform a full restore of all phpBB tables from a saved file. If your server supports it you may use a gzip or bzip2 compressed text file and it will automatically be decompressed. <strong>WARNING</strong> This will overwrite any existing data. The restore may take a long time to process please do not move from this page till it is complete. Backups are stored in the <samp>store/</samp> folder and are assumed to be generated by phpBB’s backup functionality. Restoring backups that were not created by the built in system may or may not work.',
- 'BACKUP_DELETE' => 'The backup file has been deleted successfully.',
- 'BACKUP_INVALID' => 'The selected file to backup is invalid.',
- 'BACKUP_OPTIONS' => 'Backup options',
- 'BACKUP_SUCCESS' => 'The backup file has been created successfully.',
- 'BACKUP_TYPE' => 'Backup type',
+ 'BACKUP_DELETE' => 'The backup file has been deleted successfully.',
+ 'BACKUP_INVALID' => 'The selected file to backup is invalid.',
+ 'BACKUP_NOT_SUPPORTED' => 'The selected backup is not supported',
+ 'BACKUP_OPTIONS' => 'Backup options',
+ 'BACKUP_SUCCESS' => 'The backup file has been created successfully.',
+ 'BACKUP_TYPE' => 'Backup type',
'DATABASE' => 'Database utilities',
'DATA_ONLY' => 'Data only',
diff --git a/phpBB/language/en/acp/extensions.php b/phpBB/language/en/acp/extensions.php
index e5d6789764..a96a7a2a2b 100644
--- a/phpBB/language/en/acp/extensions.php
+++ b/phpBB/language/en/acp/extensions.php
@@ -43,6 +43,7 @@ $lang = array_merge($lang, array(
'EXTENSION_NOT_AVAILABLE' => 'The selected extension is not available for this board, please verify your phpBB and PHP versions are allowed (see the details page).',
'EXTENSION_DIR_INVALID' => 'The selected extension has an invalid directory structure and cannot be enabled.',
'EXTENSION_NOT_ENABLEABLE' => 'The selected extension cannot be enabled, please verify the extension’s requirements.',
+ 'EXTENSION_NOT_INSTALLED' => 'The extension %s is not available. Please check that you have installed it correctly.',
'DETAILS' => 'Details',
diff --git a/phpBB/language/en/acp/forums.php b/phpBB/language/en/acp/forums.php
index 541d05c255..d92d3f8c9e 100644
--- a/phpBB/language/en/acp/forums.php
+++ b/phpBB/language/en/acp/forums.php
@@ -87,7 +87,7 @@ $lang = array_merge($lang, array(
'FORUM_DELETE_EXPLAIN' => 'The form below will allow you to delete a forum. If the forum is postable you are able to decide where you want to put all topics (or forums) it contained.',
'FORUM_DELETED' => 'Forum successfully deleted.',
'FORUM_DESC' => 'Description',
- 'FORUM_DESC_EXPLAIN' => 'Any HTML markup entered here will be displayed as is.',
+ 'FORUM_DESC_EXPLAIN' => 'Any HTML markup entered here will be displayed as is. If the selected forum type is a category the description is not used.',
'FORUM_EDIT_EXPLAIN' => 'The form below will allow you to customise this forum. Please note that moderation and post count controls are set via forum permissions for each user or usergroup.',
'FORUM_IMAGE' => 'Forum image',
'FORUM_IMAGE_EXPLAIN' => 'Location, relative to the phpBB root directory, of an additional image to associate with this forum.',
@@ -97,6 +97,7 @@ $lang = array_merge($lang, array(
'FORUM_LINK_TRACK_EXPLAIN' => 'Records the number of times a forum link was clicked.',
'FORUM_NAME' => 'Forum name',
'FORUM_NAME_EMPTY' => 'You must enter a name for this forum.',
+ 'FORUM_NAME_EMOJI' => 'The forum name you entered is invalid.<br>It contains the following unsupported characters:<br>%s',
'FORUM_PARENT' => 'Parent forum',
'FORUM_PASSWORD' => 'Forum password',
'FORUM_PASSWORD_CONFIRM' => 'Confirm forum password',
diff --git a/phpBB/language/en/acp/groups.php b/phpBB/language/en/acp/groups.php
index a7700ed681..5d68132a34 100644
--- a/phpBB/language/en/acp/groups.php
+++ b/phpBB/language/en/acp/groups.php
@@ -83,7 +83,7 @@ $lang = array_merge($lang, array(
'GROUP_MEMBERS' => 'Group members',
'GROUP_MEMBERS_EXPLAIN' => 'This is a complete listing of all the members of this usergroup. It includes separate sections for leaders, pending and existing members. From here you can manage all aspects of who has membership of this group and what their role is. To remove a leader but keep them in the group use Demote rather than delete. Similarly use Promote to make an existing member a leader.',
'GROUP_MESSAGE_LIMIT' => 'Group private message limit per folder',
- 'GROUP_MESSAGE_LIMIT_EXPLAIN' => 'This setting overrides the per-user folder message limit. A value of 0 means the user default limit will be used.',
+ 'GROUP_MESSAGE_LIMIT_EXPLAIN' => 'This setting overrides the per-user folder message limit. The maximum for all groups of the user is used to determine the actual value.<br />Set this value to 0 to overwrite the setting for all users of this group with the board-wide setting.',
'GROUP_MODS_ADDED' => 'New group leaders added successfully.',
'GROUP_MODS_DEMOTED' => 'Group leaders demoted successfully.',
'GROUP_MODS_PROMOTED' => 'Group members promoted successfully.',
@@ -92,7 +92,7 @@ $lang = array_merge($lang, array(
'GROUP_OPEN' => 'Open',
'GROUP_PENDING' => 'Pending members',
'GROUP_MAX_RECIPIENTS' => 'Maximum number of allowed recipients per private message',
- 'GROUP_MAX_RECIPIENTS_EXPLAIN' => 'The maximum number of allowed recipients in a private message. If 0 is entered, the board-wide setting is used.',
+ 'GROUP_MAX_RECIPIENTS_EXPLAIN' => 'The maximum number of allowed recipients in a private message. The maximum for all groups of the user is used to determine the actual value.<br />Set this value to 0 to overwrite the setting for all users of this group with the board-wide setting.',
'GROUP_OPTIONS_SAVE' => 'Group wide options',
'GROUP_PROMOTE' => 'Promote to group leader',
'GROUP_RANK' => 'Group rank',
@@ -111,6 +111,7 @@ $lang = array_merge($lang, array(
'GROUP_USERS_ADDED' => 'New users added to group successfully.',
'GROUP_USERS_EXIST' => 'The selected users are already members.',
'GROUP_USERS_REMOVE' => 'Users removed from group and new defaults set successfully.',
+ 'GROUP_USERS_INVALID' => 'No users were added to the group as the following usernames do not exist: %s',
'LEGEND_EXPLAIN' => 'These are the groups which are displayed in the group legend:',
'LEGEND_SETTINGS' => 'Legend settings',
@@ -130,6 +131,8 @@ $lang = array_merge($lang, array(
'NO_USERS_ADDED' => 'No users were added to the group.',
'NO_VALID_USERS' => 'You haven’t entered any users eligible for that action.',
+ 'PENDING_MEMBERS' => 'Pending',
+
'SELECT_GROUP' => 'Select a group',
'SPECIAL_GROUPS' => 'Pre-defined groups',
'SPECIAL_GROUPS_EXPLAIN' => 'Pre-defined groups are special groups, they cannot be deleted or directly modified. However you can still add users and alter basic settings.',
diff --git a/phpBB/language/en/acp/permissions.php b/phpBB/language/en/acp/permissions.php
index 1ade2d6eb8..54d968cdaa 100644
--- a/phpBB/language/en/acp/permissions.php
+++ b/phpBB/language/en/acp/permissions.php
@@ -54,7 +54,7 @@ $lang = array_merge($lang, array(
<br />
- <p>For further information on setting up and managing permissions on your phpBB3 board, please see the section on <a href="https://www.phpbb.com/support/docs/en/3.1/ug/quickstart/permissions/">Setting permissions of our Quick Start Guide</a>.</p>
+ <p>For further information on setting up and managing permissions on your phpBB3 board, please see the section on <a href="https://www.phpbb.com/support/docs/en/3.2/ug/quickstart/permissions/">Setting permissions of our Quick Start Guide</a>.</p>
',
'ACL_NEVER' => 'Never',
diff --git a/phpBB/language/en/acp/permissions_phpbb.php b/phpBB/language/en/acp/permissions_phpbb.php
index 2e80e61adc..ab8939932b 100644
--- a/phpBB/language/en/acp/permissions_phpbb.php
+++ b/phpBB/language/en/acp/permissions_phpbb.php
@@ -79,10 +79,11 @@ $lang = array_merge($lang, array(
'ACL_U_SAVEDRAFTS' => 'Can save drafts',
'ACL_U_CHGCENSORS' => 'Can disable word censors',
'ACL_U_SIG' => 'Can use signature',
+ 'ACL_U_EMOJI' => 'Can use emoji and rich text characters in topic title',
'ACL_U_SENDPM' => 'Can send private messages',
- 'ACL_U_MASSPM' => 'Can send messages to multiple users',
- 'ACL_U_MASSPM_GROUP'=> 'Can send messages to groups',
+ 'ACL_U_MASSPM' => 'Can send private messages to multiple users',
+ 'ACL_U_MASSPM_GROUP'=> 'Can send private messages to groups',
'ACL_U_READPM' => 'Can read private messages',
'ACL_U_PM_EDIT' => 'Can edit own private messages',
'ACL_U_PM_DELETE' => 'Can remove private messages from own folder',
@@ -107,6 +108,7 @@ $lang = array_merge($lang, array(
// Forum Permissions
$lang = array_merge($lang, array(
'ACL_F_LIST' => 'Can see forum',
+ 'ACL_F_LIST_TOPICS' => 'Can see topics',
'ACL_F_READ' => 'Can read forum',
'ACL_F_SEARCH' => 'Can search the forum',
'ACL_F_SUBSCRIBE' => 'Can subscribe forum',
@@ -120,6 +122,7 @@ $lang = array_merge($lang, array(
'ACL_F_POST' => 'Can start new topics',
'ACL_F_STICKY' => 'Can post stickies',
'ACL_F_ANNOUNCE' => 'Can post announcements',
+ 'ACL_F_ANNOUNCE_GLOBAL' => 'Can post global announcements',
'ACL_F_REPLY' => 'Can reply to topics',
'ACL_F_EDIT' => 'Can edit own posts',
'ACL_F_DELETE' => 'Can permanently delete own posts',
diff --git a/phpBB/language/en/acp/posting.php b/phpBB/language/en/acp/posting.php
index 119ad2d7e9..1667aa6011 100644
--- a/phpBB/language/en/acp/posting.php
+++ b/phpBB/language/en/acp/posting.php
@@ -56,7 +56,6 @@ $lang = array_merge($lang, array(
'BBCODE_INVALID_TAG_NAME' => 'The BBCode tag name that you selected already exists.',
'BBCODE_INVALID' => 'Your BBCode is constructed in an invalid form.',
- 'BBCODE_OPEN_ENDED_TAG' => 'Your custom BBCode must contain both an opening and a closing tag.',
'BBCODE_TAG' => 'Tag',
'BBCODE_TAG_TOO_LONG' => 'The tag name you selected is too long.',
'BBCODE_TAG_DEF_TOO_LONG' => 'The tag definition that you have entered is too long, please shorten your tag definition.',
@@ -78,13 +77,13 @@ $lang = array_merge($lang, array(
'TOO_MANY_BBCODES' => 'You cannot create any more BBCodes. Please remove one or more BBCodes then try again.',
'tokens' => array(
- 'TEXT' => 'Any text, including foreign characters, numbers, etc… You should not use this token in HTML tags. Instead try to use IDENTIFIER, INTTEXT or SIMPLETEXT.',
+ 'TEXT' => 'Any text, including foreign characters, numbers, etc…',
'SIMPLETEXT' => 'Characters from the latin alphabet (A-Z), numbers, spaces, commas, dots, minus, plus, hyphen and underscore',
'INTTEXT' => 'Unicode letter characters, numbers, spaces, commas, dots, minus, plus, hyphen, underscore and whitespaces.',
'IDENTIFIER' => 'Characters from the latin alphabet (A-Z), numbers, hyphen and underscore',
'NUMBER' => 'Any series of digits',
'EMAIL' => 'A valid email address',
- 'URL' => 'A valid URL using any protocol (http, ftp, etc… cannot be used for javascript exploits). If none is given, “http://†is prefixed to the string.',
+ 'URL' => 'A valid URL using any allowed protocol (http, ftp, etc… cannot be used for javascript exploits). If none is given, “http://†is prefixed to the string.',
'LOCAL_URL' => 'A local URL. The URL must be relative to the topic page and cannot contain a server name or protocol, as links are prefixed with “%sâ€',
'RELATIVE_URL' => 'A relative URL. You can use this to match parts of a URL, but be careful: a full URL is a valid relative URL. When you want to use relative URLs of your board, use the LOCAL_URL token.',
'COLOR' => 'A HTML colour, can be either in the numeric form <samp>#FF1234</samp> or a <a href="http://www.w3.org/TR/CSS21/syndata.html#value-def-color">CSS colour keyword</a> such as <samp>fuchsia</samp> or <samp>InactiveBorder</samp>',
diff --git a/phpBB/language/en/acp/profile.php b/phpBB/language/en/acp/profile.php
index d365aeb183..87c950581e 100644
--- a/phpBB/language/en/acp/profile.php
+++ b/phpBB/language/en/acp/profile.php
@@ -111,7 +111,7 @@ $lang = array_merge($lang, array(
'FIRST_OPTION' => 'First option',
'HIDE_PROFILE_FIELD' => 'Hide profile field',
- 'HIDE_PROFILE_FIELD_EXPLAIN' => 'Hide the profile field from all other users except the user, administrators and moderators who are still able to see this field. If the Display in user control panel option is disabled, the user will not be able to see or change this field and the field can only be changed by administrators.',
+ 'HIDE_PROFILE_FIELD_EXPLAIN' => 'Hide the profile field from all users except administrators and moderators, who are still able to see this field. If the Display in user control panel option is disabled, the user will not be able to see or change this field and the field can only be changed by administrators.',
'INVALID_CHARS_FIELD_IDENT' => 'Field identification can only contain lowercase a-z and _',
'INVALID_FIELD_IDENT_LEN' => 'Field identification can only be 17 characters long',
@@ -161,8 +161,8 @@ $lang = array_merge($lang, array(
'STEP_2_EXPLAIN_EDIT' => 'Here you are able to change some common options.<br /><strong>Please note that changes to profile fields will not affect existing profile fields entered by your users.</strong>',
'STEP_2_TITLE_CREATE' => 'Profile type specific options',
'STEP_2_TITLE_EDIT' => 'Profile type specific options',
- 'STEP_3_EXPLAIN_CREATE' => 'Since you have more than one board language installed, you have to fill out the remaining language items too. The profile field will work with the default language enabled, you are able to fill out the remaining language items later too.',
- 'STEP_3_EXPLAIN_EDIT' => 'Since you have more than one board language installed, you now can change or add the remaining language items too. The profile field will work with the default language enabled.',
+ 'STEP_3_EXPLAIN_CREATE' => 'Since you have more than one board language installed, you have to fill out the remaining language items too. If you don’t, then default language setting for this custom profile field will be used, you are able to fill out the remaining language items later too.',
+ 'STEP_3_EXPLAIN_EDIT' => 'Since you have more than one board language installed, you now can change or add the remaining language items too. If you don’t, then default language setting for this custom profile field will be used.',
'STEP_3_TITLE_CREATE' => 'Remaining language definitions',
'STEP_3_TITLE_EDIT' => 'Language definitions',
'STRING_DEFAULT_VALUE_EXPLAIN' => 'Enter a default phrase to be displayed, a default value. Leave empty if you want to show it empty at the first place.',
diff --git a/phpBB/language/en/acp/search.php b/phpBB/language/en/acp/search.php
index c52b71c121..443dbb7fb7 100644
--- a/phpBB/language/en/acp/search.php
+++ b/phpBB/language/en/acp/search.php
@@ -116,7 +116,10 @@ $lang = array_merge($lang, array(
2 => 'The current rate of indexing is approximately %1$.1f posts per second.<br />Indexing in progress…',
),
'SEARCH_INDEX_DELETE_REDIRECT' => array(
- 2 => 'All posts up to post id %2$d have been removed from the search index.<br />Deleting in progress…',
+ 2 => 'All posts up to post id %2$d have been removed from the search index, of which %1$d posts were within this step.<br />',
+ ),
+ 'SEARCH_INDEX_DELETE_REDIRECT_RATE' => array(
+ 2 => 'The current rate of deleting is approximately %1$.1f posts per second.<br />Deleting in progress…',
),
'SEARCH_INDEX_CREATED' => 'Successfully indexed all posts in the board database.',
'SEARCH_INDEX_REMOVED' => 'Successfully deleted the search index for this backend.',
diff --git a/phpBB/language/en/acp/styles.php b/phpBB/language/en/acp/styles.php
index 9293d67ecc..44be3c11cd 100644
--- a/phpBB/language/en/acp/styles.php
+++ b/phpBB/language/en/acp/styles.php
@@ -21,7 +21,7 @@ if (!defined('IN_PHPBB'))
if (empty($lang) || !is_array($lang))
{
- $lang = array();
+ $lang = [];
}
// DEVELOPERS PLEASE NOTE
@@ -36,54 +36,56 @@ if (empty($lang) || !is_array($lang))
// equally where a string contains only two placeholders which are used to wrap text
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
-$lang = array_merge($lang, array(
- 'ACP_STYLES_EXPLAIN' => 'Here you can manage the available styles on your board. You may alter existing styles, delete, deactivate, reactivate, install new ones. You can also see what a style will look like using the preview function. Also listed is the total user count for each style, note that overriding user styles will not be reflected here.',
+$lang = array_merge($lang, [
+ 'ACP_STYLES_EXPLAIN' => 'Here you can manage the styles available on your board.<br>Please note you cannot uninstall the “<strong>prosilver</strong>†style as it is phpBB’s default and primary parent style.',
- 'CANNOT_BE_INSTALLED' => 'Cannot be installed',
- 'CONFIRM_UNINSTALL_STYLES' => 'Are you sure you wish to uninstall selected styles?',
- 'COPYRIGHT' => 'Copyright',
+ 'CANNOT_BE_INSTALLED' => 'Cannot be installed',
+ 'CONFIRM_UNINSTALL_STYLES' => 'Are you sure you wish to uninstall selected styles?',
+ 'COPYRIGHT' => 'Copyright',
- 'DEACTIVATE_DEFAULT' => 'You cannot deactivate the default style.',
- 'DELETE_FROM_FS' => 'Delete from filesystem',
- 'DELETE_STYLE_FILES_FAILED' => 'Error deleting files for style "%s".',
- 'DELETE_STYLE_FILES_SUCCESS' => 'Files for style "%s" have been deleted.',
- 'DETAILS' => 'Details',
+ 'DEACTIVATE_DEFAULT' => 'You cannot deactivate the default style.',
+ 'DELETE_FROM_FS' => 'Delete from filesystem',
+ 'DELETE_STYLE_FILES_FAILED' => 'Error deleting files for style "%s".',
+ 'DELETE_STYLE_FILES_SUCCESS' => 'Files for style "%s" have been deleted.',
+ 'DETAILS' => 'Details',
- 'INHERITING_FROM' => 'Inherits from',
- 'INSTALL_STYLE' => 'Install style',
- 'INSTALL_STYLES' => 'Install styles',
- 'INSTALL_STYLES_EXPLAIN' => 'Here you can install new styles.<br />If you cannot find a specific style in list below, check to make sure style is already installed. If it is not installed, check if it was uploaded correctly.',
- 'INVALID_STYLE_ID' => 'Invalid style ID.',
+ 'INHERITING_FROM' => 'Inherits from',
+ 'INSTALL_STYLE' => 'Install style',
+ 'INSTALL_STYLES' => 'Install styles',
+ 'INSTALL_STYLES_EXPLAIN' => 'Here you can install new styles.<br>If you cannot find a specific style in list below, check to make sure style is already installed. If it is not installed, check if it was uploaded correctly.',
+ 'INVALID_STYLE_ID' => 'Invalid style ID.',
- 'NO_MATCHING_STYLES_FOUND' => 'No styles match your query.',
- 'NO_UNINSTALLED_STYLE' => 'No uninstalled styles detected.',
+ 'NO_MATCHING_STYLES_FOUND' => 'No styles match your query.',
+ 'NO_UNINSTALLED_STYLE' => 'No uninstalled styles detected.',
- 'PURGED_CACHE' => 'Cache was purged.',
+ 'PURGED_CACHE' => 'Cache was purged.',
- 'REQUIRES_STYLE' => 'This style requires the style "%s" to be installed.',
+ 'REQUIRES_STYLE' => 'This style requires the style "%s" to be installed.',
- 'STYLE_ACTIVATE' => 'Activate',
- 'STYLE_ACTIVE' => 'Active',
- 'STYLE_DEACTIVATE' => 'Deactivate',
- 'STYLE_DEFAULT' => 'Make default style',
- 'STYLE_DEFAULT_CHANGE_INACTIVE' => 'You must activate style before making it default style.',
- 'STYLE_ERR_INVALID_PARENT' => 'Invalid parent style.',
- 'STYLE_ERR_NAME_EXIST' => 'A style with that name already exists.',
- 'STYLE_ERR_STYLE_NAME' => 'You must supply a name for this style.',
- 'STYLE_INSTALLED' => 'Style "%s" has been installed.',
+ 'STYLE_ACTIVATE' => 'Activate',
+ 'STYLE_ACTIVE' => 'Active',
+ 'STYLE_DEACTIVATE' => 'Deactivate',
+ 'STYLE_DEFAULT' => 'Make default style',
+ 'STYLE_DEFAULT_CHANGE_INACTIVE' => 'You must activate style before making it default style.',
+ 'STYLE_ERR_INVALID_PARENT' => 'Invalid parent style.',
+ 'STYLE_ERR_NAME_EXIST' => 'A style with that name already exists.',
+ 'STYLE_ERR_STYLE_NAME' => 'You must supply a name for this style.',
+ 'STYLE_INSTALLED' => 'Style "%s" has been installed.',
'STYLE_INSTALLED_RETURN_INSTALLED_STYLES' => 'Return to installed styles list',
'STYLE_INSTALLED_RETURN_UNINSTALLED_STYLES' => 'Install more styles',
- 'STYLE_NAME' => 'Style name',
- 'STYLE_NAME_RESERVED' => 'Style "%s" can not be installed, because the name is reserved.',
- 'STYLE_NOT_INSTALLED' => 'Style "%s" was not installed.',
- 'STYLE_PATH' => 'Style path',
- 'STYLE_UNINSTALL' => 'Uninstall',
- 'STYLE_UNINSTALL_DEPENDENT' => 'Style "%s" cannot be uninstalled because it has one or more child styles.',
- 'STYLE_UNINSTALLED' => 'Style "%s" uninstalled successfully.',
- 'STYLE_USED_BY' => 'Used by (including robots)',
- 'STYLE_VERSION' => 'Style version',
+ 'STYLE_NAME' => 'Style name',
+ 'STYLE_NAME_RESERVED' => 'Style "%s" can not be installed, because the name is reserved.',
+ 'STYLE_NOT_INSTALLED' => 'Style "%s" was not installed.',
+ 'STYLE_PATH' => 'Style path',
+ 'STYLE_UNINSTALL' => 'Uninstall',
+ 'STYLE_UNINSTALL_DEPENDENT' => 'Style "%s" cannot be uninstalled because it has one or more child styles.',
+ 'STYLE_UNINSTALLED' => 'Style "%s" uninstalled successfully.',
+ 'STYLE_PHPBB_VERSION' => 'phpBB Version',
+ 'STYLE_USED_BY' => 'Used by (including robots)',
+ 'STYLE_VERSION' => 'Style version',
- 'UNINSTALL_DEFAULT' => 'You cannot uninstall the default style.',
+ 'UNINSTALL_PROSILVER' => 'You cannot uninstall the style “prosilverâ€.',
+ 'UNINSTALL_DEFAULT' => 'You cannot uninstall the default style.',
- 'BROWSE_STYLES_DATABASE' => 'Browse styles database',
-));
+ 'BROWSE_STYLES_DATABASE' => 'Browse styles database',
+]);
diff --git a/phpBB/language/en/captcha_qa.php b/phpBB/language/en/captcha_qa.php
index 28011eb636..637c4e035e 100644
--- a/phpBB/language/en/captcha_qa.php
+++ b/phpBB/language/en/captcha_qa.php
@@ -49,7 +49,7 @@ $lang = array_merge($lang, array(
'ANSWER' => 'Answer',
'EDIT_QUESTION' => 'Edit Question',
'QUESTIONS' => 'Questions',
- 'QUESTIONS_EXPLAIN' => 'For every form submission where you have enabled the Q&amp;A plugin, users will be asked one of the questions specified here. To use this plugin at least one question must be set in the default language. These questions should be easy for your target audience to answer but beyond the ability of a bot capable of running a Googleâ„¢ search. Using a large and regularly changed set of questions will yield the best results. Enable the strict setting if your question relies on mixed case, punctuation or whitespace.',
+ 'QUESTIONS_EXPLAIN' => 'For every form submission where you have enabled the Q&amp;A plugin, users will be asked one of the questions specified here. To use this plugin at least one question must be set in the default language. These questions should be easy for your target audience to answer but beyond the ability of a bot capable of running a Googleâ„¢ search. Only a single proper question is necessary. If you start receiving spam registrations, the question should be changed. Enable the strict setting if your question relies on mixed case, punctuation or whitespace.',
'QUESTION_DELETED' => 'Question deleted',
'QUESTION_LANG' => 'Language',
'QUESTION_LANG_EXPLAIN' => 'The language this question and its answers are written in.',
diff --git a/phpBB/language/en/captcha_recaptcha.php b/phpBB/language/en/captcha_recaptcha.php
index df2ad4e51b..dde2a4ba08 100644
--- a/phpBB/language/en/captcha_recaptcha.php
+++ b/phpBB/language/en/captcha_recaptcha.php
@@ -37,16 +37,16 @@ if (empty($lang) || !is_array($lang))
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
$lang = array_merge($lang, array(
- 'RECAPTCHA_LANG' => 'en',
+ 'RECAPTCHA_LANG' => 'en-GB', // Find the language/country code on https://developers.google.com/recaptcha/docs/language - If no code exists for your language you can use "en" or leave the string empty
'RECAPTCHA_NOT_AVAILABLE' => 'In order to use reCaptcha, you must create an account on <a href="http://www.google.com/recaptcha">www.google.com/recaptcha</a>.',
'CAPTCHA_RECAPTCHA' => 'reCaptcha',
- 'RECAPTCHA_INCORRECT' => 'The visual confirmation code you submitted was incorrect',
+ 'RECAPTCHA_INCORRECT' => 'The solution you provided was incorrect',
+ 'RECAPTCHA_NOSCRIPT' => 'Please enable JavaScript in your browser to load the challenge.',
'RECAPTCHA_PUBLIC' => 'Public reCaptcha key',
'RECAPTCHA_PUBLIC_EXPLAIN' => 'Your public reCaptcha key. Keys can be obtained on <a href="http://www.google.com/recaptcha">www.google.com/recaptcha</a>.',
'RECAPTCHA_PRIVATE' => 'Private reCaptcha key',
'RECAPTCHA_PRIVATE_EXPLAIN' => 'Your private reCaptcha key. Keys can be obtained on <a href="http://www.google.com/recaptcha">www.google.com/recaptcha</a>.',
- 'RECAPTCHA_EXPLAIN' => 'In an effort to prevent automatic submissions, we require that you type the text displayed into the field underneath.',
- 'RECAPTCHA_SOCKET_ERROR' => 'There was a problem connecting to the RECAPTCHA service: could not open socket. Try again later.',
+ 'RECAPTCHA_EXPLAIN' => 'In an effort to prevent automatic submissions, we require that you complete the following challenge.',
));
diff --git a/phpBB/language/en/cli.php b/phpBB/language/en/cli.php
index 4e27be48cc..505d12e8ff 100644
--- a/phpBB/language/en/cli.php
+++ b/phpBB/language/en/cli.php
@@ -50,7 +50,9 @@ $lang = array_merge($lang, array(
'CLI_DESCRIPTION_CRON_LIST' => 'Prints a list of ready and unready cron jobs.',
'CLI_DESCRIPTION_CRON_RUN' => 'Runs all ready cron tasks.',
'CLI_DESCRIPTION_CRON_RUN_ARGUMENT_1' => 'Name of the task to be run',
+ 'CLI_DESCRIPTION_DB_LIST' => 'List all installed and available migrations.',
'CLI_DESCRIPTION_DB_MIGRATE' => 'Updates the database by applying migrations.',
+ 'CLI_DESCRIPTION_DB_REVERT' => 'Revert a migration.',
'CLI_DESCRIPTION_DELETE_CONFIG' => 'Deletes a configuration option',
'CLI_DESCRIPTION_DISABLE_EXTENSION' => 'Disables the specified extension.',
'CLI_DESCRIPTION_ENABLE_EXTENSION' => 'Enables the specified extension.',
@@ -59,32 +61,118 @@ $lang = array_merge($lang, array(
'CLI_DESCRIPTION_GET_CONFIG' => 'Gets a configuration option’s value',
'CLI_DESCRIPTION_INCREMENT_CONFIG' => 'Increments a configuration option’s integer value',
'CLI_DESCRIPTION_LIST_EXTENSIONS' => 'Lists all extensions in the database and on the filesystem.',
+
+ 'CLI_DESCRIPTION_OPTION_ENV' => 'The Environment name.',
'CLI_DESCRIPTION_OPTION_SAFE_MODE' => 'Run in Safe Mode (without extensions).',
'CLI_DESCRIPTION_OPTION_SHELL' => 'Launch the shell.',
+
'CLI_DESCRIPTION_PURGE_EXTENSION' => 'Purges the specified extension.',
- 'CLI_DESCRIPTION_RECALCULATE_EMAIL_HASH' => 'Recalculates the user_email_hash column of the users table.',
- 'CLI_DESCRIPTION_SET_ATOMIC_CONFIG' => 'Sets a configuration option’s value only if the old matches the current value',
- 'CLI_DESCRIPTION_SET_CONFIG' => 'Sets a configuration option’s value',
+
+ 'CLI_DESCRIPTION_REPARSER_LIST' => 'Lists the types of text that can be reparsed.',
+ 'CLI_DESCRIPTION_REPARSER_AVAILABLE' => 'Available reparsers:',
+ 'CLI_DESCRIPTION_REPARSER_REPARSE' => 'Reparses stored text with the current text_formatter services.',
+ 'CLI_DESCRIPTION_REPARSER_REPARSE_ARG_1' => 'Type of text to reparse. Leave blank to reparse everything.',
+ 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_DRY_RUN' => 'Do not save any changes; just print what would happen',
+ 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MIN' => 'Lowest record ID to process',
+ 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MAX' => 'Highest record ID to process',
+ 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_SIZE' => 'Approximate number of records to process at a time',
+ 'CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RESUME' => 'Start reparsing where the last execution stopped',
+
+ 'CLI_DESCRIPTION_RECALCULATE_EMAIL_HASH' => 'Recalculates the user_email_hash column of the users table.',
+
+ 'CLI_DESCRIPTION_SET_ATOMIC_CONFIG' => 'Sets a configuration option’s value only if the old matches the current value',
+ 'CLI_DESCRIPTION_SET_CONFIG' => 'Sets a configuration option’s value',
+
+ 'CLI_DESCRIPTION_THUMBNAIL_DELETE' => 'Delete all existing thumbnails.',
+ 'CLI_DESCRIPTION_THUMBNAIL_GENERATE' => 'Generate all missing thumbnails.',
+ 'CLI_DESCRIPTION_THUMBNAIL_RECREATE' => 'Recreate all thumbnails.',
+
+ 'CLI_DESCRIPTION_UPDATE_CHECK' => 'Check if the board is up to date.',
+ 'CLI_DESCRIPTION_UPDATE_CHECK_ARGUMENT_1' => 'Name of the extension to check (if all, checks all the extensions)',
+ 'CLI_DESCRIPTION_UPDATE_CHECK_OPTION_CACHE' => 'Run check command with cache.',
+ 'CLI_DESCRIPTION_UPDATE_CHECK_OPTION_STABILITY' => 'Run command choosing to check only stable or unstable versions.',
+
'CLI_DESCRIPTION_UPDATE_HASH_BCRYPT' => 'Updates outdated password hashes to be hashed with bcrypt.',
+ 'CLI_ERROR_INVALID_STABILITY' => '"%s" needs to be set to "stable" or "unstable".',
+
+ 'CLI_DESCRIPTION_USER_ACTIVATE' => 'Activate (or deactivate) a user account.',
+ 'CLI_DESCRIPTION_USER_ACTIVATE_USERNAME' => 'Username of the account to activate.',
+ 'CLI_DESCRIPTION_USER_ACTIVATE_DEACTIVATE' => 'Deactivate the user’s account',
+ 'CLI_DESCRIPTION_USER_ACTIVATE_ACTIVE' => 'The user is already active.',
+ 'CLI_DESCRIPTION_USER_ACTIVATE_INACTIVE' => 'The user is already inactive.',
+ 'CLI_DESCRIPTION_USER_ADD' => 'Add a new user.',
+ 'CLI_DESCRIPTION_USER_ADD_OPTION_USERNAME' => 'Username of the new user',
+ 'CLI_DESCRIPTION_USER_ADD_OPTION_PASSWORD' => 'Password of the new user',
+ 'CLI_DESCRIPTION_USER_ADD_OPTION_EMAIL' => 'E-mail address of the new user',
+ 'CLI_DESCRIPTION_USER_ADD_OPTION_NOTIFY' => 'Send account activation email to the new user (not sent by default)',
+ 'CLI_DESCRIPTION_USER_DELETE' => 'Delete a user account.',
+ 'CLI_DESCRIPTION_USER_DELETE_USERNAME' => 'Username of the user to delete',
+ 'CLI_DESCRIPTION_USER_DELETE_OPTION_POSTS' => 'Delete all posts by the user. Without this option, the user’s posts will be retained.',
+ 'CLI_DESCRIPTION_USER_RECLEAN' => 'Re-clean usernames.',
+
'CLI_EXTENSION_DISABLE_FAILURE' => 'Could not disable extension %s',
'CLI_EXTENSION_DISABLE_SUCCESS' => 'Successfully disabled extension %s',
+ 'CLI_EXTENSION_DISABLED' => 'Extension %s is not enabled',
'CLI_EXTENSION_ENABLE_FAILURE' => 'Could not enable extension %s',
'CLI_EXTENSION_ENABLE_SUCCESS' => 'Successfully enabled extension %s',
+ 'CLI_EXTENSION_ENABLED' => 'Extension %s is already enabled',
+ 'CLI_EXTENSION_NOT_EXIST' => 'Extension %s does not exist',
'CLI_EXTENSION_NAME' => 'Name of the extension',
'CLI_EXTENSION_PURGE_FAILURE' => 'Could not purge extension %s',
'CLI_EXTENSION_PURGE_SUCCESS' => 'Successfully purged extension %s',
+ 'CLI_EXTENSION_UPDATE_FAILURE' => 'Could not update extension %s',
+ 'CLI_EXTENSION_UPDATE_SUCCESS' => 'Successfully updated extension %s',
'CLI_EXTENSION_NOT_FOUND' => 'No extensions were found.',
+ 'CLI_EXTENSION_NOT_ENABLEABLE' => 'Extension %s is not enableable.',
'CLI_EXTENSIONS_AVAILABLE' => 'Available',
'CLI_EXTENSIONS_DISABLED' => 'Disabled',
'CLI_EXTENSIONS_ENABLED' => 'Enabled',
'CLI_FIXUP_FIX_LEFT_RIGHT_IDS_SUCCESS' => 'Successfully repaired the tree structure of the forums and modules.',
'CLI_FIXUP_RECALCULATE_EMAIL_HASH_SUCCESS' => 'Successfully recalculated all email hashes.',
- 'CLI_FIXUP_UPDATE_HASH_BCRYPT_SUCCESS' => 'Successfully updated outdated password hashes to bcrypt.'
+ 'CLI_FIXUP_UPDATE_HASH_BCRYPT_SUCCESS' => 'Successfully updated outdated password hashes to bcrypt.',
+
+ 'CLI_MIGRATION_NAME' => 'Migration name, including the namespace (use forward slashes instead of backslashes to avoid problems).',
+ 'CLI_MIGRATIONS_AVAILABLE' => 'Available migrations',
+ 'CLI_MIGRATIONS_INSTALLED' => 'Installed migrations',
+ 'CLI_MIGRATIONS_ONLY_AVAILABLE' => 'Show only available migrations',
+ 'CLI_MIGRATIONS_EMPTY' => 'No migrations.',
+
+ 'CLI_REPARSER_REPARSE_REPARSING' => 'Reparsing %1$s (range %2$d..%3$d)',
+ 'CLI_REPARSER_REPARSE_REPARSING_START' => 'Reparsing %s...',
+ 'CLI_REPARSER_REPARSE_SUCCESS' => 'Reparsing ended with success',
+
+ // In all the case %1$s is the logical name of the file and %2$s the real name on the filesystem
+ // eg: big_image.png (2_a51529ae7932008cf8454a95af84cacd) generated.
+ 'CLI_THUMBNAIL_DELETED' => '%1$s (%2$s) deleted.',
+ 'CLI_THUMBNAIL_DELETING' => 'Deleting thumbnails',
+ 'CLI_THUMBNAIL_SKIPPED' => '%1$s (%2$s) skipped.',
+ 'CLI_THUMBNAIL_GENERATED' => '%1$s (%2$s) generated.',
+ 'CLI_THUMBNAIL_GENERATING' => 'Generating thumbnails',
+ 'CLI_THUMBNAIL_GENERATING_DONE' => 'All thumbnails have been regenerated.',
+ 'CLI_THUMBNAIL_DELETING_DONE' => 'All thumbnails have been deleted.',
+
+ 'CLI_THUMBNAIL_NOTHING_TO_GENERATE' => 'No thumbnails to generate.',
+ 'CLI_THUMBNAIL_NOTHING_TO_DELETE' => 'No thumbnails to delete.',
+
+ 'CLI_USER_ADD_SUCCESS' => 'Successfully added user %s.',
+ 'CLI_USER_DELETE_CONFIRM' => 'Are you sure you want to delete ‘%s’? [y/N]',
+ 'CLI_USER_RECLEAN_START' => 'Re-cleaning usernames',
+ 'CLI_USER_RECLEAN_DONE' => [
+ 0 => 'Re-cleaning complete. No usernames needed to be cleaned.',
+ 1 => 'Re-cleaning complete. %d username was cleaned.',
+ 2 => 'Re-cleaning complete. %d usernames were cleaned.',
+ ],
));
// Additional help for commands.
$lang = array_merge($lang, array(
'CLI_HELP_CRON_RUN' => $lang['CLI_DESCRIPTION_CRON_RUN'] . ' Optionally you can specify a cron task name to run only the specified cron task.',
+ 'CLI_HELP_USER_ACTIVATE' => 'Activate a user account, or deactivate an account using the <info>--deactivate</info> option.
+To optionally send an activation email to the user, use the <info>--send-email</info> option.',
+ 'CLI_HELP_USER_ADD' => 'The <info>%command.name%</info> command adds a new user:
+If this command is run without options, you will be prompted to enter them.
+To optionally send an email to the new user, use the <info>--send-email</info> option.',
+ 'CLI_HELP_USER_RECLEAN' => 'Re-clean usernames will check all stored usernames and ensure clean versions are also stored. Cleaned usernames are a case insensitive form, NFC normalized and transformed to ASCII.',
));
diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php
index b4b328e90d..3ba63746c8 100644
--- a/phpBB/language/en/common.php
+++ b/phpBB/language/en/common.php
@@ -48,7 +48,7 @@ $lang = array_merge($lang, array(
'USER_LANG' => 'en-gb',
// You can define different rules for the determination of plural forms here.
- // See http://wiki.phpbb.com/Plural_Rules for more information
+ // See https://area51.phpbb.com/docs/dev/32x/language/plurals.html for more information
// or ask the translation manager for help.
'PLURAL_RULE' => 1,
@@ -62,7 +62,6 @@ $lang = array_merge($lang, array(
'ACCOUNT_ALREADY_ACTIVATED' => 'Your account has already been activated.',
'ACCOUNT_DEACTIVATED' => 'Your account has been manually deactivated and is only able to be reactivated by an administrator.',
- 'ACCOUNT_NOT_ACTIVATED' => 'Your account has not been activated yet.',
'ACP' => 'Administration Control Panel',
'ACP_SHORT' => 'ACP',
'ACTIVE' => 'active',
@@ -81,8 +80,9 @@ $lang = array_merge($lang, array(
'ALL_FORUMS' => 'All forums',
'ALL_MESSAGES' => 'All messages',
'ALL_POSTS' => 'All posts',
- 'ALL_TIMES' => 'All times are <abbr title="%2$s">%1$s</abbr>',
+ 'ALL_TIMES' => 'All times are <span title="%2$s">%1$s</span>',
'ALL_TOPICS' => 'All Topics',
+ 'ALT_TEXT' => 'Alternative text',
'AND' => 'And',
'ARE_WATCHING_FORUM' => 'You have subscribed to be notified of new posts in this forum.',
'ARE_WATCHING_TOPIC' => 'You have subscribed to be notified of new posts in this topic.',
@@ -91,12 +91,14 @@ $lang = array_merge($lang, array(
'ATTACHED_IMAGE_NOT_IMAGE' => 'The image file you tried to attach is invalid.',
'AUTHOR' => 'Author',
'AUTH_NO_PROFILE_CREATED' => 'The creation of a user profile was unsuccessful.',
+ 'AUTH_PROVIDER_OAUTH_ERROR_ALREADY_LINKED' => 'This external service is already associated with another board account.',
'AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY' => 'Invalid database entry.',
'AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE' => 'Invalid service type provided to OAuth service handler.',
'AUTH_PROVIDER_OAUTH_ERROR_SERVICE_NOT_CREATED' => 'OAuth service not created',
'AUTH_PROVIDER_OAUTH_SERVICE_BITLY' => 'Bitly',
'AUTH_PROVIDER_OAUTH_SERVICE_FACEBOOK' => 'Facebook',
'AUTH_PROVIDER_OAUTH_SERVICE_GOOGLE' => 'Google',
+ 'AUTH_PROVIDER_OAUTH_SERVICE_TWITTER' => 'Twitter',
'AUTH_PROVIDER_OAUTH_TOKEN_ERROR_NOT_STORED' => 'OAuth token not stored.',
'AUTH_PROVIDER_OAUTH_TOKEN_ERROR_INCORRECTLY_STORED' => 'OAuth token incorrectly stored.',
'AVATAR_DISALLOWED_CONTENT' => 'The upload was rejected because the uploaded file was identified as a possible attack vector.',
@@ -105,11 +107,13 @@ $lang = array_merge($lang, array(
'AVATAR_EMPTY_FILEUPLOAD' => 'The uploaded avatar file is empty.',
'AVATAR_INVALID_FILENAME' => '%s is an invalid filename.',
'AVATAR_NOT_UPLOADED' => 'Avatar could not be uploaded.',
+ 'AVATAR_NO_TEMP_DIR' => 'Temporary folder could not be found or is not writable.',
'AVATAR_NO_SIZE' => 'The width or height of the linked avatar could not be determined. Please enter them manually.',
'AVATAR_PARTIAL_UPLOAD' => 'The specified file was only partially uploaded.',
'AVATAR_PHP_SIZE_NA' => 'The avatar’s filesize is too large.<br />The maximum allowed filesize set in php.ini could not be determined.',
'AVATAR_PHP_SIZE_OVERRUN' => 'The avatar’s filesize is too large. The maximum allowed upload size is %1$d %2$s.<br />Please note this is set in php.ini and cannot be overridden.',
'AVATAR_REMOTE_UPLOAD_TIMEOUT' => 'The specified avatar could not be uploaded because the request timed out.',
+ 'AVATAR_PHP_UPLOAD_STOPPED' => 'A PHP extension has stopped the file upload.',
'AVATAR_URL_INVALID' => 'The URL you specified is invalid.',
'AVATAR_URL_NOT_FOUND' => 'The file specified could not be found.',
'AVATAR_WRONG_FILESIZE' => 'The avatar’s filesize must be between 0 and %1$d %2$s.',
@@ -134,8 +138,10 @@ $lang = array_merge($lang, array(
1 => 'Users browsing this forum: %2$s and %1$d guest',
2 => 'Users browsing this forum: %2$s and %1$d guests',
),
+ 'BUTTON_DELETE' => 'Delete',
'BUTTON_EDIT' => 'Edit',
'BUTTON_FORUM_LOCKED' => 'Locked',
+ 'BUTTON_INFORMATION' => 'Information',
'BUTTON_NEW_TOPIC' => 'New Topic',
'BUTTON_PM' => 'PM',
'BUTTON_PM_FORWARD' => 'Forward',
@@ -144,7 +150,9 @@ $lang = array_merge($lang, array(
'BUTTON_PM_REPLY_ALL' => 'Reply All',
'BUTTON_POST_REPLY' => 'Post Reply',
'BUTTON_QUOTE' => 'Quote',
+ 'BUTTON_REPORT' => 'Report',
'BUTTON_TOPIC_LOCKED' => 'Locked',
+ 'BUTTON_WARN' => 'Warn',
'BYTES' => 'Bytes',
'BYTES_SHORT' => 'B',
@@ -174,6 +182,10 @@ $lang = array_merge($lang, array(
'CONTACT' => 'Contact',
'CONTACT_USER' => 'Contact %s',
'CONTACT_US' => 'Contact us',
+ 'COOKIE_CONSENT_INFO' => 'Learn more',
+ 'COOKIE_CONSENT_MSG' => 'This website uses cookies to ensure you get the best experience on our website.',
+ 'COOKIE_CONSENT_OK' => 'Got it!',
+ 'COOKIE_CONSENT_HREF' => 'http://cookiesandyou.com',
'COOKIES_DELETED' => 'All board cookies successfully deleted.',
'CURRENT_TIME' => 'It is currently %s',
@@ -181,7 +193,7 @@ $lang = array_merge($lang, array(
'DAYS' => 'Days',
'DELETE' => 'Delete',
'DELETE_ALL' => 'Delete all',
- 'DELETE_COOKIES' => 'Delete all board cookies',
+ 'DELETE_COOKIES' => 'Delete cookies',
'DELETE_MARKED' => 'Delete marked',
'DELETE_POST' => 'Delete post',
'DELIMITER' => 'Delimiter',
@@ -229,6 +241,7 @@ $lang = array_merge($lang, array(
'FACEBOOK' => 'Facebook',
'FAQ' => 'FAQ',
'FAQ_EXPLAIN' => 'Frequently Asked Questions',
+ 'FEATURE_NOT_AVAILABLE' => 'The requested feature is not available on this board.',
'FILENAME' => 'Filename',
'FILESIZE' => 'File size',
'FILEDATE' => 'File date',
@@ -449,6 +462,7 @@ $lang = array_merge($lang, array(
'NOTIFICATION_FORUM' => '<em>Forum:</em> %1$s',
'NOTIFICATION_GROUP_REQUEST' => '<strong>Group request</strong> from %1$s to join the group %2$s.',
'NOTIFICATION_GROUP_REQUEST_APPROVED' => '<strong>Group request approved</strong> to join the group %1$s.',
+ 'NOTIFICATION_METHOD_INVALID' => 'The method "%s" does not refer to a valid notification method.',
'NOTIFICATION_PM' => '<strong>Private Message</strong> from %1$s:',
'NOTIFICATION_POST' => array(
1 => '<strong>Reply</strong> from %1$s in topic:',
@@ -505,7 +519,8 @@ $lang = array_merge($lang, array(
'NO_POSTS_TIME_FRAME' => 'No posts exist inside this topic for the selected time frame.',
'NO_FEED_ENABLED' => 'Feeds are not available on this board.',
'NO_FEED' => 'The requested feed is not available.',
- 'NO_STYLE_DATA' => 'Could not get style data',
+ 'NO_STYLE_DATA' => 'Could not get style data for user_style %s and set for user_id %s',
+ 'NO_STYLE_CFG' => 'Could not get the style configuration file for: %s',
'NO_SUBJECT' => 'No subject specified', // Used for posts having no subject defined but displayed within management pages.
'NO_SUCH_SEARCH_MODULE' => 'The specified search backend doesn’t exist.',
'NO_SUPPORTED_AUTH_METHODS' => 'No supported authentication methods.',
@@ -546,6 +561,7 @@ $lang = array_merge($lang, array(
),
'OPTIONS' => 'Options',
+ 'PAGE_NOT_FOUND' => 'The requested page could not be found.',
'PAGE_OF' => 'Page <strong>%1$d</strong> of <strong>%2$d</strong>',
'PAGE_TITLE_NUMBER' => 'Page %s',
'PASSWORD' => 'Password',
@@ -554,7 +570,6 @@ $lang = array_merge($lang, array(
1 => '%d pixel',
2 => '%d pixels',
),
- 'PLAY_QUICKTIME_FILE' => 'Play Quicktime file',
'PLEASE_WAIT' => 'Please wait.',
'PM' => 'PM',
'PM_REPORTED' => 'Click to view report',
@@ -594,6 +609,7 @@ $lang = array_merge($lang, array(
'PREVIOUS' => 'Previous', // Used in pagination
'PREVIOUS_STEP' => 'Previous',
'PRIVACY' => 'Privacy policy',
+ 'PRIVACY_LINK' => 'Privacy',
'PRIVATE_MESSAGE' => 'Private message',
'PRIVATE_MESSAGES' => 'Private messages',
'PRIVATE_MESSAGING' => 'Private messaging',
@@ -692,10 +708,13 @@ $lang = array_merge($lang, array(
'SKYPE' => 'Skype',
'SMTP_NO_AUTH_SUPPORT' => 'SMTP server does not support authentication.',
'SORRY_AUTH_READ' => 'You are not authorised to read this forum.',
+ 'SORRY_AUTH_READ_TOPIC' => 'You are not authorised to read this topic.',
'SORRY_AUTH_VIEW_ATTACH' => 'You are not authorised to download this attachment.',
'SORT_BY' => 'Sort by',
+ 'SORT_DIRECTION' => 'Direction',
'SORT_JOINED' => 'Joined date',
'SORT_LOCATION' => 'Location',
+ 'SORT_OPTIONS' => 'Display and sorting options',
'SORT_RANK' => 'Rank',
'SORT_POSTS' => 'Posts',
'SORT_TOPIC_TITLE' => 'Topic title',
@@ -715,6 +734,7 @@ $lang = array_merge($lang, array(
'SUBMIT' => 'Submit',
'TB' => 'TB',
+ 'TERMS_LINK' => 'Terms',
'TERMS_USE' => 'Terms of use',
'TEST_CONNECTION' => 'Test connection',
'THE_TEAM' => 'The team',
@@ -762,6 +782,10 @@ $lang = array_merge($lang, array(
'TOPIC_REVIEW' => 'Topic review',
'TOPIC_TITLE' => 'Topic title',
'TOPIC_UNAPPROVED' => 'This topic has not been approved.',
+ 'TOPIC_UNAPPROVED_FORUM' => array(
+ 1 => 'Topic awaiting approval',
+ 2 => 'Topics awaiting approval',
+ ),
'TOPIC_DELETED' => 'This topic has been deleted.',
'TOTAL_ATTACHMENTS' => 'Attachment(s)',
'TOTAL_LOGS' => array(
@@ -864,7 +888,6 @@ $lang = array_merge($lang, array(
'WEBSITE' => 'Website',
'WHOIS' => 'Whois',
'WHO_IS_ONLINE' => 'Who is online',
- 'WLM' => 'WLM',
'WRONG_PASSWORD' => 'You entered an incorrect password.',
'WRONG_DATA_COLOUR' => 'The colour value you entered is invalid.',
diff --git a/phpBB/language/en/email/admin_activate.txt b/phpBB/language/en/email/admin_activate.txt
index a53ab1269e..71faca70b2 100644
--- a/phpBB/language/en/email/admin_activate.txt
+++ b/phpBB/language/en/email/admin_activate.txt
@@ -7,7 +7,7 @@ The account owned by "{USERNAME}" has been deactivated or newly created, you sho
Use this link to view the user's profile:
{U_USER_DETAILS}
-Use this link to activate the account:
+You may activate the account immediately by clicking on this link:
{U_ACTIVATE}
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/forum_notify.txt b/phpBB/language/en/email/forum_notify.txt
index ccae82c862..1dfe8c652d 100644
--- a/phpBB/language/en/email/forum_notify.txt
+++ b/phpBB/language/en/email/forum_notify.txt
@@ -1,4 +1,5 @@
Subject: Forum post notification - "{FORUM_NAME}"
+List-Unsubscribe: <{U_STOP_WATCHING_FORUM}>
Hello {USERNAME},
diff --git a/phpBB/language/en/email/newtopic_notify.txt b/phpBB/language/en/email/newtopic_notify.txt
index b9416d8e40..0dfc9e43b4 100644
--- a/phpBB/language/en/email/newtopic_notify.txt
+++ b/phpBB/language/en/email/newtopic_notify.txt
@@ -1,4 +1,5 @@
Subject: New topic notification - "{FORUM_NAME}"
+List-Unsubscribe: <{U_STOP_WATCHING_FORUM}>
Hello {USERNAME},
@@ -6,6 +7,10 @@ You are receiving this notification because you are watching the forum "{FORUM_N
{U_FORUM}
+To see new topic directly, visit the following link:
+
+{U_TOPIC}
+
If you no longer wish to watch this forum you can either click the "Unsubscribe forum" link found in the forum above, or by clicking the following link:
{U_STOP_WATCHING_FORUM}
diff --git a/phpBB/language/en/email/report_pm.txt b/phpBB/language/en/email/report_pm.txt
index a101a014ff..a6b8086a9a 100644
--- a/phpBB/language/en/email/report_pm.txt
+++ b/phpBB/language/en/email/report_pm.txt
@@ -1,4 +1,4 @@
-Subject: Private Message report - "{TOPIC_TITLE}"
+Subject: Private Message report - "{SUBJECT}"
Hello {USERNAME},
diff --git a/phpBB/language/en/email/test.txt b/phpBB/language/en/email/test.txt
new file mode 100644
index 0000000000..91a737248b
--- /dev/null
+++ b/phpBB/language/en/email/test.txt
@@ -0,0 +1,9 @@
+Subject: phpBB is correctly configured to send emails
+
+Hello {USERNAME},
+
+Congratulations. If you received this email, phpBB is correctly configured to send emails.
+
+In case you require assistance, please visit the phpBB support forums - https://www.phpbb.com/community/
+
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_notify.txt b/phpBB/language/en/email/topic_notify.txt
index 20b86ee729..92bf85806e 100644
--- a/phpBB/language/en/email/topic_notify.txt
+++ b/phpBB/language/en/email/topic_notify.txt
@@ -1,4 +1,5 @@
Subject: Topic reply notification - "{TOPIC_TITLE}"
+List-Unsubscribe: <{U_STOP_WATCHING_TOPIC}>
Hello {USERNAME},
diff --git a/phpBB/language/en/help/bbcode.php b/phpBB/language/en/help/bbcode.php
new file mode 100644
index 0000000000..aa5bc1666a
--- /dev/null
+++ b/phpBB/language/en/help/bbcode.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * DO NOT CHANGE
+ */
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+if (empty($lang) || !is_array($lang))
+{
+ $lang = array();
+}
+
+$lang = array_merge($lang, array(
+ 'HELP_BBCODE_BLOCK_IMAGES' => 'Showing images in posts',
+ 'HELP_BBCODE_BLOCK_INTRO' => 'Introduction',
+ 'HELP_BBCODE_BLOCK_LINKS' => 'Creating Links',
+ 'HELP_BBCODE_BLOCK_LISTS' => 'Generating lists',
+ 'HELP_BBCODE_BLOCK_OTHERS' => 'Other matters',
+ 'HELP_BBCODE_BLOCK_QUOTES' => 'Quoting and outputting fixed-width text',
+ 'HELP_BBCODE_BLOCK_TEXT' => 'Text Formatting',
+
+ 'HELP_BBCODE_IMAGES_ATTACHMENT_ANSWER' => 'Attachments can now be placed in any part of a post by using the new <strong>[attachment=][/attachment]</strong> BBCode, if the attachments functionality has been enabled by a board administrator and if you are given the appropriate permissions to create attachments. Within the posting screen is a drop-down box (respectively a button) for placing attachments inline.',
+ 'HELP_BBCODE_IMAGES_ATTACHMENT_QUESTION' => 'Adding attachments into a post',
+ 'HELP_BBCODE_IMAGES_BASIC_ANSWER' => 'phpBB BBCode incorporates a tag for including images in your posts. Two very important things to remember when using this tag are: many users do not appreciate lots of images being shown in posts and secondly the image you display must already be available on the internet (it cannot exist only on your computer for example, unless you run a webserver!). To display an image you must surround the URL pointing to the image with <strong>[img][/img]</strong> tags. For example:<br /><br /><strong>[img]</strong>https://www.phpbb.com/theme/images/logos/blue/160x52.png<strong>[/img]</strong><br /><br />As noted in the URL section above you can wrap an image in a <strong>[url][/url]</strong> tag if you wish, e.g.<br /><br /><strong>[url=https://www.phpbb.com/][img]</strong>https://www.phpbb.com/theme/images/logos/blue/160x52.png<strong>[/img][/url]</strong><br /><br />would generate:<br /><br /><a href="https://www.phpbb.com/"><img src="https://www.phpbb.com/theme/images/logos/blue/160x52.png" alt="" /></a>',
+ 'HELP_BBCODE_IMAGES_BASIC_QUESTION' => 'Adding an image to a post',
+
+ 'HELP_BBCODE_INTRO_BBCODE_ANSWER' => 'BBCode is a special implementation of HTML. Whether you can actually use BBCode in your posts on the forum is determined by the administrator. In addition you can disable BBCode on a per post basis via the posting form. BBCode itself is similar in style to HTML, tags are enclosed in square brackets [ and ] rather than &lt; and &gt; and it offers greater control over what and how something is displayed. Depending on the template you are using you may find adding BBCode to your posts is made much easier through a clickable interface above the message area on the posting form. Even with this you may find the following guide useful.',
+ 'HELP_BBCODE_INTRO_BBCODE_QUESTION' => 'What is BBCode?',
+
+ 'HELP_BBCODE_LINKS_BASIC_ANSWER' => 'phpBB BBCode supports a number of ways of creating URIs (Uniform Resource Indicators) better known as URLs.<ul><li>The first of these uses the <strong>[url=][/url]</strong> tag, whatever you type after the = sign will cause the contents of that tag to act as a URL. For example to link to phpBB.com you could use:<br /><br /><strong>[url=https://www.phpbb.com/]</strong>Visit phpBB!<strong>[/url]</strong><br /><br />This would generate the following link, <a href="https://www.phpbb.com/">Visit phpBB!</a> Please notice that the link opens in the same window or a new window depending on the users browser preferences.</li><li>If you want the URL itself displayed as the link you can do this by simply using:<br /><br /><strong>[url]</strong>https://www.phpbb.com/<strong>[/url]</strong><br /><br />This would generate the following link, <a href="https://www.phpbb.com/">https://www.phpbb.com/</a></li><li>Additionally, phpBB features something called <i>Magic Links</i>, this will turn any syntactically correct URL into a link without you needing to specify any tags or even the leading http://. For example typing www.phpbb.com into your message will automatically lead to <a href="http://www.phpbb.com/">www.phpbb.com</a> being output when you view the message.</li><li>The same thing applies equally to email addresses, you can either specify an address explicitly for example:<br /><br /><strong>[email]</strong>no.one@domain.adr<strong>[/email]</strong><br /><br />which will output <a href="mailto:no.one@domain.adr">no.one@domain.adr</a> or you can just type no.one@domain.adr into your message and it will be automatically converted when you view.</li></ul>As with all the BBCode tags you can wrap URLs around any of the other tags such as <strong>[img][/img]</strong> (see next entry), <strong>[b][/b]</strong>, etc. As with the formatting tags it is up to you to ensure the correct open and close order is following, for example:<br /><br /><strong>[url=https://www.phpbb.com/][img]</strong>https://www.phpbb.com/theme/images/logos/blue/160x52.png<strong>[/url][/img]</strong><br /><br />is <span style="text-decoration: underline">not</span> correct which may lead to your post being deleted so take care.',
+ 'HELP_BBCODE_LINKS_BASIC_QUESTION' => 'Linking to another site',
+
+ 'HELP_BBCODE_LISTS_ORDERER_ANSWER' => 'The second type of list, an ordered list, gives you control over what is output before each item. To create an ordered list you use <strong>[list=1][/list]</strong> to create a numbered list or alternatively <strong>[list=a][/list]</strong> for an alphabetical list. As with the unordered list, items are specified using <strong>[*]</strong>. For example:<br /><br /><strong>[list=1]</strong><br /><strong>[*]</strong>Go to the shops<br /><strong>[*]</strong>Buy a new computer<br /><strong>[*]</strong>Swear at computer when it crashes<br /><strong>[/list]</strong><br /><br />will generate the following:<ol style="list-style-type: decimal;"><li>Go to the shops</li><li>Buy a new computer</li><li>Swear at computer when it crashes</li></ol>Whereas for an alphabetical list you would use:<br /><br /><strong>[list=a]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: lower-alpha"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol><br /><strong>[list=A]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: upper-alpha"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol><br /><strong>[list=i]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: lower-roman"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol><br /><strong>[list=I]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: upper-roman"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol>',
+ 'HELP_BBCODE_LISTS_ORDERER_QUESTION' => 'Creating an Ordered list',
+ 'HELP_BBCODE_LISTS_UNORDERER_ANSWER' => 'BBCode supports two types of lists, unordered and ordered. They are essentially the same as their HTML equivalents. An unordered list outputs each item in your list sequentially one after the other indenting each with a bullet character. To create an unordered list you use <strong>[list][/list]</strong> and define each item within the list using <strong>[*]</strong>. For example to list your favourite colours you could use:<br /><br /><strong>[list]</strong><br /><strong>[*]</strong>Red<br /><strong>[*]</strong>Blue<br /><strong>[*]</strong>Yellow<br /><strong>[/list]</strong><br /><br />This would generate the following list:<ul><li>Red</li><li>Blue</li><li>Yellow</li></ul><br />Alternatively you can specify the list’s bullet style using <strong>[list=disc][/list]</strong>, <strong>[list=circle][/list]</strong>, or <strong>[list=square][/list]</strong>.',
+ 'HELP_BBCODE_LISTS_UNORDERER_QUESTION' => 'Creating an Unordered list',
+
+ 'HELP_BBCODE_OTHERS_CUSTOM_ANSWER' => 'If you are an administrator on this board and have the proper permissions, you can add further BBCodes through the Custom BBCodes section.',
+ 'HELP_BBCODE_OTHERS_CUSTOM_QUESTION' => 'Can I add my own tags?',
+
+ 'HELP_BBCODE_QUOTES_CODE_ANSWER' => 'If you want to output a piece of code or in fact anything that requires a fixed width, e.g. Courier type font you should enclose the text in <strong>[code][/code]</strong> tags, e.g.<br /><br /><strong>[code]</strong>echo &quot;This is some code&quot;;<strong>[/code]</strong><br /><br />All formatting used within <strong>[code][/code]</strong> tags is retained when you later view it.',
+ 'HELP_BBCODE_QUOTES_CODE_QUESTION' => 'Outputting code or fixed width data',
+ 'HELP_BBCODE_QUOTES_TEXT_ANSWER' => 'There are two ways you can quote text, with a reference or without.<ul><li>When you utilise the Quote function to reply to a post on the board you should notice that the post text is added to the message window enclosed in a <strong>[quote=&quot;&quot;][/quote]</strong> block. This method allows you to quote with a reference to a person or whatever else you choose to put! For example to quote a piece of text Mr. Blobby wrote you would enter:<br /><br /><strong>[quote=&quot;Mr. Blobby&quot;]</strong>The text Mr. Blobby wrote would go here<strong>[/quote]</strong><br /><br />The resulting output will automatically add &quot;Mr. Blobby wrote:&quot; before the actual text. Remember you <strong>must</strong> include the quotation marks &quot;&quot; around the name you are quoting, they are not optional.</li><li>The second method allows you to blindly quote something. To utilise this enclose the text in <strong>[quote][/quote]</strong> tags. When you view the message it will simply show the text within a quotation block.</li></ul>',
+ 'HELP_BBCODE_QUOTES_TEXT_QUESTION' => 'Quoting text in replies',
+
+ 'HELP_BBCODE_TEXT_BASIC_ANSWER' => 'BBCode includes tags to allow you to quickly change the basic style of your text. This is achieved in the following ways: <ul><li>To make a piece of text bold enclose it in <strong>[b][/b]</strong>, e.g. <br /><br /><strong>[b]</strong>Hello<strong>[/b]</strong><br /><br />will become <strong>Hello</strong></li><li>For underlining use <strong>[u][/u]</strong>, for example:<br /><br /><strong>[u]</strong>Good Morning<strong>[/u]</strong><br /><br />becomes <span style="text-decoration: underline">Good Morning</span></li><li>To italicise text use <strong>[i][/i]</strong>, e.g.<br /><br />This is <strong>[i]</strong>Great!<strong>[/i]</strong><br /><br />would give This is <i>Great!</i></li></ul>',
+ 'HELP_BBCODE_TEXT_BASIC_QUESTION' => 'How to create bold, italic and underlined text',
+ 'HELP_BBCODE_TEXT_COLOR_ANSWER' => 'To alter the colour or size of your text the following tags can be used. Keep in mind that how the output appears will depend on the viewers browser and system: <ul><li>Changing the colour of text is achieved by wrapping it in <strong>[color=][/color]</strong>. You can specify either a recognised colour name (eg. red, blue, yellow, etc.) or the hexadecimal triplet alternative, e.g. #FFFFFF, #000000. For example, to create red text you could use:<br /><br /><strong>[color=red]</strong>Hello!<strong>[/color]</strong><br /><br />or<br /><br /><strong>[color=#FF0000]</strong>Hello!<strong>[/color]</strong><br /><br />Both will output <span style="color:red">Hello!</span></li><li>Changing the text size is achieved in a similar way using <strong>[size=][/size]</strong>. This tag is dependent on the template the user has selected but the recommended format is a numerical value representing the text size in percent, starting at 20 (very small) through to 200 (very large) by default. For example:<br /><br /><strong>[size=30]</strong>SMALL<strong>[/size]</strong><br /><br />will generally be <span style="font-size:30%;">SMALL</span><br /><br />whereas:<br /><br /><strong>[size=200]</strong>HUGE!<strong>[/size]</strong><br /><br />will be <span style="font-size:200%;">HUGE!</span></li></ul>',
+ 'HELP_BBCODE_TEXT_COLOR_QUESTION' => 'How to change the text colour or size',
+ 'HELP_BBCODE_TEXT_COMBINE_ANSWER' => 'Yes, of course you can, for example to get someones attention you may write:<br /><br /><strong>[size=200][color=red][b]</strong>LOOK AT ME!<strong>[/b][/color][/size]</strong><br /><br />this would output <span style="color:red;font-size:200%;"><strong>LOOK AT ME!</strong></span><br /><br />We don’t recommend you output lots of text that looks like this though! Remember it is up to you, the poster, to ensure tags are closed correctly. For example the following is incorrect:<br /><br /><strong>[b][u]</strong>This is wrong<strong>[/b][/u]</strong>',
+ 'HELP_BBCODE_TEXT_COMBINE_QUESTION' => 'Can I combine formatting tags?',
+));
diff --git a/phpBB/language/en/help/faq.php b/phpBB/language/en/help/faq.php
new file mode 100644
index 0000000000..6b165da0f8
--- /dev/null
+++ b/phpBB/language/en/help/faq.php
@@ -0,0 +1,186 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * DO NOT CHANGE
+ */
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+if (empty($lang) || !is_array($lang))
+{
+ $lang = array();
+}
+
+$lang = array_merge($lang, array(
+ 'HELP_FAQ_ATTACHMENTS_ALLOWED_ANSWER' => 'Each board administrator can allow or disallow certain attachment types. If you are unsure what is allowed to be uploaded, contact the board administrator for assistance.',
+ 'HELP_FAQ_ATTACHMENTS_ALLOWED_QUESTION' => 'What attachments are allowed on this board?',
+ 'HELP_FAQ_ATTACHMENTS_OWN_ANSWER' => 'To find your list of attachments that you have uploaded, go to your User Control Panel and follow the links to the attachments section.',
+ 'HELP_FAQ_ATTACHMENTS_OWN_QUESTION' => 'How do I find all my attachments?',
+
+ 'HELP_FAQ_BLOCK_ATTACHMENTS' => 'Attachments',
+ 'HELP_FAQ_BLOCK_BOOKMARKS' => 'Subscriptions and Bookmarks',
+ 'HELP_FAQ_BLOCK_FORMATTING' => 'Formatting and Topic Types',
+ 'HELP_FAQ_BLOCK_FRIENDS' => 'Friends and Foes',
+ 'HELP_FAQ_BLOCK_GROUPS' => 'User Levels and Groups',
+ 'HELP_FAQ_BLOCK_ISSUES' => 'phpBB Issues',
+ 'HELP_FAQ_BLOCK_LOGIN' => 'Login and Registration Issues',
+ 'HELP_FAQ_BLOCK_PMS' => 'Private Messaging',
+ 'HELP_FAQ_BLOCK_POSTING' => 'Posting Issues',
+ 'HELP_FAQ_BLOCK_SEARCH' => 'Searching the Forums',
+ 'HELP_FAQ_BLOCK_USERSETTINGS' => 'User Preferences and settings',
+
+ 'HELP_FAQ_BOOKMARKS_DIFFERENCE_ANSWER' => 'In phpBB 3.0, bookmarking topics worked much like bookmarking in a web browser. You were not alerted when there was an update. As of phpBB 3.1, bookmarking is more like subscribing to a topic. You can be notified when a bookmarked topic is updated. Subscribing, however, will notify you when there is an update to a topic or forum on the board. Notification options for bookmarks and subscriptions can be configured in the User Control Panel, under “Board preferencesâ€.',
+ 'HELP_FAQ_BOOKMARKS_DIFFERENCE_QUESTION' => 'What is the difference between bookmarking and subscribing?',
+ 'HELP_FAQ_BOOKMARKS_FORUM_ANSWER' => 'To subscribe to a specific forum, click the “Subscribe forum†link, at the bottom of page, upon entering the forum.',
+ 'HELP_FAQ_BOOKMARKS_FORUM_QUESTION' => 'How do I subscribe to specific forums?',
+ 'HELP_FAQ_BOOKMARKS_REMOVE_ANSWER' => 'To remove your subscriptions, go to your User Control Panel and follow the links to your subscriptions.',
+ 'HELP_FAQ_BOOKMARKS_REMOVE_QUESTION' => 'How do I remove my subscriptions?',
+ 'HELP_FAQ_BOOKMARKS_TOPIC_ANSWER' => 'You can bookmark or subscribe to a specific topic by clicking the appropriate link in the “Topic tools†menu, conveniently located near the top and bottom of a topic discussion.<br />Replying to a topic with the “Notify me when a reply is posted†option checked will also subscribe you to the topic.',
+ 'HELP_FAQ_BOOKMARKS_TOPIC_QUESTION' => 'How do I bookmark or subscribe to specific topics?',
+
+ 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_ANSWER' => 'Announcements often contain important information for the forum you are currently reading and you should read them whenever possible. Announcements appear at the top of every page in the forum to which they are posted. As with global announcements, announcement permissions are granted by the board administrator.',
+ 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_QUESTION' => 'What are announcements?',
+ 'HELP_FAQ_FORMATTING_BBOCDE_ANSWER' => 'BBCode is a special implementation of HTML, offering great formatting control on particular objects in a post. The use of BBCode is granted by the administrator, but it can also be disabled on a per post basis from the posting form. BBCode itself is similar in style to HTML, but tags are enclosed in square brackets [ and ] rather than &lt; and &gt;. For more information on BBCode see the guide which can be accessed from the posting page.',
+ 'HELP_FAQ_FORMATTING_BBOCDE_QUESTION' => 'What is BBCode?',
+ 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_ANSWER' => 'Global announcements contain important information and you should read them whenever possible. They will appear at the top of every forum and within your User Control Panel. Global announcement permissions are granted by the board administrator.',
+ 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_QUESTION' => 'What are global announcements?',
+ 'HELP_FAQ_FORMATTING_HTML_ANSWER' => 'No. It is not possible to post HTML on this board and have it rendered as HTML. Most formatting which can be carried out using HTML can be applied using BBCode instead.',
+ 'HELP_FAQ_FORMATTING_HTML_QUESTION' => 'Can I use HTML?',
+ 'HELP_FAQ_FORMATTING_ICONS_ANSWER' => 'Topic icons are author chosen images associated with posts to indicate their content. The ability to use topic icons depends on the permissions set by the board administrator.',
+ 'HELP_FAQ_FORMATTING_ICONS_QUESTION' => 'What are topic icons?',
+ 'HELP_FAQ_FORMATTING_IMAGES_ANSWER' => 'Yes, images can be shown in your posts. If the administrator has allowed attachments, you may be able to upload the image to the board. Otherwise, you must link to an image stored on a publicly accessible web server, e.g. http://www.example.com/my-picture.gif. You cannot link to pictures stored on your own PC (unless it is a publicly accessible server) nor images stored behind authentication mechanisms, e.g. hotmail or yahoo mailboxes, password protected sites, etc. To display the image use the BBCode [img] tag.',
+ 'HELP_FAQ_FORMATTING_IMAGES_QUESTION' => 'Can I post images?',
+ 'HELP_FAQ_FORMATTING_LOCKED_ANSWER' => 'Locked topics are topics where users can no longer reply and any poll it contained was automatically ended. Topics may be locked for many reasons and were set this way by either the forum moderator or board administrator. You may also be able to lock your own topics depending on the permissions you are granted by the board administrator.',
+ 'HELP_FAQ_FORMATTING_LOCKED_QUESTION' => 'What are locked topics?',
+ 'HELP_FAQ_FORMATTING_SMILIES_ANSWER' => 'Smilies, or Emoticons, are small images which can be used to express a feeling using a short code, e.g. :) denotes happy, while :( denotes sad. The full list of emoticons can be seen in the posting form. Try not to overuse smilies, however, as they can quickly render a post unreadable and a moderator may edit them out or remove the post altogether. The board administrator may also have set a limit to the number of smilies you may use within a post.',
+ 'HELP_FAQ_FORMATTING_SMILIES_QUESTION' => 'What are Smilies?',
+ 'HELP_FAQ_FORMATTING_STICKIES_ANSWER' => 'Sticky topics within the forum appear below announcements and only on the first page. They are often quite important so you should read them whenever possible. As with announcements and global announcements, sticky topic permissions are granted by the board administrator.',
+ 'HELP_FAQ_FORMATTING_STICKIES_QUESTION' => 'What are sticky topics?',
+
+ 'HELP_FAQ_FRIENDS_BASIC_ANSWER' => 'You can use these lists to organise other members of the board. Members added to your friends list will be listed within your User Control Panel for quick access to see their online status and to send them private messages. Subject to template support, posts from these users may also be highlighted. If you add a user to your foes list, any posts they make will be hidden by default.',
+ 'HELP_FAQ_FRIENDS_BASIC_QUESTION' => 'What are my Friends and Foes lists?',
+ 'HELP_FAQ_FRIENDS_MANAGE_ANSWER' => 'You can add users to your list in two ways. Within each user’s profile, there is a link to add them to either your Friend or Foe list. Alternatively, from your User Control Panel, you can directly add users by entering their member name. You may also remove users from your list using the same page.',
+ 'HELP_FAQ_FRIENDS_MANAGE_QUESTION' => 'How can I add / remove users to my Friends or Foes list?',
+
+ 'HELP_FAQ_GROUPS_ADMINISTRATORS_ANSWER' => 'Administrators are members assigned with the highest level of control over the entire board. These members can control all facets of board operation, including setting permissions, banning users, creating usergroups or moderators, etc., dependent upon the board founder and what permissions he or she has given the other administrators. They may also have full moderator capabilities in all forums, depending on the settings put forth by the board founder.',
+ 'HELP_FAQ_GROUPS_ADMINISTRATORS_QUESTION' => 'What are Administrators?',
+ 'HELP_FAQ_GROUPS_COLORS_ANSWER' => 'It is possible for the board administrator to assign a colour to the members of a usergroup to make it easy to identify the members of this group.',
+ 'HELP_FAQ_GROUPS_COLORS_QUESTION' => 'Why do some usergroups appear in a different colour?',
+ 'HELP_FAQ_GROUPS_DEFAULT_ANSWER' => 'If you are a member of more than one usergroup, your default is used to determine which group colour and group rank should be shown for you by default. The board administrator may grant you permission to change your default usergroup via your User Control Panel.',
+ 'HELP_FAQ_GROUPS_DEFAULT_QUESTION' => 'What is a “Default usergroup�',
+ 'HELP_FAQ_GROUPS_MODERATORS_ANSWER' => 'Moderators are individuals (or groups of individuals) who look after the forums from day to day. They have the authority to edit or delete posts and lock, unlock, move, delete and split topics in the forum they moderate. Generally, moderators are present to prevent users from going off-topic or posting abusive or offensive material.',
+ 'HELP_FAQ_GROUPS_MODERATORS_QUESTION' => 'What are Moderators?',
+ 'HELP_FAQ_GROUPS_TEAM_ANSWER' => 'This page provides you with a list of board staff, including board administrators and moderators and other details such as the forums they moderate.',
+ 'HELP_FAQ_GROUPS_TEAM_QUESTION' => 'What is “The team†link?',
+ 'HELP_FAQ_GROUPS_USERGROUPS_ANSWER' => 'Usergroups are groups of users that divide the community into manageable sections board administrators can work with. Each user can belong to several groups and each group can be assigned individual permissions. This provides an easy way for administrators to change permissions for many users at once, such as changing moderator permissions or granting users access to a private forum.',
+ 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_ANSWER' => 'You can view all usergroups via the “Usergroups†link within your User Control Panel. If you would like to join one, proceed by clicking the appropriate button. Not all groups have open access, however. Some may require approval to join, some may be closed and some may even have hidden memberships. If the group is open, you can join it by clicking the appropriate button. If a group requires approval to join you may request to join by clicking the appropriate button. The user group leader will need to approve your request and may ask why you want to join the group. Please do not harass a group leader if they reject your request; they will have their reasons.',
+ 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_QUESTION' => 'Where are the usergroups and how do I join one?',
+ 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_ANSWER' => 'A usergroup leader is usually assigned when usergroups are initially created by a board administrator. If you are interested in creating a usergroup, your first point of contact should be an administrator; try sending a private message.',
+ 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_QUESTION' => 'How do I become a usergroup leader?',
+ 'HELP_FAQ_GROUPS_USERGROUPS_QUESTION' => 'What are usergroups?',
+
+ 'HELP_FAQ_ISSUES_ADMIN_ANSWER' => 'All users of the board can use the “Contact us†form, if the option was enabled by the board administrator.<br />Members of the board can also use the “The team†link.',
+ 'HELP_FAQ_ISSUES_ADMIN_QUESTION' => 'How do I contact a board administrator?',
+ 'HELP_FAQ_ISSUES_FEATURE_ANSWER' => 'This software was written by and licensed through phpBB Limited. If you believe a feature needs to be added please visit the <a href="https://www.phpbb.com/ideas/">phpBB Ideas Centre</a>, where you can upvote existing ideas or suggest new features.',
+ 'HELP_FAQ_ISSUES_FEATURE_QUESTION' => 'Why isn’t X feature available?',
+ 'HELP_FAQ_ISSUES_LEGAL_ANSWER' => 'Any of the administrators listed on the “The team†page should be an appropriate point of contact for your complaints. If this still gets no response then you should contact the owner of the domain (do a <a href="http://www.google.com/search?q=whois">whois lookup</a>) or, if this is running on a free service (e.g. Yahoo!, free.fr, f2s.com, etc.), the management or abuse department of that service. Please note that the phpBB Limited has <strong>absolutely no jurisdiction</strong> and cannot in any way be held liable over how, where or by whom this board is used. Do not contact the phpBB Limited in relation to any legal (cease and desist, liable, defamatory comment, etc.) matter <strong>not directly related</strong> to the phpBB.com website or the discrete software of phpBB itself. If you do email phpBB Limited <strong>about any third party</strong> use of this software then you should expect a terse response or no response at all.',
+ 'HELP_FAQ_ISSUES_LEGAL_QUESTION' => 'Who do I contact about abusive and/or legal matters related to this board?',
+ 'HELP_FAQ_ISSUES_WHOIS_PHPBB_ANSWER' => 'This software (in its unmodified form) is produced, released and is copyright <a href="https://www.phpbb.com/">phpBB Limited</a>. It is made available under the GNU General Public License, version 2 (GPL-2.0) and may be freely distributed. See <a href="https://www.phpbb.com/about/">About phpBB</a> for more details.',
+ 'HELP_FAQ_ISSUES_WHOIS_PHPBB_QUESTION' => 'Who wrote this bulletin board?',
+
+ 'HELP_FAQ_LOGIN_AUTO_LOGOUT_ANSWER' => 'If you do not check the <em>Remember me</em> box when you login, the board will only keep you logged in for a preset time. This prevents misuse of your account by anyone else. To stay logged in, check the <em>Remember me</em> box during login. This is not recommended if you access the board from a shared computer, e.g. library, internet cafe, university computer lab, etc. If you do not see this checkbox, it means a board administrator has disabled this feature.',
+ 'HELP_FAQ_LOGIN_AUTO_LOGOUT_QUESTION' => 'Why do I get logged off automatically?',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANSWER' => 'There are several reasons why this could occur. First, ensure your username and password are correct. If they are, contact a board administrator to make sure you haven’t been banned. It is also possible the website owner has a configuration error on their end, and they would need to fix it.',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_ANSWER' => 'It is possible an administrator has deactivated or deleted your account for some reason. Also, many boards periodically remove users who have not posted for a long time to reduce the size of the database. If this has happened, try registering again and being more involved in discussions.',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_QUESTION' => 'I registered in the past but cannot login any more?!',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_QUESTION' => 'Why can’t I login?',
+ 'HELP_FAQ_LOGIN_CANNOT_REGISTER_ANSWER' => 'It is possible a board administrator has disabled registration to prevent new visitors from signing up. A board administrator could have also banned your IP address or disallowed the username you are attempting to register. Contact a board administrator for assistance.',
+ 'HELP_FAQ_LOGIN_CANNOT_REGISTER_QUESTION' => 'Why can’t I register?',
+ 'HELP_FAQ_LOGIN_COPPA_ANSWER' => 'COPPA, or the Children’s Online Privacy Protection Act of 1998, is a law in the United States requiring websites which can potentially collect information from minors under the age of 13 to have written parental consent or some other method of legal guardian acknowledgment, allowing the collection of personally identifiable information from a minor under the age of 13. If you are unsure if this applies to you as someone trying to register or to the website you are trying to register on, contact legal counsel for assistance. Please note that phpBB Limited and the owners of this board cannot provide legal advice and is not a point of contact for legal concerns of any kind, except as outlined in question “Who do I contact about abusive and/or legal matters related to this board?â€.',
+ 'HELP_FAQ_LOGIN_COPPA_QUESTION' => 'What is COPPA?',
+ 'HELP_FAQ_LOGIN_DELETE_COOKIES_ANSWER' => '“Delete cookies†deletes the cookies created by phpBB which keep you authenticated and logged into the board. Cookies also provide functions such as read tracking if they have been enabled by a board administrator. If you are having login or logout problems, deleting board cookies may help.',
+ 'HELP_FAQ_LOGIN_DELETE_COOKIES_QUESTION' => 'What does the “Delete cookies†do?',
+ 'HELP_FAQ_LOGIN_LOST_PASSWORD_ANSWER' => 'Don’t panic! While your password cannot be retrieved, it can easily be reset. Visit the login page and click <em>I forgot my password</em>. Follow the instructions and you should be able to log in again shortly.<br />However, if you are not able to reset your password, contact a board administrator.',
+ 'HELP_FAQ_LOGIN_LOST_PASSWORD_QUESTION' => 'I’ve lost my password!',
+ 'HELP_FAQ_LOGIN_REGISTER_ANSWER' => 'You may not have to, it is up to the administrator of the board as to whether you need to register in order to post messages. However; registration will give you access to additional features not available to guest users such as definable avatar images, private messaging, emailing of fellow users, usergroup subscription, etc. It only takes a few moments to register so it is recommended you do so.',
+ 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_ANSWER' => 'First, check your username and password. If they are correct, then one of two things may have happened. If COPPA support is enabled and you specified being under 13 years old during registration, you will have to follow the instructions you received. Some boards will also require new registrations to be activated, either by yourself or by an administrator before you can logon; this information was present during registration. If you were sent an email, follow the instructions. If you did not receive an email, you may have provided an incorrect email address or the email may have been picked up by a spam filer. If you are sure the email address you provided is correct, try contacting an administrator.',
+ 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_QUESTION' => 'I registered but cannot login!',
+ 'HELP_FAQ_LOGIN_REGISTER_QUESTION' => 'Why do I need to register?',
+
+ 'HELP_FAQ_PMS_CANNOT_SEND_ANSWER' => 'There are three reasons for this; you are not registered and/or not logged on, the board administrator has disabled private messaging for the entire board, or the board administrator has prevented you from sending messages. Contact a board administrator for more information.',
+ 'HELP_FAQ_PMS_CANNOT_SEND_QUESTION' => 'I cannot send private messages!',
+ 'HELP_FAQ_PMS_SPAM_ANSWER' => 'We are sorry to hear that. The email form feature of this board includes safeguards to try and track users who send such posts, so email the board administrator with a full copy of the email you received. It is very important that this includes the headers that contain the details of the user that sent the email. The board administrator can then take action.',
+ 'HELP_FAQ_PMS_SPAM_QUESTION' => 'I have received a spamming or abusive email from someone on this board!',
+ 'HELP_FAQ_PMS_UNWANTED_ANSWER' => 'You can automatically delete private messages from a user by using message rules within your User Control Panel. If you are receiving abusive private messages from a particular user, report the messages to the moderators; they have the power to prevent a user from sending private messages.',
+ 'HELP_FAQ_PMS_UNWANTED_QUESTION' => 'I keep getting unwanted private messages!',
+
+ 'HELP_FAQ_POSTING_BUMP_ANSWER' => 'By clicking the “Bump topic†link when you are viewing it, you can “bump†the topic to the top of the forum on the first page. However, if you do not see this, then topic bumping may be disabled or the time allowance between bumps has not yet been reached. It is also possible to bump the topic simply by replying to it, however, be sure to follow the board rules when doing so.',
+ 'HELP_FAQ_POSTING_BUMP_QUESTION' => 'How do I bump my topic?',
+ 'HELP_FAQ_POSTING_CREATE_ANSWER' => 'To post a new topic in a forum, click "New Topic". To post a reply to a topic, click "Post Reply". You may need to register before you can post a message. A list of your permissions in each forum is available at the bottom of the forum and topic screens. Example: You can post new topics, You can post attachments, etc.',
+ 'HELP_FAQ_POSTING_CREATE_QUESTION' => 'How do I create a new topic or post a reply?',
+ 'HELP_FAQ_POSTING_DRAFT_ANSWER' => 'This allows you to save drafts to be completed and submitted at a later date. To reload a saved draft, visit the User Control Panel.',
+ 'HELP_FAQ_POSTING_DRAFT_QUESTION' => 'What is the “Save†button for in topic posting?',
+ 'HELP_FAQ_POSTING_EDIT_DELETE_ANSWER' => 'Unless you are a board administrator or moderator, you can only edit or delete your own posts. You can edit a post by clicking the edit button for the relevant post, sometimes for only a limited time after the post was made. If someone has already replied to the post, you will find a small piece of text output below the post when you return to the topic which lists the number of times you edited it along with the date and time. This will only appear if someone has made a reply; it will not appear if a moderator or administrator edited the post, though they may leave a note as to why they’ve edited the post at their own discretion. Please note that normal users cannot delete a post once someone has replied.',
+ 'HELP_FAQ_POSTING_EDIT_DELETE_QUESTION' => 'How do I edit or delete a post?',
+ 'HELP_FAQ_POSTING_FORUM_RESTRICTED_ANSWER' => 'Some forums may be limited to certain users or groups. To view, read, post or perform another action you may need special permissions. Contact a moderator or board administrator to grant you access.',
+ 'HELP_FAQ_POSTING_FORUM_RESTRICTED_QUESTION' => 'Why can’t I access a forum?',
+ 'HELP_FAQ_POSTING_NO_ATTACHMENTS_ANSWER' => 'Attachment permissions are granted on a per forum, per group, or per user basis. The board administrator may not have allowed attachments to be added for the specific forum you are posting in, or perhaps only certain groups can post attachments. Contact the board administrator if you are unsure about why you are unable to add attachments.',
+ 'HELP_FAQ_POSTING_NO_ATTACHMENTS_QUESTION' => 'Why can’t I add attachments?',
+ 'HELP_FAQ_POSTING_POLL_ADD_ANSWER' => 'The limit for poll options is set by the board administrator. If you feel you need to add more options to your poll than the allowed amount, contact the board administrator.',
+ 'HELP_FAQ_POSTING_POLL_ADD_QUESTION' => 'Why can’t I add more poll options?',
+ 'HELP_FAQ_POSTING_POLL_CREATE_ANSWER' => 'When posting a new topic or editing the first post of a topic, click the “Poll creation†tab below the main posting form; if you cannot see this, you do not have appropriate permissions to create polls. Enter a title and at least two options in the appropriate fields, making sure each option is on a separate line in the textarea. You can also set the number of options users may select during voting under “Options per userâ€, a time limit in days for the poll (0 for infinite duration) and lastly the option to allow users to amend their votes.',
+ 'HELP_FAQ_POSTING_POLL_CREATE_QUESTION' => 'How do I create a poll?',
+ 'HELP_FAQ_POSTING_POLL_EDIT_ANSWER' => 'As with posts, polls can only be edited by the original poster, a moderator or an administrator. To edit a poll, click to edit the first post in the topic; this always has the poll associated with it. If no one has cast a vote, users can delete the poll or edit any poll option. However, if members have already placed votes, only moderators or administrators can edit or delete it. This prevents the poll’s options from being changed mid-way through a poll.',
+ 'HELP_FAQ_POSTING_POLL_EDIT_QUESTION' => 'How do I edit or delete a poll?',
+ 'HELP_FAQ_POSTING_QUEUE_ANSWER' => 'The board administrator may have decided that posts in the forum you are posting to require review before submission. It is also possible that the administrator has placed you in a group of users whose posts require review before submission. Please contact the board administrator for further details.',
+ 'HELP_FAQ_POSTING_QUEUE_QUESTION' => 'Why does my post need to be approved?',
+ 'HELP_FAQ_POSTING_REPORT_ANSWER' => 'If the board administrator has allowed it, you should see a button for reporting posts next to the post you wish to report. Clicking this will walk you through the steps necessary to report the post.',
+ 'HELP_FAQ_POSTING_REPORT_QUESTION' => 'How can I report posts to a moderator?',
+ 'HELP_FAQ_POSTING_SIGNATURE_ANSWER' => 'To add a signature to a post you must first create one via your User Control Panel. Once created, you can check the <em>Attach a signature</em> box on the posting form to add your signature. You can also add a signature by default to all your posts by checking the appropriate radio button in the User Control Panel. If you do so, you can still prevent a signature being added to individual posts by un-checking the add signature box within the posting form.',
+ 'HELP_FAQ_POSTING_SIGNATURE_QUESTION' => 'How do I add a signature to my post?',
+ 'HELP_FAQ_POSTING_WARNING_ANSWER' => 'Each board administrator has their own set of rules for their site. If you have broken a rule, you may be issued a warning. Please note that this is the board administrator’s decision, and the phpBB Limited has nothing to do with the warnings on the given site. Contact the board administrator if you are unsure about why you were issued a warning.',
+ 'HELP_FAQ_POSTING_WARNING_QUESTION' => 'Why did I receive a warning?',
+
+ 'HELP_FAQ_SEARCH_BLANK_ANSWER' => 'Your search returned too many results for the webserver to handle. Use “Advanced search†and be more specific in the terms used and forums that are to be searched.',
+ 'HELP_FAQ_SEARCH_BLANK_QUESTION' => 'Why does my search return a blank page!?',
+ 'HELP_FAQ_SEARCH_FORUM_ANSWER' => 'Enter a search term in the search box located on the index, forum or topic pages. Advanced search can be accessed by clicking the “Advance Search†link which is available on all pages on the forum. How to access the search may depend on the style used.',
+ 'HELP_FAQ_SEARCH_FORUM_QUESTION' => 'How can I search a forum or forums?',
+ 'HELP_FAQ_SEARCH_MEMBERS_ANSWER' => 'Visit to the “Members†page and click the “Find a member†link.',
+ 'HELP_FAQ_SEARCH_MEMBERS_QUESTION' => 'How do I search for members?',
+ 'HELP_FAQ_SEARCH_NO_RESULT_ANSWER' => 'Your search was probably too vague and included many common terms which are not indexed by phpBB. Be more specific and use the options available within Advanced search.',
+ 'HELP_FAQ_SEARCH_NO_RESULT_QUESTION' => 'Why does my search return no results?',
+ 'HELP_FAQ_SEARCH_OWN_ANSWER' => 'Your own posts can be retrieved either by clicking the “Show your posts†link within the User Control Panel or by clicking the “Search user’s posts†link via your own profile page or by clicking the “Quick links†menu at the top of the board. To search for your topics, use the Advanced search page and fill in the various options appropriately.',
+ 'HELP_FAQ_SEARCH_OWN_QUESTION' => 'How can I find my own posts and topics?',
+
+ 'HELP_FAQ_USERSETTINGS_AVATAR_ANSWER' => 'There are two images which may appear along with a username when viewing posts. One of them may be an image associated with your rank, generally in the form of stars, blocks or dots, indicating how many posts you have made or your status on the board. Another, usually larger, image is known as an avatar and is generally unique or personal to each user.',
+ 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_ANSWER' => 'Within your User Control Panel, under “Profile†you can add an avatar by using one of the four following methods: Gravatar, Gallery, Remote or Upload. It is up to the board administrator to enable avatars and to choose the way in which avatars can be made available. If you are unable to use avatars, contact a board administrator.',
+ 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_QUESTION' => 'How do I display an avatar?',
+ 'HELP_FAQ_USERSETTINGS_AVATAR_QUESTION' => 'What are the images next to my username?',
+ 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_ANSWER' => 'If you are a registered user, all your settings are stored in the board database. To alter them, visit your User Control Panel; a link can usually be found by clicking on your username at the top of board pages. This system will allow you to change all your settings and preferences.',
+ 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_QUESTION' => 'How do I change my settings?',
+ 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_ANSWER' => 'Only registered users can send email to other users via the built-in email form, and only if the administrator has enabled this feature. This is to prevent malicious use of the email system by anonymous users.',
+ 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_QUESTION' => 'When I click the email link for a user it asks me to login?',
+ 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_ANSWER' => 'Within your User Control Panel, under “Board preferencesâ€, you will find the option <em>Hide your online status</em>. Enable this option and you will only appear to the administrators, moderators and yourself. You will be counted as a hidden user.',
+ 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_QUESTION' => 'How do I prevent my username appearing in the online user listings?',
+ 'HELP_FAQ_USERSETTINGS_LANGUAGE_ANSWER' => 'Either the administrator has not installed your language or nobody has translated this board into your language. Try asking a board administrator if they can install the language pack you need. If the language pack does not exist, feel free to create a new translation. More information can be found at the <a href="https://www.phpbb.com/">phpBB</a>&reg; website.',
+ 'HELP_FAQ_USERSETTINGS_LANGUAGE_QUESTION' => 'My language is not in the list!',
+ 'HELP_FAQ_USERSETTINGS_RANK_ANSWER' => 'Ranks, which appear below your username, indicate the number of posts you have made or identify certain users, e.g. moderators and administrators. In general, you cannot directly change the wording of any board ranks as they are set by the board administrator. Please do not abuse the board by posting unnecessarily just to increase your rank. Most boards will not tolerate this and the moderator or administrator will simply lower your post count.',
+ 'HELP_FAQ_USERSETTINGS_RANK_QUESTION' => 'What is my rank and how do I change it?',
+ 'HELP_FAQ_USERSETTINGS_SERVERTIME_ANSWER' => 'If you are sure you have set the timezone correctly and the time is still incorrect, then the time stored on the server clock is incorrect. Please notify an administrator to correct the problem.',
+ 'HELP_FAQ_USERSETTINGS_SERVERTIME_QUESTION' => 'I changed the timezone and the time is still wrong!',
+ 'HELP_FAQ_USERSETTINGS_TIMEZONE_ANSWER' => 'It is possible the time displayed is from a timezone different from the one you are in. If this is the case, visit your User Control Panel and change your timezone to match your particular area, e.g. London, Paris, New York, Sydney, etc. Please note that changing the timezone, like most settings, can only be done by registered users. If you are not registered, this is a good time to do so.',
+ 'HELP_FAQ_USERSETTINGS_TIMEZONE_QUESTION' => 'The times are not correct!',
+));
diff --git a/phpBB/language/en/help_bbcode.php b/phpBB/language/en/help_bbcode.php
deleted file mode 100644
index 800ce3dfb7..0000000000
--- a/phpBB/language/en/help_bbcode.php
+++ /dev/null
@@ -1,115 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-// DEVELOPERS PLEASE NOTE
-//
-// All language files should use UTF-8 as their encoding and the files must not contain a BOM.
-//
-// Placeholders can now contain order information, e.g. instead of
-// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows
-// translators to re-order the output of data while ensuring it remains correct
-//
-// You do not need this where single placeholders are used, e.g. 'Message %d' is fine
-// equally where a string contains only two placeholders which are used to wrap text
-// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
-
-$help = array(
- array(
- 0 => '--',
- 1 => 'Introduction'
- ),
- array(
- 0 => 'What is BBCode?',
- 1 => 'BBCode is a special implementation of HTML. Whether you can actually use BBCode in your posts on the forum is determined by the administrator. In addition you can disable BBCode on a per post basis via the posting form. BBCode itself is similar in style to HTML, tags are enclosed in square brackets [ and ] rather than &lt; and &gt; and it offers greater control over what and how something is displayed. Depending on the template you are using you may find adding BBCode to your posts is made much easier through a clickable interface above the message area on the posting form. Even with this you may find the following guide useful.'
- ),
- array(
- 0 => '--',
- 1 => 'Text Formatting'
- ),
- array(
- 0 => 'How to create bold, italic and underlined text',
- 1 => 'BBCode includes tags to allow you to quickly change the basic style of your text. This is achieved in the following ways: <ul><li>To make a piece of text bold enclose it in <strong>[b][/b]</strong>, e.g. <br /><br /><strong>[b]</strong>Hello<strong>[/b]</strong><br /><br />will become <strong>Hello</strong></li><li>For underlining use <strong>[u][/u]</strong>, for example:<br /><br /><strong>[u]</strong>Good Morning<strong>[/u]</strong><br /><br />becomes <span style="text-decoration: underline">Good Morning</span></li><li>To italicise text use <strong>[i][/i]</strong>, e.g.<br /><br />This is <strong>[i]</strong>Great!<strong>[/i]</strong><br /><br />would give This is <i>Great!</i></li></ul>'
- ),
- array(
- 0 => 'How to change the text colour or size',
- 1 => 'To alter the colour or size of your text the following tags can be used. Keep in mind that how the output appears will depend on the viewers browser and system: <ul><li>Changing the colour of text is achieved by wrapping it in <strong>[color=][/color]</strong>. You can specify either a recognised colour name (eg. red, blue, yellow, etc.) or the hexadecimal triplet alternative, e.g. #FFFFFF, #000000. For example, to create red text you could use:<br /><br /><strong>[color=red]</strong>Hello!<strong>[/color]</strong><br /><br />or<br /><br /><strong>[color=#FF0000]</strong>Hello!<strong>[/color]</strong><br /><br />Both will output <span style="color:red">Hello!</span></li><li>Changing the text size is achieved in a similar way using <strong>[size=][/size]</strong>. This tag is dependent on the template the user has selected but the recommended format is a numerical value representing the text size in percent, starting at 20 (very small) through to 200 (very large) by default. For example:<br /><br /><strong>[size=30]</strong>SMALL<strong>[/size]</strong><br /><br />will generally be <span style="font-size:30%;">SMALL</span><br /><br />whereas:<br /><br /><strong>[size=200]</strong>HUGE!<strong>[/size]</strong><br /><br />will be <span style="font-size:200%;">HUGE!</span></li></ul>'
- ),
- array(
- 0 => 'Can I combine formatting tags?',
- 1 => 'Yes, of course you can, for example to get someones attention you may write:<br /><br /><strong>[size=200][color=red][b]</strong>LOOK AT ME!<strong>[/b][/color][/size]</strong><br /><br />this would output <span style="color:red;font-size:200%;"><strong>LOOK AT ME!</strong></span><br /><br />We don’t recommend you output lots of text that looks like this though! Remember it is up to you, the poster, to ensure tags are closed correctly. For example the following is incorrect:<br /><br /><strong>[b][u]</strong>This is wrong<strong>[/b][/u]</strong>'
- ),
- array(
- 0 => '--',
- 1 => 'Quoting and outputting fixed-width text'
- ),
- array(
- 0 => 'Quoting text in replies',
- 1 => 'There are two ways you can quote text, with a reference or without.<ul><li>When you utilise the Quote function to reply to a post on the board you should notice that the post text is added to the message window enclosed in a <strong>[quote=&quot;&quot;][/quote]</strong> block. This method allows you to quote with a reference to a person or whatever else you choose to put! For example to quote a piece of text Mr. Blobby wrote you would enter:<br /><br /><strong>[quote=&quot;Mr. Blobby&quot;]</strong>The text Mr. Blobby wrote would go here<strong>[/quote]</strong><br /><br />The resulting output will automatically add &quot;Mr. Blobby wrote:&quot; before the actual text. Remember you <strong>must</strong> include the quotation marks &quot;&quot; around the name you are quoting, they are not optional.</li><li>The second method allows you to blindly quote something. To utilise this enclose the text in <strong>[quote][/quote]</strong> tags. When you view the message it will simply show the text within a quotation block.</li></ul>'
- ),
- array(
- 0 => 'Outputting code or fixed width data',
- 1 => 'If you want to output a piece of code or in fact anything that requires a fixed width, e.g. Courier type font you should enclose the text in <strong>[code][/code]</strong> tags, e.g.<br /><br /><strong>[code]</strong>echo &quot;This is some code&quot;;<strong>[/code]</strong><br /><br />All formatting used within <strong>[code][/code]</strong> tags is retained when you later view it. PHP syntax highlighting can be enabled using <strong>[code=php][/code]</strong> and is recommended when posting PHP code samples as it improves readability.'
- ),
- array(
- 0 => '--',
- 1 => 'Generating lists'
- ),
- array(
- 0 => 'Creating an Unordered list',
- 1 => 'BBCode supports two types of lists, unordered and ordered. They are essentially the same as their HTML equivalents. An unordered list outputs each item in your list sequentially one after the other indenting each with a bullet character. To create an unordered list you use <strong>[list][/list]</strong> and define each item within the list using <strong>[*]</strong>. For example to list your favourite colours you could use:<br /><br /><strong>[list]</strong><br /><strong>[*]</strong>Red<br /><strong>[*]</strong>Blue<br /><strong>[*]</strong>Yellow<br /><strong>[/list]</strong><br /><br />This would generate the following list:<ul><li>Red</li><li>Blue</li><li>Yellow</li></ul><br />Alternatively you can specify the list’s bullet style using <strong>[list=disc][/list]</strong>, <strong>[list=circle][/list]</strong>, or <strong>[list=square][/list]</strong>.'
- ),
- array(
- 0 => 'Creating an Ordered list',
- 1 => 'The second type of list, an ordered list, gives you control over what is output before each item. To create an ordered list you use <strong>[list=1][/list]</strong> to create a numbered list or alternatively <strong>[list=a][/list]</strong> for an alphabetical list. As with the unordered list, items are specified using <strong>[*]</strong>. For example:<br /><br /><strong>[list=1]</strong><br /><strong>[*]</strong>Go to the shops<br /><strong>[*]</strong>Buy a new computer<br /><strong>[*]</strong>Swear at computer when it crashes<br /><strong>[/list]</strong><br /><br />will generate the following:<ol style="list-style-type: decimal;"><li>Go to the shops</li><li>Buy a new computer</li><li>Swear at computer when it crashes</li></ol>Whereas for an alphabetical list you would use:<br /><br /><strong>[list=a]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: lower-alpha"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol><br /><strong>[list=A]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: upper-alpha"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol><br /><strong>[list=i]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: lower-roman"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol><br /><strong>[list=I]</strong><br /><strong>[*]</strong>The first possible answer<br /><strong>[*]</strong>The second possible answer<br /><strong>[*]</strong>The third possible answer<br /><strong>[/list]</strong><br /><br />giving<ol style="list-style-type: upper-roman"><li>The first possible answer</li><li>The second possible answer</li><li>The third possible answer</li></ol>'
- ),
- // This block will switch the FAQ-Questions to the second template column
- array(
- 0 => '--',
- 1 => '--'
- ),
- array(
- 0 => '--',
- 1 => 'Creating Links'
- ),
- array(
- 0 => 'Linking to another site',
- 1 => 'phpBB BBCode supports a number of ways of creating URIs (Uniform Resource Indicators) better known as URLs.<ul><li>The first of these uses the <strong>[url=][/url]</strong> tag, whatever you type after the = sign will cause the contents of that tag to act as a URL. For example to link to phpBB.com you could use:<br /><br /><strong>[url=https://www.phpbb.com/]</strong>Visit phpBB!<strong>[/url]</strong><br /><br />This would generate the following link, <a href="https://www.phpbb.com/">Visit phpBB!</a> Please notice that the link opens in the same window or a new window depending on the users browser preferences.</li><li>If you want the URL itself displayed as the link you can do this by simply using:<br /><br /><strong>[url]</strong>https://www.phpbb.com/<strong>[/url]</strong><br /><br />This would generate the following link, <a href="https://www.phpbb.com/">https://www.phpbb.com/</a></li><li>Additionally, phpBB features something called <i>Magic Links</i>, this will turn any syntactically correct URL into a link without you needing to specify any tags or even the leading http://. For example typing www.phpbb.com into your message will automatically lead to <a href="http://www.phpbb.com/">www.phpbb.com</a> being output when you view the message.</li><li>The same thing applies equally to email addresses, you can either specify an address explicitly for example:<br /><br /><strong>[email]</strong>no.one@domain.adr<strong>[/email]</strong><br /><br />which will output <a href="mailto:no.one@domain.adr">no.one@domain.adr</a> or you can just type no.one@domain.adr into your message and it will be automatically converted when you view.</li></ul>As with all the BBCode tags you can wrap URLs around any of the other tags such as <strong>[img][/img]</strong> (see next entry), <strong>[b][/b]</strong>, etc. As with the formatting tags it is up to you to ensure the correct open and close order is following, for example:<br /><br /><strong>[url=https://www.phpbb.com/][img]</strong>https://www.phpbb.com/theme/images/logos/blue/160x52.png<strong>[/url][/img]</strong><br /><br />is <span style="text-decoration: underline">not</span> correct which may lead to your post being deleted so take care.'
- ),
- array(
- 0 => '--',
- 1 => 'Showing images in posts'
- ),
- array(
- 0 => 'Adding an image to a post',
- 1 => 'phpBB BBCode incorporates a tag for including images in your posts. Two very important things to remember when using this tag are: many users do not appreciate lots of images being shown in posts and secondly the image you display must already be available on the internet (it cannot exist only on your computer for example, unless you run a webserver!). To display an image you must surround the URL pointing to the image with <strong>[img][/img]</strong> tags. For example:<br /><br /><strong>[img]</strong>https://www.phpbb.com/theme/images/logos/blue/160x52.png<strong>[/img]</strong><br /><br />As noted in the URL section above you can wrap an image in a <strong>[url][/url]</strong> tag if you wish, e.g.<br /><br /><strong>[url=https://www.phpbb.com/][img]</strong>https://www.phpbb.com/theme/images/logos/blue/160x52.png<strong>[/img][/url]</strong><br /><br />would generate:<br /><br /><a href="https://www.phpbb.com/"><img src="https://www.phpbb.com/theme/images/logos/blue/160x52.png" alt="" /></a>'
- ),
- array(
- 0 => 'Adding attachments into a post',
- 1 => 'Attachments can now be placed in any part of a post by using the new <strong>[attachment=][/attachment]</strong> BBCode, if the attachments functionality has been enabled by a board administrator and if you are given the appropriate permissions to create attachments. Within the posting screen is a drop-down box (respectively a button) for placing attachments inline.'
- ),
- array(
- 0 => '--',
- 1 => 'Other matters'
- ),
- array(
- 0 => 'Can I add my own tags?',
- 1 => 'If you are an administrator on this board and have the proper permissions, you can add further BBCodes through the Custom BBCodes section.'
- ),
-);
diff --git a/phpBB/language/en/help_faq.php b/phpBB/language/en/help_faq.php
deleted file mode 100644
index 8f08ac1cd3..0000000000
--- a/phpBB/language/en/help_faq.php
+++ /dev/null
@@ -1,355 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-/**
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-// DEVELOPERS PLEASE NOTE
-//
-// All language files should use UTF-8 as their encoding and the files must not contain a BOM.
-//
-// Placeholders can now contain order information, e.g. instead of
-// 'Page %s of %s' you can (and should) write 'Page %1$s of %2$s', this allows
-// translators to re-order the output of data while ensuring it remains correct
-//
-// You do not need this where single placeholders are used, e.g. 'Message %d' is fine
-// equally where a string contains only two placeholders which are used to wrap text
-// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
-
-$help = array(
- array(
- 0 => '--',
- 1 => 'Login and Registration Issues'
- ),
- array(
- 0 => 'Why do I need to register?',
- 1 => 'You may not have to, it is up to the administrator of the board as to whether you need to register in order to post messages. However; registration will give you access to additional features not available to guest users such as definable avatar images, private messaging, emailing of fellow users, usergroup subscription, etc. It only takes a few moments to register so it is recommended you do so.'
- ),
- array(
- 0 => 'What is COPPA?',
- 1 => 'COPPA, or the Children’s Online Privacy Protection Act of 1998, is a law in the United States requiring websites which can potentially collect information from minors under the age of 13 to have written parental consent or some other method of legal guardian acknowledgment, allowing the collection of personally identifiable information from a minor under the age of 13. If you are unsure if this applies to you as someone trying to register or to the website you are trying to register on, contact legal counsel for assistance. Please note that phpBB Limited and the owners of this board cannot provide legal advice and is not a point of contact for legal concerns of any kind, except as outlined in question “Who do I contact about abusive and/or legal matters related to this board?â€.',
- ),
- array(
- 0 => 'Why can’t I register?',
- 1 => 'It is possible a board administrator has disabled registration to prevent new visitors from signing up. A board administrator could have also banned your IP address or disallowed the username you are attempting to register. Contact a board administrator for assistance.',
- ),
- array(
- 0 => 'I registered but cannot login!',
- 1 => 'First, check your username and password. If they are correct, then one of two things may have happened. If COPPA support is enabled and you specified being under 13 years old during registration, you will have to follow the instructions you received. Some boards will also require new registrations to be activated, either by yourself or by an administrator before you can logon; this information was present during registration. If you were sent an email, follow the instructions. If you did not receive an email, you may have provided an incorrect email address or the email may have been picked up by a spam filer. If you are sure the email address you provided is correct, try contacting an administrator.'
- ),
- array(
- 0 => 'Why can’t I login?',
- 1 => 'There are several reasons why this could occur. First, ensure your username and password are correct. If they are, contact a board administrator to make sure you haven’t been banned. It is also possible the website owner has a configuration error on their end, and they would need to fix it.',
- ),
- array(
- 0 => 'I registered in the past but cannot login any more?!',
- 1 => 'It is possible an administrator has deactivated or deleted your account for some reason. Also, many boards periodically remove users who have not posted for a long time to reduce the size of the database. If this has happened, try registering again and being more involved in discussions.'
- ),
- array(
- 0 => 'I’ve lost my password!',
- 1 => 'Don’t panic! While your password cannot be retrieved, it can easily be reset. Visit the login page and click <em>I forgot my password</em>. Follow the instructions and you should be able to log in again shortly.<br />However, if you are not able to reset your password, contact a board administrator.',
- ),
- array(
- 0 => 'Why do I get logged off automatically?',
- 1 => 'If you do not check the <em>Remember me</em> box when you login, the board will only keep you logged in for a preset time. This prevents misuse of your account by anyone else. To stay logged in, check the <em>Remember me</em> box during login. This is not recommended if you access the board from a shared computer, e.g. library, internet cafe, university computer lab, etc. If you do not see this checkbox, it means a board administrator has disabled this feature.',
- ),
- array(
- 0 => 'What does the “Delete all board cookies†do?',
- 1 => '“Delete all board cookies†deletes the cookies created by phpBB which keep you authenticated and logged into the board. Cookies also provide functions such as read tracking if they have been enabled by a board administrator. If you are having login or logout problems, deleting board cookies may help.',
- ),
- array(
- 0 => '--',
- 1 => 'User Preferences and settings'
- ),
- array(
- 0 => 'How do I change my settings?',
- 1 => 'If you are a registered user, all your settings are stored in the board database. To alter them, visit your User Control Panel; a link can usually be found by clicking on your username at the top of board pages. This system will allow you to change all your settings and preferences.',
- ),
- array(
- 0 => 'How do I prevent my username appearing in the online user listings?',
- 1 => 'Within your User Control Panel, under “Board preferencesâ€, you will find the option <em>Hide your online status</em>. Enable this option and you will only appear to the administrators, moderators and yourself. You will be counted as a hidden user.'
- ),
- array(
- 0 => 'The times are not correct!',
- 1 => 'It is possible the time displayed is from a timezone different from the one you are in. If this is the case, visit your User Control Panel and change your timezone to match your particular area, e.g. London, Paris, New York, Sydney, etc. Please note that changing the timezone, like most settings, can only be done by registered users. If you are not registered, this is a good time to do so.'
- ),
- array(
- 0 => 'I changed the timezone and the time is still wrong!',
- 1 => 'If you are sure you have set the timezone correctly and the time is still incorrect, then the time stored on the server clock is incorrect. Please notify an administrator to correct the problem.'
- ),
- array(
- 0 => 'My language is not in the list!',
- 1 => 'Either the administrator has not installed your language or nobody has translated this board into your language. Try asking a board administrator if they can install the language pack you need. If the language pack does not exist, feel free to create a new translation. More information can be found at the <a href="https://www.phpbb.com/">phpBB</a>&reg; website.',
- ),
- array(
- 0 => 'What are the images next to my username?',
- 1 => 'There are two images which may appear along with a username when viewing posts. One of them may be an image associated with your rank, generally in the form of stars, blocks or dots, indicating how many posts you have made or your status on the board. Another, usually larger, image is known as an avatar and is generally unique or personal to each user.',
- ),
- array(
- 0 => 'How do I display an avatar?',
- 1 => 'Within your User Control Panel, under “Profile†you can add an avatar by using one of the four following methods: Gravatar, Gallery, Remote or Upload. It is up to the board administrator to enable avatars and to choose the way in which avatars can be made available. If you are unable to use avatars, contact a board administrator.',
- ),
- array(
- 0 => 'What is my rank and how do I change it?',
- 1 => 'Ranks, which appear below your username, indicate the number of posts you have made or identify certain users, e.g. moderators and administrators. In general, you cannot directly change the wording of any board ranks as they are set by the board administrator. Please do not abuse the board by posting unnecessarily just to increase your rank. Most boards will not tolerate this and the moderator or administrator will simply lower your post count.'
- ),
- array(
- 0 => 'When I click the email link for a user it asks me to login?',
- 1 => 'Only registered users can send email to other users via the built-in email form, and only if the administrator has enabled this feature. This is to prevent malicious use of the email system by anonymous users.'
- ),
- array(
- 0 => '--',
- 1 => 'Posting Issues'
- ),
- array(
- 0 => 'How do I create a new topic or post a reply?',
- 1 => 'To post a new topic in a forum, click "New Topic". To post a reply to a topic, click "Post Reply". You may need to register before you can post a message. A list of your permissions in each forum is available at the bottom of the forum and topic screens. Example: You can post new topics, You can post attachments, etc.',
- ),
- array(
- 0 => 'How do I edit or delete a post?',
- 1 => 'Unless you are a board administrator or moderator, you can only edit or delete your own posts. You can edit a post by clicking the edit button for the relevant post, sometimes for only a limited time after the post was made. If someone has already replied to the post, you will find a small piece of text output below the post when you return to the topic which lists the number of times you edited it along with the date and time. This will only appear if someone has made a reply; it will not appear if a moderator or administrator edited the post, though they may leave a note as to why they’ve edited the post at their own discretion. Please note that normal users cannot delete a post once someone has replied.'
- ),
- array(
- 0 => 'How do I add a signature to my post?',
- 1 => 'To add a signature to a post you must first create one via your User Control Panel. Once created, you can check the <em>Attach a signature</em> box on the posting form to add your signature. You can also add a signature by default to all your posts by checking the appropriate radio button in the User Control Panel. If you do so, you can still prevent a signature being added to individual posts by un-checking the add signature box within the posting form.'
- ),
- array(
- 0 => 'How do I create a poll?',
- 1 => 'When posting a new topic or editing the first post of a topic, click the “Poll creation†tab below the main posting form; if you cannot see this, you do not have appropriate permissions to create polls. Enter a title and at least two options in the appropriate fields, making sure each option is on a separate line in the textarea. You can also set the number of options users may select during voting under “Options per userâ€, a time limit in days for the poll (0 for infinite duration) and lastly the option to allow users to amend their votes.'
- ),
- array(
- 0 => 'Why can’t I add more poll options?',
- 1 => 'The limit for poll options is set by the board administrator. If you feel you need to add more options to your poll than the allowed amount, contact the board administrator.'
- ),
- array(
- 0 => 'How do I edit or delete a poll?',
- 1 => 'As with posts, polls can only be edited by the original poster, a moderator or an administrator. To edit a poll, click to edit the first post in the topic; this always has the poll associated with it. If no one has cast a vote, users can delete the poll or edit any poll option. However, if members have already placed votes, only moderators or administrators can edit or delete it. This prevents the poll’s options from being changed mid-way through a poll.'
- ),
- array(
- 0 => 'Why can’t I access a forum?',
- 1 => 'Some forums may be limited to certain users or groups. To view, read, post or perform another action you may need special permissions. Contact a moderator or board administrator to grant you access.'
- ),
- array(
- 0 => 'Why can’t I add attachments?',
- 1 => 'Attachment permissions are granted on a per forum, per group, or per user basis. The board administrator may not have allowed attachments to be added for the specific forum you are posting in, or perhaps only certain groups can post attachments. Contact the board administrator if you are unsure about why you are unable to add attachments.'
- ),
- array(
- 0 => 'Why did I receive a warning?',
- 1 => 'Each board administrator has their own set of rules for their site. If you have broken a rule, you may be issued a warning. Please note that this is the board administrator’s decision, and the phpBB Limited has nothing to do with the warnings on the given site. Contact the board administrator if you are unsure about why you were issued a warning.'
- ),
- array(
- 0 => 'How can I report posts to a moderator?',
- 1 => 'If the board administrator has allowed it, you should see a button for reporting posts next to the post you wish to report. Clicking this will walk you through the steps necessary to report the post.'
- ),
- array(
- 0 => 'What is the “Save†button for in topic posting?',
- 1 => 'This allows you to save drafts to be completed and submitted at a later date. To reload a saved draft, visit the User Control Panel.'
- ),
- array(
- 0 => 'Why does my post need to be approved?',
- 1 => 'The board administrator may have decided that posts in the forum you are posting to require review before submission. It is also possible that the administrator has placed you in a group of users whose posts require review before submission. Please contact the board administrator for further details.'
- ),
- array(
- 0 => 'How do I bump my topic?',
- 1 => 'By clicking the “Bump topic†link when you are viewing it, you can “bump†the topic to the top of the forum on the first page. However, if you do not see this, then topic bumping may be disabled or the time allowance between bumps has not yet been reached. It is also possible to bump the topic simply by replying to it, however, be sure to follow the board rules when doing so.'
- ),
- array(
- 0 => '--',
- 1 => 'Formatting and Topic Types'
- ),
- array(
- 0 => 'What is BBCode?',
- 1 => 'BBCode is a special implementation of HTML, offering great formatting control on particular objects in a post. The use of BBCode is granted by the administrator, but it can also be disabled on a per post basis from the posting form. BBCode itself is similar in style to HTML, but tags are enclosed in square brackets [ and ] rather than &lt; and &gt;. For more information on BBCode see the guide which can be accessed from the posting page.'
- ),
- array(
- 0 => 'Can I use HTML?',
- 1 => 'No. It is not possible to post HTML on this board and have it rendered as HTML. Most formatting which can be carried out using HTML can be applied using BBCode instead.'
- ),
- array(
- 0 => 'What are Smilies?',
- 1 => 'Smilies, or Emoticons, are small images which can be used to express a feeling using a short code, e.g. :) denotes happy, while :( denotes sad. The full list of emoticons can be seen in the posting form. Try not to overuse smilies, however, as they can quickly render a post unreadable and a moderator may edit them out or remove the post altogether. The board administrator may also have set a limit to the number of smilies you may use within a post.'
- ),
- array(
- 0 => 'Can I post images?',
- 1 => 'Yes, images can be shown in your posts. If the administrator has allowed attachments, you may be able to upload the image to the board. Otherwise, you must link to an image stored on a publicly accessible web server, e.g. http://www.example.com/my-picture.gif. You cannot link to pictures stored on your own PC (unless it is a publicly accessible server) nor images stored behind authentication mechanisms, e.g. hotmail or yahoo mailboxes, password protected sites, etc. To display the image use the BBCode [img] tag.'
- ),
- array(
- 0 => 'What are global announcements?',
- 1 => 'Global announcements contain important information and you should read them whenever possible. They will appear at the top of every forum and within your User Control Panel. Global announcement permissions are granted by the board administrator.'
- ),
- array(
- 0 => 'What are announcements?',
- 1 => 'Announcements often contain important information for the forum you are currently reading and you should read them whenever possible. Announcements appear at the top of every page in the forum to which they are posted. As with global announcements, announcement permissions are granted by the board administrator.'
- ),
- array(
- 0 => 'What are sticky topics?',
- 1 => 'Sticky topics within the forum appear below announcements and only on the first page. They are often quite important so you should read them whenever possible. As with announcements and global announcements, sticky topic permissions are granted by the board administrator.'
- ),
- array(
- 0 => 'What are locked topics?',
- 1 => 'Locked topics are topics where users can no longer reply and any poll it contained was automatically ended. Topics may be locked for many reasons and were set this way by either the forum moderator or board administrator. You may also be able to lock your own topics depending on the permissions you are granted by the board administrator.'
- ),
- array(
- 0 => 'What are topic icons?',
- 1 => 'Topic icons are author chosen images associated with posts to indicate their content. The ability to use topic icons depends on the permissions set by the board administrator.'
- ),
- // This block will switch the FAQ-Questions to the second template column
- array(
- 0 => '--',
- 1 => '--'
- ),
- array(
- 0 => '--',
- 1 => 'User Levels and Groups'
- ),
- array(
- 0 => 'What are Administrators?',
- 1 => 'Administrators are members assigned with the highest level of control over the entire board. These members can control all facets of board operation, including setting permissions, banning users, creating usergroups or moderators, etc., dependent upon the board founder and what permissions he or she has given the other administrators. They may also have full moderator capabilities in all forums, depending on the settings put forth by the board founder.'
- ),
- array(
- 0 => 'What are Moderators?',
- 1 => 'Moderators are individuals (or groups of individuals) who look after the forums from day to day. They have the authority to edit or delete posts and lock, unlock, move, delete and split topics in the forum they moderate. Generally, moderators are present to prevent users from going off-topic or posting abusive or offensive material.'
- ),
- array(
- 0 => 'What are usergroups?',
- 1 => 'Usergroups are groups of users that divide the community into manageable sections board administrators can work with. Each user can belong to several groups and each group can be assigned individual permissions. This provides an easy way for administrators to change permissions for many users at once, such as changing moderator permissions or granting users access to a private forum.'
- ),
- array(
- 0 => 'Where are the usergroups and how do I join one?',
- 1 => 'You can view all usergroups via the “Usergroups†link within your User Control Panel. If you would like to join one, proceed by clicking the appropriate button. Not all groups have open access, however. Some may require approval to join, some may be closed and some may even have hidden memberships. If the group is open, you can join it by clicking the appropriate button. If a group requires approval to join you may request to join by clicking the appropriate button. The user group leader will need to approve your request and may ask why you want to join the group. Please do not harass a group leader if they reject your request; they will have their reasons.'
- ),
- array(
- 0 => 'How do I become a usergroup leader?',
- 1 => 'A usergroup leader is usually assigned when usergroups are initially created by a board administrator. If you are interested in creating a usergroup, your first point of contact should be an administrator; try sending a private message.',
- ),
- array(
- 0 => 'Why do some usergroups appear in a different colour?',
- 1 => 'It is possible for the board administrator to assign a colour to the members of a usergroup to make it easy to identify the members of this group.'
- ),
- array(
- 0 => 'What is a “Default usergroup�',
- 1 => 'If you are a member of more than one usergroup, your default is used to determine which group colour and group rank should be shown for you by default. The board administrator may grant you permission to change your default usergroup via your User Control Panel.'
- ),
- array(
- 0 => 'What is “The team†link?',
- 1 => 'This page provides you with a list of board staff, including board administrators and moderators and other details such as the forums they moderate.'
- ),
- array(
- 0 => '--',
- 1 => 'Private Messaging'
- ),
- array(
- 0 => 'I cannot send private messages!',
- 1 => 'There are three reasons for this; you are not registered and/or not logged on, the board administrator has disabled private messaging for the entire board, or the board administrator has prevented you from sending messages. Contact a board administrator for more information.'
- ),
- array(
- 0 => 'I keep getting unwanted private messages!',
- 1 => 'You can automatically delete private messages from a user by using message rules within your User Control Panel. If you are receiving abusive private messages from a particular user, report the messages to the moderators; they have the power to prevent a user from sending private messages.'
- ),
- array(
- 0 => 'I have received a spamming or abusive email from someone on this board!',
- 1 => 'We are sorry to hear that. The email form feature of this board includes safeguards to try and track users who send such posts, so email the board administrator with a full copy of the email you received. It is very important that this includes the headers that contain the details of the user that sent the email. The board administrator can then take action.'
- ),
- array(
- 0 => '--',
- 1 => 'Friends and Foes'
- ),
- array(
- 0 => 'What are my Friends and Foes lists?',
- 1 => 'You can use these lists to organise other members of the board. Members added to your friends list will be listed within your User Control Panel for quick access to see their online status and to send them private messages. Subject to template support, posts from these users may also be highlighted. If you add a user to your foes list, any posts they make will be hidden by default.'
- ),
- array(
- 0 => 'How can I add / remove users to my Friends or Foes list?',
- 1 => 'You can add users to your list in two ways. Within each user’s profile, there is a link to add them to either your Friend or Foe list. Alternatively, from your User Control Panel, you can directly add users by entering their member name. You may also remove users from your list using the same page.'
- ),
- array(
- 0 => '--',
- 1 => 'Searching the Forums'
- ),
- array(
- 0 => 'How can I search a forum or forums?',
- 1 => 'Enter a search term in the search box located on the index, forum or topic pages. Advanced search can be accessed by clicking the “Advance Search†link which is available on all pages on the forum. How to access the search may depend on the style used.'
- ),
- array(
- 0 => 'Why does my search return no results?',
- 1 => 'Your search was probably too vague and included many common terms which are not indexed by phpBB. Be more specific and use the options available within Advanced search.',
- ),
- array(
- 0 => 'Why does my search return a blank page!?',
- 1 => 'Your search returned too many results for the webserver to handle. Use “Advanced search†and be more specific in the terms used and forums that are to be searched.'
- ),
- array(
- 0 => 'How do I search for members?',
- 1 => 'Visit to the “Members†page and click the “Find a member†link.'
- ),
- array(
- 0 => 'How can I find my own posts and topics?',
- 1 => 'Your own posts can be retrieved either by clicking the “Show your posts†link within the User Control Panel or by clicking the “Search user’s posts†link via your own profile page or by clicking the “Quick links†menu at the top of the board. To search for your topics, use the Advanced search page and fill in the various options appropriately.',
- ),
- array(
- 0 => '--',
- 1 => 'Subscriptions and Bookmarks',
- ),
- array(
- 0 => 'What is the difference between bookmarking and subscribing?',
- 1 => 'In phpBB 3.0, bookmarking topics worked much like bookmarking in a web browser. You were not alerted when there was an update. As of phpBB 3.1, bookmarking is more like subscribing to a topic. You can be notified when a bookmarked topic is updated. Subscribing, however, will notify you when there is an update to a topic or forum on the board. Notification options for bookmarks and subscriptions can be configured in the User Control Panel, under “Board preferencesâ€.',
- ),
- array(
- 0 => 'How do I bookmark or subscribe to specific topics?',
- 1 => 'You can bookmark or subscribe to a specific topic by clicking the appropriate link in the “Topic tools†menu, conveniently located near the top and bottom of a topic discussion.<br />Replying to a topic with the “Notify me when a reply is posted†option checked will also subscribe you to the topic.',
- ),
- array(
- 0 => 'How do I subscribe to specific forums?',
- 1 => 'To subscribe to a specific forum, click the “Subscribe forum†link, at the bottom of page, upon entering the forum.',
- ),
- array(
- 0 => 'How do I remove my subscriptions?',
- 1 => 'To remove your subscriptions, go to your User Control Panel and follow the links to your subscriptions.'
- ),
- array(
- 0 => '--',
- 1 => 'Attachments'
- ),
- array(
- 0 => 'What attachments are allowed on this board?',
- 1 => 'Each board administrator can allow or disallow certain attachment types. If you are unsure what is allowed to be uploaded, contact the board administrator for assistance.'
- ),
- array(
- 0 => 'How do I find all my attachments?',
- 1 => 'To find your list of attachments that you have uploaded, go to your User Control Panel and follow the links to the attachments section.'
- ),
- array(
- 0 => '--',
- 1 => 'phpBB Issues',
- ),
- array(
- 0 => 'Who wrote this bulletin board?',
- 1 => 'This software (in its unmodified form) is produced, released and is copyright <a href="https://www.phpbb.com/">phpBB Limited</a>. It is made available under the GNU General Public License, version 2 (GPL-2.0) and may be freely distributed. See <a href="https://www.phpbb.com/about/">About phpBB</a> for more details.',
- ),
- array(
- 0 => 'Why isn’t X feature available?',
- 1 => 'This software was written by and licensed through phpBB Limited. If you believe a feature needs to be added please visit the <a href="https://www.phpbb.com/ideas/">phpBB Ideas Centre</a>, where you can upvote existing ideas or suggest new features.'
- ),
- array(
- 0 => 'Who do I contact about abusive and/or legal matters related to this board?',
- 1 => 'Any of the administrators listed on the “The team†page should be an appropriate point of contact for your complaints. If this still gets no response then you should contact the owner of the domain (do a <a href="http://www.google.com/search?q=whois">whois lookup</a>) or, if this is running on a free service (e.g. Yahoo!, free.fr, f2s.com, etc.), the management or abuse department of that service. Please note that the phpBB Limited has <strong>absolutely no jurisdiction</strong> and cannot in any way be held liable over how, where or by whom this board is used. Do not contact the phpBB Limited in relation to any legal (cease and desist, liable, defamatory comment, etc.) matter <strong>not directly related</strong> to the phpBB.com website or the discrete software of phpBB itself. If you do email phpBB Limited <strong>about any third party</strong> use of this software then you should expect a terse response or no response at all.'
- ),
- array(
- 0 => 'How do I contact a board administrator?',
- 1 => 'All users of the board can use the “Contact us†form, if the option was enabled by the board administrator.<br />Members of the board can also use the “The team†link.',
- ),
-);
diff --git a/phpBB/language/en/install.php b/phpBB/language/en/install.php
index 0460c0613e..9bceeccde7 100644
--- a/phpBB/language/en/install.php
+++ b/phpBB/language/en/install.php
@@ -1,19 +1,19 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
/**
-* DO NOT CHANGE
-*/
+ * DO NOT CHANGE
+ */
if (!defined('IN_PHPBB'))
{
exit;
@@ -36,166 +36,27 @@ if (empty($lang) || !is_array($lang))
// equally where a string contains only two placeholders which are used to wrap text
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
+// Common installer pages
$lang = array_merge($lang, array(
- 'ADMIN_CONFIG' => 'Administrator configuration',
- 'ADMIN_PASSWORD' => 'Administrator password',
- 'ADMIN_PASSWORD_CONFIRM' => 'Confirm administrator password',
- 'ADMIN_PASSWORD_EXPLAIN' => 'Please enter a password between 6 and 30 characters in length.',
- 'ADMIN_TEST' => 'Check administrator settings',
- 'ADMIN_USERNAME' => 'Administrator username',
- 'ADMIN_USERNAME_EXPLAIN' => 'Please enter a username between 3 and 20 characters in length.',
- 'APP_MAGICK' => 'ImageMagick support [ Attachments ]',
- 'AUTHOR_NOTES' => 'Author notes<br />» %s',
- 'AVAILABLE' => 'Available',
- 'AVAILABLE_CONVERTORS' => 'Available convertors',
-
- 'BEGIN_CONVERT' => 'Begin conversion',
- 'BLANK_PREFIX_FOUND' => 'A scan of your tables has shown a valid installation using no table prefix.',
- 'BOARD_NOT_INSTALLED' => 'No installation found',
- 'BOARD_NOT_INSTALLED_EXPLAIN' => 'The phpBB Unified Convertor Framework requires a default installation of phpBB3 to function, please <a href="%s">proceed by first installing phpBB3</a>.',
- 'BACKUP_NOTICE' => 'Please backup your board before updating in case any problems arise during the update process.',
-
- 'CATEGORY' => 'Category',
- 'CACHE_STORE' => 'Cache type',
- 'CACHE_STORE_EXPLAIN' => 'The physical location where data is cached, filesystem is preferred.',
- 'CAT_CONVERT' => 'Convert',
- 'CAT_INSTALL' => 'Install',
- 'CAT_OVERVIEW' => 'Overview',
- 'CAT_UPDATE' => 'Update',
- 'CHANGE' => 'Change',
- 'CHECK_TABLE_PREFIX' => 'Please check your table prefix and try again.',
- 'CLEAN_VERIFY' => 'Cleaning up and verifying the final structure',
- 'CLEANING_USERNAMES' => 'Cleaning usernames',
- 'COLLIDING_CLEAN_USERNAME' => '<strong>%s</strong> is the clean username for:',
- 'COLLIDING_USERNAMES_FOUND' => 'Colliding usernames were found on your old board. In order to complete the conversion please delete or rename these users so that there is only one user on your old board for each clean username.',
- 'COLLIDING_USER' => '» user id: <strong>%d</strong> username: <strong>%s</strong> (%d posts)',
- 'CONFIG_CONVERT' => 'Converting the configuration',
- 'CONFIG_FILE_UNABLE_WRITE' => 'It was not possible to write the configuration file. Alternative methods for this file to be created are presented below.',
- 'CONFIG_FILE_WRITTEN' => 'The configuration file has been written. You may now proceed to the next step of the installation.',
- 'CONFIG_PHPBB_EMPTY' => 'The phpBB3 config variable for “%s†is empty.',
- 'CONFIG_RETRY' => 'Retry',
- 'CONTINUE_CONVERT' => 'Continue conversion',
- 'CONTINUE_CONVERT_BODY' => 'A previous conversion attempt has been determined. You are now able to choose between starting a new conversion or continuing the conversion.',
- 'CONTINUE_LAST' => 'Continue last statements',
- 'CONTINUE_OLD_CONVERSION' => 'Continue previously started conversion',
- 'CONVERT' => 'Convert',
- 'CONVERT_COMPLETE' => 'Conversion completed',
- 'CONVERT_COMPLETE_EXPLAIN' => 'You have now successfully converted your board to phpBB 3.1. You can now login and <a href="../">access your board</a>. Please ensure that the settings were transferred correctly before enabling your board by deleting the install directory. Remember that help on using phpBB is available online via the <a href="https://www.phpbb.com/support/docs/en/3.1/ug/">Documentation</a> and the <a href="https://www.phpbb.com/community/viewforum.php?f=466">support forums</a>.',
- 'CONVERT_INTRO' => 'Welcome to the phpBB Unified Convertor Framework',
- 'CONVERT_INTRO_BODY' => 'From here, you are able to import data from other (installed) board systems. The list below shows all the conversion modules currently available. If there is no convertor shown in this list for the board software you wish to convert from, please check our website where further conversion modules may be available for download.',
- 'CONVERT_NEW_CONVERSION' => 'New conversion',
- 'CONVERT_NOT_EXIST' => 'The specified convertor does not exist.',
- 'CONVERT_OPTIONS' => 'Options',
- 'CONVERT_SETTINGS_VERIFIED' => 'The information you entered has been verified. To start the conversion process, please push the button below.',
- 'CONV_ERR_FATAL' => 'Fatal conversion error',
-
- 'CONV_ERROR_ATTACH_FTP_DIR' => 'FTP upload for attachments is enabled at the old board. Please disable the FTP upload option and make sure a valid upload directory is specified, then copy all attachment files to this new web accessible directory. Once you have done this, restart the convertor.',
- 'CONV_ERROR_CONFIG_EMPTY' => 'There is no configuration information available for the conversion.',
- 'CONV_ERROR_FORUM_ACCESS' => 'Unable to get forum access information.',
- 'CONV_ERROR_GET_CATEGORIES' => 'Unable to get categories.',
- 'CONV_ERROR_GET_CONFIG' => 'Could not retrieve your board configuration.',
- 'CONV_ERROR_COULD_NOT_READ' => 'Unable to access/read “%sâ€.',
- 'CONV_ERROR_GROUP_ACCESS' => 'Unable to get group authentication information.',
- 'CONV_ERROR_INCONSISTENT_GROUPS' => 'Inconsistency in groups table detected in add_bots() - you need to add all special groups if you do it manually.',
- 'CONV_ERROR_INSERT_BOT' => 'Unable to insert bot into users table.',
- 'CONV_ERROR_INSERT_BOTGROUP' => 'Unable to insert bot into bots table.',
- 'CONV_ERROR_INSERT_USER_GROUP' => 'Unable to insert user into user_group table.',
- 'CONV_ERROR_MESSAGE_PARSER' => 'Message parser error',
- 'CONV_ERROR_NO_AVATAR_PATH' => 'Note to developer: you must specify $convertor[\'avatar_path\'] to use %s.',
- 'CONV_ERROR_NO_FORUM_PATH' => 'The relative path to the source board has not been specified.',
- 'CONV_ERROR_NO_GALLERY_PATH' => 'Note to developer: you must specify $convertor[\'avatar_gallery_path\'] to use %s.',
- 'CONV_ERROR_NO_GROUP' => 'Group “%1$s†could not be found in %2$s.',
- 'CONV_ERROR_NO_RANKS_PATH' => 'Note to developer: you must specify $convertor[\'ranks_path\'] to use %s.',
- 'CONV_ERROR_NO_SMILIES_PATH' => 'Note to developer: you must specify $convertor[\'smilies_path\'] to use %s.',
- 'CONV_ERROR_NO_UPLOAD_DIR' => 'Note to developer: you must specify $convertor[\'upload_path\'] to use %s.',
- 'CONV_ERROR_PERM_SETTING' => 'Unable to insert/update permission setting.',
- 'CONV_ERROR_PM_COUNT' => 'Unable to select folder pm count.',
- 'CONV_ERROR_REPLACE_CATEGORY' => 'Unable to insert new forum replacing old category.',
- 'CONV_ERROR_REPLACE_FORUM' => 'Unable to insert new forum replacing old forum.',
- 'CONV_ERROR_USER_ACCESS' => 'Unable to get user authentication information.',
- 'CONV_ERROR_WRONG_GROUP' => 'Wrong group “%1$s†defined in %2$s.',
- 'CONV_OPTIONS_BODY' => 'This page collects the data required to access the source board. Enter the database details of your former board; the converter will not change anything in the database given below. The source board should be disabled to allow a consistent conversion.',
- 'CONV_SAVED_MESSAGES' => 'Saved messages',
+ 'INSTALL_PANEL' => 'Installation Panel',
+ 'SELECT_LANG' => 'Select language',
- 'COULD_NOT_COPY' => 'Could not copy file <strong>%1$s</strong> to <strong>%2$s</strong><br /><br />Please check that the target directory exists and is writable by the webserver.',
- 'COULD_NOT_FIND_PATH' => 'Could not find path to your former board. Please check your settings and try again.<br />» %s was specified as the source path.',
+ 'STAGE_INSTALL' => 'Installing phpBB',
- 'DBMS' => 'Database type',
- 'DB_CONFIG' => 'Database configuration',
- 'DB_CONNECTION' => 'Database connection',
- 'DB_ERR_INSERT' => 'Error while processing <code>INSERT</code> query.',
- 'DB_ERR_LAST' => 'Error while processing <var>query_last</var>.',
- 'DB_ERR_QUERY_FIRST' => 'Error while executing <var>query_first</var>.',
- 'DB_ERR_QUERY_FIRST_TABLE' => 'Error while executing <var>query_first</var>, %s (“%sâ€).',
- 'DB_ERR_SELECT' => 'Error while running <code>SELECT</code> query.',
- 'DB_HOST' => 'Database server hostname or DSN',
- 'DB_HOST_EXPLAIN' => 'DSN stands for Data Source Name and is relevant only for ODBC installs. On PostgreSQL, use localhost to connect to the local server via UNIX domain socket and 127.0.0.1 to connect via TCP. For SQLite, enter the full path to your database file.',
- 'DB_NAME' => 'Database name',
- 'DB_PASSWORD' => 'Database password',
- 'DB_PORT' => 'Database server port',
- 'DB_PORT_EXPLAIN' => 'Leave this blank unless you know the server operates on a non-standard port.',
- 'DB_UPDATE_NOT_SUPPORTED' => 'We are sorry, but this script does not support updating from versions of phpBB prior to “%1$sâ€. The version you currently have installed is “%2$sâ€. Please update to a previous version before running this script. Assistance with this is available in the Support Forum on phpBB.com.',
- 'DB_USERNAME' => 'Database username',
- 'DB_TEST' => 'Test connection',
- 'DEFAULT_LANG' => 'Default board language',
- 'DEFAULT_PREFIX_IS' => 'The convertor was not able to find tables with the specified prefix. Please make sure you have entered the correct details for the board you are converting from. The default table prefix for %1$s is <strong>%2$s</strong>.',
- 'DEV_NO_TEST_FILE' => 'No value has been specified for the test_file variable in the convertor. If you are a user of this convertor, you should not be seeing this error, please report this message to the convertor author. If you are a convertor author, you must specify the name of a file which exists in the source board to allow the path to it to be verified.',
- 'DIRECTORIES_AND_FILES' => 'Directory and file setup',
- 'DISABLE_KEYS' => 'Disabling keys',
- 'DLL_FTP' => 'Remote FTP support [ Installation ]',
- 'DLL_GD' => 'GD graphics support [ Visual Confirmation ]',
- 'DLL_MBSTRING' => 'Multi-byte character support',
- 'DLL_MSSQL' => 'MSSQL Server 2000+',
- 'DLL_MSSQL_ODBC' => 'MSSQL Server 2000+ via ODBC',
- 'DLL_MSSQLNATIVE' => 'MSSQL Server 2005+ [ Native ]',
- 'DLL_MYSQL' => 'MySQL',
- 'DLL_MYSQLI' => 'MySQL with MySQLi Extension',
- 'DLL_ORACLE' => 'Oracle',
- 'DLL_POSTGRES' => 'PostgreSQL',
- 'DLL_SQLITE' => 'SQLite 2',
- 'DLL_SQLITE3' => 'SQLite 3',
- 'DLL_XML' => 'XML support [ Jabber ]',
- 'DLL_ZLIB' => 'zlib compression support [ gz, .tar.gz, .zip ]',
- 'DL_CONFIG' => 'Download config',
- 'DL_CONFIG_EXPLAIN' => 'You may download the complete config.php to your own PC. You will then need to upload the file manually, replacing any existing config.php in your phpBB 3.1 root directory. Please remember to upload the file in ASCII format (see your FTP application documentation if you are unsure how to achieve this). When you have uploaded the config.php please click “Done†to move to the next stage.',
- 'DL_DOWNLOAD' => 'Download',
- 'DONE' => 'Done',
+ // Introduction page
+ 'INTRODUCTION_TITLE' => 'Introduction',
+ 'INTRODUCTION_BODY' => 'Welcome to phpBB3!<br /><br />phpBB® is the most widely used open source bulletin board solution in the world. phpBB3 is the latest installment in a package line started in 2000. Like its predecessors, phpBB3 is feature-rich, user-friendly, and fully supported by the phpBB Team. phpBB3 greatly improves on what made phpBB2 popular, and adds commonly requested features that were not present in previous versions. We hope it exceeds your expectations.<br /><br />This installation system will guide you through installing phpBB3, updating to the latest version of phpBB3 from past releases, as well as converting to phpBB3 from a different discussion board system (including phpBB2). For more information, we encourage you to read <a href="../docs/INSTALL.html">the installation guide</a>.<br /><br />To read the phpBB3 license or learn about obtaining support and our stance on it, please select the respective options from the side menu. To continue, please select the appropriate tab above.',
- 'ENABLE_KEYS' => 'Re-enabling keys. This can take a while.',
+ // Support page
+ 'SUPPORT_TITLE' => 'Support',
+ 'SUPPORT_BODY' => 'Full support will be provided for the current stable release of phpBB3, free of charge. This includes:</p><ul><li>installation</li><li>configuration</li><li>technical questions</li><li>problems relating to potential bugs in the software</li><li>updating from Release Candidate (RC) versions to the latest stable version</li><li>converting from phpBB 2.0.x to phpBB3</li><li>converting from other discussion board software to phpBB3 (please see the <a href="https://www.phpbb.com/community/viewforum.php?f=486">Convertors Forum</a>)</li></ul><p>We encourage users still running beta versions of phpBB3 to replace their installation with a fresh copy of the latest version.</p><h2>Extensions / Styles</h2><p>For issues relating to Extensions, please post in the appropriate <a href="https://www.phpbb.com/community/viewforum.php?f=451">Extensions Forum</a>.<br />For issues relating to styles, templates and themes, please post in the appropriate <a href="https://www.phpbb.com/community/viewforum.php?f=471">Styles Forum</a>.<br /><br />If your question relates to a specific package, please post directly in the topic dedicated to the package.</p><h2>Obtaining Support</h2><p><a href="https://www.phpbb.com/support/">Support Section</a><br /><a href="https://www.phpbb.com/support/docs/en/3.2/ug/quickstart/">Quick Start Guide</a><br /><br />To ensure you stay up to date with the latest news and releases, follow us on <a href="https://www.twitter.com/phpbb/">Twitter</a> and <a href="https://www.facebook.com/phpbb/">Facebook</a><br /><br />',
- 'FILES_OPTIONAL' => 'Optional files and directories',
- 'FILES_OPTIONAL_EXPLAIN' => '<strong>Optional</strong> - These files, directories or permission settings are not required. The installation system will attempt to use various techniques to create them if they do not exist or cannot be written to. However, the presence of these will speed installation.',
- 'FILES_REQUIRED' => 'Files and Directories',
- 'FILES_REQUIRED_EXPLAIN' => '<strong>Required</strong> - In order to function correctly phpBB needs to be able to access or write to certain files or directories. If you see “Not Found†you need to create the relevant file or directory. If you see “Unwritable†you need to change the permissions on the file or directory to allow phpBB to write to it.',
- 'FILLING_TABLE' => 'Filling table <strong>%s</strong>',
- 'FILLING_TABLES' => 'Filling tables',
+ // License
+ 'LICENSE_TITLE' => 'General Public License',
- 'FINAL_STEP' => 'Process final step',
- 'FORUM_ADDRESS' => 'Board address',
- 'FORUM_ADDRESS_EXPLAIN' => 'This is the URL of your former board, for example <samp>http://www.example.com/phpBB2/</samp>. If an address is entered here and not left empty every instance of this address will be replaced by your new board address within messages, private messages and signatures.',
- 'FORUM_PATH' => 'Board path',
- 'FORUM_PATH_EXPLAIN' => 'This is the <strong>relative</strong> path on disk to your former board from the <strong>root of this phpBB3 installation</strong>.',
- 'FOUND' => 'Found',
- 'FTP_CONFIG' => 'Transfer config by FTP',
- 'FTP_CONFIG_EXPLAIN' => 'phpBB has detected the presence of the FTP module on this server. You may attempt to install your config.php via this if you wish. You will need to supply the information listed below. Remember your username and password are those to your server! (ask your hosting provider for details if you are unsure what these are).',
- 'FTP_PATH' => 'FTP path',
- 'FTP_PATH_EXPLAIN' => 'This is the path from your root directory to that of phpBB, e.g. <samp>htdocs/phpBB3/</samp>.',
- 'FTP_UPLOAD' => 'Upload',
-
- 'GPL' => 'General Public License',
-
- 'INITIAL_CONFIG' => 'Basic configuration',
- 'INITIAL_CONFIG_EXPLAIN' => 'Now that install has determined your server can run phpBB you need to supply some specific information. If you do not know how to connect to your database please contact your hosting provider (in the first instance) or use the phpBB support forums. When entering data please ensure you check it thoroughly before continuing.',
- 'INSTALL_CONGRATS' => 'Congratulations!',
- 'INSTALL_CONGRATS_EXPLAIN' => '
- You have successfully installed phpBB %1$s. Please proceed by choosing one of the following options:</p>
- <h2>Convert an existing board to phpBB3</h2>
- <p>The phpBB Unified Convertor Framework supports the conversion of phpBB 2.0.x and other board systems to phpBB3. If you have an existing board that you wish to convert, please <a href="%2$s">proceed to the convertor</a>.</p>
- <h2>Go live with your phpBB3!</h2>
- <p>Clicking the button below will take you to a form for submitting statistical data to phpBB in your Administration Control Panel (ACP). We would appreciate it if you could help us by sending that information. Afterwards you should take some time to examine the options available to you. Remember that help is available online via the <a href="https://www.phpbb.com/support/docs/en/3.1/ug/">Documentation</a>, <a href="%3$s">README</a> and the <a href="https://www.phpbb.com/community/viewforum.php?f=466">Support Forums</a>.</p><p><strong>Please delete, move or rename the install directory before using your board. While this directory exists, only the Administration Control Panel (ACP) will be accessible.</strong>',
- 'INSTALL_INTRO' => 'Welcome to Installation',
-
- 'INSTALL_INTRO_BODY' => 'With this option, it is possible to install phpBB3 onto your server.</p><p>In order to proceed, you will need your database settings. If you do not know your database settings, please contact your host and ask for them. You will not be able to continue without them. You need:</p>
+ // Install page
+ 'INSTALL_INTRO' => 'Welcome to Installation',
+ 'INSTALL_INTRO_BODY' => 'With this option, it is possible to install phpBB3 onto your server.</p><p>In order to proceed, you will need your database settings. If you do not know your database settings, please contact your host and ask for them. You will not be able to continue without them. You need:</p>
<ul>
<li>The Database Type - the database you will be using.</li>
@@ -211,7 +72,6 @@ $lang = array_merge($lang, array(
<ul>
<li>MySQL 3.23 or above (MySQLi supported)</li>
<li>PostgreSQL 8.3+</li>
- <li>SQLite 2.8.2+</li>
<li>SQLite 3.6.15+</li>
<li>MS SQL Server 2000 or above (directly or via ODBC)</li>
<li>MS SQL Server 2005 or above (native)</li>
@@ -219,380 +79,157 @@ $lang = array_merge($lang, array(
</ul>
<p>Only those databases supported on your server will be displayed.',
- 'INSTALL_INTRO_NEXT' => 'To commence the installation, please press the button below.',
- 'INSTALL_LOGIN' => 'Login',
- 'INSTALL_NEXT' => 'Next stage',
- 'INSTALL_NEXT_FAIL' => 'Some tests failed and you should correct these problems before proceeding to the next stage. Failure to do so may result in an incomplete installation.',
- 'INSTALL_NEXT_PASS' => 'All the basic tests have been passed and you may proceed to the next stage of installation. If you have changed any permissions, modules, etc. and wish to re-test you can do so if you wish.',
- 'INSTALL_PANEL' => 'Installation Panel',
- 'INSTALL_SEND_CONFIG' => 'Unfortunately phpBB could not write the configuration information directly to your config.php. This may be because the file does not exist or is not writable. A number of options will be listed below enabling you to complete installation of config.php.',
- 'INSTALL_START' => 'Start install',
- 'INSTALL_TEST' => 'Test again',
- 'INST_ERR' => 'Installation error',
- 'INST_ERR_DB_CONNECT' => 'Could not connect to the database, see error message below.',
- 'INST_ERR_DB_FORUM_PATH' => 'The database file specified is within your board directory tree. You should put this file in a non web-accessible location.',
- 'INST_ERR_DB_INVALID_PREFIX'=> 'The prefix you entered is invalid. It must start with a letter and must only contain letters, numbers and underscores.',
- 'INST_ERR_DB_NO_ERROR' => 'No error message given.',
- 'INST_ERR_DB_NO_MYSQLI' => 'The version of MySQL installed on this machine is incompatible with the “MySQL with MySQLi Extension†option you have selected. Please try the “MySQL†option instead.',
- 'INST_ERR_DB_NO_SQLITE' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 2.8.2.',
- 'INST_ERR_DB_NO_SQLITE3' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 3.6.15.',
- 'INST_ERR_DB_NO_ORACLE' => 'The version of Oracle installed on this machine requires you to set the <var>NLS_CHARACTERSET</var> parameter to <var>UTF8</var>. Either upgrade your installation to 9.2+ or change the parameter.',
- 'INST_ERR_DB_NO_POSTGRES' => 'The database you have selected was not created in <var>UNICODE</var> or <var>UTF8</var> encoding. Try installing with a database in <var>UNICODE</var> or <var>UTF8</var> encoding.',
- 'INST_ERR_DB_NO_NAME' => 'No database name specified.',
- 'INST_ERR_EMAIL_INVALID' => 'The email address you entered is invalid.',
- 'INST_ERR_EMAIL_MISMATCH' => 'The emails you entered did not match.',
- 'INST_ERR_FATAL' => 'Fatal installation error',
- 'INST_ERR_FATAL_DB' => 'A fatal and unrecoverable database error has occurred. This may be because the specified user does not have appropriate permissions to <code>CREATE TABLES</code> or <code>INSERT</code> data, etc. Further information may be given below. Please contact your hosting provider in the first instance or the support forums of phpBB for further assistance.',
- 'INST_ERR_FTP_PATH' => 'Could not change to the given directory, please check the path.',
- 'INST_ERR_FTP_LOGIN' => 'Could not login to FTP server, check your username and password.',
- 'INST_ERR_MISSING_DATA' => 'You must fill out all fields in this block.',
- 'INST_ERR_NO_DB' => 'Cannot load the PHP module for the selected database type.',
- 'INST_ERR_PASSWORD_MISMATCH' => 'The passwords you entered did not match.',
- 'INST_ERR_PASSWORD_TOO_LONG' => 'The password you entered is too long. The maximum length is 30 characters.',
- 'INST_ERR_PASSWORD_TOO_SHORT' => 'The password you entered is too short. The minimum length is 6 characters.',
- 'INST_ERR_PREFIX' => 'Tables with the specified prefix already exist, please choose an alternative.',
- 'INST_ERR_PREFIX_INVALID' => 'The table prefix you have specified is invalid for your database. Please try another, removing characters such as the hyphen.',
- 'INST_ERR_PREFIX_TOO_LONG' => 'The table prefix you have specified is too long. The maximum length is %d characters.',
- 'INST_ERR_USER_TOO_LONG' => 'The username you entered is too long. The maximum length is 20 characters.',
- 'INST_ERR_USER_TOO_SHORT' => 'The username you entered is too short. The minimum length is 3 characters.',
- 'INVALID_PRIMARY_KEY' => 'Invalid primary key : %s',
-
- 'LONG_SCRIPT_EXECUTION' => 'Please note that this can take a while... Please do not stop the script.',
-
- // mbstring
- 'MBSTRING_CHECK' => '<samp>mbstring</samp> extension check',
- 'MBSTRING_CHECK_EXPLAIN' => '<strong>Required</strong> - <samp>mbstring</samp> is a PHP extension that provides multibyte string functions. Certain features of mbstring are not compatible with phpBB and must be disabled.',
- 'MBSTRING_FUNC_OVERLOAD' => 'Function overloading',
- 'MBSTRING_FUNC_OVERLOAD_EXPLAIN' => '<var>mbstring.func_overload</var> must be set to either 0 or 4.',
- 'MBSTRING_ENCODING_TRANSLATION' => 'Transparent character encoding',
- 'MBSTRING_ENCODING_TRANSLATION_EXPLAIN' => '<var>mbstring.encoding_translation</var> must be set to 0.',
- 'MBSTRING_HTTP_INPUT' => 'HTTP input character conversion',
- 'MBSTRING_HTTP_INPUT_EXPLAIN' => '<var>mbstring.http_input</var> must be set to <samp>pass</samp>.',
- 'MBSTRING_HTTP_OUTPUT' => 'HTTP output character conversion',
- 'MBSTRING_HTTP_OUTPUT_EXPLAIN' => '<var>mbstring.http_output</var> must be set to <samp>pass</samp>.',
-
- 'MAKE_FOLDER_WRITABLE' => 'Please make sure that this folder exists and is writable by the webserver then try again:<br />»<strong>%s</strong>.',
- 'MAKE_FOLDERS_WRITABLE' => 'Please make sure that these folders exist and are writable by the webserver then try again:<br />»<strong>%s</strong>.',
-
- 'MYSQL_SCHEMA_UPDATE_REQUIRED' => 'Your MySQL database schema for phpBB is outdated. phpBB detected a schema for MySQL 3.x/4.x, but the server runs on MySQL %2$s.<br /><strong>Before you proceed the update, you need to upgrade the schema.</strong><br /><br />Please refer to the <a href="https://www.phpbb.com/kb/article/doesnt-have-a-default-value-errors/">Knowledge Base article about upgrading the MySQL schema</a>. If you encounter problems, please use <a href="https://www.phpbb.com/community/viewforum.php?f=466">our support forums</a>.',
-
- 'NAMING_CONFLICT' => 'Naming conflict: %s and %s are both aliases<br /><br />%s',
- 'NEXT_STEP' => 'Proceed to next step',
- 'NOT_FOUND' => 'Cannot find',
- 'NOT_UNDERSTAND' => 'Could not understand %s #%d, table %s (“%sâ€)',
- 'NO_CONVERTORS' => 'No convertors are available for use.',
- 'NO_CONVERT_SPECIFIED' => 'No convertor specified.',
- 'NO_LOCATION' => 'Cannot determine location. If you know ImageMagick is installed, you may specify the location later within your administration control panel',
- 'NO_TABLES_FOUND' => 'No tables found.',
-
- 'OVERVIEW_BODY' => 'Welcome to phpBB3!<br /><br />phpBB® is the most widely used open source bulletin board solution in the world. phpBB3 is the latest installment in a package line started in 2000. Like its predecessors, phpBB3 is feature-rich, user-friendly, and fully supported by the phpBB Team. phpBB3 greatly improves on what made phpBB2 popular, and adds commonly requested features that were not present in previous versions. We hope it exceeds your expectations.<br /><br />This installation system will guide you through installing phpBB3, updating to the latest version of phpBB3 from past releases, as well as converting to phpBB3 from a different discussion board system (including phpBB2). For more information, we encourage you to read <a href="../docs/INSTALL.html">the installation guide</a>.<br /><br />To read the phpBB3 license or learn about obtaining support and our stance on it, please select the respective options from the side menu. To continue, please select the appropriate tab above.',
-
- 'PCRE_UTF_SUPPORT' => 'PCRE UTF-8 support',
- 'PCRE_UTF_SUPPORT_EXPLAIN' => 'phpBB will <strong>not</strong> run if your PHP installation is not compiled with UTF-8 support in the PCRE extension.',
- 'PHP_GETIMAGESIZE_SUPPORT' => 'PHP function getimagesize() is available',
- 'PHP_GETIMAGESIZE_SUPPORT_EXPLAIN' => '<strong>Required</strong> - In order for phpBB to function correctly, the getimagesize function needs to be available.',
- 'PHP_JSON_SUPPORT' => 'PHP JSON support',
- 'PHP_JSON_SUPPORT_EXPLAIN' => '<strong>Required</strong> - In order for phpBB to function correctly, the PHP JSON extension needs to be available.',
- 'PHP_OPTIONAL_MODULE' => 'Optional modules',
- 'PHP_OPTIONAL_MODULE_EXPLAIN' => '<strong>Optional</strong> - These modules or applications are optional. However, if they are available they will enable extra features.',
- 'PHP_SUPPORTED_DB' => 'Supported databases',
- 'PHP_SUPPORTED_DB_EXPLAIN' => '<strong>Required</strong> - You must have support for at least one compatible database within PHP. If no database modules are shown as available you should contact your hosting provider or review the relevant PHP installation documentation for advice.',
- 'PHP_REGISTER_GLOBALS' => 'PHP setting <var>register_globals</var> is disabled',
- 'PHP_REGISTER_GLOBALS_EXPLAIN' => 'phpBB will still run if this setting is enabled, but if possible, it is recommended that register_globals is disabled on your PHP install for security reasons.',
- 'PHP_SAFE_MODE' => 'Safe mode',
- 'PHP_SETTINGS' => 'PHP version and settings',
- 'PHP_SETTINGS_EXPLAIN' => '<strong>Required</strong> - You must be running at least version 5.3.3 of PHP (PHP 7 is not supported) in order to install phpBB. If <var>safe mode</var> is displayed below your PHP installation is running in that mode. This will impose limitations on remote administration and similar features.',
- 'PHP_URL_FOPEN_SUPPORT' => 'PHP setting <var>allow_url_fopen</var> is enabled',
- 'PHP_URL_FOPEN_SUPPORT_EXPLAIN' => '<strong>Optional</strong> - This setting is optional, however certain phpBB functions like off-site avatars will not work properly without it.',
- 'PHP_VERSION_REQD' => 'PHP version: >= 5.3.3, < 7.0.0-dev',
- 'POST_ID' => 'Post ID',
- 'PREFIX_FOUND' => 'A scan of your tables has shown a valid installation using <strong>%s</strong> as table prefix.',
- 'PREPROCESS_STEP' => 'Executing pre-processing functions/queries',
- 'PRE_CONVERT_COMPLETE' => 'All pre-conversion steps have successfully been completed. You may now begin the actual conversion process. Please note that you may have to manually do and adjust several things. After conversion, especially check the permissions assigned, rebuild your search index which is not converted and also make sure files got copied correctly, for example avatars and smilies.',
- 'PROCESS_LAST' => 'Processing last statements',
-
- 'REFRESH_PAGE' => 'Refresh page to continue conversion',
- 'REFRESH_PAGE_EXPLAIN' => 'If set to yes, the convertor will refresh the page to continue the conversion after having finished a step. If this is your first conversion for testing purposes and to determine any errors in advance, we suggest to set this to No.',
- 'REQUIREMENTS_TITLE' => 'Installation compatibility',
- 'REQUIREMENTS_EXPLAIN' => 'Before proceeding with the full installation phpBB will carry out some tests on your server configuration and files to ensure that you are able to install and run phpBB. Please ensure you read through the results thoroughly and do not proceed until all the required tests are passed. If you wish to use any of the features depending on the optional tests, you should ensure that these tests are passed also.',
- 'RETRY_WRITE' => 'Retry writing config',
- 'RETRY_WRITE_EXPLAIN' => 'If you wish you can change the permissions on config.php to allow phpBB to write to it. Should you wish to do that you can click Retry below to try again. Remember to return the permissions on config.php after phpBB has finished installation.',
-
- 'SCRIPT_PATH' => 'Script path',
- 'SCRIPT_PATH_EXPLAIN' => 'The path where phpBB is located relative to the domain name, e.g. <samp>/phpBB3</samp>.',
- 'SELECT_LANG' => 'Select language',
- 'SERVER_CONFIG' => 'Server configuration',
- 'SEARCH_INDEX_UNCONVERTED' => 'Search index was not converted',
- 'SEARCH_INDEX_UNCONVERTED_EXPLAIN' => 'Your old search index was not converted. Searching will always yield an empty result. To create a new search index go to the Administration Control Panel, select Maintenance and then choose Search index from the submenu.',
- 'SELECT_FORUM_GA' => 'In phpBB 3.1 the global announcements are linked to forums. Select a forum for your current global announcements (can be moved later):',
- 'SOFTWARE' => 'Board software',
- 'SPECIFY_OPTIONS' => 'Specify conversion options',
- 'STAGE_ADMINISTRATOR' => 'Administrator details',
- 'STAGE_ADVANCED' => 'Advanced settings',
- 'STAGE_ADVANCED_EXPLAIN' => 'The settings on this page are only necessary to set if you know that you require something different from the default. If you are unsure, just proceed to the next page, as these settings can be altered from the Administration Control Panel later.',
- 'STAGE_CONFIG_FILE' => 'Configuration file',
- 'STAGE_CREATE_TABLE' => 'Create database tables',
- 'STAGE_CREATE_TABLE_EXPLAIN' => 'The database tables used by phpBB 3.1 have been created and populated with some initial data. Proceed to the next screen to finish installing phpBB.',
- 'STAGE_DATABASE' => 'Database settings',
- 'STAGE_FINAL' => 'Final stage',
- 'STAGE_INTRO' => 'Introduction',
- 'STAGE_IN_PROGRESS' => 'Conversion in progress',
- 'STAGE_REQUIREMENTS' => 'Requirements',
- 'STAGE_SETTINGS' => 'Settings',
- 'STARTING_CONVERT' => 'Starting conversion process',
- 'STEP_PERCENT_COMPLETED' => 'Step <strong>%d</strong> of <strong>%d</strong>',
- 'SUB_INTRO' => 'Introduction',
- 'SUB_LICENSE' => 'License',
- 'SUB_SUPPORT' => 'Support',
- 'SUCCESSFUL_CONNECT' => 'Successful connection',
- 'SUPPORT_BODY' => 'Full support will be provided for the current stable release of phpBB3, free of charge. This includes:</p><ul><li>installation</li><li>configuration</li><li>technical questions</li><li>problems relating to potential bugs in the software</li><li>updating from Release Candidate (RC) versions to the latest stable version</li><li>converting from phpBB 2.0.x to phpBB3</li><li>converting from other discussion board software to phpBB3 (please see the <a href="https://www.phpbb.com/community/viewforum.php?f=486">Convertors Forum</a>)</li></ul><p>We encourage users still running beta versions of phpBB3 to replace their installation with a fresh copy of the latest version.</p><h2>Extensions / Styles</h2><p>For issues relating to Extensions, please post in the appropriate <a href="https://www.phpbb.com/community/viewforum.php?f=451">Extensions Forum</a>.<br />For issues relating to styles, templates and themes, please post in the appropriate <a href="https://www.phpbb.com/community/viewforum.php?f=471">Styles Forum</a>.<br /><br />If your question relates to a specific package, please post directly in the topic dedicated to the package.</p><h2>Obtaining Support</h2><p><a href="https://www.phpbb.com/community/viewtopic.php?f=14&amp;t=571070">The phpBB Welcome Package</a><br /><a href="https://www.phpbb.com/support/">Support Section</a><br /><a href="https://www.phpbb.com/support/docs/en/3.1/ug/quickstart/">Quick Start Guide</a><br /><br />To ensure you stay up to date with the latest news and releases, why not <a href="https://www.phpbb.com/support/">subscribe to our mailing list</a>?<br /><br />',
- 'SYNC_FORUMS' => 'Starting to synchronise forums',
- 'SYNC_POST_COUNT' => 'Synchronising post_counts',
- 'SYNC_POST_COUNT_ID' => 'Synchronising post_counts from <var>entry</var> %1$s to %2$s.',
- 'SYNC_TOPICS' => 'Starting to synchronise topics',
- 'SYNC_TOPIC_ID' => 'Synchronising topics from <var>topic_id</var> %1$s to %2$s.',
- 'TABLES_MISSING' => 'Could not find these tables<br />» <strong>%s</strong>.',
- 'TABLE_PREFIX' => 'Prefix for tables in database',
- 'TABLE_PREFIX_EXPLAIN' => 'The prefix must start with a letter and must only contain letters, numbers and underscores.',
- 'TABLE_PREFIX_SAME' => 'The table prefix needs to be the one used by the software you are converting from.<br />» Specified table prefix was %s.',
- 'TESTS_PASSED' => 'Tests passed',
- 'TESTS_FAILED' => 'Tests failed',
+ 'ACP_LINK' => 'Take me to <a href="%1$s">the ACP</a>',
- 'UNABLE_WRITE_LOCK' => 'Unable to write lock file.',
- 'UNAVAILABLE' => 'Unavailable',
- 'UNWRITABLE' => 'Unwritable',
- 'UPDATE_TOPICS_POSTED' => 'Generating topics posted information',
- 'UPDATE_TOPICS_POSTED_ERR' => 'An error occurred while generating topics posted information. You can retry this step in the ACP after the conversion process is completed.',
- 'VERIFY_OPTIONS' => 'Verifying conversion options',
- 'VERSION' => 'Version',
+ 'INSTALL_PHPBB_INSTALLED' => 'phpBB is already installed.',
+ 'INSTALL_PHPBB_NOT_INSTALLED' => 'phpBB is not installed yet.',
+));
- 'WELCOME_INSTALL' => 'Welcome to phpBB3 Installation',
- 'WRITABLE' => 'Writable',
+// Requirements translation
+$lang = array_merge($lang, array(
+ // Filesystem requirements
+ 'FILE_NOT_EXISTS' => 'File does not exist',
+ 'FILE_NOT_EXISTS_EXPLAIN' => 'To be able to install phpBB the %1$s file needs to exist.',
+ 'FILE_NOT_EXISTS_EXPLAIN_OPTIONAL' => 'It is recommended that the %1$s file exist for a better forum user experience.',
+ 'FILE_NOT_WRITABLE' => 'File is not writable',
+ 'FILE_NOT_WRITABLE_EXPLAIN' => 'To be able to install phpBB the %1$s file needs to be writable.',
+ 'FILE_NOT_WRITABLE_EXPLAIN_OPTIONAL' => 'It is recommended that the %1$s file be writable for a better forum user experience.',
+
+ 'DIRECTORY_NOT_EXISTS' => 'Directory does not exist',
+ 'DIRECTORY_NOT_EXISTS_EXPLAIN' => 'To be able to install phpBB the %1$s directory needs to exist.',
+ 'DIRECTORY_NOT_EXISTS_EXPLAIN_OPTIONAL' => 'It is recommended that the %1$s directory exist for a better forum user experience.',
+ 'DIRECTORY_NOT_WRITABLE' => 'Directory is not writable',
+ 'DIRECTORY_NOT_WRITABLE_EXPLAIN' => 'To be able to install phpBB the %1$s directory needs to be writable.',
+ 'DIRECTORY_NOT_WRITABLE_EXPLAIN_OPTIONAL' => 'It is recommended that the %1$s directory be writable for a better forum user experience.',
+
+ // Server requirements
+ 'PHP_VERSION_REQD' => 'PHP version',
+ 'PHP_VERSION_REQD_EXPLAIN' => 'phpBB requires PHP version 5.4.0 or higher.',
+ 'PHP_GETIMAGESIZE_SUPPORT' => 'PHP getimagesize() function is required',
+ 'PHP_GETIMAGESIZE_SUPPORT_EXPLAIN' => 'In order for phpBB to function correctly, the getimagesize function needs to be available.',
+ 'PCRE_UTF_SUPPORT' => 'PCRE UTF-8 support',
+ 'PCRE_UTF_SUPPORT_EXPLAIN' => 'phpBB will not run if your PHP installation is not compiled with UTF-8 support in the PCRE extension.',
+ 'PHP_JSON_SUPPORT' => 'PHP JSON support',
+ 'PHP_JSON_SUPPORT_EXPLAIN' => 'In order for phpBB to function correctly, the PHP JSON extension needs to be available.',
+ 'PHP_XML_SUPPORT' => 'PHP XML/DOM support',
+ 'PHP_XML_SUPPORT_EXPLAIN' => 'In order for phpBB to function correctly, the PHP XML/DOM extension needs to be available.',
+ 'PHP_SUPPORTED_DB' => 'Supported databases',
+ 'PHP_SUPPORTED_DB_EXPLAIN' => 'You must have support for at least one compatible database within PHP. If no database modules are shown as available you should contact your hosting provider or review the relevant PHP installation documentation for advice.',
+
+ 'RETEST_REQUIREMENTS' => 'Retest requirements',
+
+ 'STAGE_REQUIREMENTS' => 'Check requirements',
));
-// Updater
+// General error messages
$lang = array_merge($lang, array(
- 'ALL_FILES_UP_TO_DATE' => 'All files are up to date with the latest phpBB version.',
- 'ARCHIVE_FILE' => 'Source file within archive',
-
- 'BACK' => 'Back',
- 'BINARY_FILE' => 'Binary file',
- 'BOT' => 'Spider/Robot',
-
- 'CHANGE_CLEAN_NAMES' => 'The method used to make sure a username is not used by multiple users has been changed. There are some users which have the same name when compared with the new method. You have to delete or rename these users to make sure that each name is only used by one user before you can proceed.',
- 'CHECK_FILES' => 'Check files',
- 'CHECK_FILES_AGAIN' => 'Check files again',
- 'CHECK_FILES_EXPLAIN' => 'Within the next step all files will be checked against the update files - this can take a while if this is the first file check.',
- 'CHECK_FILES_UP_TO_DATE' => 'According to your database your version is up to date. You may want to proceed with the file check to make sure all files are really up to date with the latest phpBB version.',
- 'CHECK_UPDATE_DATABASE' => 'Continue update process',
- 'COLLECTED_INFORMATION' => 'File information',
- 'COLLECTED_INFORMATION_EXPLAIN' => 'The list below shows information about the files needing an update. Please read the information in front of every status block to see what they mean and what you may need to do to perform a successful update.',
- 'COLLECTING_FILE_DIFFS' => 'Collecting file differences',
- 'COMPLETE_LOGIN_TO_BOARD' => 'You should now <a href="../ucp.php?mode=login">login to your board</a> and check if everything is working fine. Do not forget to delete, rename or move your install directory!',
- 'CONTINUE_UPDATE_NOW' => 'Continue the update process now', // Shown within the database update script at the end if called from the updater
- 'CONTINUE_UPDATE' => 'Continue update now', // Shown after file upload to indicate the update process is not yet finished
- 'CURRENT_FILE' => 'Begin of Conflict - Original File code before update',
- 'CURRENT_VERSION' => 'Current version',
-
- 'DATABASE_TYPE' => 'Database type',
- 'DATABASE_UPDATE_COMPLETE' => 'Database updater has completed!',
- 'DATABASE_UPDATE_CONTINUE' => 'Continue database update',
- 'DATABASE_UPDATE_INFO_OLD' => 'The database update file within the install directory is outdated. Please make sure you uploaded the correct version of the file.',
- 'DATABASE_UPDATE_NOT_COMPLETED' => 'The database update has not yet completed.',
- 'DATABASE_VERSION' => 'Database version',
- 'DELETE_USER_REMOVE' => 'Delete user and remove posts',
- 'DELETE_USER_RETAIN' => 'Delete user but keep posts',
- 'DESTINATION' => 'Destination file',
- 'DIFF_INLINE' => 'Inline',
- 'DIFF_RAW' => 'Raw unified diff',
- 'DIFF_SEP_EXPLAIN' => 'Code block used within the updated/new file',
- 'DIFF_SIDE_BY_SIDE' => 'Side by Side',
- 'DIFF_UNIFIED' => 'Unified diff',
- 'DO_NOT_UPDATE' => 'Do not update this file',
- 'DONE' => 'Done',
- 'DOWNLOAD' => 'Download',
- 'DOWNLOAD_AS' => 'Download as',
- 'DOWNLOAD_UPDATE_METHOD_BUTTON' => 'Download modified files archive (recommended)',
- 'DOWNLOAD_CONFLICTS' => 'Download conflicts for this file',
- 'DOWNLOAD_CONFLICTS_EXPLAIN' => 'Search for &lt;&lt;&lt; to spot conflicts',
- 'DOWNLOAD_UPDATE_METHOD' => 'Download modified files archive',
- 'DOWNLOAD_UPDATE_METHOD_EXPLAIN' => 'Once downloaded you should unpack the archive. You will find the modified files you need to upload to your phpBB root directory within it. Please upload the files to their respective locations then. After you have uploaded all files, please check the files again with the other button below.',
+ 'INST_ERR_MISSING_DATA' => 'You must fill out all fields in this block.',
- 'EDIT_USERNAME' => 'Edit username',
- 'ERROR' => 'Error',
- 'EVERYTHING_UP_TO_DATE' => 'Everything is up to date with the latest phpBB version. You should now <a href="%1$s">login to your board</a> and check if everything is working fine. Do not forget to delete, rename or move your install directory! Please send us updated information about your server and board configurations from the <a href="%2$s">Send statistics</a> module in your ACP.',
+ 'TIMEOUT_DETECTED_TITLE' => 'The installer detected a timeout',
+ 'TIMEOUT_DETECTED_MESSAGE' => 'The installer has detected a timeout, you may try to refresh the page, which may lead to data corruption. We suggest that you either increase your timeout settings or try to use the CLI.',
+));
- 'FILE_ALREADY_UP_TO_DATE' => 'File is already up to date.',
- 'FILE_DIFF_NOT_ALLOWED' => 'File not allowed to be diffed.',
- 'FILE_USED' => 'Information used from', // Single file
- 'FILES_CONFLICT' => 'Conflict files',
- 'FILES_CONFLICT_EXPLAIN' => 'The following files are modified and do not represent the original files from the old version. phpBB determined that these files create conflicts if they are tried to be merged. Please investigate the conflicts and try to manually resolve them or continue the update choosing the preferred merging method. If you resolve the conflicts manually check the files again after you modified them. You are also able to choose between the preferred merge method for every file. The first one will result in a file where the conflicting lines from your old file will be lost, the other one will result in losing the changes from the newer file.',
- 'FILES_DELETED' => 'Deleted files',
- 'FILES_DELETED_EXPLAIN' => 'The following files do not exist in the new version. These files have to be deleted from your installation.',
- 'FILES_MODIFIED' => 'Modified files',
- 'FILES_MODIFIED_EXPLAIN' => 'The following files are modified and do not represent the original files from the old version. The updated file will be a merge between your modifications and the new file.',
- 'FILES_NEW' => 'New files',
- 'FILES_NEW_EXPLAIN' => 'The following files currently do not exist within your installation. These files will be added to your installation.',
- 'FILES_NEW_CONFLICT' => 'New conflicting files',
- 'FILES_NEW_CONFLICT_EXPLAIN' => 'The following files are new within the latest version but it has been determined that there is already a file with the same name within the same position. This file will be overwritten by the new file.',
- 'FILES_NOT_MODIFIED' => 'Not modified files',
- 'FILES_NOT_MODIFIED_EXPLAIN' => 'The following files are not modified and represent the original phpBB files from the version you want to update from.',
- 'FILES_UP_TO_DATE' => 'Already updated files',
- 'FILES_UP_TO_DATE_EXPLAIN' => 'The following files are already up to date and do not need to be updated.',
- 'FILES_VERSION' => 'Files Version',
- 'FTP_SETTINGS' => 'FTP settings',
- 'FTP_UPDATE_METHOD' => 'FTP upload',
+// Data obtaining translations
+$lang = array_merge($lang, array(
+ 'STAGE_OBTAIN_DATA' => 'Set installation data',
- 'INCOMPATIBLE_UPDATE_FILES' => 'The update files found are incompatible with your installed version. Your installed version is %1$s and the update file is for updating phpBB %2$s to %3$s.',
- 'INCOMPLETE_UPDATE_FILES' => 'The update files are incomplete.',
- 'INLINE_UPDATE_SUCCESSFUL' => 'The database update was successful. Now you need to continue the update process.',
-
- 'KEEP_OLD_NAME' => 'Keep username',
-
- 'LATEST_VERSION' => 'Latest version',
- 'LINE' => 'Line',
- 'LINE_ADDED' => 'Added',
- 'LINE_MODIFIED' => 'Modified',
- 'LINE_REMOVED' => 'Removed',
- 'LINE_UNMODIFIED' => 'Unmodified',
- 'LOGIN_UPDATE_EXPLAIN' => 'In order to update your installation you need to login first.',
-
- 'MAPPING_FILE_STRUCTURE' => 'To ease the upload here are the file locations which map your phpBB installation.',
-
- 'MERGE_MODIFICATIONS_OPTION' => 'Merge modifications',
-
- 'MERGE_NO_MERGE_NEW_OPTION' => 'Do not merge - use new file',
- 'MERGE_NO_MERGE_MOD_OPTION' => 'Do not merge - use currently installed file',
- 'MERGE_MOD_FILE_OPTION' => 'Merge modifications (removes new phpBB code within conflicting block)',
- 'MERGE_NEW_FILE_OPTION' => 'Merge modifications (removes modified code within conflicting block)',
- 'MERGE_SELECT_ERROR' => 'Conflicting file merge modes are not correctly selected.',
- 'MERGING_FILES' => 'Merging differences',
- 'MERGING_FILES_EXPLAIN' => 'Currently collecting final file changes.<br /><br />Please wait until phpBB has completed all operations on changed files.',
-
- 'NEW_FILE' => 'End of Conflict',
- 'NEW_USERNAME' => 'New username',
- 'NO_AUTH_UPDATE' => 'Not authorised to update',
- 'NO_ERRORS' => 'No errors',
- 'NO_UPDATE_FILES' => 'Not updating the following files',
- 'NO_UPDATE_FILES_EXPLAIN' => 'The following files are new or modified but the directory they normally reside in could not be found on your installation. If this list contains files to other directories than language/ or styles/ than you may have modified your directory structure and the update may be incomplete.',
- 'NO_UPDATE_FILES_OUTDATED' => 'No valid update directory was found, please make sure you uploaded the relevant files.<br /><br />Your installation does <strong>not</strong> seem to be up to date. Updates are available for your version of phpBB %1$s, please visit <a href="https://www.phpbb.com/downloads/" rel="external">https://www.phpbb.com/downloads/</a> to obtain the correct package to update from Version %2$s to Version %3$s.',
- 'NO_UPDATE_FILES_UP_TO_DATE' => 'Your version is up to date. There is no need to run the update tool. If you want to make an integrity check on your files make sure you uploaded the correct update files.',
- 'NO_UPDATE_INFO' => 'Update file information could not be found.',
- 'NO_UPDATES_REQUIRED' => 'No updates required',
- 'NO_VISIBLE_CHANGES' => 'No visible changes',
- 'NOTICE' => 'Notice',
- 'NUM_CONFLICTS' => 'Number of conflicts',
- 'NUMBER_OF_FILES_COLLECTED' => 'Currently differences from %1$d of %2$d files have been checked.<br />Please wait until all files are checked.',
+ //
+ // Admin data
+ //
+ 'STAGE_ADMINISTRATOR' => 'Administrator details',
- 'OLD_UPDATE_FILES' => 'Update files are out of date. The update files found are for updating from phpBB %1$s to phpBB %2$s but the latest version of phpBB is %3$s.',
+ // Form labels
+ 'ADMIN_CONFIG' => 'Administrator configuration',
+ 'ADMIN_PASSWORD' => 'Administrator password',
+ 'ADMIN_PASSWORD_CONFIRM' => 'Confirm administrator password',
+ 'ADMIN_PASSWORD_EXPLAIN' => 'Please enter a password between 6 and 30 characters in length.',
+ 'ADMIN_USERNAME' => 'Administrator username',
+ 'ADMIN_USERNAME_EXPLAIN' => 'Please enter a username between 3 and 20 characters in length.',
- 'PACKAGE_UPDATES_TO' => 'Current package updates to version',
+ // Errors
+ 'INST_ERR_EMAIL_INVALID' => 'The email address you entered is invalid.',
+ 'INST_ERR_PASSWORD_MISMATCH' => 'The passwords you entered did not match.',
+ 'INST_ERR_PASSWORD_TOO_LONG' => 'The password you entered is too long. The maximum length is 30 characters.',
+ 'INST_ERR_PASSWORD_TOO_SHORT' => 'The password you entered is too short. The minimum length is 6 characters.',
+ 'INST_ERR_USER_TOO_LONG' => 'The username you entered is too long. The maximum length is 20 characters.',
+ 'INST_ERR_USER_TOO_SHORT' => 'The username you entered is too short. The minimum length is 3 characters.',
+
+ //
+ // Board data
+ //
+ // Form labels
+ 'BOARD_CONFIG' => 'Bulletin board configuration',
+ 'DEFAULT_LANGUAGE' => 'Default language',
+ 'BOARD_NAME' => 'Title of the board',
+ 'BOARD_DESCRIPTION' => 'Short description of the board',
+
+ //
+ // Database data
+ //
+ 'STAGE_DATABASE' => 'Database settings',
+
+ // Form labels
+ 'DB_CONFIG' => 'Database configuration',
+ 'DBMS' => 'Database type',
+ 'DB_HOST' => 'Database server hostname or DSN',
+ 'DB_HOST_EXPLAIN' => 'DSN stands for Data Source Name and is relevant only for ODBC installs. On PostgreSQL, use localhost to connect to the local server via UNIX domain socket and 127.0.0.1 to connect via TCP. For SQLite, enter the full path to your database file.',
+ 'DB_PORT' => 'Database server port',
+ 'DB_PORT_EXPLAIN' => 'Leave this blank unless you know the server operates on a non-standard port.',
+ 'DB_PASSWORD' => 'Database password',
+ 'DB_NAME' => 'Database name',
+ 'DB_USERNAME' => 'Database username',
+ 'DATABASE_VERSION' => 'Database version',
+ 'TABLE_PREFIX' => 'Prefix for tables in database',
+ 'TABLE_PREFIX_EXPLAIN' => 'The prefix must start with a letter and must only contain letters, numbers and underscores.',
+
+ // Database options
+ 'DB_OPTION_MSSQL_ODBC' => 'MSSQL Server 2000+ via ODBC',
+ 'DB_OPTION_MSSQLNATIVE' => 'MSSQL Server 2005+ [ Native ]',
+ 'DB_OPTION_MYSQL' => 'MySQL',
+ 'DB_OPTION_MYSQLI' => 'MySQL with MySQLi Extension',
+ 'DB_OPTION_ORACLE' => 'Oracle',
+ 'DB_OPTION_POSTGRES' => 'PostgreSQL',
+ 'DB_OPTION_SQLITE3' => 'SQLite 3',
+
+ // Errors
+ 'INST_ERR_DB' => 'Database installation error',
+ 'INST_ERR_NO_DB' => 'Cannot load the PHP module for the selected database type.',
+ 'INST_ERR_DB_INVALID_PREFIX' => 'The prefix you entered is invalid. It must start with a letter and must only contain letters, numbers and underscores.',
+ 'INST_ERR_PREFIX_TOO_LONG' => 'The table prefix you have specified is too long. The maximum length is %d characters.',
+ 'INST_ERR_DB_NO_NAME' => 'No database name specified.',
+ 'INST_ERR_DB_FORUM_PATH' => 'The database file specified is within your board directory tree. You should put this file in a non web-accessible location.',
+ 'INST_ERR_DB_CONNECT' => 'Could not connect to the database, see error message below.',
+ 'INST_ERR_DB_NO_WRITABLE' => 'Both the database and the directory containing it must be writable.',
+ 'INST_ERR_DB_NO_ERROR' => 'No error message given.',
+ 'INST_ERR_PREFIX' => 'Tables with the specified prefix already exist, please choose an alternative.',
+ 'INST_ERR_DB_NO_MYSQLI' => 'The version of MySQL installed on this machine is incompatible with the “MySQL with MySQLi Extension†option you have selected. Please try the “MySQL†option instead.',
+ 'INST_ERR_DB_NO_SQLITE3' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 3.6.15.',
+ 'INST_ERR_DB_NO_ORACLE' => 'The version of Oracle installed on this machine requires you to set the <var>NLS_CHARACTERSET</var> parameter to <var>UTF8</var>. Either upgrade your installation to 9.2+ or change the parameter.',
+ 'INST_ERR_DB_NO_POSTGRES' => 'The database you have selected was not created in <var>UNICODE</var> or <var>UTF8</var> encoding. Try installing with a database in <var>UNICODE</var> or <var>UTF8</var> encoding.',
+ 'INST_SCHEMA_FILE_NOT_WRITABLE' => 'The schema file is not writable',
+
+ //
+ // Email data
+ //
+ 'EMAIL_CONFIG' => 'E-mail configuration',
+
+ // Package info
'PACKAGE_VERSION' => 'Package version installed',
- 'PERFORM_DATABASE_UPDATE' => 'Perform database update',
- 'PERFORM_DATABASE_UPDATE_EXPLAIN' => 'Below you will find a button to the database update script. The database update can take a while, so please do not stop the execution if it seems to hang. After the database update has been performed just follow the instructions to continue the update process.',
- 'PREVIOUS_VERSION' => 'Previous version',
- 'PROGRESS' => 'Progress',
-
- 'RELEASE_ANNOUNCEMENT' => 'Announcement',
- 'RESULT' => 'Result',
- 'RUN_DATABASE_SCRIPT' => 'Update my database now',
-
- 'SELECT_DIFF_MODE' => 'Select diff mode',
- 'SELECT_DOWNLOAD_FORMAT' => 'Select download archive format',
- 'SELECT_FTP_SETTINGS' => 'Select FTP settings',
- 'SHOW_DIFF_CONFLICT' => 'Show differences/conflicts',
- 'SHOW_DIFF_DELETED' => 'Show file contents',
- 'SHOW_DIFF_FINAL' => 'Show resulting file',
- 'SHOW_DIFF_MODIFIED' => 'Show merged differences',
- 'SHOW_DIFF_NEW' => 'Show file contents',
- 'SHOW_DIFF_NEW_CONFLICT' => 'Show differences',
- 'SHOW_DIFF_NOT_MODIFIED' => 'Show differences',
- 'SOME_QUERIES_FAILED' => 'Some queries failed, the statements and errors are listed below.',
- 'SQL' => 'SQL',
- 'SQL_FAILURE_EXPLAIN' => 'This is probably nothing to worry about, update will continue. Should this fail to complete you may need to seek help at our support forums. See <a href="../docs/README.html">README</a> for details on how to obtain advice.',
- 'STAGE_FILE_CHECK' => 'Check files',
- 'STAGE_UPDATE_DB' => 'Update database',
- 'STAGE_UPDATE_FILES' => 'Update files',
- 'STAGE_VERSION_CHECK' => 'Version check',
- 'STATUS_CONFLICT' => 'Modified file producing conflicts',
- 'STATUS_DELETED' => 'Deleted file',
- 'STATUS_MODIFIED' => 'Modified file',
- 'STATUS_NEW' => 'New file',
- 'STATUS_NEW_CONFLICT' => 'Conflicting new file',
- 'STATUS_NOT_MODIFIED' => 'Not modified file',
- 'STATUS_UP_TO_DATE' => 'Already updated file',
-
- 'TOGGLE_DISPLAY' => 'View/Hide file list',
- 'TRY_DOWNLOAD_METHOD' => 'You may want to try the download modified files method.<br />This method always works and is also the recommended update path.',
- 'TRY_DOWNLOAD_METHOD_BUTTON'=> 'Try this method now',
-
- 'UPDATE_COMPLETED' => 'Update completed',
- 'UPDATE_DATABASE' => 'Update database',
- 'UPDATE_DATABASE_EXPLAIN' => 'Within the next step the database will be updated.',
- 'UPDATE_DATABASE_SCHEMA' => 'Updating database schema',
- 'UPDATE_FILES' => 'Update files',
- 'UPDATE_FILES_NOTICE' => 'Please make sure you have updated your board files too, this file is only updating your database.',
'UPDATE_INCOMPLETE' => 'Your phpBB installation has not been correctly updated.',
'UPDATE_INCOMPLETE_MORE' => 'Please read the information below in order to fix this error.',
'UPDATE_INCOMPLETE_EXPLAIN' => '<h1>Incomplete update</h1>
- <p>We noticed that the last update of your phpBB installation hasn’t been completed. Visit the <a href="%1$s" title="%1$s">database_update script</a> and run it. If it is missing, please <a href="https://www.phpbb.com/downloads/" title="phpBB downloads">download your package version</a>, upload the "install" folder to your phpBB root directory (where your config.php file is) and <a href="%1$s" title="%1$s">run the database update script</a>.</p>',
-
- 'UPDATE_INSTALLATION' => 'Update phpBB installation',
- 'UPDATE_INSTALLATION_EXPLAIN' => 'With this option, it is possible to update your phpBB installation to the latest version.<br />During the process all of your files will be checked for their integrity. You are able to review all differences and files before the update.<br /><br />The file update itself can be done in two different ways.</p><h2>Manual Update</h2><p>With this update you only download your personal set of changed files to make sure you do not lose your file modifications you may have done. After you downloaded this package you need to manually upload the files to their correct position under your phpBB root directory. Once done, you are able to do the file check stage again to see if you moved the files to their correct location.</p><h2>Automatic Update with FTP</h2><p>This method is similar to the first one but without the need to download the changed files and uploading them on your own. This will be done for you. In order to use this method you need to know your FTP login details since you will be asked for them. Once finished you will be redirected to the file check again to make sure everything got updated correctly.<br /><br />',
- 'UPDATE_INSTRUCTIONS' => '
-
- <h1>Release announcement</h1>
-
- <p>Please read the release announcement for the latest version before you continue your update process, it may contain useful information. It also contains full download links as well as the change log.</p>
-
- <br />
-
- <h1>How to update your installation with the Automatic Update Package</h1>
-
- <p>The recommended way of updating your installation listed here is only valid for the automatic update package. You are also able to update your installation using the methods listed within the INSTALL.html document. The steps for updating phpBB3 automatically are:</p>
+ <p>We noticed that the last update of your phpBB installation hasn’t been completed. Visit the <a href="%1$s" title="%1$s">database updater</a>, ensure <em>Update database only</em> is selected and click on <strong>Submit</strong>. Don\'t forget to delete the "install"-directory after you have updated the database sucessfully.</p>',
- <ul style="margin-left: 20px; font-size: 1.1em;">
- <li>Go to the <a href="https://www.phpbb.com/downloads/" title="https://www.phpbb.com/downloads/">phpBB.com downloads page</a> and download the "Automatic Update Package" archive.<br /><br /></li>
- <li>Unpack the archive.<br /><br /></li>
- <li>Upload the complete uncompressed "install" and "vendor" folders to your phpBB root directory (where your config.php file is).<br /><br /></li>
- </ul>
-
- <p>Once uploaded your board will be offline for normal users due to the install directory you uploaded now present.<br /><br />
- <strong><a href="%1$s" title="%1$s">Now start the update process by pointing your browser to the install folder</a>.</strong><br />
- <br />
- You will then be guided through the update process. You will be notified once the update is complete.
- </p>
- ',
- 'UPDATE_METHOD' => 'Update method',
- 'UPDATE_METHOD_EXPLAIN' => 'You are now able to choose your preferred update method. Using the FTP upload will present you with a form you need to enter your FTP account details into. With this method the files will be automatically moved to the new location and backups of the old files being created by appending .bak to the filename. If you choose to download the modified files you are able to unpack and upload them to their correct location manually later.',
- 'UPDATE_REQUIRES_FILE' => 'The updater requires that the following file is present: %s',
- 'UPDATE_SUCCESS' => 'Update was successful',
- 'UPDATE_SUCCESS_EXPLAIN' => 'Successfully updated all files. The next step involves checking all files again to make sure the files got updated correctly.',
- 'UPDATE_VERSION_OPTIMIZE' => 'Updating version and optimising tables',
- 'UPDATING_DATA' => 'Updating data',
- 'UPDATING_TO_LATEST_STABLE' => 'Updating database to latest stable release',
- 'UPDATED_VERSION' => 'Updated version',
+ //
+ // Server data
+ //
+ // Form labels
'UPGRADE_INSTRUCTIONS' => 'A new feature release <strong>%1$s</strong> is available. Please read <a href="%2$s" title="%2$s"><strong>the release announcement</strong></a> to learn about what it has to offer, and how to upgrade.',
- 'UPLOAD_METHOD' => 'Upload method',
-
- 'UPDATE_DB_SUCCESS' => 'Database update was successful.',
- 'UPDATE_FILE_SUCCESS' => 'File update was successful.',
- 'USER_ACTIVE' => 'Active user',
- 'USER_INACTIVE' => 'Inactive user',
-
- 'VERSION_CHECK' => 'Version check',
- 'VERSION_CHECK_EXPLAIN' => 'Checks to see if your phpBB installation is up to date.',
- 'VERSION_NOT_UP_TO_DATE' => 'Your phpBB installation is not up to date. Please continue the update process.',
- 'VERSION_NOT_UP_TO_DATE_ACP' => 'Your phpBB installation is not up to date.<br />Below is a link to the release announcement, which contains more information as well as instructions on updating.',
- 'VERSION_NOT_UP_TO_DATE_TITLE' => 'Your phpBB installation is not up to date.',
- 'VERSION_UP_TO_DATE' => 'Your phpBB installation is up to date. Although there are no updates available at this time, you may continue in order to perform a file validity check.',
- 'VERSION_UP_TO_DATE_ACP' => 'Your phpBB installation is up to date. There are no updates available at this time.',
- 'VIEWING_FILE_CONTENTS' => 'Viewing file contents',
- 'VIEWING_FILE_DIFF' => 'Viewing file differences',
-
- 'WRONG_INFO_FILE_FORMAT' => 'Wrong info file format',
+ 'SERVER_CONFIG' => 'Server configuration',
+ 'SCRIPT_PATH' => 'Script path',
+ 'SCRIPT_PATH_EXPLAIN' => 'The path where phpBB is located relative to the domain name, e.g. <samp>/phpBB3</samp>.',
));
// Default database schema entries...
@@ -640,3 +277,323 @@ $lang = array_merge($lang, array(
'TOPICS_TOPIC_TITLE' => 'Welcome to phpBB3',
));
+
+// Common navigation items' translation
+$lang = array_merge($lang, array(
+ 'MENU_OVERVIEW' => 'Overview',
+ 'MENU_INTRO' => 'Introduction',
+ 'MENU_LICENSE' => 'License',
+ 'MENU_SUPPORT' => 'Support',
+));
+
+// Task names
+$lang = array_merge($lang, array(
+ // Install filesystem
+ 'TASK_CREATE_CONFIG_FILE' => 'Creating configuration file',
+
+ // Install database
+ 'TASK_ADD_CONFIG_SETTINGS' => 'Adding configuration settings',
+ 'TASK_ADD_DEFAULT_DATA' => 'Adding default settings to the database',
+ 'TASK_CREATE_DATABASE_SCHEMA_FILE' => 'Creating database schema file',
+ 'TASK_SETUP_DATABASE' => 'Setting up database',
+ 'TASK_CREATE_TABLES' => 'Creating tables',
+
+ // Install data
+ 'TASK_ADD_BOTS' => 'Registering bots',
+ 'TASK_ADD_LANGUAGES' => 'Installing available languages',
+ 'TASK_ADD_MODULES' => 'Installing modules',
+ 'TASK_CREATE_SEARCH_INDEX' => 'Creating search index',
+
+ // Install finish tasks
+ 'TASK_INSTALL_EXTENSIONS' => 'Installing packaged extensions',
+ 'TASK_NOTIFY_USER' => 'Sending notification e-mail',
+ 'TASK_POPULATE_MIGRATIONS' => 'Populating migrations',
+
+ // Installer general progress messages
+ 'INSTALLER_FINISHED' => 'The installer has finished successfully',
+));
+
+// Installer's general messages
+$lang = array_merge($lang, array(
+ 'MODULE_NOT_FOUND' => 'Module not found',
+ 'MODULE_NOT_FOUND_DESCRIPTION' => 'A module could not be found because the service, %s, is undefined.',
+
+ 'TASK_NOT_FOUND' => 'Task not found',
+ 'TASK_NOT_FOUND_DESCRIPTION' => 'A task could not be found because the service, %s, is undefined.',
+
+ 'SKIP_MODULE' => 'Skip “%s†module',
+ 'SKIP_TASK' => 'Skip “%s†task',
+
+ 'TASK_SERVICE_INSTALLER_MISSING' => 'All installer task services should start with “installerâ€',
+ 'TASK_CLASS_NOT_FOUND' => 'Installer task service definition is invalid. Service name “%1$s†given, the expected class namespace is “%2$s†for that. For more information please see the documentation of task_interface.',
+
+ 'INSTALLER_CONFIG_NOT_WRITABLE' => 'The installer config file is not writable.',
+));
+
+// CLI messages
+$lang = array_merge($lang, array(
+ 'CLI_INSTALL_BOARD' => 'Install phpBB',
+ 'CLI_UPDATE_BOARD' => 'Update phpBB',
+ 'CLI_INSTALL_SHOW_CONFIG' => 'Show the configuration which will be used',
+ 'CLI_INSTALL_VALIDATE_CONFIG' => 'Validate a configuration file',
+ 'CLI_CONFIG_FILE' => 'Config file to use',
+ 'MISSING_FILE' => 'Unable to access file %1$s',
+ 'MISSING_DATA' => 'Config file is missing data or might contain invalid settings.',
+ 'INVALID_YAML_FILE' => 'Could not parse YAML file %1$s',
+ 'CONFIGURATION_VALID' => 'The configuration file is valid',
+));
+
+// Common updater messages
+$lang = array_merge($lang, array(
+ 'UPDATE_INSTALLATION' => 'Update phpBB installation',
+ 'UPDATE_INSTALLATION_EXPLAIN' => 'With this option, it is possible to update your phpBB installation to the latest version.<br />During the process all of your files will be checked for their integrity. You are able to review all differences and files before the update.<br /><br />The file update itself can be done in two different ways.</p><h2>Manual Update</h2><p>With this update you only download your personal set of changed files to make sure you do not lose your file modifications you may have done. After you downloaded this package you need to manually upload the files to their correct position under your phpBB root directory. Once done, you are able to do the file check stage again to see if you moved the files to their correct location.</p><h2>Automatic Update with FTP</h2><p>This method is similar to the first one but without the need to download the changed files and uploading them on your own. This will be done for you. In order to use this method you need to know your FTP login details since you will be asked for them. Once finished you will be redirected to the file check again to make sure everything got updated correctly.<br /><br />',
+ 'UPDATE_INSTRUCTIONS' => '
+
+ <h1>Release announcement</h1>
+
+ <p>Please read the release announcement for the latest version before you continue your update process, it may contain useful information. It also contains full download links as well as the change log.</p>
+
+ <br />
+
+ <h1>How to update your installation with the Full Package</h1>
+
+ <p>The recommended way of updating your installation is using the full package. If core phpBB files have been modified in your installation you may wish to use the automatic update package in order to not lose these changes. You are also able to update your installation using the other methods listed within the INSTALL.html document. The steps for updating phpBB3 using the full package are:</p>
+
+ <ol style="margin-left: 20px; font-size: 1.1em;">
+ <li><strong class="error">Backup all board files and the database.</strong></li>
+ <li>Go to the <a href="https://www.phpbb.com/downloads/" title="https://www.phpbb.com/downloads/">phpBB.com downloads page</a> and download the latest "Full Package" archive.</li>
+ <li>Unpack the archive.</li>
+ <li>Remove (delete) the <code class="inline">config.php</code> file, and the <code class="inline">/images</code>, <code class="inline">/store</code> and <code class="inline">/files</code> folders <em>from the package</em> (not your site).</li>
+ <li>Go to the ACP, Board settings, and make sure prosilver is set as the default style. If not, set it to prosilver.</li>
+ <li>Delete the <code class="inline">/vendor</code> and <code class="inline">/cache</code> folders from the board’s root folder on the host.</li>
+ <li>Via FTP or SSH upload the remaining files and folders (that is, the remaining CONTENTS of the phpBB3 folder) to the root folder of your board installation on the server, overwriting the existing files. (Note: take care not to delete any extensions in your <code class="inline">/ext</code> folder when uploading the new phpBB3 contents.)</li>
+ <li><strong><a href="%1$s" title="%1$s">Now start the update process by pointing your browser to the install folder</a>.</strong></li>
+ <li>Follow the steps to update the database and let that run to completion.</li>
+ <li>Via FTP or SSH delete the <code class="inline">/install</code> folder from the root of your board installation.<br><br></li>
+ </ol>
+
+ <p>You now have a new up to date board containing all your users and posts. Follow up tasks:</p>
+ <ul style="margin-left: 20px; font-size: 1.1em;">
+ <li>Update your language pack</li>
+ <li>Update your style<br><br></li>
+ </ul>
+
+ <h1>How to update your installation with the Automatic Update Package</h1>
+
+ <p>The automatic update package is only recommended in case core phpBB files have been modified in your installation. You are also able to update your installation using the methods listed within the INSTALL.html document. The steps for updating phpBB3 using the automatic update package are:</p>
+
+ <ol style="margin-left: 20px; font-size: 1.1em;">
+ <li>Go to the <a href="https://www.phpbb.com/downloads/" title="https://www.phpbb.com/downloads/">phpBB.com downloads page</a> and download the "Automatic Update Package" archive.</li>
+ <li>Unpack the archive.</li>
+ <li>Upload the complete uncompressed "install" and "vendor" folders to your phpBB root directory (where your config.php file is).<br><br></li>
+ </ol>
+
+ <p>Once uploaded your board will be offline for normal users due to the install directory you uploaded now being present.<br /><br />
+ <strong><a href="%1$s" title="%1$s">Now start the update process by pointing your browser to the install folder</a>.</strong><br />
+ <br />
+ You will then be guided through the update process. You will be notified once the update is complete.
+ </p>
+ ',
+));
+
+// Updater forms
+$lang = array_merge($lang, array(
+ // Updater types
+ 'UPDATE_TYPE' => 'Type of update to run',
+
+ 'UPDATE_TYPE_ALL' => 'Update filesystem and database',
+ 'UPDATE_TYPE_DB_ONLY' => 'Update database only',
+
+ // File updater methods
+ 'UPDATE_FILE_METHOD_TITLE' => 'File updater methods',
+
+ 'UPDATE_FILE_METHOD' => 'File updater method',
+ 'UPDATE_FILE_METHOD_DOWNLOAD' => 'Download modified files in an archive',
+ 'UPDATE_FILE_METHOD_FTP' => 'Update files via FTP (Automatic)',
+ 'UPDATE_FILE_METHOD_FILESYSTEM' => 'Update files via direct file access (Automatic)',
+
+ // File updater archives
+ 'SELECT_DOWNLOAD_FORMAT' => 'Select download archive format',
+
+ // FTP settings
+ 'FTP_SETTINGS' => 'FTP settings',
+));
+
+// Requirements messages
+$lang = array_merge($lang, array(
+ 'UPDATE_FILES_NOT_FOUND' => 'No valid update directory was found, please make sure you uploaded the relevant files.',
+
+ 'NO_UPDATE_FILES_UP_TO_DATE' => 'Your version is up to date. There is no need to run the update tool. If you want to make an integrity check on your files make sure you uploaded the correct update files.',
+ 'OLD_UPDATE_FILES' => 'Update files are out of date. The update files found are for updating from phpBB %1$s to phpBB %2$s but the latest version of phpBB is %3$s.',
+ 'INCOMPATIBLE_UPDATE_FILES' => 'The update files found are incompatible with your installed version. Your installed version is %1$s and the update file is for updating phpBB %2$s to %3$s.',
+));
+
+// Update files
+$lang = array_merge($lang, array(
+ 'STAGE_UPDATE_FILES' => 'Update files',
+
+ // Check files
+ 'UPDATE_CHECK_FILES' => 'Check files to update',
+
+ // Update file differ
+ 'FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ' => 'The file differ failed to open %s.',
+
+ 'UPDATE_FILE_DIFF' => 'Diffing changed files',
+ 'ALL_FILES_DIFFED' => 'All modified files has been diffed.',
+
+ // File status
+ 'UPDATE_CONTINUE_FILE_UPDATE' => 'Update files',
+
+ 'DOWNLOAD' => 'Download',
+ 'DOWNLOAD_CONFLICTS' => 'Download merge conflicts archive',
+ 'DOWNLOAD_CONFLICTS_EXPLAIN' => 'Search for &lt;&lt;&lt; to spot conflicts',
+ 'DOWNLOAD_UPDATE_METHOD' => 'Download modified files archive',
+ 'DOWNLOAD_UPDATE_METHOD_EXPLAIN' => 'Once downloaded you should unpack the archive. You will find the modified files you need to upload to your phpBB root directory within it. Please upload the files to their respective locations then. After you have uploaded all files, you may continue with the update process.',
+
+ 'FILE_ALREADY_UP_TO_DATE' => 'File is already up to date.',
+ 'FILE_DIFF_NOT_ALLOWED' => 'File not allowed to be diffed.',
+ 'FILE_USED' => 'Information used from', // Single file
+ 'FILES_CONFLICT' => 'Conflict files',
+ 'FILES_CONFLICT_EXPLAIN' => 'The following files are modified and do not represent the original files from the old version. phpBB determined that these files create conflicts if they are tried to be merged. Please investigate the conflicts and try to manually resolve them or continue the update choosing the preferred merging method. If you resolve the conflicts manually check the files again after you modified them. You are also able to choose between the preferred merge method for every file. The first one will result in a file where the conflicting lines from your old file will be lost, the other one will result in losing the changes from the newer file.',
+ 'FILES_DELETED' => 'Deleted files',
+ 'FILES_DELETED_EXPLAIN' => 'The following files do not exist in the new version. These files have to be deleted from your installation.',
+ 'FILES_MODIFIED' => 'Modified files',
+ 'FILES_MODIFIED_EXPLAIN' => 'The following files are modified and do not represent the original files from the old version. The updated file will be a merge between your modifications and the new file.',
+ 'FILES_NEW' => 'New files',
+ 'FILES_NEW_EXPLAIN' => 'The following files currently do not exist within your installation. These files will be added to your installation.',
+ 'FILES_NEW_CONFLICT' => 'New conflicting files',
+ 'FILES_NEW_CONFLICT_EXPLAIN' => 'The following files are new within the latest version but it has been determined that there is already a file with the same name within the same position. This file will be overwritten by the new file.',
+ 'FILES_NOT_MODIFIED' => 'Not modified files',
+ 'FILES_NOT_MODIFIED_EXPLAIN' => 'The following files are not modified and represent the original phpBB files from the version you want to update from.',
+ 'FILES_UP_TO_DATE' => 'Already updated files',
+ 'FILES_UP_TO_DATE_EXPLAIN' => 'The following files are already up to date and do not need to be updated.',
+ 'FILES_VERSION' => 'Files Version',
+ 'TOGGLE_DISPLAY' => 'View/Hide file list',
+
+ // File updater
+ 'UPDATE_UPDATING_FILES' => 'Updating files',
+
+ 'UPDATE_FILE_UPDATER_HAS_FAILED' => 'File updater “%1$s“ has failed. The installer will try to fallback to “%2$s“.',
+ 'UPDATE_FILE_UPDATERS_HAVE_FAILED' => 'The file updater failed. No further fallback methods are available.',
+
+ 'UPDATE_CONTINUE_UPDATE_PROCESS' => 'Continue update process',
+ 'UPDATE_RECHECK_UPDATE_FILES' => 'Check files again',
+));
+
+// Update database
+$lang = array_merge($lang, array(
+ 'STAGE_UPDATE_DATABASE' => 'Update database',
+
+ 'INLINE_UPDATE_SUCCESSFUL' => 'The database update was successful.',
+
+ 'TASK_UPDATE_EXTENSIONS' => 'Updating extensions',
+));
+
+// Converter
+$lang = array_merge($lang, array(
+ // Common converter messages
+ 'CONVERT_NOT_EXIST' => 'The specified convertor does not exist.',
+ 'DEV_NO_TEST_FILE' => 'No value has been specified for the test_file variable in the convertor. If you are a user of this convertor, you should not be seeing this error, please report this message to the convertor author. If you are a convertor author, you must specify the name of a file which exists in the source board to allow the path to it to be verified.',
+ 'COULD_NOT_FIND_PATH' => 'Could not find path to your former board. Please check your settings and try again.<br />» %s was specified as the source path.',
+ 'CONFIG_PHPBB_EMPTY' => 'The phpBB3 config variable for “%s†is empty.',
+
+ 'MAKE_FOLDER_WRITABLE' => 'Please make sure that this folder exists and is writable by the webserver then try again:<br />»<strong>%s</strong>.',
+ 'MAKE_FOLDERS_WRITABLE' => 'Please make sure that these folders exist and are writable by the webserver then try again:<br />»<strong>%s</strong>.',
+
+ 'INSTALL_TEST' => 'Test again',
+
+ 'NO_TABLES_FOUND' => 'No tables found.',
+ 'TABLES_MISSING' => 'Could not find these tables<br />» <strong>%s</strong>.',
+ 'CHECK_TABLE_PREFIX' => 'Please check your table prefix and try again.',
+
+ // Conversion in progress
+ 'CONTINUE_CONVERT' => 'Continue conversion',
+ 'CONTINUE_CONVERT_BODY' => 'A previous conversion attempt has been determined. You are now able to choose between starting a new conversion or continuing the conversion.',
+ 'CONVERT_NEW_CONVERSION' => 'New conversion',
+ 'CONTINUE_OLD_CONVERSION' => 'Continue previously started conversion',
+
+ // Start conversion
+ 'SUB_INTRO' => 'Introduction',
+ 'CONVERT_INTRO' => 'Welcome to the phpBB Unified Convertor Framework',
+ 'CONVERT_INTRO_BODY' => 'From here, you are able to import data from other (installed) board systems. The list below shows all the conversion modules currently available. If there is no convertor shown in this list for the board software you wish to convert from, please check our website where further conversion modules may be available for download.',
+ 'AVAILABLE_CONVERTORS' => 'Available convertors',
+ 'NO_CONVERTORS' => 'No convertors are available for use.',
+ 'CONVERT_OPTIONS' => 'Options',
+ 'SOFTWARE' => 'Board software',
+ 'VERSION' => 'Version',
+ 'CONVERT' => 'Convert',
+
+ // Settings
+ 'STAGE_SETTINGS' => 'Settings',
+ 'TABLE_PREFIX_SAME' => 'The table prefix needs to be the one used by the software you are converting from.<br />» Specified table prefix was %s.',
+ 'DEFAULT_PREFIX_IS' => 'The convertor was not able to find tables with the specified prefix. Please make sure you have entered the correct details for the board you are converting from. The default table prefix for %1$s is <strong>%2$s</strong>.',
+ 'SPECIFY_OPTIONS' => 'Specify conversion options',
+ 'FORUM_PATH' => 'Board path',
+ 'FORUM_PATH_EXPLAIN' => 'This is the <strong>relative</strong> path on disk to your former board from the <strong>root of this phpBB3 installation</strong>.',
+ 'REFRESH_PAGE' => 'Refresh page to continue conversion',
+ 'REFRESH_PAGE_EXPLAIN' => 'If set to yes, the convertor will refresh the page to continue the conversion after having finished a step. If this is your first conversion for testing purposes and to determine any errors in advance, we suggest to set this to No.',
+
+ // Conversion
+ 'STAGE_IN_PROGRESS' => 'Conversion in progress',
+
+ 'AUTHOR_NOTES' => 'Author notes<br />» %s',
+ 'STARTING_CONVERT' => 'Starting conversion process',
+ 'CONFIG_CONVERT' => 'Converting the configuration',
+ 'DONE' => 'Done',
+ 'PREPROCESS_STEP' => 'Executing pre-processing functions/queries',
+ 'FILLING_TABLE' => 'Filling table <strong>%s</strong>',
+ 'FILLING_TABLES' => 'Filling tables',
+ 'DB_ERR_INSERT' => 'Error while processing <code>INSERT</code> query.',
+ 'DB_ERR_LAST' => 'Error while processing <var>query_last</var>.',
+ 'DB_ERR_QUERY_FIRST' => 'Error while executing <var>query_first</var>.',
+ 'DB_ERR_QUERY_FIRST_TABLE' => 'Error while executing <var>query_first</var>, %s (“%sâ€).',
+ 'DB_ERR_SELECT' => 'Error while running <code>SELECT</code> query.',
+ 'STEP_PERCENT_COMPLETED' => 'Step <strong>%d</strong> of <strong>%d</strong>',
+ 'FINAL_STEP' => 'Process final step',
+ 'SYNC_FORUMS' => 'Starting to synchronise forums',
+ 'SYNC_POST_COUNT' => 'Synchronising post_counts',
+ 'SYNC_POST_COUNT_ID' => 'Synchronising post_counts from <var>entry</var> %1$s to %2$s.',
+ 'SYNC_TOPICS' => 'Starting to synchronise topics',
+ 'SYNC_TOPIC_ID' => 'Synchronising topics from <var>topic_id</var> %1$s to %2$s.',
+ 'PROCESS_LAST' => 'Processing last statements',
+ 'UPDATE_TOPICS_POSTED' => 'Generating topics posted information',
+ 'UPDATE_TOPICS_POSTED_ERR' => 'An error occurred while generating topics posted information. You can retry this step in the ACP after the conversion process is completed.',
+ 'CONTINUE_LAST' => 'Continue last statements',
+ 'CLEAN_VERIFY' => 'Cleaning up and verifying the final structure',
+ 'NOT_UNDERSTAND' => 'Could not understand %s #%d, table %s (“%sâ€)',
+ 'NAMING_CONFLICT' => 'Naming conflict: %s and %s are both aliases<br /><br />%s',
+
+ // Finish conversion
+ 'CONVERT_COMPLETE' => 'Conversion completed',
+ 'CONVERT_COMPLETE_EXPLAIN' => 'You have now successfully converted your board to phpBB 3.2. You can now login and <a href="../">access your board</a>. Please ensure that the settings were transferred correctly before enabling your board by deleting the install directory. Remember that help on using phpBB is available online via the <a href="https://www.phpbb.com/support/docs/en/3.2/ug/">Documentation</a> and the <a href="https://www.phpbb.com/community/viewforum.php?f=466">support forums</a>.',
+
+ 'CONV_ERROR_ATTACH_FTP_DIR' => 'FTP upload for attachments is enabled at the old board. Please disable the FTP upload option and make sure a valid upload directory is specified, then copy all attachment files to this new web accessible directory. Once you have done this, restart the convertor.',
+ 'CONV_ERROR_CONFIG_EMPTY' => 'There is no configuration information available for the conversion.',
+ 'CONV_ERROR_FORUM_ACCESS' => 'Unable to get forum access information.',
+ 'CONV_ERROR_GET_CATEGORIES' => 'Unable to get categories.',
+ 'CONV_ERROR_GET_CONFIG' => 'Could not retrieve your board configuration.',
+ 'CONV_ERROR_COULD_NOT_READ' => 'Unable to access/read “%sâ€.',
+ 'CONV_ERROR_GROUP_ACCESS' => 'Unable to get group authentication information.',
+ 'CONV_ERROR_INCONSISTENT_GROUPS' => 'Inconsistency in groups table detected in add_bots() - you need to add all special groups if you do it manually.',
+ 'CONV_ERROR_INSERT_BOT' => 'Unable to insert bot into users table.',
+ 'CONV_ERROR_INSERT_BOTGROUP' => 'Unable to insert bot into bots table.',
+ 'CONV_ERROR_INSERT_USER_GROUP' => 'Unable to insert user into user_group table.',
+ 'CONV_ERROR_MESSAGE_PARSER' => 'Message parser error',
+ 'CONV_ERROR_NO_AVATAR_PATH' => 'Note to developer: you must specify $convertor[\'avatar_path\'] to use %s.',
+ 'CONV_ERROR_NO_FORUM_PATH' => 'The relative path to the source board has not been specified.',
+ 'CONV_ERROR_NO_GALLERY_PATH' => 'Note to developer: you must specify $convertor[\'avatar_gallery_path\'] to use %s.',
+ 'CONV_ERROR_NO_GROUP' => 'Group “%1$s†could not be found in %2$s.',
+ 'CONV_ERROR_NO_RANKS_PATH' => 'Note to developer: you must specify $convertor[\'ranks_path\'] to use %s.',
+ 'CONV_ERROR_NO_SMILIES_PATH' => 'Note to developer: you must specify $convertor[\'smilies_path\'] to use %s.',
+ 'CONV_ERROR_NO_UPLOAD_DIR' => 'Note to developer: you must specify $convertor[\'upload_path\'] to use %s.',
+ 'CONV_ERROR_PERM_SETTING' => 'Unable to insert/update permission setting.',
+ 'CONV_ERROR_PM_COUNT' => 'Unable to select folder pm count.',
+ 'CONV_ERROR_REPLACE_CATEGORY' => 'Unable to insert new forum replacing old category.',
+ 'CONV_ERROR_REPLACE_FORUM' => 'Unable to insert new forum replacing old forum.',
+ 'CONV_ERROR_USER_ACCESS' => 'Unable to get user authentication information.',
+ 'CONV_ERROR_WRONG_GROUP' => 'Wrong group “%1$s†defined in %2$s.',
+ 'CONV_OPTIONS_BODY' => 'This page collects the data required to access the source board. Enter the database details of your former board; the converter will not change anything in the database given below. The source board should be disabled to allow a consistent conversion.',
+ 'CONV_SAVED_MESSAGES' => 'Saved messages',
+
+ 'PRE_CONVERT_COMPLETE' => 'All pre-conversion steps have successfully been completed. You may now begin the actual conversion process. Please note that you may have to manually do and adjust several things. After conversion, especially check the permissions assigned, rebuild your search index which is not converted and also make sure files got copied correctly, for example avatars and smilies.',
+));
diff --git a/phpBB/language/en/mcp.php b/phpBB/language/en/mcp.php
index a961068657..b196a1d658 100644
--- a/phpBB/language/en/mcp.php
+++ b/phpBB/language/en/mcp.php
@@ -135,6 +135,7 @@ $lang = array_merge($lang, array(
'LOCK_TOPICS_CONFIRM' => 'Are you sure you want to lock all selected topics?',
'LOGS_CURRENT_TOPIC' => 'Currently viewing logs of:',
'LOGIN_EXPLAIN_MCP' => 'To moderate this forum you must login.',
+ 'LOGVIEW_VIEWPOST' => 'View post',
'LOGVIEW_VIEWTOPIC' => 'View topic',
'LOGVIEW_VIEWLOGS' => 'View topic log',
'LOGVIEW_VIEWFORUM' => 'View forum',
diff --git a/phpBB/language/en/migrator.php b/phpBB/language/en/migrator.php
index b3b5995cc0..8a82d40be5 100644
--- a/phpBB/language/en/migrator.php
+++ b/phpBB/language/en/migrator.php
@@ -48,11 +48,19 @@ $lang = array_merge($lang, array(
'MIGRATION_EFFECTIVELY_INSTALLED' => 'Migration already effectively installed (skipped): %s',
'MIGRATION_EXCEPTION_ERROR' => 'Something went wrong during the request and an exception was thrown. The changes made before the error occurred were reversed to the best of our abilities, but you should check the board for errors.',
'MIGRATION_NOT_FULFILLABLE' => 'The migration "%1$s" is not fulfillable, missing migration "%2$s".',
+ 'MIGRATION_NOT_INSTALLED' => 'The migration "%s" is not installed.',
'MIGRATION_NOT_VALID' => '%s is not a valid migration.',
'MIGRATION_SCHEMA_DONE' => 'Installed Schema: %1$s; Time: %2$.2f seconds',
'MIGRATION_SCHEMA_IN_PROGRESS' => 'Installing Schema: %1$s; Time: %2$.2f seconds',
'MIGRATION_SCHEMA_RUNNING' => 'Installing Schema: %s.',
+ 'MIGRATION_REVERT_DATA_DONE' => 'Reverted Data: %1$s; Time: %2$.2f seconds',
+ 'MIGRATION_REVERT_DATA_IN_PROGRESS' => 'Reverting Data: %1$s; Time: %2$.2f seconds',
+ 'MIGRATION_REVERT_DATA_RUNNING' => 'Reverting Data: %s.',
+ 'MIGRATION_REVERT_SCHEMA_DONE' => 'Reverted Schema: %1$s; Time: %2$.2f seconds',
+ 'MIGRATION_REVERT_SCHEMA_IN_PROGRESS' => 'Reverting Schema: %1$s; Time: %2$.2f seconds',
+ 'MIGRATION_REVERT_SCHEMA_RUNNING' => 'Reverting Schema: %s.',
+
'MIGRATION_INVALID_DATA_MISSING_CONDITION' => 'A migration is invalid. An if statement helper is missing a condition.',
'MIGRATION_INVALID_DATA_MISSING_STEP' => 'A migration is invalid. An if statement helper is missing a valid call to a migration step.',
'MIGRATION_INVALID_DATA_CUSTOM_NOT_CALLABLE' => 'A migration is invalid. A custom callable function could not be called.',
diff --git a/phpBB/language/en/posting.php b/phpBB/language/en/posting.php
index ef52f59753..426475e77a 100644
--- a/phpBB/language/en/posting.php
+++ b/phpBB/language/en/posting.php
@@ -43,6 +43,7 @@ $lang = array_merge($lang, array(
'ADD_POLL' => 'Poll creation',
'ADD_POLL_EXPLAIN' => 'If you do not want to add a poll to your topic leave the fields blank.',
'ALREADY_DELETED' => 'Sorry but this message is already deleted.',
+ 'ATTACH_COMMENT_NO_EMOJIS' => 'The attachment comment contains forbidden characters (Emoji).',
'ATTACH_DISK_FULL' => 'There is not enough free disk space to post this attachment.',
'ATTACH_QUOTA_REACHED' => 'Sorry, the board attachment quota has been reached.',
'ATTACH_SIG' => 'Attach a signature (signatures can be altered via the UCP)',
@@ -145,6 +146,7 @@ $lang = array_merge($lang, array(
'LOAD_DRAFT_EXPLAIN' => 'Here you are able to select the draft you want to continue writing. Your current post will be cancelled, all current post contents will be deleted. View, edit and delete drafts within your User Control Panel.',
'LOGIN_EXPLAIN_BUMP' => 'You need to login in order to bump topics within this forum.',
'LOGIN_EXPLAIN_DELETE' => 'You need to login in order to delete posts within this forum.',
+ 'LOGIN_EXPLAIN_SOFT_DELETE' => 'You need to login in order to soft-delete posts within this forum.',
'LOGIN_EXPLAIN_POST' => 'You need to login in order to post within this forum.',
'LOGIN_EXPLAIN_QUOTE' => 'You need to login in order to quote posts within this forum.',
'LOGIN_EXPLAIN_REPLY' => 'You need to login in order to reply to topics within this forum.',
@@ -182,8 +184,10 @@ $lang = array_merge($lang, array(
'NO_POLL_TITLE' => 'You have to enter a poll title.',
'NO_POST' => 'The requested post does not exist.',
'NO_POST_MODE' => 'No post mode specified.',
+ 'NO_TEMP_DIR' => 'Temporary folder could not be found or is not writable.',
'PARTIAL_UPLOAD' => 'The uploaded file was only partially uploaded.',
+ 'PHP_UPLOAD_STOPPED' => 'A PHP extension has stopped the file upload.',
'PHP_SIZE_NA' => 'The attachment’s file size is too large.<br />Could not determine the maximum size defined by PHP in php.ini.',
'PHP_SIZE_OVERRUN' => 'The attachment’s file size is too large, the maximum upload size is %1$d %2$s.<br />Please note this is set in php.ini and cannot be overridden.',
'PLACE_INLINE' => 'Place inline',
@@ -239,9 +243,9 @@ $lang = array_merge($lang, array(
'SMILIES' => 'Smilies',
'SMILIES_ARE_OFF' => 'Smilies are <em>OFF</em>',
'SMILIES_ARE_ON' => 'Smilies are <em>ON</em>',
- 'STICKY_ANNOUNCE_TIME_LIMIT'=> 'Sticky/Announcement time limit',
+ 'STICKY_ANNOUNCE_TIME_LIMIT'=> 'Sticky/Announcement/Global time limit',
'STICK_TOPIC_FOR' => 'Stick topic for',
- 'STICK_TOPIC_FOR_EXPLAIN' => 'Enter 0 for a never ending Sticky/Announcement. Please note that this number is relative to the date of the post.',
+ 'STICK_TOPIC_FOR_EXPLAIN' => 'Enter 0 for a never ending Sticky/Announcement/Global. Please note that this number is relative to the date of the post.',
'STYLES_TIP' => 'Tip: Styles can be applied quickly to selected text.',
'TOO_FEW_CHARS' => 'Your message contains too few characters.',
diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php
index 93ee07b1cf..8549230b9f 100644
--- a/phpBB/language/en/ucp.php
+++ b/phpBB/language/en/ucp.php
@@ -89,6 +89,7 @@ $lang = array_merge($lang, array(
'ATTACHMENTS_EXPLAIN' => 'This is a list of attachments you have made in posts to this board.',
'ATTACHMENTS_DELETED' => 'Attachments successfully deleted.',
'ATTACHMENT_DELETED' => 'Attachment successfully deleted.',
+ 'ATTACHMENT_LOCKED' => 'This topic is locked, you cannot delete the attachment.',
'AUTOLOGIN_SESSION_KEYS_DELETED'=> 'The selected "Remember Me" login keys were successfully deleted.',
'AVATAR_CATEGORY' => 'Category',
'AVATAR_DRIVER_GRAVATAR_TITLE' => 'Gravatar',
@@ -115,7 +116,7 @@ $lang = array_merge($lang, array(
'BIRTHDAY' => 'Birthday',
'BIRTHDAY_EXPLAIN' => 'Setting a year will list your age when it is your birthday.',
'BOARD_DATE_FORMAT' => 'My date format',
- 'BOARD_DATE_FORMAT_EXPLAIN' => 'The syntax used is identical to the PHP <a href="http://www.php.net/date">date()</a> function.',
+ 'BOARD_DATE_FORMAT_EXPLAIN' => 'The syntax used is identical to the PHP <a href="https://secure.php.net/manual/function.date.php">date()</a> function.',
'BOARD_LANGUAGE' => 'My language',
'BOARD_STYLE' => 'My board style',
'BOARD_TIMEZONE' => 'My timezone',
@@ -272,6 +273,7 @@ $lang = array_merge($lang, array(
'IMPORTANT_NEWS' => 'Important announcements',
'INVALID_USER_BIRTHDAY' => 'The entered birthday is not a valid date.',
'INVALID_CHARS_USERNAME' => 'The username contains forbidden characters.',
+ 'INVALID_EMOJIS_USERNAME' => 'The username contains forbidden characters (Emoji).',
'INVALID_CHARS_NEW_PASSWORD'=> 'The password does not contain the required characters.',
'ITEMS_REQUIRED' => 'The items marked with * are required profile fields and need to be filled out.',
@@ -302,6 +304,7 @@ $lang = array_merge($lang, array(
'MESSAGE_EDITED' => 'Message successfully edited.',
'MESSAGE_HISTORY' => 'Message history',
'MESSAGE_REMOVED_FROM_OUTBOX' => 'This message was deleted by its author.',
+ 'MESSAGE_REPORTED_MESSAGE' => 'Reported message',
'MESSAGE_SENT_ON' => 'on',
'MESSAGE_STORED' => 'This message has been sent successfully.',
'MESSAGE_TO' => 'To',
@@ -328,6 +331,7 @@ $lang = array_merge($lang, array(
'NOTIFICATION_GROUP_MODERATION' => 'Moderation Notifications',
'NOTIFICATION_GROUP_ADMINISTRATION' => 'Administration Notifications',
'NOTIFICATION_GROUP_POSTING' => 'Posting Notifications',
+ 'NOTIFICATION_METHOD_BOARD' => 'Notifications',
'NOTIFICATION_METHOD_EMAIL' => 'Email',
'NOTIFICATION_METHOD_JABBER' => 'Jabber',
'NOTIFICATION_TYPE' => 'Notification type',
@@ -372,10 +376,10 @@ $lang = array_merge($lang, array(
'NO_AUTH_EDIT_MESSAGE' => 'You are not authorised to edit private messages.',
'NO_AUTH_FORWARD_MESSAGE' => 'You are not authorised to forward private messages.',
'NO_AUTH_GROUP_MESSAGE' => 'You are not authorised to send private messages to groups.',
- 'NO_AUTH_PASSWORD_REMINDER' => 'You are not authorised to request a new password.',
'NO_AUTH_PROFILEINFO' => 'You are not authorised to change your profile information.',
'NO_AUTH_READ_HOLD_MESSAGE' => 'You are not authorised to read private messages that are on hold.',
'NO_AUTH_READ_MESSAGE' => 'You are not authorised to read private messages.',
+ 'NO_AUTH_PRINT_MESSAGE' => 'You are not authorised to print private messages.',
'NO_AUTH_READ_REMOVED_MESSAGE' => 'You are not able to read this message because it was removed by the author.',
'NO_AUTH_SEND_MESSAGE' => 'You are not authorised to send private messages.',
'NO_AUTH_SIGNATURE' => 'You are not authorised to define a signature.',
@@ -385,6 +389,7 @@ $lang = array_merge($lang, array(
'NO_BOOKMARKS_SELECTED' => 'You have selected no bookmarks.',
'NO_EDIT_READ_MESSAGE' => 'Private message cannot be edited because it has already been read.',
'NO_EMAIL_USER' => 'The email/username information submitted could not be found.',
+ 'EMAIL_NOT_UNIQUE' => 'Email you specified is used by multiple users. You must specify username as well.',
'NO_FOES' => 'No foes currently defined',
'NO_FRIENDS' => 'No friends currently defined',
'NO_FRIENDS_OFFLINE' => 'No friends offline',
@@ -410,7 +415,7 @@ $lang = array_merge($lang, array(
'PASS_TYPE_SYMBOL_EXPLAIN' => 'Password must be between %1$s and %2$s long, must contain letters in mixed case, must contain numbers and must contain symbols.',
'PASSWORD' => 'Password',
'PASSWORD_ACTIVATED' => 'Your new password has been activated.',
- 'PASSWORD_UPDATED' => 'A new password was sent to your registered email address.',
+ 'PASSWORD_UPDATED_IF_EXISTED' => 'If your account exists, a new password was sent to your registered email address. If you do not receive an email, it may be because you are banned, your account is not activated, or you are not allowed to change your password. Contact admin if any of those reasons apply. Also, check your spam filter.',
'PERMISSIONS_RESTORED' => 'Successfully restored original permissions.',
'PERMISSIONS_TRANSFERRED' => 'Successfully transferred permissions from <strong>%s</strong>, you are now able to browse the board with this user’s permissions.<br />Please note that admin permissions were not transferred. You are able to revert to your permission set at any time.',
'PM_DISABLED' => 'Private messaging has been disabled on this board.',
diff --git a/phpBB/language/en/viewforum.php b/phpBB/language/en/viewforum.php
index 9946a3eda4..e2a6e2a718 100644
--- a/phpBB/language/en/viewforum.php
+++ b/phpBB/language/en/viewforum.php
@@ -53,7 +53,8 @@ $lang = array_merge($lang, array(
'NEW_POSTS_LOCKED' => 'New posts [ Locked ]', // Not used anymore
'NO_NEW_POSTS_HOT' => 'No new posts [ Popular ]', // Not used anymore
'NO_NEW_POSTS_LOCKED' => 'No new posts [ Locked ]', // Not used anymore
- 'NO_READ_ACCESS' => 'You do not have the required permissions to read topics within this forum.',
+ 'NO_READ_ACCESS' => 'You do not have the required permissions to view or read topics within this forum.',
+ 'NO_FORUMS_IN_CATEGORY' => 'This category has no forums.',
'NO_UNREAD_POSTS_HOT' => 'No unread posts [ Popular ]',
'NO_UNREAD_POSTS_LOCKED' => 'No unread posts [ Locked ]',
diff --git a/phpBB/language/en/viewtopic.php b/phpBB/language/en/viewtopic.php
index 5890eecdb6..5d127acb3d 100644
--- a/phpBB/language/en/viewtopic.php
+++ b/phpBB/language/en/viewtopic.php
@@ -88,6 +88,7 @@ $lang = array_merge($lang, array(
'NO_UNREAD_POSTS' => 'There are no new unread posts for this topic.',
'NO_VOTE_OPTION' => 'You must specify an option when voting.',
'NO_VOTES' => 'No votes',
+ 'NO_AUTH_PRINT_TOPIC' => 'You are not authorised to print topics.',
'POLL_ENDED_AT' => 'Poll ended at %s',
'POLL_RUN_TILL' => 'Poll runs till %s',
diff --git a/phpBB/mcp.php b/phpBB/mcp.php
index f9d46db528..c4a8a66c18 100644
--- a/phpBB/mcp.php
+++ b/phpBB/mcp.php
@@ -33,10 +33,10 @@ $module = new p_master();
$template->assign_var('S_IN_MCP', true);
// Basic parameter data
-$id = request_var('i', '');
+$id = $request->variable('i', '');
-$mode = request_var('mode', array(''));
-$mode = sizeof($mode) ? array_shift($mode) : request_var('mode', '');
+$mode = $request->variable('mode', array(''));
+$mode = count($mode) ? array_shift($mode) : $request->variable('mode', '');
// Only Moderators can go beyond this point
if (!$user->data['is_registered'])
@@ -50,16 +50,16 @@ if (!$user->data['is_registered'])
}
$quickmod = (isset($_REQUEST['quickmod'])) ? true : false;
-$action = request_var('action', '');
-$action_ary = request_var('action', array('' => 0));
+$action = $request->variable('action', '');
+$action_ary = $request->variable('action', array('' => 0));
-$forum_action = request_var('forum_action', '');
+$forum_action = $request->variable('forum_action', '');
if ($forum_action !== '' && $request->variable('sort', false, false, \phpbb\request\request_interface::POST))
{
$action = $forum_action;
}
-if (sizeof($action_ary))
+if (count($action_ary))
{
list($action, ) = each($action_ary);
}
@@ -71,12 +71,12 @@ if ($mode == 'topic_logs')
$quickmod = false;
}
-$post_id = request_var('p', 0);
-$topic_id = request_var('t', 0);
-$forum_id = request_var('f', 0);
-$report_id = request_var('r', 0);
-$user_id = request_var('u', 0);
-$username = utf8_normalize_nfc(request_var('username', '', true));
+$post_id = $request->variable('p', 0);
+$topic_id = $request->variable('t', 0);
+$forum_id = $request->variable('f', 0);
+$report_id = $request->variable('r', 0);
+$user_id = $request->variable('u', 0);
+$username = $request->variable('username', '', true);
if ($post_id)
{
@@ -111,8 +111,8 @@ if (!$auth->acl_getf_global('m_'))
'lock' => 'f_user_lock',
'make_sticky' => 'f_sticky',
'make_announce' => 'f_announce',
- 'make_global' => 'f_announce',
- 'make_normal' => array('f_announce', 'f_sticky')
+ 'make_global' => 'f_announce_global',
+ 'make_normal' => array('f_announce', 'f_announce_global', 'f_sticky')
);
$allow_user = false;
@@ -127,6 +127,7 @@ if (!$auth->acl_getf_global('m_'))
if (!$allow_user)
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
}
@@ -134,6 +135,7 @@ if (!$auth->acl_getf_global('m_'))
// if the user cannot read the forum he tries to access then we won't allow mcp access either
if ($forum_id && !$auth->acl_get('f_read', $forum_id))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
@@ -192,7 +194,7 @@ if ($quickmod)
case 'topic_logs':
// Reset start parameter if we jumped from the quickmod dropdown
- if (request_var('start', 0))
+ if ($request->variable('start', 0))
{
$request->overwrite('start', 0);
}
diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php
index b1982958d5..1343bd7c60 100644
--- a/phpBB/memberlist.php
+++ b/phpBB/memberlist.php
@@ -20,7 +20,7 @@ $phpEx = substr(strrchr(__FILE__, '.'), 1);
include($phpbb_root_path . 'common.' . $phpEx);
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
-$mode = request_var('mode', '');
+$mode = $request->variable('mode', '');
if ($mode === 'contactadmin')
{
@@ -37,11 +37,11 @@ $user->setup(array('memberlist', 'groups'));
$template->assign_var('S_IN_MEMBERLIST', true);
// Grab data
-$action = request_var('action', '');
-$user_id = request_var('u', ANONYMOUS);
-$username = request_var('un', '', true);
-$group_id = request_var('g', 0);
-$topic_id = request_var('t', 0);
+$action = $request->variable('action', '');
+$user_id = $request->variable('u', ANONYMOUS);
+$username = $request->variable('un', '', true);
+$group_id = $request->variable('g', 0);
+$topic_id = $request->variable('t', 0);
// Redirect when old mode is used
if ($mode == 'leaders')
@@ -75,6 +75,7 @@ switch ($mode)
{
if ($user->data['user_id'] != ANONYMOUS)
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_VIEW_USERS');
}
@@ -83,12 +84,15 @@ switch ($mode)
break;
}
-$start = request_var('start', 0);
+/** @var \phpbb\group\helper $group_helper */
+$group_helper = $phpbb_container->get('group_helper');
+
+$start = $request->variable('start', 0);
$submit = (isset($_POST['submit'])) ? true : false;
$default_key = 'c';
-$sort_key = request_var('sk', $default_key);
-$sort_dir = request_var('sd', 'a');
+$sort_key = $request->variable('sk', $default_key);
+$sort_dir = $request->variable('sd', 'a');
$user_types = array(USER_NORMAL, USER_FOUNDER);
if ($auth->acl_get('a_user'))
@@ -145,7 +149,7 @@ switch ($mode)
}
else
{
- $row['group_name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $row['group_name'] = $group_helper->get_name($row['group_name']);
$row['u_group'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $row['group_id']);
}
@@ -169,7 +173,7 @@ switch ($mode)
'LEFT_JOIN' => array(
array(
'FROM' => array(USERS_TABLE => 'u'),
- 'ON' => 'ug.user_id = u.user_id AND ug.user_pending = 0',
+ 'ON' => 'ug.user_id = u.user_id',
),
array(
'FROM' => array(GROUPS_TABLE => 'g'),
@@ -177,7 +181,7 @@ switch ($mode)
),
),
- 'WHERE' => $db->sql_in_set('g.group_id', $group_ids, false, true),
+ 'WHERE' => $db->sql_in_set('g.group_id', $group_ids, false, true) . ' AND ug.user_pending = 0',
'ORDER_BY' => 'u.username_clean ASC',
);
@@ -372,6 +376,7 @@ switch ($mode)
if (!$auth->acl_get('u_sendim'))
{
+ send_status_line(403, 'Forbidden');
trigger_error('NOT_AUTHORISED');
}
@@ -422,7 +427,7 @@ switch ($mode)
include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
$subject = sprintf($user->lang['IM_JABBER_SUBJECT'], $user->data['username'], $config['server_name']);
- $message = utf8_normalize_nfc(request_var('message', '', true));
+ $message = $request->variable('message', '', true);
if (empty($message))
{
@@ -484,9 +489,31 @@ switch ($mode)
}
// Get user...
- $sql = 'SELECT *
- FROM ' . USERS_TABLE . '
- WHERE ' . (($username) ? "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'" : "user_id = $user_id");
+ $sql_array = array(
+ 'SELECT' => 'u.*',
+ 'FROM' => array(
+ USERS_TABLE => 'u'
+ ),
+ 'WHERE' => (($username) ? "u.username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'" : "u.user_id = $user_id"),
+ );
+
+ /**
+ * Modify user data SQL before member profile row is created
+ *
+ * @event core.memberlist_modify_viewprofile_sql
+ * @var int user_id The user ID
+ * @var string username The username
+ * @var array sql_array Array containing the main query
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'user_id',
+ 'username',
+ 'sql_array',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_viewprofile_sql', compact($vars)));
+
+ $sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql);
$member = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -518,12 +545,37 @@ switch ($mode)
$sql_uid_ary = ($auth_hidden_groups) ? array($user_id) : array($user_id, (int) $user->data['user_id']);
// Do the SQL thang
- $sql = 'SELECT g.group_id, g.group_name, g.group_type, ug.user_id
- FROM ' . GROUPS_TABLE . ' g, ' . USER_GROUP_TABLE . ' ug
- WHERE ' . $db->sql_in_set('ug.user_id', $sql_uid_ary) . '
- AND g.group_id = ug.group_id
- AND ug.user_pending = 0';
- $result = $db->sql_query($sql);
+ $sql_ary = [
+ 'SELECT' => 'g.group_id, g.group_name, g.group_type, ug.user_id',
+
+ 'FROM' => [
+ GROUPS_TABLE => 'g',
+ ],
+
+ 'LEFT_JOIN' => [
+ [
+ 'FROM' => [USER_GROUP_TABLE => 'ug'],
+ 'ON' => 'g.group_id = ug.group_id',
+ ],
+ ],
+
+ 'WHERE' => $db->sql_in_set('ug.user_id', $sql_uid_ary) . '
+ AND ug.user_pending = 0',
+ ];
+
+ /**
+ * Modify the query used to get the group data
+ *
+ * @event core.modify_memberlist_viewprofile_group_sql
+ * @var array sql_ary Array containing the query
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'sql_ary',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.modify_memberlist_viewprofile_group_sql', compact($vars)));
+
+ $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
// Divide data into profile data and current user data
$profile_groups = $user_groups = array();
@@ -547,20 +599,14 @@ switch ($mode)
$group_data = $group_sort = array();
foreach ($profile_groups as $row)
{
- if ($row['group_type'] == GROUP_SPECIAL)
- {
- // Lookup group name in language dictionary
- if (isset($user->lang['G_' . $row['group_name']]))
- {
- $row['group_name'] = $user->lang['G_' . $row['group_name']];
- }
- }
- else if (!$auth_hidden_groups && $row['group_type'] == GROUP_HIDDEN && !isset($user_groups[$row['group_id']]))
+ if (!$auth_hidden_groups && $row['group_type'] == GROUP_HIDDEN && !isset($user_groups[$row['group_id']]))
{
// Skip over hidden groups the user cannot see
continue;
}
+ $row['group_name'] = $group_helper->get_name($row['group_name']);
+
$group_sort[$row['group_id']] = utf8_clean_string($row['group_name']);
$group_data[$row['group_id']] = $row;
}
@@ -568,6 +614,20 @@ switch ($mode)
unset($user_groups);
asort($group_sort);
+ /**
+ * Modify group data before options is created and data is unset
+ *
+ * @event core.modify_memberlist_viewprofile_group_data
+ * @var array group_data Array containing the group data
+ * @var array group_sort Array containing the sorted group data
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'group_data',
+ 'group_sort',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.modify_memberlist_viewprofile_group_data', compact($vars)));
+
$group_options = '';
foreach ($group_sort as $group_id => $null)
{
@@ -649,6 +709,7 @@ switch ($mode)
$profile_fields = array();
if ($config['load_cpf_viewprofile'])
{
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$profile_fields = $cp->grab_profile_fields_data($user_id);
$profile_fields = (isset($profile_fields[$user_id])) ? $cp->generate_profile_fields_template_data($profile_fields[$user_id]) : array();
@@ -702,42 +763,58 @@ switch ($mode)
$member['posts_in_queue'] = 0;
}
- $template->assign_vars(array(
- 'L_POSTS_IN_QUEUE' => $user->lang('NUM_POSTS_IN_QUEUE', $member['posts_in_queue']),
+ // Define the main array of vars to assign to memberlist_view.html
+ $template_ary = array(
+ 'L_POSTS_IN_QUEUE' => $user->lang('NUM_POSTS_IN_QUEUE', $member['posts_in_queue']),
- 'POSTS_DAY' => $user->lang('POST_DAY', $posts_per_day),
- 'POSTS_PCT' => $user->lang('POST_PCT', $percentage),
+ 'POSTS_DAY' => $user->lang('POST_DAY', $posts_per_day),
+ 'POSTS_PCT' => $user->lang('POST_PCT', $percentage),
- 'SIGNATURE' => $member['user_sig'],
- 'POSTS_IN_QUEUE'=> $member['posts_in_queue'],
+ 'SIGNATURE' => $member['user_sig'],
+ 'POSTS_IN_QUEUE' => $member['posts_in_queue'],
- 'PM_IMG' => $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE']),
- 'L_SEND_EMAIL_USER' => $user->lang('SEND_EMAIL_USER', $member['username']),
- 'EMAIL_IMG' => $user->img('icon_contact_email', $user->lang['EMAIL']),
- 'JABBER_IMG' => $user->img('icon_contact_jabber', $user->lang['JABBER']),
- 'SEARCH_IMG' => $user->img('icon_user_search', $user->lang['SEARCH']),
+ 'PM_IMG' => $user->img('icon_contact_pm', $user->lang['SEND_PRIVATE_MESSAGE']),
+ 'L_SEND_EMAIL_USER' => $user->lang('SEND_EMAIL_USER', $member['username']),
+ 'EMAIL_IMG' => $user->img('icon_contact_email', $user->lang['EMAIL']),
+ 'JABBER_IMG' => $user->img('icon_contact_jabber', $user->lang['JABBER']),
+ 'SEARCH_IMG' => $user->img('icon_user_search', $user->lang['SEARCH']),
- 'S_PROFILE_ACTION' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group'),
- 'S_GROUP_OPTIONS' => $group_options,
- 'S_CUSTOM_FIELDS' => (isset($profile_fields['row']) && sizeof($profile_fields['row'])) ? true : false,
+ 'S_PROFILE_ACTION' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group'),
+ 'S_GROUP_OPTIONS' => $group_options,
+ 'S_CUSTOM_FIELDS' => (isset($profile_fields['row']) && count($profile_fields['row'])) ? true : false,
- 'U_USER_ADMIN' => ($auth->acl_get('a_user')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview&amp;u=' . $user_id, true, $user->session_id) : '',
- 'U_USER_BAN' => ($auth->acl_get('m_ban') && $user_id != $user->data['user_id']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=ban&amp;mode=user&amp;u=' . $user_id, true, $user->session_id) : '',
- 'U_MCP_QUEUE' => ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '',
+ 'U_USER_ADMIN' => ($auth->acl_get('a_user')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview&amp;u=' . $user_id, true, $user->session_id) : '',
+ 'U_USER_BAN' => ($auth->acl_get('m_ban') && $user_id != $user->data['user_id']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=ban&amp;mode=user&amp;u=' . $user_id, true, $user->session_id) : '',
+ 'U_MCP_QUEUE' => ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '',
- 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_id) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&amp;u={$user_id}&amp;hash=" . generate_link_hash('switchperm')) : '',
- 'U_EDIT_SELF' => ($user_id == $user->data['user_id'] && $auth->acl_get('u_chgprofileinfo')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_profile&amp;mode=profile_info') : '',
+ 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_id) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&amp;u={$user_id}&amp;hash=" . generate_link_hash('switchperm')) : '',
+ 'U_EDIT_SELF' => ($user_id == $user->data['user_id'] && $auth->acl_get('u_chgprofileinfo')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_profile&amp;mode=profile_info') : '',
- 'S_USER_NOTES' => ($user_notes_enabled) ? true : false,
- 'S_WARN_USER' => ($warn_user_enabled) ? true : false,
- 'S_ZEBRA' => ($user->data['user_id'] != $user_id && $user->data['is_registered'] && $zebra_enabled) ? true : false,
- 'U_ADD_FRIEND' => (!$friend && !$foe && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;add=' . urlencode(htmlspecialchars_decode($member['username']))) : '',
- 'U_ADD_FOE' => (!$friend && !$foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;mode=foes&amp;add=' . urlencode(htmlspecialchars_decode($member['username']))) : '',
- 'U_REMOVE_FRIEND' => ($friend && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;remove=1&amp;usernames[]=' . $user_id) : '',
- 'U_REMOVE_FOE' => ($foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;remove=1&amp;mode=foes&amp;usernames[]=' . $user_id) : '',
+ 'S_USER_NOTES' => ($user_notes_enabled) ? true : false,
+ 'S_WARN_USER' => ($warn_user_enabled) ? true : false,
+ 'S_ZEBRA' => ($user->data['user_id'] != $user_id && $user->data['is_registered'] && $zebra_enabled) ? true : false,
+ 'U_ADD_FRIEND' => (!$friend && !$foe && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;add=' . urlencode(htmlspecialchars_decode($member['username']))) : '',
+ 'U_ADD_FOE' => (!$friend && !$foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;mode=foes&amp;add=' . urlencode(htmlspecialchars_decode($member['username']))) : '',
+ 'U_REMOVE_FRIEND' => ($friend && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;remove=1&amp;usernames[]=' . $user_id) : '',
+ 'U_REMOVE_FOE' => ($foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&amp;remove=1&amp;mode=foes&amp;usernames[]=' . $user_id) : '',
- 'U_CANONICAL' => generate_board_url() . '/' . append_sid("memberlist.$phpEx", 'mode=viewprofile&amp;u=' . $user_id, true, ''),
- ));
+ 'U_CANONICAL' => generate_board_url() . '/' . append_sid("memberlist.$phpEx", 'mode=viewprofile&amp;u=' . $user_id, true, ''),
+ );
+
+ /**
+ * Modify user's template vars before we display the profile
+ *
+ * @event core.memberlist_modify_view_profile_template_vars
+ * @var array template_ary Array with user's template vars
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'template_ary',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_view_profile_template_vars', compact($vars)));
+
+ // Assign vars to memberlist_view.html
+ $template->assign_vars($template_ary);
if (!empty($profile_fields['row']))
{
@@ -797,8 +874,8 @@ switch ($mode)
include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
}
- $user_id = request_var('u', 0);
- $topic_id = request_var('t', 0);
+ $user_id = $request->variable('u', 0);
+ $topic_id = $request->variable('t', 0);
if ($user_id)
{
@@ -816,6 +893,8 @@ switch ($mode)
{
trigger_error('NO_EMAIL');
}
+
+ /** @var $form \phpbb\message\form */
$form = $phpbb_container->get('message.form.' . $form_name);
$form->bind($request);
@@ -871,6 +950,8 @@ switch ($mode)
// The basic memberlist
$page_title = $user->lang['MEMBERLIST'];
$template_html = 'memberlist_body.html';
+
+ /* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// Sorting
@@ -919,9 +1000,9 @@ switch ($mode)
$sql_select = $sql_where_data = $sql_from = $sql_where = $order_by = '';
- $form = request_var('form', '');
- $field = request_var('field', '');
- $select_single = request_var('select_single', false);
+ $form = $request->variable('form', '');
+ $field = $request->variable('field', '');
+ $select_single = $request->variable('select_single', false);
// Search URL parameters, if any of these are in the URL we do a search
$search_params = array('username', 'email', 'jabber', 'search_group_id', 'joined_select', 'active_select', 'count_select', 'joined', 'active', 'count', 'ip');
@@ -929,22 +1010,22 @@ switch ($mode)
// We validate form and field here, only id/class allowed
$form = (!preg_match('/^[a-z0-9_-]+$/i', $form)) ? '' : $form;
$field = (!preg_match('/^[a-z0-9_-]+$/i', $field)) ? '' : $field;
- if ((($mode == '' || $mode == 'searchuser') || sizeof(array_intersect($request->variable_names(\phpbb\request\request_interface::GET), $search_params)) > 0) && ($config['load_search'] || $auth->acl_get('a_')))
+ if ((($mode == '' || $mode == 'searchuser') || count(array_intersect($request->variable_names(\phpbb\request\request_interface::GET), $search_params)) > 0) && ($config['load_search'] || $auth->acl_get('a_')))
{
- $username = request_var('username', '', true);
- $email = strtolower(request_var('email', ''));
- $jabber = request_var('jabber', '');
- $search_group_id = request_var('search_group_id', 0);
+ $username = $request->variable('username', '', true);
+ $email = strtolower($request->variable('email', ''));
+ $jabber = $request->variable('jabber', '');
+ $search_group_id = $request->variable('search_group_id', 0);
// when using these, make sure that we actually have values defined in $find_key_match
- $joined_select = request_var('joined_select', 'lt');
- $active_select = request_var('active_select', 'lt');
- $count_select = request_var('count_select', 'eq');
+ $joined_select = $request->variable('joined_select', 'lt');
+ $active_select = $request->variable('active_select', 'lt');
+ $count_select = $request->variable('count_select', 'eq');
- $joined = explode('-', request_var('joined', ''));
- $active = explode('-', request_var('active', ''));
- $count = (request_var('count', '') !== '') ? request_var('count', 0) : '';
- $ipdomain = request_var('ip', '');
+ $joined = explode('-', $request->variable('joined', ''));
+ $active = explode('-', $request->variable('active', ''));
+ $count = ($request->variable('count', '') !== '') ? $request->variable('count', 0) : '';
+ $ipdomain = $request->variable('ip', '');
$find_key_match = array('lt' => '<', 'gt' => '>', 'eq' => '=');
@@ -976,7 +1057,7 @@ switch ($mode)
$sql_where .= ($jabber) ? ' AND u.user_jabber ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), $jabber)) . ' ' : '';
$sql_where .= (is_numeric($count) && isset($find_key_match[$count_select])) ? ' AND u.user_posts ' . $find_key_match[$count_select] . ' ' . (int) $count . ' ' : '';
- if (isset($find_key_match[$joined_select]) && sizeof($joined) == 3)
+ if (isset($find_key_match[$joined_select]) && count($joined) == 3)
{
$joined_time = gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]);
@@ -986,13 +1067,24 @@ switch ($mode)
}
}
- if (isset($find_key_match[$active_select]) && sizeof($active) == 3 && $auth->acl_get('u_viewonline'))
+ if (isset($find_key_match[$active_select]) && count($active) == 3 && $auth->acl_get('u_viewonline'))
{
$active_time = gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]);
if ($active_time !== false)
{
- $sql_where .= " AND u.user_lastvisit " . $find_key_match[$active_select] . ' ' . $active_time;
+ if ($active_select === 'lt' && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0)
+ {
+ $sql_where .= ' AND u.user_lastvisit = 0';
+ }
+ else if ($active_select === 'gt')
+ {
+ $sql_where .= ' AND u.user_lastvisit ' . $find_key_match[$active_select] . ' ' . $active_time;
+ }
+ else
+ {
+ $sql_where .= ' AND (u.user_lastvisit > 0 AND u.user_lastvisit < ' . $active_time . ')';
+ }
}
}
@@ -1078,7 +1170,7 @@ switch ($mode)
}
}
- $first_char = request_var('first_char', '');
+ $first_char = $request->variable('first_char', '');
if ($first_char == 'other')
{
@@ -1142,18 +1234,18 @@ switch ($mode)
$avatar_img = phpbb_get_group_avatar($group_row);
// ... same for group rank
- $user_rank_data = array(
+ $group_rank_data = array(
'title' => null,
'img' => null,
'img_src' => null,
);
if ($group_row['group_rank'])
{
- $user_rank_data = phpbb_get_user_rank($group_row, false);
+ $group_rank_data = $group_helper->get_rank($group_row);
- if ($user_rank_data['img'])
+ if ($group_rank_data['img'])
{
- $user_rank_data['img'] .= '<br />';
+ $group_rank_data['img'] .= '<br />';
}
}
// include modules for manage groups link display or not
@@ -1177,14 +1269,14 @@ switch ($mode)
$template->assign_vars(array(
'GROUP_DESC' => generate_text_for_display($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_bitfield'], $group_row['group_desc_options']),
- 'GROUP_NAME' => ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'],
+ 'GROUP_NAME' => $group_helper->get_name($group_row['group_name']),
'GROUP_COLOR' => $group_row['group_colour'],
'GROUP_TYPE' => $user->lang['GROUP_IS_' . $group_row['l_group_type']],
- 'GROUP_RANK' => $user_rank_data['title'],
+ 'GROUP_RANK' => $group_rank_data['title'],
'AVATAR_IMG' => $avatar_img,
- 'RANK_IMG' => $user_rank_data['img'],
- 'RANK_IMG_SRC' => $user_rank_data['img_src'],
+ 'RANK_IMG' => $group_rank_data['img'],
+ 'RANK_IMG_SRC' => $group_rank_data['img_src'],
'U_PM' => ($auth->acl_get('u_sendpm') && $auth->acl_get('u_masspm_group') && $group_row['group_receive_pm'] && $config['allow_privmsg'] && $config['allow_mass_pm']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&amp;mode=compose&amp;g=' . $group_id) : '',
'U_MANAGE' => ($can_manage_group) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_groups&amp;mode=manage') : false,)
@@ -1250,7 +1342,7 @@ switch ($mode)
// Build a relevant pagination_url
$params = $sort_params = array();
- // We do not use request_var() here directly to save some calls (not all variables are set)
+ // We do not use $request->variable() here directly to save some calls (not all variables are set)
$check_params = array(
'g' => array('g', 0),
'sk' => array('sk', $default_key),
@@ -1267,7 +1359,7 @@ switch ($mode)
'count_select' => array('count_select', 'eq'),
'joined' => array('joined', ''),
'active' => array('active', ''),
- 'count' => (request_var('count', '') !== '') ? array('count', 0) : array('count', ''),
+ 'count' => ($request->variable('count', '') !== '') ? array('count', 0) : array('count', ''),
'ip' => array('ip', ''),
'first_char' => array('first_char', ''),
);
@@ -1280,7 +1372,7 @@ switch ($mode)
continue;
}
- $param = call_user_func_array('request_var', $call);
+ $param = call_user_func_array(array($request, 'variable'), $call);
// Encode strings, convert everything else to int in order to prevent empty parameters.
$param = urlencode($key) . '=' . ((is_string($param)) ? urlencode($param) : (int) $param);
$params[] = $param;
@@ -1304,11 +1396,6 @@ switch ($mode)
}
$sort_params[] = "mode=$mode";
- $pagination_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&amp;', $params));
- $sort_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&amp;', $sort_params));
-
- unset($search_params, $sort_params);
-
$u_first_char_params = implode('&amp;', $u_first_char_params);
$u_first_char_params .= ($u_first_char_params) ? '&amp;' : '';
@@ -1320,20 +1407,51 @@ switch ($mode)
}
$first_characters['other'] = $user->lang['OTHER'];
+ $first_char_block_vars = [];
+
foreach ($first_characters as $char => $desc)
{
- $template->assign_block_vars('first_char', array(
+ $first_char_block_vars[] = [
'DESC' => $desc,
'VALUE' => $char,
'S_SELECTED' => ($first_char == $char) ? true : false,
'U_SORT' => append_sid("{$phpbb_root_path}memberlist.$phpEx", $u_first_char_params . 'first_char=' . $char) . '#memberlist',
- ));
+ ];
}
+ /**
+ * Modify memberlist sort and pagination parameters
+ *
+ * @event core.memberlist_modify_sort_pagination_params
+ * @var array sort_params Array with URL parameters for sorting
+ * @var array params Array with URL parameters for pagination
+ * @var array first_characters Array that maps each letter in a-z, 'other' and the empty string to their display representation
+ * @var string u_first_char_params Concatenated URL parameters for first character search links
+ * @var array first_char_block_vars Template block variables for each first character
+ * @var int total_users Total number of users found in this search
+ * @since 3.2.6-RC1
+ */
+ $vars = [
+ 'sort_params',
+ 'params',
+ 'first_characters',
+ 'u_first_char_params',
+ 'first_char_block_vars',
+ 'total_users',
+ ];
+ extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_sort_pagination_params', compact($vars)));
+
+ $template->assign_block_vars_array('first_char', $first_char_block_vars);
+
+ $pagination_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&amp;', $params));
+ $sort_url = append_sid("{$phpbb_root_path}memberlist.$phpEx", implode('&amp;', $sort_params));
+
+ unset($search_params, $sort_params);
+
// Some search user specific data
if (($mode == '' || $mode == 'searchuser') && ($config['load_search'] || $auth->acl_get('a_')))
{
- $group_selected = request_var('search_group_id', 0);
+ $group_selected = $request->variable('search_group_id', 0);
$s_group_select = '<option value="0"' . ((!$group_selected) ? ' selected="selected"' : '') . '>&nbsp;</option>';
$group_ids = array();
@@ -1377,7 +1495,7 @@ switch ($mode)
while ($row = $db->sql_fetchrow($result))
{
$group_ids[] = $row['group_id'];
- $s_group_select .= '<option value="' . $row['group_id'] . '"' . (($group_selected == $row['group_id']) ? ' selected="selected"' : '') . '>' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>';
+ $s_group_select .= '<option value="' . $row['group_id'] . '"' . (($group_selected == $row['group_id']) ? ' selected="selected"' : '') . '>' . $group_helper->get_name($row['group_name']) . '</option>';
}
$db->sql_freeresult($result);
@@ -1433,6 +1551,7 @@ switch ($mode)
// Load custom profile fields
if ($config['load_cpf_memberlist'])
{
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
$cp_row = $cp->generate_profile_fields_template_headlines('field_show_on_ml');
@@ -1444,7 +1563,7 @@ switch ($mode)
$leaders_set = false;
// So, did we get any users?
- if (sizeof($user_list))
+ if (count($user_list))
{
// Session time?! Session time...
$sql = 'SELECT session_user_id, MAX(session_time) AS session_time
@@ -1464,19 +1583,58 @@ switch ($mode)
// Do the SQL thang
if ($mode == 'group')
{
- $sql = "SELECT u.*
- $sql_select
- FROM " . USERS_TABLE . " u
- $sql_from
- WHERE " . $db->sql_in_set('u.user_id', $user_list) . "
- $sql_where_data";
+ $sql_from_ary = explode(',', $sql_from);
+ $extra_tables = [];
+ foreach ($sql_from_ary as $entry)
+ {
+ $table_data = explode(' ', trim($entry));
+
+ if (empty($table_data[0]) || empty($table_data[1]))
+ {
+ continue;
+ }
+
+ $extra_tables[$table_data[0]] = $table_data[1];
+ }
+
+ $sql_array = array(
+ 'SELECT' => 'u.*' . $sql_select,
+ 'FROM' => array_merge([USERS_TABLE => 'u'], $extra_tables),
+ 'WHERE' => $db->sql_in_set('u.user_id', $user_list) . $sql_where_data . '',
+ );
}
else
{
- $sql = 'SELECT *
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $user_list);
+ $sql_array = array(
+ 'SELECT' => 'u.*',
+ 'FROM' => array(
+ USERS_TABLE => 'u'
+ ),
+ 'WHERE' => $db->sql_in_set('u.user_id', $user_list),
+ );
}
+
+ /**
+ * Modify user data SQL before member row is created
+ *
+ * @event core.memberlist_modify_memberrow_sql
+ * @var string mode Memberlist mode
+ * @var string sql_select Additional select statement
+ * @var string sql_from Additional from statement
+ * @var array sql_array Array containing the main query
+ * @var array user_list Array containing list of users
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'sql_select',
+ 'sql_from',
+ 'sql_array',
+ 'user_list',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_memberrow_sql', compact($vars)));
+
+ $sql = $db->sql_build_query('SELECT', $sql_array);
$result = $db->sql_query($sql);
$id_cache = array();
@@ -1487,9 +1645,10 @@ switch ($mode)
$id_cache[$row['user_id']] = $row;
}
+
$db->sql_freeresult($result);
- // Load custom profile fields
+ // Load custom profile fields if required
if ($config['load_cpf_memberlist'])
{
// Grab all profile fields from users in id cache for later use - similar to the poster cache
@@ -1516,7 +1675,7 @@ switch ($mode)
}
// do we need to display contact fields as such
- $use_contact_fields = false;
+ $use_contact_fields = true;
/**
* Modify list of users before member row is created
@@ -1529,7 +1688,7 @@ switch ($mode)
$vars = array('user_list', 'use_contact_fields');
extract($phpbb_dispatcher->trigger_event('core.memberlist_memberrow_before', compact($vars)));
- for ($i = 0, $end = sizeof($user_list); $i < $end; ++$i)
+ for ($i = 0, $end = count($user_list); $i < $end; ++$i)
{
$user_id = $user_list[$i];
$row = $id_cache[$user_id];
@@ -1545,21 +1704,21 @@ switch ($mode)
$memberrow = array_merge(phpbb_show_profile($row, false, false, false), array(
'ROW_NUMBER' => $i + ($start + 1),
- 'S_CUSTOM_PROFILE' => (isset($cp_row['row']) && sizeof($cp_row['row'])) ? true : false,
+ 'S_CUSTOM_PROFILE' => (isset($cp_row['row']) && count($cp_row['row'])) ? true : false,
'S_GROUP_LEADER' => $is_leader,
'S_INACTIVE' => $row['user_type'] == USER_INACTIVE,
'U_VIEW_PROFILE' => get_username_string('profile', $user_id, $row['username']),
));
- if (isset($cp_row['row']) && sizeof($cp_row['row']))
+ if (isset($cp_row['row']) && count($cp_row['row']))
{
$memberrow = array_merge($memberrow, $cp_row['row']);
}
$template->assign_block_vars('memberrow', $memberrow);
- if (isset($cp_row['blockrow']) && sizeof($cp_row['blockrow']))
+ if (isset($cp_row['blockrow']) && count($cp_row['blockrow']))
{
foreach ($cp_row['blockrow'] as $field_data)
{
@@ -1574,7 +1733,7 @@ switch ($mode)
$pagination->generate_template_pagination($pagination_url, 'pagination', 'start', $total_users, $config['topics_per_page'], $start);
// Generate page
- $template->assign_vars(array(
+ $template_vars = array(
'TOTAL_USERS' => $user->lang('LIST_USERS', (int) $total_users),
'PROFILE_IMG' => $user->img('icon_user_profile', $user->lang['PROFILE']),
@@ -1599,8 +1758,22 @@ switch ($mode)
'S_LEADERS_SET' => $leaders_set,
'S_MODE_SELECT' => $s_sort_key,
'S_ORDER_SELECT' => $s_sort_dir,
- 'S_MODE_ACTION' => $pagination_url)
+ 'S_MODE_ACTION' => $pagination_url,
);
+
+ /**
+ * Modify memberlist page template vars
+ *
+ * @event core.memberlist_modify_template_vars
+ * @var array params Array containing URL parameters
+ * @var string sort_url Sorting URL base
+ * @var array template_vars Array containing template vars
+ * @since 3.2.2-RC1
+ */
+ $vars = array('params', 'sort_url', 'template_vars');
+ extract($phpbb_dispatcher->trigger_event('core.memberlist_modify_template_vars', compact($vars)));
+
+ $template->assign_vars($template_vars);
}
// Output the page
diff --git a/phpBB/phpbb/attachment/delete.php b/phpBB/phpbb/attachment/delete.php
new file mode 100644
index 0000000000..3c98e21587
--- /dev/null
+++ b/phpBB/phpbb/attachment/delete.php
@@ -0,0 +1,480 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\attachment;
+
+use \phpbb\config\config;
+use \phpbb\db\driver\driver_interface;
+use \phpbb\event\dispatcher;
+use \phpbb\filesystem\filesystem;
+
+/**
+ * Attachment delete class
+ */
+class delete
+{
+ /** @var config */
+ protected $config;
+
+ /** @var driver_interface */
+ protected $db;
+
+ /** @var dispatcher */
+ protected $dispatcher;
+
+ /** @var filesystem */
+ protected $filesystem;
+
+ /** @var resync */
+ protected $resync;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ /** @var array Attachement IDs */
+ protected $ids;
+
+ /** @var string SQL ID string */
+ private $sql_id;
+
+ /** @var string SQL where string */
+ private $sql_where = '';
+
+ /** @var int Number of deleted items */
+ private $num_deleted;
+
+ /** @var array Post IDs */
+ private $post_ids = array();
+
+ /** @var array Message IDs */
+ private $message_ids = array();
+
+ /** @var array Topic IDs */
+ private $topic_ids = array();
+
+ /** @var array Info of physical file */
+ private $physical = array();
+
+ /**
+ * Attachment delete class constructor
+ *
+ * @param config $config
+ * @param driver_interface $db
+ * @param dispatcher $dispatcher
+ * @param filesystem $filesystem
+ * @param resync $resync
+ * @param string $phpbb_root_path
+ */
+ public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, filesystem $filesystem, resync $resync, $phpbb_root_path)
+ {
+ $this->config = $config;
+ $this->db = $db;
+ $this->dispatcher = $dispatcher;
+ $this->filesystem = $filesystem;
+ $this->resync = $resync;
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * Delete Attachments
+ *
+ * @param string $mode can be: post|message|topic|attach|user
+ * @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
+ * @param bool $resync set this to false if you are deleting posts or topics
+ *
+ * @return int|bool Number of deleted attachments or false if something
+ * went wrong during attachment deletion
+ */
+ public function delete($mode, $ids, $resync = true)
+ {
+ if (!$this->set_attachment_ids($ids))
+ {
+ return false;
+ }
+
+ $this->set_sql_constraints($mode);
+
+ $sql_id = $this->sql_id;
+
+ /**
+ * Perform additional actions before collecting data for attachment(s) deletion
+ *
+ * @event core.delete_attachments_collect_data_before
+ * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
+ * @var mixed ids Array or comma separated list of ids corresponding to the mode
+ * @var bool resync Flag indicating if posts/messages/topics should be synchronized
+ * @var string sql_id The field name to collect/delete data for depending on the mode
+ * @since 3.1.7-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'ids',
+ 'resync',
+ 'sql_id',
+ );
+ extract($this->dispatcher->trigger_event('core.delete_attachments_collect_data_before', compact($vars)));
+
+ $this->sql_id = $sql_id;
+ unset($sql_id);
+
+ // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
+ $this->collect_attachment_info($resync);
+
+ // Delete attachments from database
+ $this->delete_attachments_from_db($mode, $ids, $resync);
+
+ $sql_id = $this->sql_id;
+ $post_ids = $this->post_ids;
+ $topic_ids = $this->topic_ids;
+ $message_ids = $this->message_ids;
+ $physical = $this->physical;
+ $num_deleted = $this->num_deleted;
+
+ /**
+ * Perform additional actions after attachment(s) deletion from the database
+ *
+ * @event core.delete_attachments_from_database_after
+ * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
+ * @var mixed ids Array or comma separated list of ids corresponding to the mode
+ * @var bool resync Flag indicating if posts/messages/topics should be synchronized
+ * @var string sql_id The field name to collect/delete data for depending on the mode
+ * @var array post_ids Array with post ids for deleted attachment(s)
+ * @var array topic_ids Array with topic ids for deleted attachment(s)
+ * @var array message_ids Array with private message ids for deleted attachment(s)
+ * @var array physical Array with deleted attachment(s) physical file(s) data
+ * @var int num_deleted The number of deleted attachment(s) from the database
+ * @since 3.1.7-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'ids',
+ 'resync',
+ 'sql_id',
+ 'post_ids',
+ 'topic_ids',
+ 'message_ids',
+ 'physical',
+ 'num_deleted',
+ );
+ extract($this->dispatcher->trigger_event('core.delete_attachments_from_database_after', compact($vars)));
+
+ $this->sql_id = $sql_id;
+ $this->post_ids = $post_ids;
+ $this->topic_ids = $topic_ids;
+ $this->message_ids = $message_ids;
+ $this->physical = $physical;
+ $this->num_deleted = $num_deleted;
+ unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical, $num_deleted);
+
+ if (!$this->num_deleted)
+ {
+ return 0;
+ }
+
+ // Delete attachments from filesystem
+ $this->remove_from_filesystem($mode, $ids, $resync);
+
+ // If we do not resync, we do not need to adjust any message, post, topic or user entries
+ if (!$resync)
+ {
+ return $this->num_deleted;
+ }
+
+ // No more use for the original ids
+ unset($ids);
+
+ // Update post indicators for posts now no longer having attachments
+ $this->resync->resync('post', $this->post_ids);
+
+ // Update message table if messages are affected
+ $this->resync->resync('message', $this->message_ids);
+
+ // Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic
+ $this->resync->resync('topic', $this->topic_ids);
+
+ return $this->num_deleted;
+ }
+
+ /**
+ * Set attachment IDs
+ *
+ * @param mixed $ids ID or array of IDs
+ *
+ * @return bool True if attachment IDs were set, false if not
+ */
+ protected function set_attachment_ids($ids)
+ {
+ // 0 is as bad as an empty array
+ if (empty($ids))
+ {
+ return false;
+ }
+
+ if (is_array($ids))
+ {
+ $ids = array_unique($ids);
+ $this->ids = array_map('intval', $ids);
+ }
+ else
+ {
+ $this->ids = array((int) $ids);
+ }
+
+ return true;
+ }
+
+ /**
+ * Set SQL constraints based on mode
+ *
+ * @param string $mode Delete mode; can be: post|message|topic|attach|user
+ */
+ private function set_sql_constraints($mode)
+ {
+ switch ($mode)
+ {
+ case 'post':
+ case 'message':
+ $this->sql_id = 'post_msg_id';
+ $this->sql_where = ' AND in_message = ' . ($mode == 'message' ? 1 : 0);
+ break;
+
+ case 'topic':
+ $this->sql_id = 'topic_id';
+ break;
+
+ case 'user':
+ $this->sql_id = 'poster_id';
+ break;
+
+ case 'attach':
+ default:
+ $this->sql_id = 'attach_id';
+ break;
+ }
+ }
+
+ /**
+ * Collect info about attachment IDs
+ *
+ * @param bool $resync Whether topics/posts should be resynced after delete
+ */
+ protected function collect_attachment_info($resync)
+ {
+ // Collect post and topic ids for later use if we need to touch remaining entries (if resync is enabled)
+ $sql = 'SELECT post_msg_id, topic_id, in_message, physical_filename, thumbnail, filesize, is_orphan
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
+
+ $sql .= $this->sql_where;
+
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // We only need to store post/message/topic ids if resync is enabled and the file is not orphaned
+ if ($resync && !$row['is_orphan'])
+ {
+ if (!$row['in_message'])
+ {
+ $this->post_ids[] = $row['post_msg_id'];
+ $this->topic_ids[] = $row['topic_id'];
+ }
+ else
+ {
+ $this->message_ids[] = $row['post_msg_id'];
+ }
+ }
+
+ $this->physical[] = array('filename' => $row['physical_filename'], 'thumbnail' => $row['thumbnail'], 'filesize' => $row['filesize'], 'is_orphan' => $row['is_orphan']);
+ }
+ $this->db->sql_freeresult($result);
+
+ // IDs should be unique
+ $this->post_ids = array_unique($this->post_ids);
+ $this->message_ids = array_unique($this->message_ids);
+ $this->topic_ids = array_unique($this->topic_ids);
+ }
+
+ /**
+ * Delete attachments from database table
+ */
+ protected function delete_attachments_from_db($mode, $ids, $resync)
+ {
+ $sql_id = $this->sql_id;
+ $post_ids = $this->post_ids;
+ $topic_ids = $this->topic_ids;
+ $message_ids = $this->message_ids;
+ $physical = $this->physical;
+
+ /**
+ * Perform additional actions before attachment(s) deletion
+ *
+ * @event core.delete_attachments_before
+ * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
+ * @var mixed ids Array or comma separated list of ids corresponding to the mode
+ * @var bool resync Flag indicating if posts/messages/topics should be synchronized
+ * @var string sql_id The field name to collect/delete data for depending on the mode
+ * @var array post_ids Array with post ids for deleted attachment(s)
+ * @var array topic_ids Array with topic ids for deleted attachment(s)
+ * @var array message_ids Array with private message ids for deleted attachment(s)
+ * @var array physical Array with deleted attachment(s) physical file(s) data
+ * @since 3.1.7-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'ids',
+ 'resync',
+ 'sql_id',
+ 'post_ids',
+ 'topic_ids',
+ 'message_ids',
+ 'physical',
+ );
+ extract($this->dispatcher->trigger_event('core.delete_attachments_before', compact($vars)));
+
+ $this->sql_id = $sql_id;
+ $this->post_ids = $post_ids;
+ $this->topic_ids = $topic_ids;
+ $this->message_ids = $message_ids;
+ $this->physical = $physical;
+ unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical);
+
+ // Delete attachments
+ $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . '
+ WHERE ' . $this->db->sql_in_set($this->sql_id, $this->ids);
+
+ $sql .= $this->sql_where;
+
+ $this->db->sql_query($sql);
+ $this->num_deleted = $this->db->sql_affectedrows();
+ }
+
+ /**
+ * Delete attachments from filesystem
+ */
+ protected function remove_from_filesystem($mode, $ids, $resync)
+ {
+ $space_removed = $files_removed = 0;
+
+ foreach ($this->physical as $file_ary)
+ {
+ if ($this->unlink_attachment($file_ary['filename'], 'file', true) && !$file_ary['is_orphan'])
+ {
+ // Only non-orphaned files count to the file size
+ $space_removed += $file_ary['filesize'];
+ $files_removed++;
+ }
+
+ if ($file_ary['thumbnail'])
+ {
+ $this->unlink_attachment($file_ary['filename'], 'thumbnail', true);
+ }
+ }
+
+ $sql_id = $this->sql_id;
+ $post_ids = $this->post_ids;
+ $topic_ids = $this->topic_ids;
+ $message_ids = $this->message_ids;
+ $physical = $this->physical;
+ $num_deleted = $this->num_deleted;
+
+ /**
+ * Perform additional actions after attachment(s) deletion from the filesystem
+ *
+ * @event core.delete_attachments_from_filesystem_after
+ * @var string mode Variable containing attachments deletion mode, can be: post|message|topic|attach|user
+ * @var mixed ids Array or comma separated list of ids corresponding to the mode
+ * @var bool resync Flag indicating if posts/messages/topics should be synchronized
+ * @var string sql_id The field name to collect/delete data for depending on the mode
+ * @var array post_ids Array with post ids for deleted attachment(s)
+ * @var array topic_ids Array with topic ids for deleted attachment(s)
+ * @var array message_ids Array with private message ids for deleted attachment(s)
+ * @var array physical Array with deleted attachment(s) physical file(s) data
+ * @var int num_deleted The number of deleted attachment(s) from the database
+ * @var int space_removed The size of deleted files(s) from the filesystem
+ * @var int files_removed The number of deleted file(s) from the filesystem
+ * @since 3.1.7-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'ids',
+ 'resync',
+ 'sql_id',
+ 'post_ids',
+ 'topic_ids',
+ 'message_ids',
+ 'physical',
+ 'num_deleted',
+ 'space_removed',
+ 'files_removed',
+ );
+ extract($this->dispatcher->trigger_event('core.delete_attachments_from_filesystem_after', compact($vars)));
+
+ $this->sql_id = $sql_id;
+ $this->post_ids = $post_ids;
+ $this->topic_ids = $topic_ids;
+ $this->message_ids = $message_ids;
+ $this->physical = $physical;
+ $this->num_deleted = $num_deleted;
+ unset($sql_id, $post_ids, $topic_ids, $message_ids, $physical, $num_deleted);
+
+ if ($space_removed || $files_removed)
+ {
+ $this->config->increment('upload_dir_size', $space_removed * (-1), false);
+ $this->config->increment('num_files', $files_removed * (-1), false);
+ }
+ }
+
+ /**
+ * Delete attachment from filesystem
+ *
+ * @param string $filename Filename of attachment
+ * @param string $mode Delete mode
+ * @param bool $entry_removed Whether entry was removed. Defaults to false
+ * @return bool True if file was removed, false if not
+ */
+ public function unlink_attachment($filename, $mode = 'file', $entry_removed = false)
+ {
+ // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself.
+ $sql = 'SELECT COUNT(attach_id) AS num_entries
+ FROM ' . ATTACHMENTS_TABLE . "
+ WHERE physical_filename = '" . $this->db->sql_escape(utf8_basename($filename)) . "'";
+ $result = $this->db->sql_query($sql);
+ $num_entries = (int) $this->db->sql_fetchfield('num_entries');
+ $this->db->sql_freeresult($result);
+
+ // Do not remove file if at least one additional entry with the same name exist.
+ if (($entry_removed && $num_entries > 0) || (!$entry_removed && $num_entries > 1))
+ {
+ return false;
+ }
+
+ $filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename);
+ $filepath = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename;
+
+ try
+ {
+ if ($this->filesystem->exists($filepath))
+ {
+ $this->filesystem->remove($this->phpbb_root_path . $this->config['upload_path'] . '/' . $filename);
+ return true;
+ }
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $exception)
+ {
+ // Fail is covered by return statement below
+ }
+
+ return false;
+ }
+}
diff --git a/phpBB/phpbb/attachment/manager.php b/phpBB/phpbb/attachment/manager.php
new file mode 100644
index 0000000000..3c47171b2f
--- /dev/null
+++ b/phpBB/phpbb/attachment/manager.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\attachment;
+
+/**
+ * Attachment manager
+ */
+class manager
+{
+ /** @var delete Attachment delete class */
+ protected $delete;
+
+ /** @var resync Attachment resync class */
+ protected $resync;
+
+ /** @var upload Attachment upload class */
+ protected $upload;
+
+ /**
+ * Constructor for attachment manager
+ *
+ * @param delete $delete Attachment delete class
+ * @param resync $resync Attachment resync class
+ * @param upload $upload Attachment upload class
+ */
+ public function __construct(delete $delete, resync $resync, upload $upload)
+ {
+ $this->delete = $delete;
+ $this->resync = $resync;
+ $this->upload = $upload;
+ }
+
+ /**
+ * Wrapper method for deleting attachments
+ *
+ * @param string $mode can be: post|message|topic|attach|user
+ * @param mixed $ids can be: post_ids, message_ids, topic_ids, attach_ids, user_ids
+ * @param bool $resync set this to false if you are deleting posts or topics
+ *
+ * @return int|bool Number of deleted attachments or false if something
+ * went wrong during attachment deletion
+ */
+ public function delete($mode, $ids, $resync = true)
+ {
+ return $this->delete->delete($mode, $ids, $resync);
+ }
+
+ /**
+ * Wrapper method for deleting attachments from filesystem
+ *
+ * @param string $filename Filename of attachment
+ * @param string $mode Delete mode
+ * @param bool $entry_removed Whether entry was removed. Defaults to false
+ * @return bool True if file was removed, false if not
+ */
+ public function unlink($filename, $mode = 'file', $entry_removed = false)
+ {
+ return $this->delete->unlink_attachment($filename, $mode, $entry_removed);
+ }
+
+ /**
+ * Wrapper method for resyncing specified type
+ *
+ * @param string $type Type of resync
+ * @param array $ids IDs to resync
+ */
+ public function resync($type, $ids)
+ {
+ $this->resync->resync($type, $ids);
+ }
+
+ /**
+ * Wrapper method for uploading attachment
+ *
+ * @param string $form_name The form name of the file upload input
+ * @param int $forum_id The id of the forum
+ * @param bool $local Whether the file is local or not
+ * @param string $local_storage The path to the local file
+ * @param bool $is_message Whether it is a PM or not
+ * @param array $local_filedata An file data object created for the local file
+ *
+ * @return array File data array
+ */
+ public function upload($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = [])
+ {
+ return $this->upload->upload($form_name, $forum_id, $local, $local_storage, $is_message, $local_filedata);
+ }
+}
diff --git a/phpBB/phpbb/attachment/resync.php b/phpBB/phpbb/attachment/resync.php
new file mode 100644
index 0000000000..aeacf82511
--- /dev/null
+++ b/phpBB/phpbb/attachment/resync.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\attachment;
+
+use \phpbb\db\driver\driver_interface;
+
+/**
+ * Attachment resync class
+ */
+class resync
+{
+ /** @var driver_interface */
+ protected $db;
+
+ /** @var string Attachment table SQL ID */
+ private $attach_sql_id;
+
+ /** @var string Resync table SQL ID */
+ private $resync_sql_id;
+
+ /** @var string Resync SQL table */
+ private $resync_table;
+
+ /** @var string SQL where statement */
+ private $sql_where;
+
+ /**
+ * Constructor for attachment resync class
+ *
+ * @param driver_interface $db Database driver
+ */
+ public function __construct(driver_interface $db)
+ {
+ $this->db = $db;
+ }
+
+ /**
+ * Set type constraints for attachment resync
+ *
+ * @param string $type Type of resync; can be: message|post|topic
+ */
+ protected function set_type_constraints($type)
+ {
+ switch ($type)
+ {
+ case 'message':
+ $this->attach_sql_id = 'post_msg_id';
+ $this->sql_where = ' AND in_message = 1
+ AND is_orphan = 0';
+ $this->resync_table = PRIVMSGS_TABLE;
+ $this->resync_sql_id = 'msg_id';
+ break;
+
+ case 'post':
+ $this->attach_sql_id = 'post_msg_id';
+ $this->sql_where = ' AND in_message = 0
+ AND is_orphan = 0';
+ $this->resync_table = POSTS_TABLE;
+ $this->resync_sql_id = 'post_id';
+ break;
+
+ case 'topic':
+ $this->attach_sql_id = 'topic_id';
+ $this->sql_where = ' AND is_orphan = 0';
+ $this->resync_table = TOPICS_TABLE;
+ $this->resync_sql_id = 'topic_id';
+ break;
+ }
+ }
+
+ /**
+ * Resync specified type
+ *
+ * @param string $type Type of resync
+ * @param array $ids IDs to resync
+ */
+ public function resync($type, $ids)
+ {
+ if (empty($type) || !is_array($ids) || !count($ids) || !in_array($type, array('post', 'topic', 'message')))
+ {
+ return;
+ }
+
+ $this->set_type_constraints($type);
+
+ // Just check which elements are still having an assigned attachment
+ // not orphaned by querying the attachments table
+ $sql = 'SELECT ' . $this->attach_sql_id . '
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE ' . $this->db->sql_in_set($this->attach_sql_id, $ids)
+ . $this->sql_where;
+ $result = $this->db->sql_query($sql);
+
+ $remaining_ids = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $remaining_ids[] = $row[$this->attach_sql_id];
+ }
+ $this->db->sql_freeresult($result);
+
+ // Now only unset those ids remaining
+ $ids = array_diff($ids, $remaining_ids);
+
+ if (count($ids))
+ {
+ $sql = 'UPDATE ' . $this->resync_table . '
+ SET ' . $type . '_attachment = 0
+ WHERE ' . $this->db->sql_in_set($this->resync_sql_id, $ids);
+ $this->db->sql_query($sql);
+ }
+ }
+
+}
diff --git a/phpBB/phpbb/attachment/upload.php b/phpBB/phpbb/attachment/upload.php
new file mode 100644
index 0000000000..b9d32058db
--- /dev/null
+++ b/phpBB/phpbb/attachment/upload.php
@@ -0,0 +1,334 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\attachment;
+
+use phpbb\auth\auth;
+use \phpbb\cache\service;
+use \phpbb\config\config;
+use \phpbb\event\dispatcher;
+use \phpbb\language\language;
+use \phpbb\mimetype\guesser;
+use \phpbb\plupload\plupload;
+use \phpbb\user;
+
+/**
+ * Attachment upload class
+ */
+class upload
+{
+ /** @var auth */
+ protected $auth;
+
+ /** @var service */
+ protected $cache;
+
+ /** @var config */
+ protected $config;
+
+ /** @var \phpbb\files\upload Upload class */
+ protected $files_upload;
+
+ /** @var language */
+ protected $language;
+
+ /** @var guesser Mimetype guesser */
+ protected $mimetype_guesser;
+
+ /** @var dispatcher */
+ protected $phpbb_dispatcher;
+
+ /** @var plupload Plupload */
+ protected $plupload;
+
+ /** @var user */
+ protected $user;
+
+ /** @var \phpbb\files\filespec Current filespec instance */
+ private $file;
+
+ /** @var array File data */
+ private $file_data = array(
+ 'error' => array()
+ );
+
+ /** @var array Extensions array */
+ private $extensions;
+
+ /**
+ * Constructor for attachments upload class
+ *
+ * @param auth $auth
+ * @param service $cache
+ * @param config $config
+ * @param \phpbb\files\upload $files_upload
+ * @param language $language
+ * @param guesser $mimetype_guesser
+ * @param dispatcher $phpbb_dispatcher
+ * @param plupload $plupload
+ * @param user $user
+ * @param $phpbb_root_path
+ */
+ public function __construct(auth $auth, service $cache, config $config, \phpbb\files\upload $files_upload, language $language, guesser $mimetype_guesser, dispatcher $phpbb_dispatcher, plupload $plupload, user $user, $phpbb_root_path)
+ {
+ $this->auth = $auth;
+ $this->cache = $cache;
+ $this->config = $config;
+ $this->files_upload = $files_upload;
+ $this->language = $language;
+ $this->mimetype_guesser = $mimetype_guesser;
+ $this->phpbb_dispatcher = $phpbb_dispatcher;
+ $this->plupload = $plupload;
+ $this->user = $user;
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * Upload Attachment - filedata is generated here
+ * Uses upload class
+ *
+ * @param string $form_name The form name of the file upload input
+ * @param int $forum_id The id of the forum
+ * @param bool $local Whether the file is local or not
+ * @param string $local_storage The path to the local file
+ * @param bool $is_message Whether it is a PM or not
+ * @param array $local_filedata An file data object created for the local file
+ *
+ * @return array File data array
+ */
+ public function upload($form_name, $forum_id, $local = false, $local_storage = '', $is_message = false, $local_filedata = array())
+ {
+ $this->init_files_upload($forum_id, $is_message);
+
+ $this->file_data['post_attach'] = $local || $this->files_upload->is_valid($form_name);
+
+ if (!$this->file_data['post_attach'])
+ {
+ $this->file_data['error'][] = $this->language->lang('NO_UPLOAD_FORM_FOUND');
+ return $this->file_data;
+ }
+
+ $this->file = ($local) ? $this->files_upload->handle_upload('files.types.local', $local_storage, $local_filedata) : $this->files_upload->handle_upload('files.types.form', $form_name);
+
+ if ($this->file->init_error())
+ {
+ $this->file_data['post_attach'] = false;
+ return $this->file_data;
+ }
+
+ // Whether the uploaded file is in the image category
+ $is_image = (isset($this->extensions[$this->file->get('extension')]['display_cat'])) ? $this->extensions[$this->file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
+
+ if (!$this->auth->acl_get('a_') && !$this->auth->acl_get('m_', $forum_id))
+ {
+ // Check Image Size, if it is an image
+ if ($is_image)
+ {
+ $this->file->upload->set_allowed_dimensions(0, 0, $this->config['img_max_width'], $this->config['img_max_height']);
+ }
+
+ // Admins and mods are allowed to exceed the allowed filesize
+ if (!empty($this->extensions[$this->file->get('extension')]['max_filesize']))
+ {
+ $allowed_filesize = $this->extensions[$this->file->get('extension')]['max_filesize'];
+ }
+ else
+ {
+ $allowed_filesize = ($is_message) ? $this->config['max_filesize_pm'] : $this->config['max_filesize'];
+ }
+
+ $this->file->upload->set_max_filesize($allowed_filesize);
+ }
+
+ $this->file->clean_filename('unique', $this->user->data['user_id'] . '_');
+
+ // Are we uploading an image *and* this image being within the image category?
+ // Only then perform additional image checks.
+ $this->file->move_file($this->config['upload_path'], false, !$is_image);
+
+ // Do we have to create a thumbnail?
+ $this->file_data['thumbnail'] = ($is_image && $this->config['img_create_thumbnail']) ? 1 : 0;
+
+ // Make sure the image category only holds valid images...
+ $this->check_image($is_image);
+
+ if (count($this->file->error))
+ {
+ $this->file->remove();
+ $this->file_data['error'] = array_merge($this->file_data['error'], $this->file->error);
+ $this->file_data['post_attach'] = false;
+
+ return $this->file_data;
+ }
+
+ $this->fill_file_data();
+
+ $filedata = $this->file_data;
+
+ /**
+ * Event to modify uploaded file before submit to the post
+ *
+ * @event core.modify_uploaded_file
+ * @var array filedata Array containing uploaded file data
+ * @var bool is_image Flag indicating if the file is an image
+ * @since 3.1.0-RC3
+ */
+ $vars = array(
+ 'filedata',
+ 'is_image',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.modify_uploaded_file', compact($vars)));
+ $this->file_data = $filedata;
+ unset($filedata);
+
+ // Check for attachment quota and free space
+ if (!$this->check_attach_quota() || !$this->check_disk_space())
+ {
+ return $this->file_data;
+ }
+
+ // Create Thumbnail
+ $this->create_thumbnail();
+
+ return $this->file_data;
+ }
+
+ /**
+ * Create thumbnail for file if necessary
+ *
+ * @return array Updated $filedata
+ */
+ protected function create_thumbnail()
+ {
+ if ($this->file_data['thumbnail'])
+ {
+ $source = $this->file->get('destination_file');
+ $destination = $this->file->get('destination_path') . '/thumb_' . $this->file->get('realname');
+
+ if (!create_thumbnail($source, $destination, $this->file->get('mimetype')))
+ {
+ $this->file_data['thumbnail'] = 0;
+ }
+ }
+ }
+
+ /**
+ * Init files upload class
+ *
+ * @param int $forum_id Forum ID
+ * @param bool $is_message Whether attachment is inside PM or not
+ */
+ protected function init_files_upload($forum_id, $is_message)
+ {
+ if ($this->config['check_attachment_content'] && isset($this->config['mime_triggers']))
+ {
+ $this->files_upload->set_disallowed_content(explode('|', $this->config['mime_triggers']));
+ }
+ else if (!$this->config['check_attachment_content'])
+ {
+ $this->files_upload->set_disallowed_content(array());
+ }
+
+ $this->extensions = $this->cache->obtain_attach_extensions((($is_message) ? false : (int) $forum_id));
+ $this->files_upload->set_allowed_extensions(array_keys($this->extensions['_allowed_']));
+ }
+
+ /**
+ * Check if uploaded file is really an image
+ *
+ * @param bool $is_image Whether file is image
+ */
+ protected function check_image($is_image)
+ {
+ // Make sure the image category only holds valid images...
+ if ($is_image && !$this->file->is_image())
+ {
+ $this->file->remove();
+
+ if ($this->plupload && $this->plupload->is_active())
+ {
+ $this->plupload->emit_error(104, 'ATTACHED_IMAGE_NOT_IMAGE');
+ }
+
+ // If this error occurs a user tried to exploit an IE Bug by renaming extensions
+ // Since the image category is displaying content inline we need to catch this.
+ $this->file->set_error($this->language->lang('ATTACHED_IMAGE_NOT_IMAGE'));
+ }
+ }
+
+ /**
+ * Check if attachment quota was reached
+ *
+ * @return bool False if attachment quota was reached, true if not
+ */
+ protected function check_attach_quota()
+ {
+ if ($this->config['attachment_quota'])
+ {
+ if (intval($this->config['upload_dir_size']) + $this->file->get('filesize') > $this->config['attachment_quota'])
+ {
+ $this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
+ $this->file_data['post_attach'] = false;
+
+ $this->file->remove();
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if there is enough free space available on disk
+ *
+ * @return bool True if disk space is available, false if not
+ */
+ protected function check_disk_space()
+ {
+ if ($free_space = @disk_free_space($this->phpbb_root_path . $this->config['upload_path']))
+ {
+ if ($free_space <= $this->file->get('filesize'))
+ {
+ if ($this->auth->acl_get('a_'))
+ {
+ $this->file_data['error'][] = $this->language->lang('ATTACH_DISK_FULL');
+ }
+ else
+ {
+ $this->file_data['error'][] = $this->language->lang('ATTACH_QUOTA_REACHED');
+ }
+ $this->file_data['post_attach'] = false;
+
+ $this->file->remove();
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Fills file data with file information and current time as filetime
+ */
+ protected function fill_file_data()
+ {
+ $this->file_data['filesize'] = $this->file->get('filesize');
+ $this->file_data['mimetype'] = $this->file->get('mimetype');
+ $this->file_data['extension'] = $this->file->get('extension');
+ $this->file_data['physical_filename'] = $this->file->get('realname');
+ $this->file_data['real_filename'] = $this->file->get('uploadname');
+ $this->file_data['filetime'] = time();
+ }
+}
diff --git a/phpBB/phpbb/auth/auth.php b/phpBB/phpbb/auth/auth.php
index 37d4352c10..f46a21a8ae 100644
--- a/phpBB/phpbb/auth/auth.php
+++ b/phpBB/phpbb/auth/auth.php
@@ -72,8 +72,8 @@ class auth
// Verify bitstring length with options provided...
$renew = false;
- $global_length = sizeof($this->acl_options['global']);
- $local_length = sizeof($this->acl_options['local']);
+ $global_length = count($this->acl_options['global']);
+ $local_length = count($this->acl_options['local']);
// Specify comparing length (bitstring is padded to 31 bits)
$global_length = ($global_length % 31) ? ($global_length - ($global_length % 31) + 31) : $global_length;
@@ -236,7 +236,7 @@ class auth
$sql = 'SELECT forum_id
FROM ' . FORUMS_TABLE;
- if (sizeof($this->acl))
+ if (count($this->acl))
{
$sql .= ' WHERE ' . $db->sql_in_set('forum_id', array_keys($this->acl), true);
}
@@ -278,7 +278,7 @@ class auth
}
// If we get forum_ids not having this permission, we need to fill the remaining parts
- if ($negate && sizeof($this->acl_forum_ids))
+ if ($negate && count($this->acl_forum_ids))
{
foreach ($this->acl_forum_ids as $f)
{
@@ -455,7 +455,7 @@ class auth
{
$hold_str = '';
- if (sizeof($hold_ary))
+ if (count($hold_ary))
{
ksort($hold_ary);
@@ -940,6 +940,7 @@ class auth
global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
global $phpbb_dispatcher;
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$provider = $provider_collection->get_provider();
diff --git a/phpBB/phpbb/auth/provider/db.php b/phpBB/phpbb/auth/provider/db.php
index d8c5fb72de..1adf85ee05 100644
--- a/phpBB/phpbb/auth/provider/db.php
+++ b/phpBB/phpbb/auth/provider/db.php
@@ -155,6 +155,7 @@ class db extends \phpbb\auth\provider\base
// Every auth module is able to define what to do by itself...
if ($show_captcha)
{
+ /* @var $captcha_factory \phpbb\captcha\factory */
$captcha_factory = $this->phpbb_container->get('captcha.factory');
$captcha = $captcha_factory->get_instance($this->config['captcha_plugin']);
$captcha->init(CONFIRM_LOGIN);
diff --git a/phpBB/phpbb/auth/provider/ldap.php b/phpBB/phpbb/auth/provider/ldap.php
index c48b771ab0..0789a6234d 100644
--- a/phpBB/phpbb/auth/provider/ldap.php
+++ b/phpBB/phpbb/auth/provider/ldap.php
@@ -99,7 +99,7 @@ class ldap extends \phpbb\auth\provider\base
@ldap_close($ldap);
- if (!is_array($result) || sizeof($result) < 2)
+ if (!is_array($result) || count($result) < 2)
{
return sprintf($this->user->lang['LDAP_NO_IDENTITY'], $this->user->data['username']);
}
@@ -192,7 +192,7 @@ class ldap extends \phpbb\auth\provider\base
$ldap_result = @ldap_get_entries($ldap, $search);
- if (is_array($ldap_result) && sizeof($ldap_result) > 1)
+ if (is_array($ldap_result) && count($ldap_result) > 1)
{
if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password)))
{
diff --git a/phpBB/phpbb/auth/provider/oauth/oauth.php b/phpBB/phpbb/auth/provider/oauth/oauth.php
index bd2a414033..e3f8394bba 100644
--- a/phpBB/phpbb/auth/provider/oauth/oauth.php
+++ b/phpBB/phpbb/auth/provider/oauth/oauth.php
@@ -63,6 +63,13 @@ class oauth extends \phpbb\auth\provider\base
protected $auth_provider_oauth_token_storage_table;
/**
+ * OAuth state table
+ *
+ * @var string
+ */
+ protected $auth_provider_oauth_state_table;
+
+ /**
* OAuth account association table
*
* @var string
@@ -127,6 +134,7 @@ class oauth extends \phpbb\auth\provider\base
* @param \phpbb\request\request_interface $request
* @param \phpbb\user $user
* @param string $auth_provider_oauth_token_storage_table
+ * @param string $auth_provider_oauth_state_table
* @param string $auth_provider_oauth_token_account_assoc
* @param \phpbb\di\service_collection $service_providers Contains \phpbb\auth\provider\oauth\service_interface
* @param string $users_table
@@ -135,7 +143,7 @@ class oauth extends \phpbb\auth\provider\base
* @param string $phpbb_root_path
* @param string $php_ext
*/
- public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request_interface $request, \phpbb\user $user, $auth_provider_oauth_token_storage_table, $auth_provider_oauth_token_account_assoc, \phpbb\di\service_collection $service_providers, $users_table, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, \phpbb\event\dispatcher_interface $dispatcher, $phpbb_root_path, $php_ext)
+ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\passwords\manager $passwords_manager, \phpbb\request\request_interface $request, \phpbb\user $user, $auth_provider_oauth_token_storage_table, $auth_provider_oauth_state_table, $auth_provider_oauth_token_account_assoc, \phpbb\di\service_collection $service_providers, $users_table, \Symfony\Component\DependencyInjection\ContainerInterface $phpbb_container, \phpbb\event\dispatcher_interface $dispatcher, $phpbb_root_path, $php_ext)
{
$this->db = $db;
$this->config = $config;
@@ -143,6 +151,7 @@ class oauth extends \phpbb\auth\provider\base
$this->request = $request;
$this->user = $user;
$this->auth_provider_oauth_token_storage_table = $auth_provider_oauth_token_storage_table;
+ $this->auth_provider_oauth_state_table = $auth_provider_oauth_state_table;
$this->auth_provider_oauth_token_account_assoc = $auth_provider_oauth_token_account_assoc;
$this->service_providers = $service_providers;
$this->users_table = $users_table;
@@ -182,7 +191,7 @@ class oauth extends \phpbb\auth\provider\base
return $provider->login($username, $password);
}
- // Requst the name of the OAuth service
+ // Request the name of the OAuth service
$service_name_original = $this->request->variable('oauth_service', '', false);
$service_name = 'auth.provider.oauth.service.' . strtolower($service_name_original);
if ($service_name_original === '' || !array_key_exists($service_name, $this->service_providers))
@@ -197,26 +206,57 @@ class oauth extends \phpbb\auth\provider\base
// Get the service credentials for the given service
$service_credentials = $this->service_providers[$service_name]->get_service_credentials();
- $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
+ $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
$query = 'mode=login&login=external&oauth_service=' . $service_name_original;
$service = $this->get_service($service_name_original, $storage, $service_credentials, $query, $this->service_providers[$service_name]->get_auth_scope());
- if ($this->request->is_set('code', \phpbb\request\request_interface::GET))
+ if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET))
+ || ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET)))
{
$this->service_providers[$service_name]->set_external_service_provider($service);
$unique_id = $this->service_providers[$service_name]->perform_auth_login();
- // Check to see if this provider is already assosciated with an account
+ /**
+ * Check to see if this provider is already associated with an account.
+ *
+ * Enforcing a data type to make data contains strings and not integers,
+ * so values are quoted in the SQL WHERE statement.
+ */
$data = array(
- 'provider' => $service_name_original,
- 'oauth_provider_id' => $unique_id
+ 'provider' => (string) $service_name_original,
+ 'oauth_provider_id' => (string) $unique_id
);
+
$sql = 'SELECT user_id FROM ' . $this->auth_provider_oauth_token_account_assoc . '
WHERE ' . $this->db->sql_build_array('SELECT', $data);
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
+ $redirect_data = array(
+ 'auth_provider' => 'oauth',
+ 'login_link_oauth_service' => $service_name_original,
+ );
+
+ /**
+ * Event is triggered before check if provider is already associated with an account
+ *
+ * @event core.oauth_login_after_check_if_provider_id_has_match
+ * @var array row User row
+ * @var array data Provider data
+ * @var array redirect_data Data to be appended to the redirect url
+ * @var \OAuth\Common\Service\ServiceInterface service OAuth service
+ * @since 3.2.3-RC1
+ * @changed 3.2.6-RC1 Added redirect_data
+ */
+ $vars = array(
+ 'row',
+ 'data',
+ 'redirect_data',
+ 'service',
+ );
+ extract($this->dispatcher->trigger_event('core.oauth_login_after_check_if_provider_id_has_match', compact($vars)));
+
if (!$row)
{
// The user does not yet exist, ask to link or create profile
@@ -224,15 +264,12 @@ class oauth extends \phpbb\auth\provider\base
'status' => LOGIN_SUCCESS_LINK_PROFILE,
'error_msg' => 'LOGIN_OAUTH_ACCOUNT_NOT_LINKED',
'user_row' => array(),
- 'redirect_data' => array(
- 'auth_provider' => 'oauth',
- 'login_link_oauth_service' => $service_name_original,
- ),
+ 'redirect_data' => $redirect_data,
);
}
// Retrieve the user's account
- $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts
+ $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_ip, user_type, user_login_attempts
FROM ' . $this->users_table . '
WHERE user_id = ' . (int) $row['user_id'];
$result = $this->db->sql_query($sql);
@@ -244,11 +281,36 @@ class oauth extends \phpbb\auth\provider\base
throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY');
}
+ /**
+ * Check if the user is banned.
+ * The fourth parameter, return, has to be true,
+ * otherwise the OAuth login is still called and
+ * an uncaught exception is thrown as there is no
+ * token stored in the database.
+ */
+ $ban = $this->user->check_ban($row['user_id'], $row['user_ip'], $row['user_email'], true);
+ if (!empty($ban))
+ {
+ $till_date = !empty($ban['ban_end']) ? $this->user->format_date($ban['ban_end']) : '';
+ $message = !empty($ban['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
+
+ $contact_link = phpbb_get_board_contact_link($this->config, $this->phpbb_root_path, $this->php_ext);
+ $message = $this->user->lang($message, $till_date, '<a href="' . $contact_link . '">', '</a>');
+ $message .= !empty($ban['ban_give_reason']) ? '<br /><br />' . $this->user->lang('BOARD_BAN_REASON', $ban['ban_give_reason']) : '';
+ $message .= !empty($ban['ban_triggered_by']) ? '<br /><br /><em>' . $this->user->lang('BAN_TRIGGERED_BY_' . strtoupper($ban['ban_triggered_by'])) . '</em>' : '';
+
+ return array(
+ 'status' => LOGIN_BREAK,
+ 'error_msg' => $message,
+ 'user_row' => $row,
+ );
+ }
+
// Update token storage to store the user_id
$storage->set_user_id($row['user_id']);
/**
- * Event is triggered after user is successfuly logged in via OAuth.
+ * Event is triggered after user is successfully logged in via OAuth.
*
* @event core.auth_oauth_login_after
* @var array row User row
@@ -268,7 +330,15 @@ class oauth extends \phpbb\auth\provider\base
}
else
{
- $url = $service->getAuthorizationUri();
+ if ($service::OAUTH_VERSION === 1)
+ {
+ $token = $service->requestRequestToken();
+ $url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ }
+ else
+ {
+ $url = $service->getAuthorizationUri();
+ }
header('Location: ' . $url);
}
}
@@ -358,7 +428,7 @@ class oauth extends \phpbb\auth\provider\base
if ($credentials['key'] && $credentials['secret'])
{
$actual_name = str_replace('auth.provider.oauth.service.', '', $service_name);
- $redirect_url = build_url(false) . '&login=external&oauth_service=' . $actual_name;
+ $redirect_url = generate_board_url() . '/ucp.' . $this->php_ext . '?mode=login&login=external&oauth_service=' . $actual_name;
$login_data['BLOCK_VARS'][$service_name] = array(
'REDIRECT_URL' => redirect($redirect_url, true),
'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
@@ -483,7 +553,7 @@ class oauth extends \phpbb\auth\provider\base
*/
protected function link_account_login_link(array $link_data, $service_name)
{
- $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
+ $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
// Check for an access token, they should have one
if (!$storage->has_access_token_by_session($service_name))
@@ -526,13 +596,14 @@ class oauth extends \phpbb\auth\provider\base
*/
protected function link_account_auth_link(array $link_data, $service_name)
{
- $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
+ $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
$query = 'i=ucp_auth_link&mode=auth_link&link=1&oauth_service=' . strtolower($link_data['oauth_service']);
$service_credentials = $this->service_providers[$service_name]->get_service_credentials();
$scopes = $this->service_providers[$service_name]->get_auth_scope();
$service = $this->get_service(strtolower($link_data['oauth_service']), $storage, $service_credentials, $query, $scopes);
- if ($this->request->is_set('code', \phpbb\request\request_interface::GET))
+ if (($service::OAUTH_VERSION === 2 && $this->request->is_set('code', \phpbb\request\request_interface::GET))
+ || ($service::OAUTH_VERSION === 1 && $this->request->is_set('oauth_token', \phpbb\request\request_interface::GET)))
{
$this->service_providers[$service_name]->set_external_service_provider($service);
$unique_id = $this->service_providers[$service_name]->perform_auth_login();
@@ -548,7 +619,15 @@ class oauth extends \phpbb\auth\provider\base
}
else
{
- $url = $service->getAuthorizationUri();
+ if ($service::OAUTH_VERSION === 1)
+ {
+ $token = $service->requestRequestToken();
+ $url = $service->getAuthorizationUri(array('oauth_token' => $token->getRequestToken()));
+ }
+ else
+ {
+ $url = $service->getAuthorizationUri();
+ }
header('Location: ' . $url);
}
}
@@ -560,6 +639,21 @@ class oauth extends \phpbb\auth\provider\base
*/
protected function link_account_perform_link(array $data)
{
+ // Check if the external account is already associated with other user
+ $sql = 'SELECT user_id
+ FROM ' . $this->auth_provider_oauth_token_account_assoc . "
+ WHERE provider = '" . $this->db->sql_escape($data['provider']) . "'
+ AND oauth_provider_id = '" . $this->db->sql_escape($data['oauth_provider_id']) . "'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row)
+ {
+ trigger_error('AUTH_PROVIDER_OAUTH_ERROR_ALREADY_LINKED');
+ }
+
+ // Link account
$sql = 'INSERT INTO ' . $this->auth_provider_oauth_token_account_assoc . '
' . $this->db->sql_build_array('INSERT', $data);
$this->db->sql_query($sql);
@@ -583,7 +677,7 @@ class oauth extends \phpbb\auth\provider\base
public function logout($data, $new_session)
{
// Clear all tokens belonging to the user
- $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
+ $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
$storage->clearAllTokens();
return;
@@ -608,7 +702,7 @@ class oauth extends \phpbb\auth\provider\base
$oauth_user_ids = array();
- if ($rows !== false && sizeof($rows))
+ if ($rows !== false && count($rows))
{
foreach ($rows as $row)
{
@@ -631,6 +725,7 @@ class oauth extends \phpbb\auth\provider\base
'oauth_service' => $actual_name,
),
+ 'SERVICE_ID' => $actual_name,
'SERVICE_NAME' => $this->user->lang['AUTH_PROVIDER_OAUTH_SERVICE_' . strtoupper($actual_name)],
'UNIQUE_ID' => (isset($oauth_user_ids[$actual_name])) ? $oauth_user_ids[$actual_name] : null,
);
@@ -664,9 +759,9 @@ class oauth extends \phpbb\auth\provider\base
AND user_id = " . (int) $user_id;
$this->db->sql_query($sql);
- // Clear all tokens belonging to the user on this servce
+ // Clear all tokens belonging to the user on this service
$service_name = 'auth.provider.oauth.service.' . strtolower($link_data['oauth_service']);
- $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table);
+ $storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->auth_provider_oauth_token_storage_table, $this->auth_provider_oauth_state_table);
$storage->clearToken($service_name);
}
}
diff --git a/phpBB/phpbb/auth/provider/oauth/service/twitter.php b/phpBB/phpbb/auth/provider/oauth/service/twitter.php
new file mode 100644
index 0000000000..06beac51e2
--- /dev/null
+++ b/phpBB/phpbb/auth/provider/oauth/service/twitter.php
@@ -0,0 +1,102 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\auth\provider\oauth\service;
+
+/**
+* Twitter OAuth service
+*/
+class twitter extends \phpbb\auth\provider\oauth\service\base
+{
+ /**
+ * phpBB config
+ *
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * phpBB request
+ *
+ * @var \phpbb\request\request_interface
+ */
+ protected $request;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\config\config $config
+ * @param \phpbb\request\request_interface $request
+ */
+ public function __construct(\phpbb\config\config $config, \phpbb\request\request_interface $request)
+ {
+ $this->config = $config;
+ $this->request = $request;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_service_credentials()
+ {
+ return array(
+ 'key' => $this->config['auth_oauth_twitter_key'],
+ 'secret' => $this->config['auth_oauth_twitter_secret'],
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function perform_auth_login()
+ {
+ if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter))
+ {
+ throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
+ }
+
+ $storage = $this->service_provider->getStorage();
+ $token = $storage->retrieveAccessToken('Twitter');
+ $tokensecret = $token->getRequestTokenSecret();
+
+ // This was a callback request from twitter, get the token
+ $this->service_provider->requestAccessToken(
+ $this->request->variable('oauth_token', ''),
+ $this->request->variable('oauth_verifier', ''),
+ $tokensecret
+ );
+
+ // Send a request with it
+ $result = json_decode($this->service_provider->request('account/verify_credentials.json'), true);
+
+ // Return the unique identifier returned from twitter
+ return $result['id'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function perform_token_auth()
+ {
+ if (!($this->service_provider instanceof \OAuth\OAuth1\Service\Twitter))
+ {
+ throw new \phpbb\auth\provider\oauth\service\exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
+ }
+
+ // Send a request with it
+ $result = json_decode($this->service_provider->request('account/verify_credentials.json'), true);
+
+ // Return the unique identifier returned from twitter
+ return $result['id'];
+ }
+}
diff --git a/phpBB/phpbb/auth/provider/oauth/token_storage.php b/phpBB/phpbb/auth/provider/oauth/token_storage.php
index 9b6afae255..b0c2fd0d62 100644
--- a/phpBB/phpbb/auth/provider/oauth/token_storage.php
+++ b/phpBB/phpbb/auth/provider/oauth/token_storage.php
@@ -17,6 +17,7 @@ use OAuth\OAuth1\Token\StdOAuth1Token;
use OAuth\Common\Token\TokenInterface;
use OAuth\Common\Storage\TokenStorageInterface;
use OAuth\Common\Storage\Exception\TokenNotFoundException;
+use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException;
/**
* OAuth storage wrapper for phpbb's cache
@@ -42,7 +43,14 @@ class token_storage implements TokenStorageInterface
*
* @var string
*/
- protected $auth_provider_oauth_table;
+ protected $oauth_token_table;
+
+ /**
+ * OAuth state table
+ *
+ * @var string
+ */
+ protected $oauth_state_table;
/**
* @var object|TokenInterface
@@ -50,17 +58,24 @@ class token_storage implements TokenStorageInterface
protected $cachedToken;
/**
+ * @var string
+ */
+ protected $cachedState;
+
+ /**
* Creates token storage for phpBB.
*
* @param \phpbb\db\driver\driver_interface $db
* @param \phpbb\user $user
- * @param string $auth_provider_oauth_table
+ * @param string $oauth_token_table
+ * @param string $oauth_state_table
*/
- public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $auth_provider_oauth_table)
+ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\user $user, $oauth_token_table, $oauth_state_table)
{
$this->db = $db;
$this->user = $user;
- $this->auth_provider_oauth_table = $auth_provider_oauth_table;
+ $this->oauth_token_table = $oauth_token_table;
+ $this->oauth_state_table = $oauth_state_table;
}
/**
@@ -98,15 +113,31 @@ class token_storage implements TokenStorageInterface
$this->cachedToken = $token;
$data = array(
- 'user_id' => (int) $this->user->data['user_id'],
- 'provider' => $service,
'oauth_token' => $this->json_encode_token($token),
- 'session_id' => $this->user->data['session_id'],
);
- $sql = 'INSERT INTO ' . $this->auth_provider_oauth_table . '
- ' . $this->db->sql_build_array('INSERT', $data);
+ $sql = 'UPDATE ' . $this->oauth_token_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $data) . '
+ WHERE user_id = ' . (int) $this->user->data['user_id'] . '
+ ' . ((int) $this->user->data['user_id'] === ANONYMOUS ? "AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'" : '') . "
+ AND provider = '" . $this->db->sql_escape($service) . "'";
$this->db->sql_query($sql);
+
+ if (!$this->db->sql_affectedrows())
+ {
+ $data = array(
+ 'user_id' => (int) $this->user->data['user_id'],
+ 'provider' => $service,
+ 'oauth_token' => $this->json_encode_token($token),
+ 'session_id' => $this->user->data['session_id'],
+ );
+
+ $sql = 'INSERT INTO ' . $this->oauth_token_table . $this->db->sql_build_array('INSERT', $data);
+
+ $this->db->sql_query($sql);
+ }
+
+ return $this;
}
/**
@@ -143,7 +174,7 @@ class token_storage implements TokenStorageInterface
$this->cachedToken = null;
- $sql = 'DELETE FROM ' . $this->auth_provider_oauth_table . '
+ $sql = 'DELETE FROM ' . $this->oauth_token_table . '
WHERE user_id = ' . (int) $this->user->data['user_id'] . "
AND provider = '" . $this->db->sql_escape($service) . "'";
@@ -153,6 +184,8 @@ class token_storage implements TokenStorageInterface
}
$this->db->sql_query($sql);
+
+ return $this;
}
/**
@@ -162,7 +195,7 @@ class token_storage implements TokenStorageInterface
{
$this->cachedToken = null;
- $sql = 'DELETE FROM ' . $this->auth_provider_oauth_table . '
+ $sql = 'DELETE FROM ' . $this->oauth_token_table . '
WHERE user_id = ' . (int) $this->user->data['user_id'];
if ((int) $this->user->data['user_id'] === ANONYMOUS)
@@ -171,6 +204,124 @@ class token_storage implements TokenStorageInterface
}
$this->db->sql_query($sql);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function storeAuthorizationState($service, $state)
+ {
+ $service = $this->get_service_name_for_db($service);
+
+ $this->cachedState = $state;
+
+ $data = array(
+ 'user_id' => (int) $this->user->data['user_id'],
+ 'provider' => $service,
+ 'oauth_state' => $state,
+ 'session_id' => $this->user->data['session_id'],
+ );
+
+ $sql = 'INSERT INTO ' . $this->oauth_state_table . '
+ ' . $this->db->sql_build_array('INSERT', $data);
+ $this->db->sql_query($sql);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasAuthorizationState($service)
+ {
+ $service = $this->get_service_name_for_db($service);
+
+ if ($this->cachedState)
+ {
+ return true;
+ }
+
+ $data = array(
+ 'user_id' => (int) $this->user->data['user_id'],
+ 'provider' => $service,
+ );
+
+ if ((int) $this->user->data['user_id'] === ANONYMOUS)
+ {
+ $data['session_id'] = $this->user->data['session_id'];
+ }
+
+ return (bool) $this->get_state_row($data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function retrieveAuthorizationState($service)
+ {
+ $service = $this->get_service_name_for_db($service);
+
+ if ($this->cachedState)
+ {
+ return $this->cachedState;
+ }
+
+ $data = array(
+ 'user_id' => (int) $this->user->data['user_id'],
+ 'provider' => $service,
+ );
+
+ if ((int) $this->user->data['user_id'] === ANONYMOUS)
+ {
+ $data['session_id'] = $this->user->data['session_id'];
+ }
+
+ return $this->get_state_row($data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearAuthorizationState($service)
+ {
+ $service = $this->get_service_name_for_db($service);
+
+ $this->cachedState = null;
+
+ $sql = 'DELETE FROM ' . $this->oauth_state_table . '
+ WHERE user_id = ' . (int) $this->user->data['user_id'] . "
+ AND provider = '" . $this->db->sql_escape($service) . "'";
+
+ if ((int) $this->user->data['user_id'] === ANONYMOUS)
+ {
+ $sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'";
+ }
+
+ $this->db->sql_query($sql);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearAllAuthorizationStates()
+ {
+ $this->cachedState = null;
+
+ $sql = 'DELETE FROM ' . $this->oauth_state_table . '
+ WHERE user_id = ' . (int) $this->user->data['user_id'];
+
+ if ((int) $this->user->data['user_id'] === ANONYMOUS)
+ {
+ $sql .= " AND session_id = '" . $this->db->sql_escape($this->user->data['session_id']) . "'";
+ }
+
+ $this->db->sql_query($sql);
+
+ return $this;
}
/**
@@ -185,7 +336,7 @@ class token_storage implements TokenStorageInterface
return;
}
- $sql = 'UPDATE ' . $this->auth_provider_oauth_table . '
+ $sql = 'UPDATE ' . $this->oauth_token_table . '
SET ' . $this->db->sql_build_array('UPDATE', array(
'user_id' => (int) $user_id
)) . '
@@ -218,6 +369,29 @@ class token_storage implements TokenStorageInterface
}
/**
+ * Checks to see if a state exists solely by the session_id of the user
+ *
+ * @param string $service The name of the OAuth service
+ * @return bool true if they have state, false if they don't
+ */
+ public function has_state_by_session($service)
+ {
+ $service = $this->get_service_name_for_db($service);
+
+ if ($this->cachedState)
+ {
+ return true;
+ }
+
+ $data = array(
+ 'session_id' => $this->user->data['session_id'],
+ 'provider' => $service,
+ );
+
+ return (bool) $this->get_state_row($data);
+ }
+
+ /**
* A helper function that performs the query for has access token functions
*
* @param array $data
@@ -245,6 +419,23 @@ class token_storage implements TokenStorageInterface
return $this->_retrieve_access_token($data);
}
+ public function retrieve_state_by_session($service)
+ {
+ $service = $this->get_service_name_for_db($service);
+
+ if ($this->cachedState)
+ {
+ return $this->cachedState;
+ }
+
+ $data = array(
+ 'session_id' => $this->user->data['session_id'],
+ 'provider' => $service,
+ );
+
+ return $this->_retrieve_state($data);
+ }
+
/**
* A helper function that performs the query for retrieve access token functions
* Also checks if the token is a valid token
@@ -276,6 +467,26 @@ class token_storage implements TokenStorageInterface
}
/**
+ * A helper function that performs the query for retrieve state functions
+ *
+ * @param array $data
+ * @return mixed
+ * @throws \OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException
+ */
+ protected function _retrieve_state($data)
+ {
+ $row = $this->get_state_row($data);
+
+ if (!$row)
+ {
+ throw new AuthorizationStateNotFoundException();
+ }
+
+ $this->cachedState = $row['oauth_state'];
+ return $this->cachedState;
+ }
+
+ /**
* A helper function that performs the query for retrieving an access token
*
* @param array $data
@@ -283,7 +494,24 @@ class token_storage implements TokenStorageInterface
*/
protected function get_access_token_row($data)
{
- $sql = 'SELECT oauth_token FROM ' . $this->auth_provider_oauth_table . '
+ $sql = 'SELECT oauth_token FROM ' . $this->oauth_token_table . '
+ WHERE ' . $this->db->sql_build_array('SELECT', $data);
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ return $row;
+ }
+
+ /**
+ * A helper function that performs the query for retrieving a state
+ *
+ * @param array $data
+ * @return mixed
+ */
+ protected function get_state_row($data)
+ {
+ $sql = 'SELECT oauth_state FROM ' . $this->oauth_state_table . '
WHERE ' . $this->db->sql_build_array('SELECT', $data);
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
diff --git a/phpBB/phpbb/auth/provider/provider_interface.php b/phpBB/phpbb/auth/provider/provider_interface.php
index 35e0f559a1..463324ff46 100644
--- a/phpBB/phpbb/auth/provider/provider_interface.php
+++ b/phpBB/phpbb/auth/provider/provider_interface.php
@@ -71,9 +71,10 @@ interface provider_interface
* options with whatever configuraton values are passed to it as an array.
* It then returns the name of the acp file related to this authentication
* provider.
- * @param array $new_config Contains the new configuration values that
- * have been set in acp_board.
- * @return array|null Returns null if not implemented or an array with
+ *
+ * @param \phpbb\config\config $new_config Contains the new configuration values
+ * that have been set in acp_board.
+ * @return array|null Returns null if not implemented or an array with
* the template file name and an array of the vars
* that the template needs that must conform to the
* following example:
diff --git a/phpBB/phpbb/avatar/driver/driver.php b/phpBB/phpbb/avatar/driver/driver.php
index ad186635f2..45681f3e59 100644
--- a/phpBB/phpbb/avatar/driver/driver.php
+++ b/phpBB/phpbb/avatar/driver/driver.php
@@ -30,6 +30,9 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface
*/
protected $config;
+ /** @var \FastImageSize\FastImageSize */
+ protected $imagesize;
+
/**
* Current $phpbb_root_path
* @var string
@@ -73,14 +76,16 @@ abstract class driver implements \phpbb\avatar\driver\driver_interface
* Construct a driver object
*
* @param \phpbb\config\config $config phpBB configuration
+ * @param \FastImageSize\FastImageSize $imagesize FastImageSize class
* @param string $phpbb_root_path Path to the phpBB root
* @param string $php_ext PHP file extension
* @param \phpbb\path_helper $path_helper phpBB path helper
* @param \phpbb\cache\driver\driver_interface $cache Cache driver
*/
- public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null)
+ public function __construct(\phpbb\config\config $config, \FastImageSize\FastImageSize $imagesize, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\cache\driver\driver_interface $cache = null)
{
$this->config = $config;
+ $this->imagesize = $imagesize;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
$this->path_helper = $path_helper;
diff --git a/phpBB/phpbb/avatar/driver/gravatar.php b/phpBB/phpbb/avatar/driver/gravatar.php
index 7a43b55852..3e4e7ff98b 100644
--- a/phpBB/phpbb/avatar/driver/gravatar.php
+++ b/phpBB/phpbb/avatar/driver/gravatar.php
@@ -98,8 +98,8 @@ class gravatar extends \phpbb\avatar\driver\driver
return false;
}
- // Make sure getimagesize works...
- if (function_exists('getimagesize') && ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0))
+ // Get image dimensions if they are not set
+ if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
{
/**
* default to the minimum of the maximum allowed avatar size if the size
@@ -108,20 +108,20 @@ class gravatar extends \phpbb\avatar\driver\driver
$row['avatar_width'] = $row['avatar_height'] = min($this->config['avatar_max_width'], $this->config['avatar_max_height']);
$url = $this->get_gravatar_url($row);
- if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = getimagesize($url)) === false))
+ if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false))
{
$error[] = 'UNABLE_GET_IMAGE_SIZE';
return false;
}
- if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0))
+ if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['width'] <= 0))
{
$error[] = 'AVATAR_NO_SIZE';
return false;
}
- $row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data[0];
- $row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data[1];
+ $row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data['width'];
+ $row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data['height'];
}
if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
diff --git a/phpBB/phpbb/avatar/driver/local.php b/phpBB/phpbb/avatar/driver/local.php
index 75c384f31e..4b84e4201c 100644
--- a/phpBB/phpbb/avatar/driver/local.php
+++ b/phpBB/phpbb/avatar/driver/local.php
@@ -64,7 +64,7 @@ class local extends \phpbb\avatar\driver\driver
$table_cols = isset($row['avatar_gallery_cols']) ? $row['avatar_gallery_cols'] : 4;
$row_count = $col_count = $avatar_pos = 0;
- $avatar_count = sizeof($avatar_list[$category]);
+ $avatar_count = count($avatar_list[$category]);
reset($avatar_list[$category]);
@@ -158,7 +158,7 @@ class local extends \phpbb\avatar\driver\driver
*/
protected function get_avatar_list($user)
{
- $avatar_list = ($this->cache == null) ? false : $this->cache->get('_avatar_local_list');
+ $avatar_list = ($this->cache == null) ? false : $this->cache->get('_avatar_local_list_' . $user->data['user_lang']);
if ($avatar_list === false)
{
@@ -174,13 +174,15 @@ class local extends \phpbb\avatar\driver\driver
// Match all images in the gallery folder
if (preg_match('#^[^&\'"<>]+\.(?:' . implode('|', $this->allowed_extensions) . ')$#i', $image) && is_file($file_path . '/' . $image))
{
- if (function_exists('getimagesize'))
+ $dims = $this->imagesize->getImageSize($file_path . '/' . $image);
+
+ if ($dims === false)
{
- $dims = getimagesize($file_path . '/' . $image);
+ $dims = array(0, 0);
}
else
{
- $dims = array(0, 0);
+ $dims = array($dims['width'], $dims['height']);
}
$cat = ($path == $file_path) ? $user->lang['NO_AVATAR_CATEGORY'] : str_replace("$path/", '', $file_path);
$avatar_list[$cat][$image] = array(
@@ -196,7 +198,7 @@ class local extends \phpbb\avatar\driver\driver
if ($this->cache != null)
{
- $this->cache->put('_avatar_local_list', $avatar_list, 86400);
+ $this->cache->put('_avatar_local_list_' . $user->data['user_lang'], $avatar_list, 86400);
}
}
diff --git a/phpBB/phpbb/avatar/driver/remote.php b/phpBB/phpbb/avatar/driver/remote.php
index 2811cc2389..b16549ffb7 100644
--- a/phpBB/phpbb/avatar/driver/remote.php
+++ b/phpBB/phpbb/avatar/driver/remote.php
@@ -49,6 +49,8 @@ class remote extends \phpbb\avatar\driver\driver
*/
public function process_form($request, $template, $user, $row, &$error)
{
+ global $phpbb_dispatcher;
+
$url = $request->variable('avatar_remote_url', '');
$width = $request->variable('avatar_remote_width', 0);
$height = $request->variable('avatar_remote_height', 0);
@@ -84,6 +86,24 @@ class remote extends \phpbb\avatar\driver\driver
return false;
}
+ /**
+ * Event to make custom validation of avatar upload
+ *
+ * @event core.ucp_profile_avatar_upload_validation
+ * @var string url Image url
+ * @var string width Image width
+ * @var string height Image height
+ * @var array error Error message array
+ * @since 3.2.9-RC1
+ */
+ $vars = array('url', 'width', 'height', 'error');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_profile_avatar_upload_validation', compact($vars)));
+
+ if (!empty($error))
+ {
+ return false;
+ }
+
// Check if this url looks alright
// Do not allow specifying the port (see RFC 3986) or IP addresses
if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.('. implode('|', $this->allowed_extensions) . ')$#i', $url) ||
@@ -95,38 +115,30 @@ class remote extends \phpbb\avatar\driver\driver
return false;
}
- // Make sure getimagesize works...
- if (function_exists('getimagesize'))
+ // Get image dimensions
+ if (($width <= 0 || $height <= 0) && (($image_data = $this->imagesize->getImageSize($url)) === false))
{
- if (($width <= 0 || $height <= 0) && (($image_data = @getimagesize($url)) === false))
- {
- $error[] = 'UNABLE_GET_IMAGE_SIZE';
- return false;
- }
-
- if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0))
- {
- $error[] = 'AVATAR_NO_SIZE';
- return false;
- }
-
- $width = ($width && $height) ? $width : $image_data[0];
- $height = ($width && $height) ? $height : $image_data[1];
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ return false;
}
- if ($width <= 0 || $height <= 0)
+ if (!empty($image_data) && ($image_data['width'] <= 0 || $image_data['height'] <= 0))
{
$error[] = 'AVATAR_NO_SIZE';
return false;
}
- if (!class_exists('fileupload'))
+ $width = ($width && $height) ? $width : $image_data['width'];
+ $height = ($width && $height) ? $height : $image_data['height'];
+
+ if ($width <= 0 || $height <= 0)
{
- include($this->phpbb_root_path . 'includes/functions_upload.' . $this->php_ext);
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
}
- $types = \fileupload::image_types();
- $extension = strtolower(\filespec::get_extension($url));
+ $types = \phpbb\files\upload::image_types();
+ $extension = strtolower(\phpbb\files\filespec::get_extension($url));
// Check if this is actually an image
if ($file_stream = @fopen($url, 'r'))
@@ -175,15 +187,15 @@ class remote extends \phpbb\avatar\driver\driver
return false;
}
- if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
+ if (!empty($image_data) && (!isset($types[$image_data['type']]) || !in_array($extension, $types[$image_data['type']])))
{
- if (!isset($types[$image_data[2]]))
+ if (!isset($types[$image_data['type']]))
{
$error[] = 'UNABLE_GET_IMAGE_SIZE';
}
else
{
- $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data[2]][0], $extension);
+ $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data['type']][0], $extension);
}
return false;
diff --git a/phpBB/phpbb/avatar/driver/upload.php b/phpBB/phpbb/avatar/driver/upload.php
index 0dae5607f6..a012bb15b6 100644
--- a/phpBB/phpbb/avatar/driver/upload.php
+++ b/phpBB/phpbb/avatar/driver/upload.php
@@ -19,9 +19,9 @@ namespace phpbb\avatar\driver;
class upload extends \phpbb\avatar\driver\driver
{
/**
- * @var \phpbb\mimetype\guesser
- */
- protected $mimetype_guesser;
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
/**
* @var \phpbb\event\dispatcher_interface
@@ -29,24 +29,31 @@ class upload extends \phpbb\avatar\driver\driver
protected $dispatcher;
/**
+ * @var \phpbb\files\factory
+ */
+ protected $files_factory;
+
+ /**
* Construct a driver object
*
* @param \phpbb\config\config $config phpBB configuration
* @param string $phpbb_root_path Path to the phpBB root
* @param string $php_ext PHP file extension
- * @param \phpbb_path_helper $path_helper phpBB path helper
- * @param \phpbb\mimetype\guesser $mimetype_guesser Mimetype guesser
+ * @param \phpbb\filesystem\filesystem_interface $filesystem phpBB filesystem helper
+ * @param \phpbb\path_helper $path_helper phpBB path helper
* @param \phpbb\event\dispatcher_interface $dispatcher phpBB Event dispatcher object
+ * @param \phpbb\files\factory $files_factory File classes factory
* @param \phpbb\cache\driver\driver_interface $cache Cache driver
*/
- public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\path_helper $path_helper, \phpbb\mimetype\guesser $mimetype_guesser, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\cache\driver\driver_interface $cache = null)
+ public function __construct(\phpbb\config\config $config, $phpbb_root_path, $php_ext, \phpbb\filesystem\filesystem_interface $filesystem, \phpbb\path_helper $path_helper, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\files\factory $files_factory, \phpbb\cache\driver\driver_interface $cache = null)
{
$this->config = $config;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
+ $this->filesystem = $filesystem;
$this->path_helper = $path_helper;
- $this->mimetype_guesser = $mimetype_guesser;
$this->dispatcher = $dispatcher;
+ $this->files_factory = $files_factory;
$this->cache = $cache;
}
@@ -92,19 +99,24 @@ class upload extends \phpbb\avatar\driver\driver
return false;
}
- if (!class_exists('fileupload'))
- {
- include($this->phpbb_root_path . 'includes/functions_upload.' . $this->php_ext);
- }
-
- $upload = new \fileupload('AVATAR_', $this->allowed_extensions, $this->config['avatar_filesize'], $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], (isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
+ /** @var \phpbb\files\upload $upload */
+ $upload = $this->files_factory->get('upload')
+ ->set_error_prefix('AVATAR_')
+ ->set_allowed_extensions($this->allowed_extensions)
+ ->set_max_filesize($this->config['avatar_filesize'])
+ ->set_allowed_dimensions(
+ $this->config['avatar_min_width'],
+ $this->config['avatar_min_height'],
+ $this->config['avatar_max_width'],
+ $this->config['avatar_max_height'])
+ ->set_disallowed_content((isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
$url = $request->variable('avatar_upload_url', '');
$upload_file = $request->file('avatar_upload_file');
if (!empty($upload_file['name']))
{
- $file = $upload->form_upload('avatar_upload_file', $this->mimetype_guesser);
+ $file = $upload->handle_upload('files.types.form', 'avatar_upload_file');
}
else if (!empty($this->config['allow_avatar_remote_upload']) && !empty($url))
{
@@ -136,7 +148,8 @@ class upload extends \phpbb\avatar\driver\driver
// Do not allow specifying the port (see RFC 3986) or IP addresses
// remote_upload() will do its own check for allowed filetypes
- if (preg_match('@^(http|https|ftp)://[^/:?#]+:[0-9]+[/:?#]@i', $url) ||
+ if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.('. implode('|', $this->allowed_extensions) . ')$#i', $url) ||
+ preg_match('@^(http|https|ftp)://[^/:?#]+:[0-9]+[/:?#]@i', $url) ||
preg_match('#^(http|https|ftp)://(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])#i', $url) ||
preg_match('#^(http|https|ftp)://(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){0,5}(?:[\dA-F]{1,4}(?::[\dA-F]{1,4})?|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:)|(?:::))#i', $url))
{
@@ -144,7 +157,7 @@ class upload extends \phpbb\avatar\driver\driver
return false;
}
- $file = $upload->remote_upload($url, $this->mimetype_guesser);
+ $file = $upload->handle_upload('files.types.remote', $url);
}
else
{
@@ -155,7 +168,7 @@ class upload extends \phpbb\avatar\driver\driver
$file->clean_filename('avatar', $prefix, $row['id']);
// If there was an error during upload, then abort operation
- if (sizeof($file->error))
+ if (count($file->error))
{
$file->remove();
$error = $file->error;
@@ -191,15 +204,18 @@ class upload extends \phpbb\avatar\driver\driver
*
* @event core.avatar_driver_upload_move_file_before
* @var array filedata Array containing uploaded file data
+ * @var \phpbb\files\filespec file Instance of filespec class
* @var string destination Destination directory where the file is going to be moved
* @var string prefix Prefix for the avatar filename
* @var array row Array with avatar row data
* @var array error Array of errors, if filled in by this event file will not be moved
* @since 3.1.6-RC1
* @changed 3.1.9-RC1 Added filedata
+ * @changed 3.2.3-RC1 Added file
*/
$vars = array(
'filedata',
+ 'file',
'destination',
'prefix',
'row',
@@ -209,7 +225,7 @@ class upload extends \phpbb\avatar\driver\driver
unset($filedata);
- if (!sizeof($error))
+ if (!count($error))
{
// Move file and overwrite any existing image
$file->move_file($destination, true);
@@ -217,7 +233,7 @@ class upload extends \phpbb\avatar\driver\driver
// If there was an error during move, then clean up leftovers
$error = array_merge($error, $file->error);
- if (sizeof($error))
+ if (count($error))
{
$file->remove();
return false;
@@ -279,12 +295,20 @@ class upload extends \phpbb\avatar\driver\driver
);
extract($this->dispatcher->trigger_event('core.avatar_driver_upload_delete_before', compact($vars)));
- if (!sizeof($error) && file_exists($filename))
+ if (!count($error) && $this->filesystem->exists($filename))
{
- @unlink($filename);
+ try
+ {
+ $this->filesystem->remove($filename);
+ return true;
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Fail is covered by return statement below
+ }
}
- return true;
+ return false;
}
/**
@@ -302,6 +326,6 @@ class upload extends \phpbb\avatar\driver\driver
*/
protected function can_upload()
{
- return (file_exists($this->phpbb_root_path . $this->config['avatar_path']) && phpbb_is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
+ return ($this->filesystem->exists($this->phpbb_root_path . $this->config['avatar_path']) && $this->filesystem->is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
}
}
diff --git a/phpBB/phpbb/avatar/manager.php b/phpBB/phpbb/avatar/manager.php
index 26eb17c265..a909a91042 100644
--- a/phpBB/phpbb/avatar/manager.php
+++ b/phpBB/phpbb/avatar/manager.php
@@ -22,6 +22,12 @@ class manager
protected $config;
/**
+ * phpBB event dispatcher
+ * @var \phpbb\event\dispatcher_interface
+ */
+ protected $phpbb_dispatcher;
+
+ /**
* Array that contains a list of enabled drivers
* @var array
*/
@@ -49,11 +55,13 @@ class manager
* Construct an avatar manager object
*
* @param \phpbb\config\config $config phpBB configuration
+ * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher phpBB event dispatcher
* @param array $avatar_drivers Avatar drivers passed via the service container
*/
- public function __construct(\phpbb\config\config $config, $avatar_drivers)
+ public function __construct(\phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, $avatar_drivers)
{
$this->config = $config;
+ $this->phpbb_dispatcher = $phpbb_dispatcher;
$this->register_avatar_drivers($avatar_drivers);
}
@@ -263,7 +271,7 @@ class manager
$config_name = $driver->get_config_name();
return array(
- 'allow_avatar_' . $config_name => array('lang' => 'ALLOW_' . strtoupper(str_replace('\\', '_', $config_name)), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
+ 'allow_avatar_' . $config_name => array('lang' => 'ALLOW_' . strtoupper(str_replace('\\', '_', $config_name)), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
);
}
@@ -331,6 +339,19 @@ class manager
WHERE user_avatar = '" . $db->sql_escape($avatar_data['avatar']) . "'";
$db->sql_query($sql);
}
+
+ /**
+ * Event is triggered after user avatar has been deleted
+ *
+ * @event core.avatar_manager_avatar_delete_after
+ * @var \phpbb\user user phpBB user object
+ * @var array avatar_data Normalised avatar-related user data
+ * @var string table Table to delete avatar from
+ * @var string prefix Column prefix to delete avatar from
+ * @since 3.2.4-RC1
+ */
+ $vars = array('user', 'avatar_data', 'table', 'prefix');
+ extract($this->phpbb_dispatcher->trigger_event('core.avatar_manager_avatar_delete_after', compact($vars)));
}
/**
diff --git a/phpBB/phpbb/cache/driver/apcu.php b/phpBB/phpbb/cache/driver/apcu.php
new file mode 100644
index 0000000000..c96cf0de57
--- /dev/null
+++ b/phpBB/phpbb/cache/driver/apcu.php
@@ -0,0 +1,74 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\cache\driver;
+
+/**
+* ACM for APCU
+*/
+class apcu extends \phpbb\cache\driver\memory
+{
+ var $extension = 'apcu';
+
+ /**
+ * {@inheritDoc}
+ */
+ function purge()
+ {
+ /*
+ * Use an iterator to selectively delete our cache entries without disturbing
+ * any other cache users (e.g. other phpBB boards hosted on this server)
+ */
+ apcu_delete(new \APCUIterator('#^' . $this->key_prefix . '#'));
+
+ parent::purge();
+ }
+
+ /**
+ * Fetch an item from the cache
+ *
+ * @access protected
+ * @param string $var Cache key
+ * @return mixed Cached data
+ */
+ function _read($var)
+ {
+ return apcu_fetch($this->key_prefix . $var);
+ }
+
+ /**
+ * Store data in the cache
+ *
+ * @access protected
+ * @param string $var Cache key
+ * @param mixed $data Data to store
+ * @param int $ttl Time-to-live of cached data
+ * @return bool True if the operation succeeded
+ */
+ function _write($var, $data, $ttl = 2592000)
+ {
+ return apcu_store($this->key_prefix . $var, $data, $ttl);
+ }
+
+ /**
+ * Remove an item from the cache
+ *
+ * @access protected
+ * @param string $var Cache key
+ * @return bool True if the operation succeeded
+ */
+ function _delete($var)
+ {
+ return apcu_delete($this->key_prefix . $var);
+ }
+}
diff --git a/phpBB/phpbb/cache/driver/base.php b/phpBB/phpbb/cache/driver/base.php
index 53c50eeda3..3eca521148 100644
--- a/phpBB/phpbb/cache/driver/base.php
+++ b/phpBB/phpbb/cache/driver/base.php
@@ -49,7 +49,9 @@ abstract class base implements \phpbb\cache\driver\driver_interface
$this->remove_dir($fileInfo->getPathname());
}
else if (strpos($filename, 'container_') === 0 ||
+ strpos($filename, 'autoload_') === 0 ||
strpos($filename, 'url_matcher') === 0 ||
+ strpos($filename, 'url_generator') === 0 ||
strpos($filename, 'sql_') === 0 ||
strpos($filename, 'data_') === 0)
{
@@ -95,14 +97,14 @@ abstract class base implements \phpbb\cache\driver\driver_interface
{
// Remove extra spaces and tabs
$query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
+ $query_id = md5($query);
- if (($rowset = $this->_read('sql_' . md5($query))) === false)
+ if (($result = $this->_read('sql_' . $query_id)) === false)
{
return false;
}
- $query_id = sizeof($this->sql_rowset);
- $this->sql_rowset[$query_id] = $rowset;
+ $this->sql_rowset[$query_id] = $result;
$this->sql_row_pointer[$query_id] = 0;
return $query_id;
@@ -121,7 +123,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface
*/
function sql_fetchrow($query_id)
{
- if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id]))
+ if ($this->sql_row_pointer[$query_id] < count($this->sql_rowset[$query_id]))
{
return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++];
}
@@ -134,7 +136,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface
*/
function sql_fetchfield($query_id, $field)
{
- if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id]))
+ if ($this->sql_row_pointer[$query_id] < count($this->sql_rowset[$query_id]))
{
return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false;
}
@@ -147,7 +149,7 @@ abstract class base implements \phpbb\cache\driver\driver_interface
*/
function sql_rowseek($rownum, $query_id)
{
- if ($rownum >= sizeof($this->sql_rowset[$query_id]))
+ if ($rownum >= count($this->sql_rowset[$query_id]))
{
return false;
}
@@ -181,13 +183,9 @@ abstract class base implements \phpbb\cache\driver\driver_interface
*/
function remove_file($filename, $check = false)
{
- if (!function_exists('phpbb_is_writable'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/functions.' . $phpEx);
- }
+ global $phpbb_filesystem;
- if ($check && !phpbb_is_writable($this->cache_dir))
+ if ($check && !$phpbb_filesystem->is_writable($this->cache_dir))
{
// E_USER_ERROR - not using language entry - intended.
trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR);
diff --git a/phpBB/phpbb/cache/driver/dummy.php b/phpBB/phpbb/cache/driver/dummy.php
new file mode 100644
index 0000000000..1f74f6dd77
--- /dev/null
+++ b/phpBB/phpbb/cache/driver/dummy.php
@@ -0,0 +1,153 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\cache\driver;
+
+/**
+* ACM dummy Caching
+*/
+class dummy extends \phpbb\cache\driver\base
+{
+ /**
+ * Set cache path
+ */
+ function __construct()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function load()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function unload()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function save()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function tidy()
+ {
+ global $config;
+
+ // This cache always has a tidy room.
+ $config->set('cache_last_gc', time(), false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function get($var_name)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function put($var_name, $var, $ttl = 0)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function purge()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function destroy($var_name, $table = '')
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function _exists($var_name)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_load($query)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl)
+ {
+ return $query_result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_exists($query_id)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_fetchrow($query_id)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_fetchfield($query_id, $field)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_rowseek($rownum, $query_id)
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_freeresult($query_id)
+ {
+ return false;
+ }
+}
diff --git a/phpBB/phpbb/cache/driver/eaccelerator.php b/phpBB/phpbb/cache/driver/eaccelerator.php
index 1697758acc..740855144f 100644
--- a/phpBB/phpbb/cache/driver/eaccelerator.php
+++ b/phpBB/phpbb/cache/driver/eaccelerator.php
@@ -44,9 +44,11 @@ class eaccelerator extends \phpbb\cache\driver\memory
*/
function tidy()
{
+ global $config;
+
eaccelerator_gc();
- set_config('cache_last_gc', time(), true);
+ $config->set('cache_last_gc', time(), false);
}
/**
diff --git a/phpBB/phpbb/cache/driver/file.php b/phpBB/phpbb/cache/driver/file.php
index 1e9ee960dc..de6f444251 100644
--- a/phpBB/phpbb/cache/driver/file.php
+++ b/phpBB/phpbb/cache/driver/file.php
@@ -21,14 +21,26 @@ class file extends \phpbb\cache\driver\base
var $var_expires = array();
/**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
* Set cache path
*
* @param string $cache_dir Define the path to the cache directory (default: $phpbb_root_path . 'cache/')
*/
function __construct($cache_dir = null)
{
- global $phpbb_root_path;
- $this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_root_path . 'cache/';
+ global $phpbb_container;
+
+ $this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_container->getParameter('core.cache_dir');
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+
+ if (!is_dir($this->cache_dir))
+ {
+ @mkdir($this->cache_dir, 0777, true);
+ }
}
/**
@@ -63,14 +75,8 @@ class file extends \phpbb\cache\driver\base
if (!$this->_write('data_global'))
{
- if (!function_exists('phpbb_is_writable'))
- {
- global $phpbb_root_path;
- include($phpbb_root_path . 'includes/functions.' . $phpEx);
- }
-
// Now, this occurred how often? ... phew, just tell the user then...
- if (!phpbb_is_writable($this->cache_dir))
+ if (!$this->filesystem->is_writable($this->cache_dir))
{
// We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload())
die('Fatal: ' . $this->cache_dir . ' is NOT writable.');
@@ -89,7 +95,7 @@ class file extends \phpbb\cache\driver\base
*/
function tidy()
{
- global $phpEx;
+ global $config, $phpEx;
$dir = @opendir($this->cache_dir);
@@ -129,7 +135,7 @@ class file extends \phpbb\cache\driver\base
if (file_exists($this->cache_dir . 'data_global.' . $phpEx))
{
- if (!sizeof($this->vars))
+ if (!count($this->vars))
{
$this->load();
}
@@ -143,7 +149,7 @@ class file extends \phpbb\cache\driver\base
}
}
- set_config('cache_last_gc', time(), true);
+ $config->set('cache_last_gc', time(), false);
}
/**
@@ -284,7 +290,7 @@ class file extends \phpbb\cache\driver\base
}
else
{
- if (!sizeof($this->vars))
+ if (!count($this->vars))
{
$this->load();
}
@@ -306,7 +312,7 @@ class file extends \phpbb\cache\driver\base
// Remove extra spaces and tabs
$query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
- $query_id = sizeof($this->sql_rowset);
+ $query_id = md5($query);
$this->sql_rowset[$query_id] = array();
$this->sql_row_pointer[$query_id] = 0;
@@ -316,7 +322,7 @@ class file extends \phpbb\cache\driver\base
}
$db->sql_freeresult($query_result);
- if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query))
+ if ($this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl + time(), $query))
{
return $query_id;
}
@@ -573,13 +579,14 @@ class file extends \phpbb\cache\driver\base
@opcache_invalidate($file);
}
- if (!function_exists('phpbb_chmod'))
+ try
{
- global $phpbb_root_path;
- include($phpbb_root_path . 'includes/functions.' . $phpEx);
+ $this->filesystem->phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
}
-
- phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE);
$return_value = true;
}
diff --git a/phpBB/phpbb/cache/driver/memcached.php b/phpBB/phpbb/cache/driver/memcached.php
index a7da22d7e8..7d66759ec2 100644
--- a/phpBB/phpbb/cache/driver/memcached.php
+++ b/phpBB/phpbb/cache/driver/memcached.php
@@ -65,10 +65,10 @@ class memcached extends \phpbb\cache\driver\memory
$this->memcached->setOption(\Memcached::OPT_COMPRESSION, false);
}
- foreach (explode(',', PHPBB_ACM_MEMCACHE) as $u)
+ foreach (explode(',', PHPBB_ACM_MEMCACHED) as $u)
{
preg_match('#(.*)/(\d+)#', $u, $parts);
- $this->memcache->addServer(trim($parts[1]), (int) trim($parts[2]));
+ $this->memcached->addServer(trim($parts[1]), (int) trim($parts[2]));
}
}
diff --git a/phpBB/phpbb/cache/driver/memory.php b/phpBB/phpbb/cache/driver/memory.php
index 0b0e323e3d..eba9549877 100644
--- a/phpBB/phpbb/cache/driver/memory.php
+++ b/phpBB/phpbb/cache/driver/memory.php
@@ -25,9 +25,9 @@ abstract class memory extends \phpbb\cache\driver\base
*/
function __construct()
{
- global $phpbb_root_path, $dbname, $table_prefix;
+ global $phpbb_root_path, $dbname, $table_prefix, $phpbb_container;
- $this->cache_dir = $phpbb_root_path . 'cache/';
+ $this->cache_dir = $phpbb_container->getParameter('core.cache_dir');
$this->key_prefix = substr(md5($dbname . $table_prefix), 0, 8) . '_';
if (!isset($this->extension) || !extension_loaded($this->extension))
@@ -51,10 +51,11 @@ abstract class memory extends \phpbb\cache\driver\base
function load()
{
// grab the global cache
- $this->vars = $this->_read('global');
+ $data = $this->_read('global');
- if ($this->vars !== false)
+ if ($data !== false)
{
+ $this->vars = $data;
return true;
}
@@ -81,9 +82,10 @@ abstract class memory extends \phpbb\cache\driver\base
*/
function tidy()
{
- // cache has auto GC, no need to have any code here :)
+ global $config;
- set_config('cache_last_gc', time(), true);
+ // cache has auto GC, no need to have any code here :)
+ $config->set('cache_last_gc', time(), false);
}
/**
@@ -187,7 +189,7 @@ abstract class memory extends \phpbb\cache\driver\base
}
else
{
- if (!sizeof($this->vars))
+ if (!count($this->vars))
{
$this->load();
}
@@ -203,7 +205,7 @@ abstract class memory extends \phpbb\cache\driver\base
{
// Remove extra spaces and tabs
$query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
- $hash = md5($query);
+ $query_id = md5($query);
// determine which tables this query belongs to
// Some queries use backticks, namely the get_database_size() query
@@ -244,14 +246,13 @@ abstract class memory extends \phpbb\cache\driver\base
$temp = array();
}
- $temp[$hash] = true;
+ $temp[$query_id] = true;
// This must never expire
$this->_write('sql_' . $table_name, $temp, 0);
}
// store them in the right place
- $query_id = sizeof($this->sql_rowset);
$this->sql_rowset[$query_id] = array();
$this->sql_row_pointer[$query_id] = 0;
@@ -261,7 +262,7 @@ abstract class memory extends \phpbb\cache\driver\base
}
$db->sql_freeresult($query_result);
- $this->_write('sql_' . $hash, $this->sql_rowset[$query_id], $ttl);
+ $this->_write('sql_' . $query_id, $this->sql_rowset[$query_id], $ttl);
return $query_id;
}
diff --git a/phpBB/phpbb/cache/driver/null.php b/phpBB/phpbb/cache/driver/null.php
deleted file mode 100644
index a45cf97862..0000000000
--- a/phpBB/phpbb/cache/driver/null.php
+++ /dev/null
@@ -1,151 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\cache\driver;
-
-/**
-* ACM Null Caching
-*/
-class null extends \phpbb\cache\driver\base
-{
- /**
- * Set cache path
- */
- function __construct()
- {
- }
-
- /**
- * {@inheritDoc}
- */
- function load()
- {
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- function unload()
- {
- }
-
- /**
- * {@inheritDoc}
- */
- function save()
- {
- }
-
- /**
- * {@inheritDoc}
- */
- function tidy()
- {
- // This cache always has a tidy room.
- set_config('cache_last_gc', time(), true);
- }
-
- /**
- * {@inheritDoc}
- */
- function get($var_name)
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function put($var_name, $var, $ttl = 0)
- {
- }
-
- /**
- * {@inheritDoc}
- */
- function purge()
- {
- }
-
- /**
- * {@inheritDoc}
- */
- function destroy($var_name, $table = '')
- {
- }
-
- /**
- * {@inheritDoc}
- */
- function _exists($var_name)
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_load($query)
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl)
- {
- return $query_result;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_exists($query_id)
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_fetchrow($query_id)
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_fetchfield($query_id, $field)
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_rowseek($rownum, $query_id)
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_freeresult($query_id)
- {
- return false;
- }
-}
diff --git a/phpBB/phpbb/cache/driver/redis.php b/phpBB/phpbb/cache/driver/redis.php
index eda774491c..eaeb529918 100644
--- a/phpBB/phpbb/cache/driver/redis.php
+++ b/phpBB/phpbb/cache/driver/redis.php
@@ -137,6 +137,10 @@ class redis extends \phpbb\cache\driver\memory
*/
function _write($var, $data, $ttl = 2592000)
{
+ if ($ttl == 0)
+ {
+ return $this->redis->set($var, $data);
+ }
return $this->redis->setex($var, $ttl, $data);
}
diff --git a/phpBB/phpbb/cache/service.php b/phpBB/phpbb/cache/service.php
index 56727c2ad5..502ae27625 100644
--- a/phpBB/phpbb/cache/service.php
+++ b/phpBB/phpbb/cache/service.php
@@ -141,6 +141,7 @@ class service
$icons[$row['icons_id']]['img'] = $row['icons_url'];
$icons[$row['icons_id']]['width'] = (int) $row['icons_width'];
$icons[$row['icons_id']]['height'] = (int) $row['icons_height'];
+ $icons[$row['icons_id']]['alt'] = ($row['icons_alt']) ? $row['icons_alt'] : '';
$icons[$row['icons_id']]['display'] = (bool) $row['display_on_posting'];
}
$this->db->sql_freeresult($result);
@@ -226,7 +227,7 @@ class service
// Store allowed extensions forum wise
if ($row['allow_group'])
{
- $extensions['_allowed_post'][$extension] = (!sizeof($allowed_forums)) ? 0 : $allowed_forums;
+ $extensions['_allowed_post'][$extension] = (!count($allowed_forums)) ? 0 : $allowed_forums;
}
if ($row['allow_in_pm'])
@@ -301,7 +302,6 @@ class service
{
switch ($this->db->get_sql_layer())
{
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$sql = 'SELECT user_id, bot_agent, bot_ip
diff --git a/phpBB/phpbb/captcha/char_cube3d.php b/phpBB/phpbb/captcha/char_cube3d.php
index a712b16dce..0255259ac4 100644
--- a/phpBB/phpbb/captcha/char_cube3d.php
+++ b/phpBB/phpbb/captcha/char_cube3d.php
@@ -220,7 +220,7 @@ class char_cube3d
*/
function scale($vector, $length)
{
- if (sizeof($vector) == 2)
+ if (count($vector) == 2)
{
return array($vector[0] * $length, $vector[1] * $length);
}
diff --git a/phpBB/phpbb/captcha/colour_manager.php b/phpBB/phpbb/captcha/colour_manager.php
index 6ca3c3fd2c..82332da810 100644
--- a/phpBB/phpbb/captcha/colour_manager.php
+++ b/phpBB/phpbb/captcha/colour_manager.php
@@ -256,7 +256,7 @@ class colour_manager
if (is_array($resource))
{
$results = array();
- for ($i = 0, $size = sizeof($resource); $i < $size; ++$i)
+ for ($i = 0, $size = count($resource); $i < $size; ++$i)
{
$results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original));
}
diff --git a/phpBB/phpbb/captcha/gd.php b/phpBB/phpbb/captcha/gd.php
index 652df28f8a..91b2f89d81 100644
--- a/phpBB/phpbb/captcha/gd.php
+++ b/phpBB/phpbb/captcha/gd.php
@@ -97,13 +97,12 @@ class gd
if ($config['captcha_gd_3d_noise'])
{
- $xoffset = mt_rand(0,9);
$noise_bitmaps = $this->captcha_noise_bg_bitmaps();
for ($i = 0; $i < $code_len; ++$i)
{
- $noise[$i] = new char_cube3d($noise_bitmaps, mt_rand(1, sizeof($noise_bitmaps['data'])));
+ $noise[$i] = new char_cube3d($noise_bitmaps, mt_rand(1, count($noise_bitmaps['data'])));
- list($min, $max) = $noise[$i]->range();
+ $noise[$i]->range();
//$box = $noise[$i]->dimensions($sizes[$i]);
}
$xoffset = 0;
@@ -151,8 +150,6 @@ class gd
*/
function wave($img)
{
- global $config;
-
$period_x = mt_rand(12,18);
$period_y = mt_rand(7,14);
$amp_x = mt_rand(5,10);
@@ -1661,32 +1658,32 @@ class gd
'height' => 15,
'data' => array(
- 'A' => $chars['A'][mt_rand(0, min(sizeof($chars['A']), $config['captcha_gd_fonts']) -1)],
- 'B' => $chars['B'][mt_rand(0, min(sizeof($chars['B']), $config['captcha_gd_fonts']) -1)],
- 'C' => $chars['C'][mt_rand(0, min(sizeof($chars['C']), $config['captcha_gd_fonts']) -1)],
- 'D' => $chars['D'][mt_rand(0, min(sizeof($chars['D']), $config['captcha_gd_fonts']) -1)],
- 'E' => $chars['E'][mt_rand(0, min(sizeof($chars['E']), $config['captcha_gd_fonts']) -1)],
- 'F' => $chars['F'][mt_rand(0, min(sizeof($chars['F']), $config['captcha_gd_fonts']) -1)],
- 'G' => $chars['G'][mt_rand(0, min(sizeof($chars['G']), $config['captcha_gd_fonts']) -1)],
- 'H' => $chars['H'][mt_rand(0, min(sizeof($chars['H']), $config['captcha_gd_fonts']) -1)],
- 'I' => $chars['I'][mt_rand(0, min(sizeof($chars['I']), $config['captcha_gd_fonts']) -1)],
- 'J' => $chars['J'][mt_rand(0, min(sizeof($chars['J']), $config['captcha_gd_fonts']) -1)],
- 'K' => $chars['K'][mt_rand(0, min(sizeof($chars['K']), $config['captcha_gd_fonts']) -1)],
- 'L' => $chars['L'][mt_rand(0, min(sizeof($chars['L']), $config['captcha_gd_fonts']) -1)],
- 'M' => $chars['M'][mt_rand(0, min(sizeof($chars['M']), $config['captcha_gd_fonts']) -1)],
- 'N' => $chars['N'][mt_rand(0, min(sizeof($chars['N']), $config['captcha_gd_fonts']) -1)],
- 'O' => $chars['O'][mt_rand(0, min(sizeof($chars['O']), $config['captcha_gd_fonts']) -1)],
- 'P' => $chars['P'][mt_rand(0, min(sizeof($chars['P']), $config['captcha_gd_fonts']) -1)],
- 'Q' => $chars['Q'][mt_rand(0, min(sizeof($chars['Q']), $config['captcha_gd_fonts']) -1)],
- 'R' => $chars['R'][mt_rand(0, min(sizeof($chars['R']), $config['captcha_gd_fonts']) -1)],
- 'S' => $chars['S'][mt_rand(0, min(sizeof($chars['S']), $config['captcha_gd_fonts']) -1)],
- 'T' => $chars['T'][mt_rand(0, min(sizeof($chars['T']), $config['captcha_gd_fonts']) -1)],
- 'U' => $chars['U'][mt_rand(0, min(sizeof($chars['U']), $config['captcha_gd_fonts']) -1)],
- 'V' => $chars['V'][mt_rand(0, min(sizeof($chars['V']), $config['captcha_gd_fonts']) -1)],
- 'W' => $chars['W'][mt_rand(0, min(sizeof($chars['W']), $config['captcha_gd_fonts']) -1)],
- 'X' => $chars['X'][mt_rand(0, min(sizeof($chars['X']), $config['captcha_gd_fonts']) -1)],
- 'Y' => $chars['Y'][mt_rand(0, min(sizeof($chars['Y']), $config['captcha_gd_fonts']) -1)],
- 'Z' => $chars['Z'][mt_rand(0, min(sizeof($chars['Z']), $config['captcha_gd_fonts']) -1)],
+ 'A' => $chars['A'][mt_rand(0, min(count($chars['A']), $config['captcha_gd_fonts']) -1)],
+ 'B' => $chars['B'][mt_rand(0, min(count($chars['B']), $config['captcha_gd_fonts']) -1)],
+ 'C' => $chars['C'][mt_rand(0, min(count($chars['C']), $config['captcha_gd_fonts']) -1)],
+ 'D' => $chars['D'][mt_rand(0, min(count($chars['D']), $config['captcha_gd_fonts']) -1)],
+ 'E' => $chars['E'][mt_rand(0, min(count($chars['E']), $config['captcha_gd_fonts']) -1)],
+ 'F' => $chars['F'][mt_rand(0, min(count($chars['F']), $config['captcha_gd_fonts']) -1)],
+ 'G' => $chars['G'][mt_rand(0, min(count($chars['G']), $config['captcha_gd_fonts']) -1)],
+ 'H' => $chars['H'][mt_rand(0, min(count($chars['H']), $config['captcha_gd_fonts']) -1)],
+ 'I' => $chars['I'][mt_rand(0, min(count($chars['I']), $config['captcha_gd_fonts']) -1)],
+ 'J' => $chars['J'][mt_rand(0, min(count($chars['J']), $config['captcha_gd_fonts']) -1)],
+ 'K' => $chars['K'][mt_rand(0, min(count($chars['K']), $config['captcha_gd_fonts']) -1)],
+ 'L' => $chars['L'][mt_rand(0, min(count($chars['L']), $config['captcha_gd_fonts']) -1)],
+ 'M' => $chars['M'][mt_rand(0, min(count($chars['M']), $config['captcha_gd_fonts']) -1)],
+ 'N' => $chars['N'][mt_rand(0, min(count($chars['N']), $config['captcha_gd_fonts']) -1)],
+ 'O' => $chars['O'][mt_rand(0, min(count($chars['O']), $config['captcha_gd_fonts']) -1)],
+ 'P' => $chars['P'][mt_rand(0, min(count($chars['P']), $config['captcha_gd_fonts']) -1)],
+ 'Q' => $chars['Q'][mt_rand(0, min(count($chars['Q']), $config['captcha_gd_fonts']) -1)],
+ 'R' => $chars['R'][mt_rand(0, min(count($chars['R']), $config['captcha_gd_fonts']) -1)],
+ 'S' => $chars['S'][mt_rand(0, min(count($chars['S']), $config['captcha_gd_fonts']) -1)],
+ 'T' => $chars['T'][mt_rand(0, min(count($chars['T']), $config['captcha_gd_fonts']) -1)],
+ 'U' => $chars['U'][mt_rand(0, min(count($chars['U']), $config['captcha_gd_fonts']) -1)],
+ 'V' => $chars['V'][mt_rand(0, min(count($chars['V']), $config['captcha_gd_fonts']) -1)],
+ 'W' => $chars['W'][mt_rand(0, min(count($chars['W']), $config['captcha_gd_fonts']) -1)],
+ 'X' => $chars['X'][mt_rand(0, min(count($chars['X']), $config['captcha_gd_fonts']) -1)],
+ 'Y' => $chars['Y'][mt_rand(0, min(count($chars['Y']), $config['captcha_gd_fonts']) -1)],
+ 'Z' => $chars['Z'][mt_rand(0, min(count($chars['Z']), $config['captcha_gd_fonts']) -1)],
'1' => array(
array(0,0,0,1,1,0,0,0,0),
diff --git a/phpBB/phpbb/captcha/gd_wave.php b/phpBB/phpbb/captcha/gd_wave.php
index d48fc753a5..f2ec4137d2 100644
--- a/phpBB/phpbb/captcha/gd_wave.php
+++ b/phpBB/phpbb/captcha/gd_wave.php
@@ -23,8 +23,6 @@ class gd_wave
function execute($code, $seed)
{
- global $starttime;
-
// seed the random generator
mt_srand($seed);
@@ -77,7 +75,6 @@ class gd_wave
// TODO
$background = imagecolorallocate($img, mt_rand(155, 255), mt_rand(155, 255), mt_rand(155, 255));
imagefill($img, 0, 0, $background);
- $black = imagecolorallocate($img, 0, 0, 0);
$random = array();
$fontcolors = array();
@@ -155,7 +152,7 @@ class gd_wave
// rather than recalculating from absolute coordinates
// What we cache into the $img_buffer contains the raised text coordinates.
$img_pos_prev = $img_buffer[0][0] = array($box['upper_left']['x'], $box['upper_left']['y']);
- $cur_height = $prev_height = $this->wave_height(0, 0, $subdivision_factor);
+ $prev_height = $this->wave_height(0, 0, $subdivision_factor);
$full_x = $plane_x * $subdivision_factor;
$full_y = $plane_y * $subdivision_factor;
diff --git a/phpBB/phpbb/captcha/plugins/captcha_abstract.php b/phpBB/phpbb/captcha/plugins/captcha_abstract.php
index 24ed7f939d..b508767d17 100644
--- a/phpBB/phpbb/captcha/plugins/captcha_abstract.php
+++ b/phpBB/phpbb/captcha/plugins/captcha_abstract.php
@@ -34,12 +34,12 @@ abstract class captcha_abstract
function init($type)
{
- global $config, $db, $user;
+ global $config, $request;
// read input
- $this->confirm_id = request_var('confirm_id', '');
- $this->confirm_code = request_var('confirm_code', '');
- $refresh = request_var('refresh_vc', false) && $config['confirm_refresh'];
+ $this->confirm_id = $request->variable('confirm_id', '');
+ $this->confirm_code = $request->variable('confirm_code', '');
+ $refresh = $request->variable('refresh_vc', false) && $config['confirm_refresh'];
$this->type = (int) $type;
@@ -56,8 +56,6 @@ abstract class captcha_abstract
function execute_demo()
{
- global $user;
-
$this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS));
$this->seed = hexdec(substr(unique_id(), 4, 10));
@@ -117,7 +115,7 @@ abstract class captcha_abstract
function get_demo_template($id)
{
- global $config, $user, $template, $phpbb_admin_path, $phpEx;
+ global $config, $template, $request, $phpbb_admin_path, $phpEx;
$variables = '';
@@ -125,7 +123,7 @@ abstract class captcha_abstract
{
foreach ($this->captcha_vars as $captcha_var => $template_var)
{
- $variables .= '&amp;' . rawurlencode($captcha_var) . '=' . request_var($captcha_var, (int) $config[$captcha_var]);
+ $variables .= '&amp;' . rawurlencode($captcha_var) . '=' . $request->variable($captcha_var, (int) $config[$captcha_var]);
}
}
@@ -153,7 +151,7 @@ abstract class captcha_abstract
function garbage_collect($type)
{
- global $db, $config;
+ global $db;
$sql = 'SELECT DISTINCT c.session_id
FROM ' . CONFIRM_TABLE . ' c
@@ -171,7 +169,7 @@ abstract class captcha_abstract
}
while ($row = $db->sql_fetchrow($result));
- if (sizeof($sql_in))
+ if (count($sql_in))
{
$sql = 'DELETE FROM ' . CONFIRM_TABLE . '
WHERE ' . $db->sql_in_set('session_id', $sql_in);
@@ -193,9 +191,9 @@ abstract class captcha_abstract
function validate()
{
- global $config, $db, $user;
+ global $user;
- if (empty($user->lang))
+ if (!$user->is_setup())
{
$user->setup();
}
@@ -350,7 +348,9 @@ abstract class captcha_abstract
function is_solved()
{
- if (request_var('confirm_code', false) && $this->solved === 0)
+ global $request;
+
+ if ($request->variable('confirm_code', false) && $this->solved === 0)
{
$this->validate();
}
diff --git a/phpBB/phpbb/captcha/plugins/gd.php b/phpBB/phpbb/captcha/plugins/gd.php
index f6200b5b2f..6d3c9bb3d2 100644
--- a/phpBB/phpbb/captcha/plugins/gd.php
+++ b/phpBB/phpbb/captcha/plugins/gd.php
@@ -51,40 +51,33 @@ class gd extends captcha_abstract
return 'CAPTCHA_GD';
}
- function acp_page($id, &$module)
+ function acp_page($id, $module)
{
- global $db, $user, $auth, $template;
- global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
+ global $user, $template, $phpbb_log, $request;
+ global $config;
$user->add_lang('acp/board');
- $config_vars = array(
- 'enable_confirm' => 'REG_ENABLE',
- 'enable_post_confirm' => 'POST_ENABLE',
- 'confirm_refresh' => 'CONFIRM_REFRESH',
- 'captcha_gd' => 'CAPTCHA_GD',
- );
-
$module->tpl_name = 'captcha_gd_acp';
$module->page_title = 'ACP_VC_SETTINGS';
$form_key = 'acp_captcha';
add_form_key($form_key);
- $submit = request_var('submit', '');
+ $submit = $request->variable('submit', '');
if ($submit && check_form_key($form_key))
{
$captcha_vars = array_keys($this->captcha_vars);
foreach ($captcha_vars as $captcha_var)
{
- $value = request_var($captcha_var, 0);
+ $value = $request->variable($captcha_var, 0);
if ($value >= 0)
{
- set_config($captcha_var, $value);
+ $config->set($captcha_var, $value);
}
}
- add_log('admin', 'LOG_CONFIG_VISUAL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action));
}
else if ($submit)
@@ -95,7 +88,7 @@ class gd extends captcha_abstract
{
foreach ($this->captcha_vars as $captcha_var => $template_var)
{
- $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var];
+ $var = (isset($_REQUEST[$captcha_var])) ? $request->variable($captcha_var, 0) : $config[$captcha_var];
$template->assign_var($template_var, $var);
}
@@ -109,7 +102,7 @@ class gd extends captcha_abstract
function execute_demo()
{
- global $config;
+ global $config, $request;
$config_old = $config;
@@ -121,7 +114,7 @@ class gd extends captcha_abstract
foreach ($this->captcha_vars as $captcha_var => $template_var)
{
- $config->set($captcha_var, request_var($captcha_var, (int) $config[$captcha_var]));
+ $config->set($captcha_var, $request->variable($captcha_var, (int) $config[$captcha_var]));
}
parent::execute_demo();
$config = $config_old;
diff --git a/phpBB/phpbb/captcha/plugins/gd_wave.php b/phpBB/phpbb/captcha/plugins/gd_wave.php
index e1d44df778..4ac26ed2b7 100644
--- a/phpBB/phpbb/captcha/plugins/gd_wave.php
+++ b/phpBB/phpbb/captcha/plugins/gd_wave.php
@@ -33,9 +33,9 @@ class gd_wave extends captcha_abstract
return '\\phpbb\\captcha\\gd_wave';
}
- function acp_page($id, &$module)
+ function acp_page($id, $module)
{
- global $config, $db, $template, $user;
+ global $user;
trigger_error($user->lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action));
}
diff --git a/phpBB/phpbb/captcha/plugins/nogd.php b/phpBB/phpbb/captcha/plugins/nogd.php
index 6845e5935c..da67cd2bf4 100644
--- a/phpBB/phpbb/captcha/plugins/nogd.php
+++ b/phpBB/phpbb/captcha/plugins/nogd.php
@@ -33,7 +33,7 @@ class nogd extends captcha_abstract
return '\\phpbb\\captcha\\non_gd';
}
- function acp_page($id, &$module)
+ function acp_page($id, $module)
{
global $user;
diff --git a/phpBB/phpbb/captcha/plugins/qa.php b/phpBB/phpbb/captcha/plugins/qa.php
index a9d133d8f2..966b8d32f2 100644
--- a/phpBB/phpbb/captcha/plugins/qa.php
+++ b/phpBB/phpbb/captcha/plugins/qa.php
@@ -21,7 +21,7 @@ class qa
{
var $confirm_id;
var $answer;
- var $question_ids;
+ var $question_ids = [];
var $question_text;
var $question_lang;
var $question_strict;
@@ -58,14 +58,14 @@ class qa
*/
function init($type)
{
- global $config, $db, $user;
+ global $config, $db, $user, $request;
// load our language file
$user->add_lang('captcha_qa');
// read input
- $this->confirm_id = request_var('qa_confirm_id', '');
- $this->answer = utf8_normalize_nfc(request_var('qa_answer', '', true));
+ $this->confirm_id = $request->variable('qa_confirm_id', '');
+ $this->answer = $request->variable('qa_answer', '', true);
$this->type = (int) $type;
$this->question_lang = $user->lang_name;
@@ -84,7 +84,7 @@ class qa
$db->sql_freeresult($result);
// fallback to the board default lang
- if (!sizeof($this->question_ids))
+ if (!count($this->question_ids))
{
$this->question_lang = $config['default_lang'];
@@ -101,14 +101,13 @@ class qa
}
// final fallback to any language
- if (!sizeof($this->question_ids))
+ if (!count($this->question_ids))
{
$this->question_lang = '';
$sql = 'SELECT q.question_id, q.lang_iso
FROM ' . $this->table_captcha_questions . ' q, ' . $this->table_captcha_answers . ' a
- WHERE q.question_id = a.question_id
- GROUP BY lang_iso';
+ WHERE q.question_id = a.question_id';
$result = $db->sql_query($sql, 7200);
while ($row = $db->sql_fetchrow($result))
@@ -135,9 +134,9 @@ class qa
*/
public function is_installed()
{
- global $db;
+ global $phpbb_container;
- $db_tool = new \phpbb\db\tools($db);
+ $db_tool = $phpbb_container->get('dbal.tools');
return $db_tool->sql_table_exists($this->table_captcha_questions);
}
@@ -311,7 +310,7 @@ class qa
}
while ($row = $db->sql_fetchrow($result));
- if (sizeof($sql_in))
+ if (count($sql_in))
{
$sql = 'DELETE FROM ' . $this->table_qa_confirm . '
WHERE ' . $db->sql_in_set('confirm_id', $sql_in);
@@ -334,10 +333,9 @@ class qa
*/
function install()
{
- global $db;
-
- $db_tool = new \phpbb\db\tools($db);
+ global $phpbb_container;
+ $db_tool = $phpbb_container->get('dbal.tools');
$schemas = array(
$this->table_captcha_questions => array (
'COLUMNS' => array(
@@ -396,7 +394,7 @@ class qa
$error = '';
- if (!sizeof($this->question_ids))
+ if (!count($this->question_ids))
{
/** @var \phpbb\log\log_interface $phpbb_log */
$phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_ERROR_CAPTCHA', time(), array($user->lang('CONFIRM_QUESTION_MISSING')));
@@ -440,7 +438,7 @@ class qa
{
global $db, $user;
- if (!sizeof($this->question_ids))
+ if (!count($this->question_ids))
{
return;
}
@@ -466,7 +464,7 @@ class qa
{
global $db, $user;
- if (!sizeof($this->question_ids))
+ if (!count($this->question_ids))
{
return;
}
@@ -537,7 +535,7 @@ class qa
{
global $db, $user;
- if (!strlen($this->confirm_id) || !sizeof($this->question_ids))
+ if (!strlen($this->confirm_id) || !count($this->question_ids))
{
return false;
}
@@ -572,9 +570,9 @@ class qa
*/
function check_answer()
{
- global $db;
+ global $db, $request;
- $answer = ($this->question_strict) ? utf8_normalize_nfc(request_var('qa_answer', '', true)) : utf8_clean_string(utf8_normalize_nfc(request_var('qa_answer', '', true)));
+ $answer = ($this->question_strict) ? $request->variable('qa_answer', '', true) : utf8_clean_string($request->variable('qa_answer', '', true));
$sql = 'SELECT answer_text
FROM ' . $this->table_captcha_answers . '
@@ -626,7 +624,9 @@ class qa
*/
function is_solved()
{
- if (request_var('qa_answer', false) && $this->solved === 0)
+ global $request;
+
+ if ($request->variable('qa_answer', false) && $this->solved === 0)
{
$this->validate();
}
@@ -637,10 +637,9 @@ class qa
/**
* API function - The ACP backend, this marks the end of the easy methods
*/
- function acp_page($id, &$module)
+ function acp_page($id, $module)
{
- global $user, $template;
- global $config;
+ global $config, $request, $phpbb_log, $template, $user;
$user->add_lang('acp/board');
$user->add_lang('captcha_qa');
@@ -655,9 +654,9 @@ class qa
$form_key = 'acp_captcha';
add_form_key($form_key);
- $submit = request_var('submit', false);
- $question_id = request_var('question_id', 0);
- $action = request_var('action', '');
+ $submit = $request->variable('submit', false);
+ $question_id = $request->variable('question_id', 0);
+ $action = $request->variable('action', '');
// we have two pages, so users might want to navigate from one to the other
$list_url = $module->u_action . "&amp;configure=1&amp;select_captcha=" . $this->get_service_name();
@@ -762,7 +761,7 @@ class qa
$this->acp_add_question($question_input);
}
- add_log('admin', 'LOG_CONFIG_VISUAL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url));
}
}
@@ -776,7 +775,7 @@ class qa
/**
* This handles the list overview
*/
- function acp_question_list(&$module)
+ function acp_question_list($module)
{
global $db, $template;
@@ -848,7 +847,9 @@ class qa
*/
function acp_get_question_input()
{
- $answers = utf8_normalize_nfc(request_var('answers', '', true));
+ global $request;
+
+ $answers = $request->variable('answers', '', true);
// Convert answers into array and filter if answers are set
if (strlen($answers))
@@ -859,9 +860,9 @@ class qa
}
$question = array(
- 'question_text' => request_var('question_text', '', true),
- 'strict' => request_var('strict', false),
- 'lang_iso' => request_var('lang_iso', ''),
+ 'question_text' => $request->variable('question_text', '', true),
+ 'strict' => $request->variable('strict', false),
+ 'lang_iso' => $request->variable('lang_iso', ''),
'answers' => $answers,
);
return $question;
@@ -977,7 +978,7 @@ class qa
if (!isset($langs[$question_data['lang_iso']]) ||
!strlen($question_data['question_text']) ||
- !sizeof($question_data['answers']) ||
+ !count($question_data['answers']) ||
!is_array($question_data['answers']))
{
return false;
diff --git a/phpBB/phpbb/captcha/plugins/recaptcha.php b/phpBB/phpbb/captcha/plugins/recaptcha.php
index 584f3afec1..b7c0b5f5e2 100644
--- a/phpBB/phpbb/captcha/plugins/recaptcha.php
+++ b/phpBB/phpbb/captcha/plugins/recaptcha.php
@@ -18,12 +18,6 @@ class recaptcha extends captcha_abstract
var $recaptcha_server = 'http://www.google.com/recaptcha/api';
var $recaptcha_server_secure = 'https://www.google.com/recaptcha/api'; // class constants :(
- // We are opening a socket to port 80 of this host and send
- // the POST request asking for verification to the path specified here.
- var $recaptcha_verify_server = 'www.google.com';
- var $recaptcha_verify_path = '/recaptcha/api/verify';
-
- var $challenge;
var $response;
/**
@@ -37,12 +31,11 @@ class recaptcha extends captcha_abstract
function init($type)
{
- global $config, $db, $user;
+ global $user, $request;
$user->add_lang('captcha_recaptcha');
parent::init($type);
- $this->challenge = request_var('recaptcha_challenge_field', '');
- $this->response = request_var('recaptcha_response_field', '');
+ $this->response = $request->variable('g-recaptcha-response', '');
}
public function is_available()
@@ -73,9 +66,9 @@ class recaptcha extends captcha_abstract
throw new \Exception('No generator class given.');
}
- function acp_page($id, &$module)
+ function acp_page($id, $module)
{
- global $config, $db, $template, $user;
+ global $config, $template, $user, $phpbb_log, $request;
$captcha_vars = array(
'recaptcha_pubkey' => 'RECAPTCHA_PUBKEY',
@@ -87,21 +80,21 @@ class recaptcha extends captcha_abstract
$form_key = 'acp_captcha';
add_form_key($form_key);
- $submit = request_var('submit', '');
+ $submit = $request->variable('submit', '');
if ($submit && check_form_key($form_key))
{
$captcha_vars = array_keys($captcha_vars);
foreach ($captcha_vars as $captcha_var)
{
- $value = request_var($captcha_var, '');
+ $value = $request->variable($captcha_var, '');
if ($value)
{
- set_config($captcha_var, $value);
+ $config->set($captcha_var, $value);
}
}
- add_log('admin', 'LOG_CONFIG_VISUAL');
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_CONFIG_VISUAL');
trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action));
}
else if ($submit)
@@ -112,7 +105,7 @@ class recaptcha extends captcha_abstract
{
foreach ($captcha_vars as $captcha_var => $template_var)
{
- $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : '');
+ $var = (isset($_REQUEST[$captcha_var])) ? $request->variable($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : '');
$template->assign_var($template_var, $var);
}
@@ -151,7 +144,6 @@ class recaptcha extends captcha_abstract
$template->assign_vars(array(
'RECAPTCHA_SERVER' => $this->recaptcha_server,
'RECAPTCHA_PUBKEY' => isset($config['recaptcha_pubkey']) ? $config['recaptcha_pubkey'] : '',
- 'RECAPTCHA_ERRORGET' => '',
'S_RECAPTCHA_AVAILABLE' => self::is_available(),
'S_CONFIRM_CODE' => true,
'S_TYPE' => $this->type,
@@ -202,106 +194,25 @@ class recaptcha extends captcha_abstract
}
}
-// Code from here on is based on recaptchalib.php
-/*
- * This is a PHP library that handles calling reCAPTCHA.
- * - Documentation and latest version
- * http://recaptcha.net/plugins/php/
- * - Get a reCAPTCHA API Key
- * http://recaptcha.net/api/getkey
- * - Discussion group
- * http://groups.google.com/group/recaptcha
- *
- * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
- * AUTHORS:
- * Mike Crawford
- * Ben Maurer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
- /**
- * Submits an HTTP POST to a reCAPTCHA server
- * @param string $host
- * @param string $path
- * @param array $data
- * @param int port
- * @return array response
- */
- function _recaptcha_http_post($host, $path, $data, $port = 80)
- {
- $req = $this->_recaptcha_qsencode ($data);
-
- $http_request = "POST $path HTTP/1.0\r\n";
- $http_request .= "Host: $host\r\n";
- $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
- $http_request .= "Content-Length: " . strlen($req) . "\r\n";
- $http_request .= "User-Agent: reCAPTCHA/PHP/phpBB\r\n";
- $http_request .= "\r\n";
- $http_request .= $req;
-
- $response = '';
- if (false == ($fs = @fsockopen($host, $port, $errno, $errstr, 10)))
- {
- trigger_error('RECAPTCHA_SOCKET_ERROR', E_USER_ERROR);
- }
-
- fwrite($fs, $http_request);
-
- while (!feof($fs))
- {
- // One TCP-IP packet
- $response .= fgets($fs, 1160);
- }
- fclose($fs);
- $response = explode("\r\n\r\n", $response, 2);
-
- return $response;
- }
-
/**
* Calls an HTTP POST function to verify if the user's guess was correct
- * @param array $extra_params an array of extra variables to post to the server
- * @return ReCaptchaResponse
+ *
+ * @return bool|string Returns false on success or error string on failure.
*/
- function recaptcha_check_answer($extra_params = array())
+ function recaptcha_check_answer()
{
global $config, $user;
//discard spam submissions
- if ($this->challenge == null || strlen($this->challenge) == 0 || $this->response == null || strlen($this->response) == 0)
+ if ($this->response == null || strlen($this->response) == 0)
{
return $user->lang['RECAPTCHA_INCORRECT'];
}
- $response = $this->_recaptcha_http_post($this->recaptcha_verify_server, $this->recaptcha_verify_path,
- array(
- 'privatekey' => $config['recaptcha_privkey'],
- 'remoteip' => $user->ip,
- 'challenge' => $this->challenge,
- 'response' => $this->response
- ) + $extra_params
- );
-
- $answers = explode("\n", $response[1]);
+ $recaptcha = new \ReCaptcha\ReCaptcha($config['recaptcha_privkey']);
+ $result = $recaptcha->verify($this->response, $user->ip);
- if (trim($answers[0]) === 'true')
+ if ($result->isSuccess())
{
$this->solved = true;
return false;
@@ -311,22 +222,4 @@ class recaptcha extends captcha_abstract
return $user->lang['RECAPTCHA_INCORRECT'];
}
}
-
- /**
- * Encodes the given data into a query string format
- * @param $data - array of string elements to be encoded
- * @return string - encoded request
- */
- function _recaptcha_qsencode($data)
- {
- $req = '';
- foreach ($data as $key => $value)
- {
- $req .= $key . '=' . urlencode(stripslashes($value)) . '&';
- }
-
- // Cut the last '&'
- $req = substr($req, 0, strlen($req) - 1);
- return $req;
- }
}
diff --git a/phpBB/phpbb/composer.json b/phpBB/phpbb/composer.json
index 6b3888ef64..0b6299d6bc 100644
--- a/phpBB/phpbb/composer.json
+++ b/phpBB/phpbb/composer.json
@@ -22,11 +22,11 @@
"classmap": [""]
},
"require": {
- "php": ">=5.3.3"
+ "php": ">=5.4"
},
"extra": {
"branch-alias": {
- "dev-master": "3.1.x-dev"
+ "dev-master": "3.3.x-dev"
}
}
}
diff --git a/phpBB/phpbb/console/application.php b/phpBB/phpbb/console/application.php
index bc4897af18..dc9b8016b2 100644
--- a/phpBB/phpbb/console/application.php
+++ b/phpBB/phpbb/console/application.php
@@ -13,6 +13,7 @@
namespace phpbb\console;
+use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Shell;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -26,18 +27,18 @@ class application extends \Symfony\Component\Console\Application
protected $in_shell = false;
/**
- * @var \phpbb\user User object
+ * @var \phpbb\language\language User object
*/
- protected $user;
+ protected $language;
/**
- * @param string $name The name of the application
- * @param string $version The version of the application
- * @param \phpbb\user $user The user which runs the application (used for translation)
+ * @param string $name The name of the application
+ * @param string $version The version of the application
+ * @param \phpbb\language\language $language The user which runs the application (used for translation)
*/
- public function __construct($name, $version, \phpbb\user $user)
+ public function __construct($name, $version, \phpbb\language\language $language)
{
- $this->user = $user;
+ $this->language = $language;
parent::__construct($name, $version);
}
@@ -49,12 +50,7 @@ class application extends \Symfony\Component\Console\Application
{
$input_definition = parent::getDefaultInputDefinition();
- $input_definition->addOption(new InputOption(
- 'safe-mode',
- null,
- InputOption::VALUE_NONE,
- $this->user->lang('CLI_DESCRIPTION_OPTION_SAFE_MODE')
- ));
+ $this->register_global_options($input_definition);
return $input_definition;
}
@@ -76,12 +72,20 @@ class application extends \Symfony\Component\Console\Application
return parent::getHelp();
}
- $this->getDefinition()->addOption(new InputOption(
- '--shell',
- '-s',
- InputOption::VALUE_NONE,
- $this->user->lang('CLI_DESCRIPTION_OPTION_SHELL')
- ));
+ try
+ {
+ $definition = $this->getDefinition();
+ $definition->addOption(new InputOption(
+ '--shell',
+ '-s',
+ InputOption::VALUE_NONE,
+ $this->language->lang('CLI_DESCRIPTION_OPTION_SHELL')
+ ));
+ }
+ catch (\LogicException $e)
+ {
+ // Do nothing
+ }
return parent::getHelp();
}
@@ -117,4 +121,33 @@ class application extends \Symfony\Component\Console\Application
return parent::doRun($input, $output);
}
+
+ /**
+ * Register global options
+ *
+ * @param InputDefinition $definition An InputDefinition instance
+ */
+ protected function register_global_options(InputDefinition $definition)
+ {
+ try
+ {
+ $definition->addOption(new InputOption(
+ 'safe-mode',
+ null,
+ InputOption::VALUE_NONE,
+ $this->language->lang('CLI_DESCRIPTION_OPTION_SAFE_MODE')
+ ));
+
+ $definition->addOption(new InputOption(
+ 'env',
+ 'e',
+ InputOption::VALUE_REQUIRED,
+ $this->language->lang('CLI_DESCRIPTION_OPTION_ENV')
+ ));
+ }
+ catch (\LogicException $e)
+ {
+ // Do nothing
+ }
+ }
}
diff --git a/phpBB/phpbb/console/command/cache/purge.php b/phpBB/phpbb/console/command/cache/purge.php
index d0c2ef6f72..b7a51b2bb4 100644
--- a/phpBB/phpbb/console/command/cache/purge.php
+++ b/phpBB/phpbb/console/command/cache/purge.php
@@ -14,6 +14,7 @@ namespace phpbb\console\command\cache;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class purge extends \phpbb\console\command\command
{
@@ -39,7 +40,7 @@ class purge extends \phpbb\console\command\command
* @param \phpbb\cache\driver\driver_interface $cache Cache instance
* @param \phpbb\db\driver\driver_interface $db Database connection
* @param \phpbb\auth\auth $auth Auth instance
- * @param \phpbb\log\log $log Logger instance
+ * @param \phpbb\log\log_interface $log Logger instance
* @param \phpbb\config\config $config Config instance
*/
public function __construct(\phpbb\user $user, \phpbb\cache\driver\driver_interface $cache, \phpbb\db\driver\driver_interface $db, \phpbb\auth\auth $auth, \phpbb\log\log_interface $log, \phpbb\config\config $config)
@@ -71,7 +72,7 @@ class purge extends \phpbb\console\command\command
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
- * @return null
+ * @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
@@ -84,6 +85,7 @@ class purge extends \phpbb\console\command\command
$this->log->add('admin', ANONYMOUS, '', 'LOG_PURGE_CACHE', time(), array());
- $output->writeln($this->user->lang('PURGE_CACHE_SUCCESS'));
+ $io = new SymfonyStyle($input, $output);
+ $io->success($this->user->lang('PURGE_CACHE_SUCCESS'));
}
}
diff --git a/phpBB/phpbb/console/command/command.php b/phpBB/phpbb/console/command/command.php
index 638c989da2..0124c00d22 100644
--- a/phpBB/phpbb/console/command/command.php
+++ b/phpBB/phpbb/console/command/command.php
@@ -13,6 +13,10 @@
namespace phpbb\console\command;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
abstract class command extends \Symfony\Component\Console\Command\Command
{
/** @var \phpbb\user */
@@ -28,4 +32,45 @@ abstract class command extends \Symfony\Component\Console\Command\Command
$this->user = $user;
parent::__construct();
}
+
+ /**
+ * Create a styled progress bar
+ *
+ * @param int $max Max value for the progress bar
+ * @param SymfonyStyle $io Symfony style output decorator
+ * @param OutputInterface $output The output stream, used to print messages
+ * @param bool $message Should we display message output under the progress bar?
+ * @return ProgressBar
+ */
+ public function create_progress_bar($max, SymfonyStyle $io, OutputInterface $output, $message = false)
+ {
+ $progress = $io->createProgressBar($max);
+ if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERBOSE)
+ {
+ $progress->setFormat('<info>[%percent:3s%%]</info> %message%');
+ $progress->setOverwrite(false);
+ }
+ else if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE)
+ {
+ $progress->setFormat('<info>[%current:s%/%max:s%]</info><comment>[%elapsed%/%estimated%][%memory%]</comment> %message%');
+ $progress->setOverwrite(false);
+ }
+ else
+ {
+ $io->newLine(2);
+ $progress->setFormat(
+ " %current:s%/%max:s% %bar% %percent:3s%%\n" .
+ " " . ($message ? '%message%' : ' ') . " %elapsed:6s%/%estimated:-6s% %memory:6s%\n");
+ $progress->setBarWidth(60);
+ }
+
+ if (!defined('PHP_WINDOWS_VERSION_BUILD'))
+ {
+ $progress->setEmptyBarCharacter('â–‘'); // light shade character \u2591
+ $progress->setProgressCharacter('');
+ $progress->setBarCharacter('â–“'); // dark shade character \u2593
+ }
+
+ return $progress;
+ }
}
diff --git a/phpBB/phpbb/console/command/config/command.php b/phpBB/phpbb/console/command/config/command.php
index f0ad5d4d19..19f67d3b6c 100644
--- a/phpBB/phpbb/console/command/config/command.php
+++ b/phpBB/phpbb/console/command/config/command.php
@@ -17,7 +17,7 @@ abstract class command extends \phpbb\console\command\command
/** @var \phpbb\config\config */
protected $config;
- function __construct(\phpbb\user $user, \phpbb\config\config $config)
+ public function __construct(\phpbb\user $user, \phpbb\config\config $config)
{
$this->config = $config;
diff --git a/phpBB/phpbb/console/command/config/delete.php b/phpBB/phpbb/console/command/config/delete.php
index efd276d7e3..2da0801337 100644
--- a/phpBB/phpbb/console/command/config/delete.php
+++ b/phpBB/phpbb/console/command/config/delete.php
@@ -15,6 +15,7 @@ namespace phpbb\console\command\config;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class delete extends command
{
@@ -42,22 +43,24 @@ class delete extends command
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
- * @return null
+ * @return void
* @see \phpbb\config\config::delete()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$key = $input->getArgument('key');
if (isset($this->config[$key]))
{
$this->config->delete($key);
- $output->writeln('<info>' . $this->user->lang('CLI_CONFIG_DELETE_SUCCESS', $key) . '</info>');
+ $io->success($this->user->lang('CLI_CONFIG_DELETE_SUCCESS', $key));
}
else
{
- $output->writeln('<error>' . $this->user->lang('CLI_CONFIG_NOT_EXISTS', $key) . '</error>');
+ $io->error($this->user->lang('CLI_CONFIG_NOT_EXISTS', $key));
}
}
}
diff --git a/phpBB/phpbb/console/command/config/get.php b/phpBB/phpbb/console/command/config/get.php
index 9c03b49a3d..f065787110 100644
--- a/phpBB/phpbb/console/command/config/get.php
+++ b/phpBB/phpbb/console/command/config/get.php
@@ -16,6 +16,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class get extends command
{
@@ -49,11 +50,13 @@ class get extends command
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
- * @return null
+ * @return void
* @see \phpbb\config\config::offsetGet()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$key = $input->getArgument('key');
if (isset($this->config[$key]) && $input->getOption('no-newline'))
@@ -66,7 +69,7 @@ class get extends command
}
else
{
- $output->writeln('<error>' . $this->user->lang('CLI_CONFIG_NOT_EXISTS', $key) . '</error>');
+ $io->error($this->user->lang('CLI_CONFIG_NOT_EXISTS', $key));
}
}
}
diff --git a/phpBB/phpbb/console/command/config/increment.php b/phpBB/phpbb/console/command/config/increment.php
index b4d7438b66..647380a0bf 100644
--- a/phpBB/phpbb/console/command/config/increment.php
+++ b/phpBB/phpbb/console/command/config/increment.php
@@ -16,6 +16,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class increment extends command
{
@@ -54,17 +55,19 @@ class increment extends command
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
- * @return null
+ * @return void
* @see \phpbb\config\config::increment()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$key = $input->getArgument('key');
$increment = $input->getArgument('increment');
$use_cache = !$input->getOption('dynamic');
$this->config->increment($key, $increment, $use_cache);
- $output->writeln('<info>' . $this->user->lang('CLI_CONFIG_INCREMENT_SUCCESS', $key) . '</info>');
+ $io->success($this->user->lang('CLI_CONFIG_INCREMENT_SUCCESS', $key));
}
}
diff --git a/phpBB/phpbb/console/command/config/set.php b/phpBB/phpbb/console/command/config/set.php
index 695de31013..e9f7f8f91e 100644
--- a/phpBB/phpbb/console/command/config/set.php
+++ b/phpBB/phpbb/console/command/config/set.php
@@ -16,6 +16,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class set extends command
{
@@ -54,17 +55,19 @@ class set extends command
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
- * @return null
+ * @return void
* @see \phpbb\config\config::set()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$key = $input->getArgument('key');
$value = $input->getArgument('value');
$use_cache = !$input->getOption('dynamic');
$this->config->set($key, $value, $use_cache);
- $output->writeln('<info>' . $this->user->lang('CLI_CONFIG_SET_SUCCESS', $key) . '</info>');
+ $io->success($this->user->lang('CLI_CONFIG_SET_SUCCESS', $key));
}
}
diff --git a/phpBB/phpbb/console/command/config/set_atomic.php b/phpBB/phpbb/console/command/config/set_atomic.php
index e8c69a0885..475d8a9271 100644
--- a/phpBB/phpbb/console/command/config/set_atomic.php
+++ b/phpBB/phpbb/console/command/config/set_atomic.php
@@ -16,6 +16,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class set_atomic extends command
{
@@ -65,6 +66,8 @@ class set_atomic extends command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$key = $input->getArgument('key');
$old_value = $input->getArgument('old');
$new_value = $input->getArgument('new');
@@ -72,12 +75,12 @@ class set_atomic extends command
if ($this->config->set_atomic($key, $old_value, $new_value, $use_cache))
{
- $output->writeln('<info>' . $this->user->lang('CLI_CONFIG_SET_SUCCESS', $key) . '</info>');
+ $io->success($this->user->lang('CLI_CONFIG_SET_SUCCESS', $key));
return 0;
}
else
{
- $output->writeln('<error>' . $this->user->lang('CLI_CONFIG_SET_FAILURE', $key) . '</error>');
+ $io->error($this->user->lang('CLI_CONFIG_SET_FAILURE', $key));
return 1;
}
}
diff --git a/phpBB/phpbb/console/command/cron/cron_list.php b/phpBB/phpbb/console/command/cron/cron_list.php
index c515fd9e80..ea61e45235 100644
--- a/phpBB/phpbb/console/command/cron/cron_list.php
+++ b/phpBB/phpbb/console/command/cron/cron_list.php
@@ -14,6 +14,7 @@ namespace phpbb\console\command\cron;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class cron_list extends \phpbb\console\command\command
{
@@ -51,61 +52,43 @@ class cron_list extends \phpbb\console\command\command
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
- * @return null
+ * @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$tasks = $this->cron_manager->get_tasks();
if (empty($tasks))
{
- $output->writeln($this->user->lang('CRON_NO_TASKS'));
+ $io->error($this->user->lang('CRON_NO_TASKS'));
return;
}
- $ready_tasks = array();
- $not_ready_tasks = array();
+ $ready_tasks = $not_ready_tasks = array();
foreach ($tasks as $task)
{
if ($task->is_ready())
{
- $ready_tasks[] = $task;
+ $ready_tasks[] = $task->get_name();
}
else
{
- $not_ready_tasks[] = $task;
+ $not_ready_tasks[] = $task->get_name();
}
}
if (!empty($ready_tasks))
{
- $output->writeln('<info>' . $this->user->lang('TASKS_READY') . '</info>');
- $this->print_tasks_names($ready_tasks, $output);
- }
-
- if (!empty($ready_tasks) && !empty($not_ready_tasks))
- {
- $output->writeln('');
+ $io->title($this->user->lang('TASKS_READY'));
+ $io->listing($ready_tasks);
}
if (!empty($not_ready_tasks))
{
- $output->writeln('<info>' . $this->user->lang('TASKS_NOT_READY') . '</info>');
- $this->print_tasks_names($not_ready_tasks, $output);
- }
- }
-
- /**
- * Print a list of cron jobs
- *
- * @param array $tasks A list of task to display
- * @param OutputInterface $output An OutputInterface instance
- */
- protected function print_tasks_names(array $tasks, OutputInterface $output)
- {
- foreach ($tasks as $task)
- {
- $output->writeln($task->get_name());
+ $io->title($this->user->lang('TASKS_NOT_READY'));
+ $io->listing($not_ready_tasks);
}
}
}
diff --git a/phpBB/phpbb/console/command/cron/run.php b/phpBB/phpbb/console/command/cron/run.php
index a9648fcd41..dea6493007 100644
--- a/phpBB/phpbb/console/command/cron/run.php
+++ b/phpBB/phpbb/console/command/cron/run.php
@@ -13,6 +13,7 @@
namespace phpbb\console\command\cron;
+use phpbb\exception\runtime_exception;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
@@ -93,8 +94,7 @@ class run extends \phpbb\console\command\command
}
else
{
- $output->writeln('<error>' . $this->user->lang('CRON_LOCK_ERROR') . '</error>');
- return 1;
+ throw new runtime_exception('CRON_LOCK_ERROR', array(), null, 1);
}
}
@@ -165,8 +165,7 @@ class run extends \phpbb\console\command\command
}
else
{
- $output->writeln('<error>' . $this->user->lang('CRON_NO_SUCH_TASK', $task_name) . '</error>');
- return 2;
+ throw new runtime_exception('CRON_NO_SUCH_TASK', array( $task_name), null, 2);
}
}
}
diff --git a/phpBB/phpbb/console/command/db/console_migrator_output_handler.php b/phpBB/phpbb/console/command/db/console_migrator_output_handler.php
index b9741a3838..568b2646d4 100644
--- a/phpBB/phpbb/console/command/db/console_migrator_output_handler.php
+++ b/phpBB/phpbb/console/command/db/console_migrator_output_handler.php
@@ -13,8 +13,8 @@
namespace phpbb\console\command\db;
+use phpbb\db\output_handler\migrator_output_handler_interface;
use phpbb\user;
-use phpbb\db\migrator_output_handler_interface;
use Symfony\Component\Console\Output\OutputInterface;
class console_migrator_output_handler implements migrator_output_handler_interface
diff --git a/phpBB/phpbb/console/command/db/list_command.php b/phpBB/phpbb/console/command/db/list_command.php
new file mode 100644
index 0000000000..77f26dd786
--- /dev/null
+++ b/phpBB/phpbb/console/command/db/list_command.php
@@ -0,0 +1,81 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+namespace phpbb\console\command\db;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class list_command extends \phpbb\console\command\db\migration_command
+{
+ protected function configure()
+ {
+ $this
+ ->setName('db:list')
+ ->setDescription($this->user->lang('CLI_DESCRIPTION_DB_LIST'))
+ ->addOption(
+ 'available',
+ 'u',
+ InputOption::VALUE_NONE,
+ $this->user->lang('CLI_MIGRATIONS_ONLY_AVAILABLE')
+ )
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $show_installed = !$input->getOption('available');
+ $installed = $available = array();
+
+ foreach ($this->load_migrations() as $name)
+ {
+ if ($this->migrator->migration_state($name) !== false)
+ {
+ $installed[] = $name;
+ }
+ else
+ {
+ $available[] = $name;
+ }
+ }
+
+ if ($show_installed)
+ {
+ $io->section($this->user->lang('CLI_MIGRATIONS_INSTALLED'));
+
+ if (!empty($installed))
+ {
+ $io->listing($installed);
+ }
+ else
+ {
+ $io->text($this->user->lang('CLI_MIGRATIONS_EMPTY'));
+ $io->newLine();
+ }
+ }
+
+ $io->section($this->user->lang('CLI_MIGRATIONS_AVAILABLE'));
+ if (!empty($available))
+ {
+ $io->listing($available);
+ }
+ else
+ {
+ $io->text($this->user->lang('CLI_MIGRATIONS_EMPTY'));
+ $io->newLine();
+ }
+ }
+}
diff --git a/phpBB/phpbb/console/command/db/migrate.php b/phpBB/phpbb/console/command/db/migrate.php
index 87c2a057d1..4270e2d703 100644
--- a/phpBB/phpbb/console/command/db/migrate.php
+++ b/phpBB/phpbb/console/command/db/migrate.php
@@ -12,52 +12,48 @@
*/
namespace phpbb\console\command\db;
+use phpbb\db\output_handler\log_wrapper_migrator_output_handler;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
-class migrate extends \phpbb\console\command\command
+class migrate extends \phpbb\console\command\db\migration_command
{
- /** @var \phpbb\db\migrator */
- protected $migrator;
-
- /** @var \phpbb\extension\manager */
- protected $extension_manager;
-
- /** @var \phpbb\config\config */
- protected $config;
-
- /** @var \phpbb\cache\service */
- protected $cache;
-
/** @var \phpbb\log\log */
protected $log;
/** @var string phpBB root path */
protected $phpbb_root_path;
- function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\log\log $log, $phpbb_root_path)
+ /** @var \phpbb\filesystem\filesystem_interface */
+ protected $filesystem;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ public function __construct(\phpbb\user $user, \phpbb\language\language $language, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache, \phpbb\log\log $log, \phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path)
{
- $this->migrator = $migrator;
- $this->extension_manager = $extension_manager;
- $this->config = $config;
- $this->cache = $cache;
+ $this->language = $language;
$this->log = $log;
+ $this->filesystem = $filesystem;
$this->phpbb_root_path = $phpbb_root_path;
- parent::__construct($user);
- $this->user->add_lang(array('common', 'install', 'migrator'));
+ parent::__construct($user, $migrator, $extension_manager, $config, $cache);
+ $this->language->add_lang(array('common', 'install', 'migrator'));
}
protected function configure()
{
$this
->setName('db:migrate')
- ->setDescription($this->user->lang('CLI_DESCRIPTION_DB_MIGRATE'))
+ ->setDescription($this->language->lang('CLI_DESCRIPTION_DB_MIGRATE'))
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
- $this->migrator->set_output_handler(new \phpbb\db\log_wrapper_migrator_output_handler($this->user, new console_migrator_output_handler($this->user, $output), $this->phpbb_root_path . 'store/migrations_' . time() . '.log'));
+ $io = new SymfonyStyle($input, $output);
+
+ $this->migrator->set_output_handler(new log_wrapper_migrator_output_handler($this->language, new console_migrator_output_handler($this->user, $output), $this->phpbb_root_path . 'store/migrations_' . time() . '.log', $this->filesystem));
$this->migrator->create_migrations_table();
@@ -73,7 +69,7 @@ class migrate extends \phpbb\console\command\command
}
catch (\phpbb\db\migration\exception $e)
{
- $output->writeln('<error>' . $e->getLocalisedMessage($this->user) . '</error>');
+ $io->error($e->getLocalisedMessage($this->user));
$this->finalise_update();
return 1;
}
@@ -85,23 +81,6 @@ class migrate extends \phpbb\console\command\command
}
$this->finalise_update();
- $output->writeln($this->user->lang['DATABASE_UPDATE_COMPLETE']);
- }
-
- protected function load_migrations()
- {
- $migrations = $this->extension_manager
- ->get_finder()
- ->core_path('phpbb/db/migration/data/')
- ->extension_directory('/migrations')
- ->get_classes();
-
- $this->migrator->set_migrations($migrations);
- }
-
- protected function finalise_update()
- {
- $this->cache->purge();
- $this->config->increment('assets_version', 1);
+ $io->success($this->language->lang('INLINE_UPDATE_SUCCESSFUL'));
}
}
diff --git a/phpBB/phpbb/console/command/db/migration_command.php b/phpBB/phpbb/console/command/db/migration_command.php
new file mode 100644
index 0000000000..851f404fab
--- /dev/null
+++ b/phpBB/phpbb/console/command/db/migration_command.php
@@ -0,0 +1,56 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+namespace phpbb\console\command\db;
+
+abstract class migration_command extends \phpbb\console\command\command
+{
+ /** @var \phpbb\db\migrator */
+ protected $migrator;
+
+ /** @var \phpbb\extension\manager */
+ protected $extension_manager;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /** @var \phpbb\cache\service */
+ protected $cache;
+
+ public function __construct(\phpbb\user $user, \phpbb\db\migrator $migrator, \phpbb\extension\manager $extension_manager, \phpbb\config\config $config, \phpbb\cache\service $cache)
+ {
+ $this->migrator = $migrator;
+ $this->extension_manager = $extension_manager;
+ $this->config = $config;
+ $this->cache = $cache;
+ parent::__construct($user);
+ }
+
+ protected function load_migrations()
+ {
+ $migrations = $this->extension_manager
+ ->get_finder()
+ ->core_path('phpbb/db/migration/data/')
+ ->extension_directory('/migrations')
+ ->get_classes();
+
+ $this->migrator->set_migrations($migrations);
+
+ return $this->migrator->get_migrations();
+ }
+
+ protected function finalise_update()
+ {
+ $this->cache->purge();
+ $this->config->increment('assets_version', 1);
+ }
+}
diff --git a/phpBB/phpbb/console/command/db/revert.php b/phpBB/phpbb/console/command/db/revert.php
new file mode 100644
index 0000000000..3c79d8c554
--- /dev/null
+++ b/phpBB/phpbb/console/command/db/revert.php
@@ -0,0 +1,74 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+namespace phpbb\console\command\db;
+
+use phpbb\db\output_handler\log_wrapper_migrator_output_handler;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class revert extends \phpbb\console\command\db\migrate
+{
+ protected function configure()
+ {
+ $this
+ ->setName('db:revert')
+ ->setDescription($this->language->lang('CLI_DESCRIPTION_DB_REVERT'))
+ ->addArgument(
+ 'name',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_MIGRATION_NAME')
+ )
+ ;
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $name = str_replace('/', '\\', $input->getArgument('name'));
+
+ $this->migrator->set_output_handler(new log_wrapper_migrator_output_handler($this->language, new console_migrator_output_handler($this->user, $output), $this->phpbb_root_path . 'store/migrations_' . time() . '.log', $this->filesystem));
+
+ $this->cache->purge();
+
+ if (!in_array($name, $this->load_migrations()))
+ {
+ $io->error($this->language->lang('MIGRATION_NOT_VALID', $name));
+ return 1;
+ }
+ else if ($this->migrator->migration_state($name) === false)
+ {
+ $io->error($this->language->lang('MIGRATION_NOT_INSTALLED', $name));
+ return 1;
+ }
+
+ try
+ {
+ while ($this->migrator->migration_state($name) !== false)
+ {
+ $this->migrator->revert($name);
+ }
+ }
+ catch (\phpbb\db\migration\exception $e)
+ {
+ $io->error($e->getLocalisedMessage($this->user));
+ $this->finalise_update();
+ return 1;
+ }
+
+ $this->finalise_update();
+ $io->success($this->language->lang('INLINE_UPDATE_SUCCESSFUL'));
+ }
+}
diff --git a/phpBB/phpbb/console/command/dev/migration_tips.php b/phpBB/phpbb/console/command/dev/migration_tips.php
index f9047bdac8..2ca0ddde2f 100644
--- a/phpBB/phpbb/console/command/dev/migration_tips.php
+++ b/phpBB/phpbb/console/command/dev/migration_tips.php
@@ -20,7 +20,7 @@ class migration_tips extends \phpbb\console\command\command
/** @var \phpbb\extension\manager */
protected $extension_manager;
- function __construct(\phpbb\user $user, \phpbb\extension\manager $extension_manager)
+ public function __construct(\phpbb\user $user, \phpbb\extension\manager $extension_manager)
{
$this->extension_manager = $extension_manager;
parent::__construct($user);
diff --git a/phpBB/phpbb/console/command/extension/disable.php b/phpBB/phpbb/console/command/extension/disable.php
index 1eee16cbd9..b2e10fb960 100644
--- a/phpBB/phpbb/console/command/extension/disable.php
+++ b/phpBB/phpbb/console/command/extension/disable.php
@@ -15,6 +15,7 @@ namespace phpbb\console\command\extension;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class disable extends command
{
@@ -33,19 +34,28 @@ class disable extends command
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$name = $input->getArgument('extension-name');
+
+ if (!$this->manager->is_enabled($name))
+ {
+ $io->error($this->user->lang('CLI_EXTENSION_DISABLED', $name));
+ return 2;
+ }
+
$this->manager->disable($name);
$this->manager->load_extensions();
if ($this->manager->is_enabled($name))
{
- $output->writeln('<error>' . $this->user->lang('CLI_EXTENSION_DISABLE_FAILURE', $name) . '</error>');
+ $io->error($this->user->lang('CLI_EXTENSION_DISABLE_FAILURE', $name));
return 1;
}
else
{
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_DISABLE', time(), array($name));
- $output->writeln('<info>' . $this->user->lang('CLI_EXTENSION_DISABLE_SUCCESS', $name) . '</info>');
+ $io->success($this->user->lang('CLI_EXTENSION_DISABLE_SUCCESS', $name));
return 0;
}
}
diff --git a/phpBB/phpbb/console/command/extension/enable.php b/phpBB/phpbb/console/command/extension/enable.php
index 59ff11e9b7..a6f5b10e86 100644
--- a/phpBB/phpbb/console/command/extension/enable.php
+++ b/phpBB/phpbb/console/command/extension/enable.php
@@ -15,6 +15,7 @@ namespace phpbb\console\command\extension;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class enable extends command
{
@@ -33,19 +34,42 @@ class enable extends command
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$name = $input->getArgument('extension-name');
+
+ if (!$this->manager->is_available($name))
+ {
+ $io->error($this->user->lang('CLI_EXTENSION_NOT_EXIST', $name));
+ return 1;
+ }
+
+ $extension = $this->manager->get_extension($name);
+
+ if (!$extension->is_enableable())
+ {
+ $io->error($this->user->lang('CLI_EXTENSION_NOT_ENABLEABLE', $name));
+ return 1;
+ }
+
+ if ($this->manager->is_enabled($name))
+ {
+ $io->error($this->user->lang('CLI_EXTENSION_ENABLED', $name));
+ return 1;
+ }
+
$this->manager->enable($name);
$this->manager->load_extensions();
if ($this->manager->is_enabled($name))
{
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_ENABLE', time(), array($name));
- $output->writeln('<info>' . $this->user->lang('CLI_EXTENSION_ENABLE_SUCCESS', $name) . '</info>');
+ $io->success($this->user->lang('CLI_EXTENSION_ENABLE_SUCCESS', $name));
return 0;
}
else
{
- $output->writeln('<error>' . $this->user->lang('CLI_EXTENSION_ENABLE_FAILURE', $name) . '</error>');
+ $io->error($this->user->lang('CLI_EXTENSION_ENABLE_FAILURE', $name));
return 1;
}
}
diff --git a/phpBB/phpbb/console/command/extension/purge.php b/phpBB/phpbb/console/command/extension/purge.php
index 517e9a74c9..25bde503f7 100644
--- a/phpBB/phpbb/console/command/extension/purge.php
+++ b/phpBB/phpbb/console/command/extension/purge.php
@@ -15,6 +15,7 @@ namespace phpbb\console\command\extension;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class purge extends command
{
@@ -33,19 +34,21 @@ class purge extends command
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$name = $input->getArgument('extension-name');
$this->manager->purge($name);
$this->manager->load_extensions();
if ($this->manager->is_enabled($name))
{
- $output->writeln('<error>' . $this->user->lang('CLI_EXTENSION_PURGE_FAILURE', $name) . '</error>');
+ $io->error($this->user->lang('CLI_EXTENSION_PURGE_FAILURE', $name));
return 1;
}
else
{
$this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_PURGE', time(), array($name));
- $output->writeln('<info>' . $this->user->lang('CLI_EXTENSION_PURGE_SUCCESS', $name) . '</info>');
+ $io->success($this->user->lang('CLI_EXTENSION_PURGE_SUCCESS', $name));
return 0;
}
}
diff --git a/phpBB/phpbb/console/command/extension/show.php b/phpBB/phpbb/console/command/extension/show.php
index f9322034d7..7bad0c0a5a 100644
--- a/phpBB/phpbb/console/command/extension/show.php
+++ b/phpBB/phpbb/console/command/extension/show.php
@@ -14,6 +14,7 @@ namespace phpbb\console\command\extension;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class show extends command
{
@@ -27,36 +28,27 @@ class show extends command
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$this->manager->load_extensions();
$all = array_keys($this->manager->all_available());
if (empty($all))
{
- $output->writeln('<comment>' . $this->user->lang('CLI_EXTENSION_NOT_FOUND') . '</comment>');
+ $io->note($this->user->lang('CLI_EXTENSION_NOT_FOUND'));
return 3;
}
$enabled = array_keys($this->manager->all_enabled());
- $this->print_extension_list($output, $this->user->lang('CLI_EXTENSIONS_ENABLED') . $this->user->lang('COLON'), $enabled);
-
- $output->writeln('');
+ $io->section($this->user->lang('CLI_EXTENSIONS_ENABLED'));
+ $io->listing($enabled);
$disabled = array_keys($this->manager->all_disabled());
- $this->print_extension_list($output, $this->user->lang('CLI_EXTENSIONS_DISABLED') . $this->user->lang('COLON'), $disabled);
-
- $output->writeln('');
+ $io->section($this->user->lang('CLI_EXTENSIONS_DISABLED'));
+ $io->listing($disabled);
$purged = array_diff($all, $enabled, $disabled);
- $this->print_extension_list($output, $this->user->lang('CLI_EXTENSIONS_AVAILABLE') . $this->user->lang('COLON'), $purged);
- }
-
- protected function print_extension_list(OutputInterface $output, $type, array $extensions)
- {
- $output->writeln("<info>$type</info>");
-
- foreach ($extensions as $extension)
- {
- $output->writeln(" - $extension");
- }
+ $io->section($this->user->lang('CLI_EXTENSIONS_AVAILABLE'));
+ $io->listing($purged);
}
}
diff --git a/phpBB/phpbb/console/command/fixup/fix_left_right_ids.php b/phpBB/phpbb/console/command/fixup/fix_left_right_ids.php
index f55e1761bc..271b099a6c 100644
--- a/phpBB/phpbb/console/command/fixup/fix_left_right_ids.php
+++ b/phpBB/phpbb/console/command/fixup/fix_left_right_ids.php
@@ -15,6 +15,7 @@ namespace phpbb\console\command\fixup;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class fix_left_right_ids extends \phpbb\console\command\command
{
@@ -67,6 +68,8 @@ class fix_left_right_ids extends \phpbb\console\command\command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
// Fix Left/Right IDs for the modules table
$result = $this->db->sql_query('SELECT DISTINCT(module_class) FROM ' . MODULES_TABLE);
while ($row = $this->db->sql_fetchrow($result))
@@ -83,7 +86,7 @@ class fix_left_right_ids extends \phpbb\console\command\command
$this->cache->purge();
- $output->writeln('<info>' . $this->user->lang('CLI_FIXUP_FIX_LEFT_RIGHT_IDS_SUCCESS') . '</info>');
+ $io->success($this->user->lang('CLI_FIXUP_FIX_LEFT_RIGHT_IDS_SUCCESS'));
}
/**
diff --git a/phpBB/phpbb/console/command/fixup/recalculate_email_hash.php b/phpBB/phpbb/console/command/fixup/recalculate_email_hash.php
index ec4e1b0ee7..6f7096296d 100644
--- a/phpBB/phpbb/console/command/fixup/recalculate_email_hash.php
+++ b/phpBB/phpbb/console/command/fixup/recalculate_email_hash.php
@@ -14,13 +14,14 @@ namespace phpbb\console\command\fixup;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
class recalculate_email_hash extends \phpbb\console\command\command
{
/** @var \phpbb\db\driver\driver_interface */
protected $db;
- function __construct(\phpbb\user $user, \phpbb\db\driver\driver_interface $db)
+ public function __construct(\phpbb\user $user, \phpbb\db\driver\driver_interface $db)
{
$this->db = $db;
@@ -37,6 +38,8 @@ class recalculate_email_hash extends \phpbb\console\command\command
protected function execute(InputInterface $input, OutputInterface $output)
{
+ $io = new SymfonyStyle($input, $output);
+
$sql = 'SELECT user_id, user_email, user_email_hash
FROM ' . USERS_TABLE . '
WHERE user_type <> ' . USER_IGNORE . "
@@ -59,17 +62,15 @@ class recalculate_email_hash extends \phpbb\console\command\command
if ($output->getVerbosity() >= OutputInterface::VERBOSITY_DEBUG)
{
- $output->writeln(sprintf(
- 'user_id %d, email %s => %s',
- $row['user_id'],
- $row['user_email'],
- $user_email_hash
- ));
+ $io->table(
+ array('user_id', 'user_email', 'user_email_hash'),
+ array(array($row['user_id'], $row['user_email'], $user_email_hash))
+ );
}
}
}
$this->db->sql_freeresult($result);
- $output->writeln('<info>' . $this->user->lang('CLI_FIXUP_RECALCULATE_EMAIL_HASH_SUCCESS') . '</info>');
+ $io->success($this->user->lang('CLI_FIXUP_RECALCULATE_EMAIL_HASH_SUCCESS'));
}
}
diff --git a/phpBB/phpbb/console/command/fixup/update_hashes.php b/phpBB/phpbb/console/command/fixup/update_hashes.php
index 4bcc3b5d19..9a0e9bc798 100644
--- a/phpBB/phpbb/console/command/fixup/update_hashes.php
+++ b/phpBB/phpbb/console/command/fixup/update_hashes.php
@@ -101,9 +101,9 @@ class update_hashes extends \phpbb\console\command\command
{
$new_hash = $this->passwords_manager->hash($row['user_password'], array($this->default_type));
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_password = "' . $this->db->sql_escape($new_hash) . '"
- WHERE user_id = ' . (int) $row['user_id'];
+ $sql = 'UPDATE ' . USERS_TABLE . "
+ SET user_password = '" . $this->db->sql_escape($new_hash) . "'
+ WHERE user_id = " . (int) $row['user_id'];
$this->db->sql_query($sql);
$progress_bar->advance();
}
diff --git a/phpBB/phpbb/console/command/reparser/list_all.php b/phpBB/phpbb/console/command/reparser/list_all.php
new file mode 100644
index 0000000000..a79578abf0
--- /dev/null
+++ b/phpBB/phpbb/console/command/reparser/list_all.php
@@ -0,0 +1,72 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\console\command\reparser;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class list_all extends \phpbb\console\command\command
+{
+ /**
+ * @var string[] Names of the reparser services
+ */
+ protected $reparser_names;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\user $user
+ * @param \phpbb\di\service_collection $reparsers
+ */
+ public function __construct(\phpbb\user $user, \phpbb\di\service_collection $reparsers)
+ {
+ parent::__construct($user);
+ $this->reparser_names = array();
+ foreach ($reparsers as $reparser)
+ {
+ // Store the names without the "text_reparser." prefix
+ $this->reparser_names[] = $reparser->get_name();
+ }
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('reparser:list')
+ ->setDescription($this->user->lang('CLI_DESCRIPTION_REPARSER_LIST'))
+ ;
+ }
+
+ /**
+ * Executes the command reparser:list
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return integer
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+ $io->section($this->user->lang('CLI_DESCRIPTION_REPARSER_AVAILABLE'));
+ $io->listing($this->reparser_names);
+
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/console/command/reparser/reparse.php b/phpBB/phpbb/console/command/reparser/reparse.php
new file mode 100644
index 0000000000..f285977ea2
--- /dev/null
+++ b/phpBB/phpbb/console/command/reparser/reparse.php
@@ -0,0 +1,242 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\console\command\reparser;
+
+use phpbb\exception\runtime_exception;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class reparse extends \phpbb\console\command\command
+{
+ /**
+ * @var InputInterface
+ */
+ protected $input;
+
+ /**
+ * @var SymfonyStyle
+ */
+ protected $io;
+
+ /**
+ * @var OutputInterface
+ */
+ protected $output;
+
+ /**
+ * @var \phpbb\lock\db
+ */
+ protected $reparse_lock;
+
+ /**
+ * @var \phpbb\textreparser\manager
+ */
+ protected $reparser_manager;
+
+ /**
+ * @var \phpbb\di\service_collection
+ */
+ protected $reparsers;
+
+ /**
+ * @var array The reparser's last $current ID as values
+ */
+ protected $resume_data;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\user $user
+ * @param \phpbb\lock\db $reparse_lock
+ * @param \phpbb\textreparser\manager $reparser_manager
+ * @param \phpbb\di\service_collection $reparsers
+ */
+ public function __construct(\phpbb\user $user, \phpbb\lock\db $reparse_lock, \phpbb\textreparser\manager $reparser_manager, \phpbb\di\service_collection $reparsers)
+ {
+ require_once __DIR__ . '/../../../../includes/functions_content.php';
+
+ $this->reparse_lock = $reparse_lock;
+ $this->reparser_manager = $reparser_manager;
+ $this->reparsers = $reparsers;
+ parent::__construct($user);
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('reparser:reparse')
+ ->setDescription($this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE'))
+ ->addArgument('reparser-name', InputArgument::OPTIONAL, $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_ARG_1'))
+ ->addOption(
+ 'dry-run',
+ null,
+ InputOption::VALUE_NONE,
+ $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_DRY_RUN')
+ )
+ ->addOption(
+ 'resume',
+ null,
+ InputOption::VALUE_NONE,
+ $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RESUME')
+ )
+ ->addOption(
+ 'range-min',
+ null,
+ InputOption::VALUE_REQUIRED,
+ $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MIN'),
+ 1
+ )
+ ->addOption(
+ 'range-max',
+ null,
+ InputOption::VALUE_REQUIRED,
+ $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_MAX')
+ )
+ ->addOption(
+ 'range-size',
+ null,
+ InputOption::VALUE_REQUIRED,
+ $this->user->lang('CLI_DESCRIPTION_REPARSER_REPARSE_OPT_RANGE_SIZE'),
+ 100
+ );
+ ;
+ }
+
+ /**
+ * Executes the command reparser:reparse
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return integer
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->input = $input;
+ $this->output = $output;
+ $this->io = new SymfonyStyle($input, $output);
+
+ if (!$this->reparse_lock->acquire())
+ {
+ throw new runtime_exception('REPARSE_LOCK_ERROR', array(), null, 1);
+ }
+
+ $name = $input->getArgument('reparser-name');
+ if ($name)
+ {
+ $name = $this->reparser_manager->find_reparser($name);
+ $this->reparse($name);
+ }
+ else
+ {
+ foreach ($this->reparsers as $name => $service)
+ {
+ $this->reparse($name);
+ }
+ }
+
+ $this->io->success($this->user->lang('CLI_REPARSER_REPARSE_SUCCESS'));
+
+ $this->reparse_lock->release();
+
+ return 0;
+ }
+
+ /**
+ * Get an option value, adjusted for given reparser
+ *
+ * Will use the last saved value if --resume is set and the option was not specified
+ * on the command line
+ *
+ * @param string $option_name Option name
+ * @return integer
+ */
+ protected function get_option($option_name)
+ {
+ // Return the option from the resume_data if applicable
+ if ($this->input->getOption('resume') && isset($this->resume_data[$option_name]) && !$this->input->hasParameterOption('--' . $option_name))
+ {
+ return $this->resume_data[$option_name];
+ }
+
+ return $this->input->getOption($option_name);
+ }
+
+ /**
+ * Reparse all text handled by given reparser within given range
+ *
+ * @param string $name Reparser service name
+ */
+ protected function reparse($name)
+ {
+ $reparser = $this->reparsers[$name];
+ $this->resume_data = $this->reparser_manager->get_resume_data($name);
+ if ($this->input->getOption('dry-run'))
+ {
+ $reparser->disable_save();
+ }
+ else
+ {
+ $reparser->enable_save();
+ }
+
+ // Start at range-max if specified or at the highest ID otherwise
+ $max = $this->get_option('range-max');
+ $min = $this->get_option('range-min');
+ $size = $this->get_option('range-size');
+
+ // range-max has no default value, it must be computed for each reparser
+ if ($max === null)
+ {
+ $max = $reparser->get_max_id();
+ }
+
+ if ($max < $min)
+ {
+ return;
+ }
+
+ $this->io->section($this->user->lang('CLI_REPARSER_REPARSE_REPARSING', $reparser->get_name(), $min, $max));
+
+ $progress = $this->create_progress_bar($max, $this->io, $this->output, true);
+ $progress->setMessage($this->user->lang('CLI_REPARSER_REPARSE_REPARSING_START', $reparser->get_name()));
+ $progress->start();
+
+ // Start from $max and decrement $current by $size until we reach $min
+ $current = $max;
+ while ($current >= $min)
+ {
+ $start = max($min, $current + 1 - $size);
+ $end = max($min, $current);
+
+ $progress->setMessage($this->user->lang('CLI_REPARSER_REPARSE_REPARSING', $reparser->get_name(), $start, $end));
+ $reparser->reparse_range($start, $end);
+
+ $current = $start - 1;
+ $progress->setProgress($max + 1 - $start);
+
+ $this->reparser_manager->update_resume_data($name, $min, $current, $size, !$this->input->getOption('dry-run'));
+ }
+ $progress->finish();
+
+ $this->io->newLine(2);
+ }
+}
diff --git a/phpBB/phpbb/console/command/thumbnail/delete.php b/phpBB/phpbb/console/command/thumbnail/delete.php
new file mode 100644
index 0000000000..7b95c20cf2
--- /dev/null
+++ b/phpBB/phpbb/console/command/thumbnail/delete.php
@@ -0,0 +1,160 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+namespace phpbb\console\command\thumbnail;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class delete extends \phpbb\console\command\command
+{
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * phpBB root path
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param \config\config $config The config
+ * @param \phpbb\user $user The user object (used to get language information)
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param string $phpbb_root_path Root path
+ */
+ public function __construct(\phpbb\config\config $config, \phpbb\user $user, \phpbb\db\driver\driver_interface $db, $phpbb_root_path)
+ {
+ $this->config = $config;
+ $this->db = $db;
+ $this->phpbb_root_path = $phpbb_root_path;
+
+ parent::__construct($user);
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('thumbnail:delete')
+ ->setDescription($this->user->lang('CLI_DESCRIPTION_THUMBNAIL_DELETE'))
+ ;
+ }
+
+ /**
+ * Executes the command thumbnail:delete.
+ *
+ * Deletes all existing thumbnails and updates the database accordingly.
+ *
+ * @param InputInterface $input The input stream used to get the argument and verbose option.
+ * @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
+ *
+ * @return int 0 if all is ok, 1 if a thumbnail couldn't be deleted.
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $io->section($this->user->lang('CLI_THUMBNAIL_DELETING'));
+
+ $sql = 'SELECT COUNT(*) AS nb_missing_thumbnails
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE thumbnail = 1';
+ $result = $this->db->sql_query($sql);
+ $nb_missing_thumbnails = (int) $this->db->sql_fetchfield('nb_missing_thumbnails');
+ $this->db->sql_freeresult($result);
+
+ if ($nb_missing_thumbnails === 0)
+ {
+ $io->warning($this->user->lang('CLI_THUMBNAIL_NOTHING_TO_DELETE'));
+ return 0;
+ }
+
+ $sql = 'SELECT attach_id, physical_filename, extension, real_filename, mimetype
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE thumbnail = 1';
+ $result = $this->db->sql_query($sql);
+
+ $progress = $this->create_progress_bar($nb_missing_thumbnails, $io, $output);
+
+ $progress->setMessage($this->user->lang('CLI_THUMBNAIL_DELETING'));
+
+ $progress->start();
+
+ $thumbnail_deleted = array();
+ $return = 0;
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $thumbnail_path = $this->phpbb_root_path . $this->config['upload_path'] . '/thumb_' . $row['physical_filename'];
+
+ if (@unlink($thumbnail_path))
+ {
+ $thumbnail_deleted[] = $row['attach_id'];
+
+ if (count($thumbnail_deleted) === 250)
+ {
+ $this->commit_changes($thumbnail_deleted);
+ $thumbnail_deleted = array();
+ }
+
+ $progress->setMessage($this->user->lang('CLI_THUMBNAIL_DELETED', $row['real_filename'], $row['physical_filename']));
+ }
+ else
+ {
+ $return = 1;
+ $progress->setMessage('<error>' . $this->user->lang('CLI_THUMBNAIL_SKIPPED', $row['real_filename'], $row['physical_filename']) . '</error>');
+ }
+
+ $progress->advance();
+ }
+ $this->db->sql_freeresult($result);
+
+ if (!empty($thumbnail_deleted))
+ {
+ $this->commit_changes($thumbnail_deleted);
+ }
+
+ $progress->finish();
+
+ $io->newLine(2);
+ $io->success($this->user->lang('CLI_THUMBNAIL_DELETING_DONE'));
+
+ return $return;
+ }
+
+ /**
+ * Commits the changes to the database
+ *
+ * @param array $thumbnail_deleted
+ */
+ protected function commit_changes(array $thumbnail_deleted)
+ {
+ $sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
+ SET thumbnail = 0
+ WHERE ' . $this->db->sql_in_set('attach_id', $thumbnail_deleted);
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/console/command/thumbnail/generate.php b/phpBB/phpbb/console/command/thumbnail/generate.php
new file mode 100644
index 0000000000..1f6582b17b
--- /dev/null
+++ b/phpBB/phpbb/console/command/thumbnail/generate.php
@@ -0,0 +1,186 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\console\command\thumbnail;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class generate extends \phpbb\console\command\command
+{
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\cache\service
+ */
+ protected $cache;
+
+ /**
+ * phpBB root path
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * PHP extension.
+ *
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \config\config $config The config
+ * @param \phpbb\user $user The user object (used to get language information)
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param \phpbb\cache\service $cache The cache service
+ * @param string $phpbb_root_path Root path
+ * @param string $php_ext PHP extension
+ */
+ public function __construct(\phpbb\config\config $config, \phpbb\user $user, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $phpbb_root_path, $php_ext)
+ {
+ $this->config = $config;
+ $this->db = $db;
+ $this->cache = $cache;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ parent::__construct($user);
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('thumbnail:generate')
+ ->setDescription($this->user->lang('CLI_DESCRIPTION_THUMBNAIL_GENERATE'))
+ ;
+ }
+
+ /**
+ * Executes the command thumbnail:generate.
+ *
+ * Generate a thumbnail for all attachments which need one and don't have it yet.
+ *
+ * @param InputInterface $input The input stream used to get the argument and verboe option.
+ * @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
+ *
+ * @return int 0.
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $io->section($this->user->lang('CLI_THUMBNAIL_GENERATING'));
+
+ $sql = 'SELECT COUNT(*) AS nb_missing_thumbnails
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE thumbnail = 0';
+ $result = $this->db->sql_query($sql);
+ $nb_missing_thumbnails = (int) $this->db->sql_fetchfield('nb_missing_thumbnails');
+ $this->db->sql_freeresult($result);
+
+ if ($nb_missing_thumbnails === 0)
+ {
+ $io->warning($this->user->lang('CLI_THUMBNAIL_NOTHING_TO_GENERATE'));
+ return 0;
+ }
+
+ $extensions = $this->cache->obtain_attach_extensions(true);
+
+ $sql = 'SELECT attach_id, physical_filename, extension, real_filename, mimetype
+ FROM ' . ATTACHMENTS_TABLE . '
+ WHERE thumbnail = 0';
+ $result = $this->db->sql_query($sql);
+
+ if (!function_exists('create_thumbnail'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_posting.' . $this->php_ext);
+ }
+
+ $progress = $this->create_progress_bar($nb_missing_thumbnails, $io, $output);
+
+ $progress->setMessage($this->user->lang('CLI_THUMBNAIL_GENERATING'));
+
+ $progress->start();
+
+ $thumbnail_created = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (isset($extensions[$row['extension']]['display_cat']) && $extensions[$row['extension']]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE)
+ {
+ $source = $this->phpbb_root_path . $this->config['upload_path'] . '/' . $row['physical_filename'];
+ $destination = $this->phpbb_root_path . $this->config['upload_path'] . '/thumb_' . $row['physical_filename'];
+
+ if (create_thumbnail($source, $destination, $row['mimetype']))
+ {
+ $thumbnail_created[] = (int) $row['attach_id'];
+
+ if (count($thumbnail_created) === 250)
+ {
+ $this->commit_changes($thumbnail_created);
+ $thumbnail_created = array();
+ }
+
+ $progress->setMessage($this->user->lang('CLI_THUMBNAIL_GENERATED', $row['real_filename'], $row['physical_filename']));
+ }
+ else
+ {
+ $progress->setMessage('<info>' . $this->user->lang('CLI_THUMBNAIL_SKIPPED', $row['real_filename'], $row['physical_filename']) . '</info>');
+ }
+ }
+
+ $progress->advance();
+ }
+ $this->db->sql_freeresult($result);
+
+ if (!empty($thumbnail_created))
+ {
+ $this->commit_changes($thumbnail_created);
+ }
+
+ $progress->finish();
+
+ $io->newLine(2);
+ $io->success($this->user->lang('CLI_THUMBNAIL_GENERATING_DONE'));
+
+ return 0;
+ }
+
+ /**
+ * Commits the changes to the database
+ *
+ * @param array $thumbnail_created
+ */
+ protected function commit_changes(array $thumbnail_created)
+ {
+ $sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
+ SET thumbnail = 1
+ WHERE ' . $this->db->sql_in_set('attach_id', $thumbnail_created);
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/console/command/thumbnail/recreate.php b/phpBB/phpbb/console/command/thumbnail/recreate.php
new file mode 100644
index 0000000000..382da290bf
--- /dev/null
+++ b/phpBB/phpbb/console/command/thumbnail/recreate.php
@@ -0,0 +1,72 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+namespace phpbb\console\command\thumbnail;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class recreate extends \phpbb\console\command\command
+{
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('thumbnail:recreate')
+ ->setDescription($this->user->lang('CLI_DESCRIPTION_THUMBNAIL_RECREATE'))
+ ;
+ }
+
+ /**
+ * Executes the command thumbnail:recreate.
+ *
+ * This command is a "macro" to execute thumbnail:delete and then thumbnail:generate.
+ *
+ * @param InputInterface $input The input stream used to get the argument and verboe option.
+ * @param OutputInterface $output The output stream, used for printing verbose-mode and error information.
+ *
+ * @return int 0 if all is ok, 1 if a thumbnail couldn't be deleted.
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $parameters = array(
+ 'command' => 'thumbnail:delete'
+ );
+
+ if ($input->getOption('verbose'))
+ {
+ $parameters['-' . str_repeat('v', $output->getVerbosity() - 1)] = true;
+ }
+
+ $this->getApplication()->setAutoExit(false);
+
+ $input_delete = new ArrayInput($parameters);
+ $return = $this->getApplication()->run($input_delete, $output);
+
+ if ($return === 0)
+ {
+ $parameters['command'] = 'thumbnail:generate';
+
+ $input_create = new ArrayInput($parameters);
+ $return = $this->getApplication()->run($input_create, $output);
+ }
+
+ $this->getApplication()->setAutoExit(true);
+
+ return $return;
+ }
+}
diff --git a/phpBB/phpbb/console/command/update/check.php b/phpBB/phpbb/console/command/update/check.php
new file mode 100644
index 0000000000..9ced651e8b
--- /dev/null
+++ b/phpBB/phpbb/console/command/update/check.php
@@ -0,0 +1,331 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\console\command\update;
+
+use phpbb\config\config;
+use phpbb\exception\exception_interface;
+use phpbb\language\language;
+use phpbb\user;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class check extends \phpbb\console\command\command
+{
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerBuilder */
+ protected $phpbb_container;
+ /**
+ * @var language
+ */
+ private $language;
+
+ /**
+ * Construct method
+ */
+ public function __construct(user $user, config $config, ContainerInterface $phpbb_container, language $language)
+ {
+ $this->config = $config;
+ $this->phpbb_container = $phpbb_container;
+ $this->language = $language;
+
+ $this->language->add_lang(array('acp/common', 'acp/extensions'));
+
+ parent::__construct($user);
+ }
+
+ /**
+ * Configures the service.
+ *
+ * Sets the name and description of the command.
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('update:check')
+ ->setDescription($this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK'))
+ ->addArgument('ext-name', InputArgument::OPTIONAL, $this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK_ARGUMENT_1'))
+ ->addOption('stability', null, InputOption::VALUE_REQUIRED, $this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK_OPTION_STABILITY'))
+ ->addOption('cache', 'c', InputOption::VALUE_NONE, $this->language->lang('CLI_DESCRIPTION_UPDATE_CHECK_OPTION_CACHE'))
+ ;
+ }
+
+ /**
+ * Executes the command.
+ *
+ * Checks if an update is available.
+ * If at least one is available, a message is printed and if verbose mode is set the list of possible updates is printed.
+ * If their is none, nothing is printed unless verbose mode is set.
+ *
+ * @param InputInterface $input Input stream, used to get the options.
+ * @param OutputInterface $output Output stream, used to print messages.
+ * @return int 0 if the board is up to date, 1 if it is not and 2 if an error occured.
+ * @throws \RuntimeException
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $recheck = true;
+ if ($input->getOption('cache'))
+ {
+ $recheck = false;
+ }
+
+ $stability = null;
+ if ($input->getOption('stability'))
+ {
+ $stability = $input->getOption('stability');
+ if (!($stability == 'stable') && !($stability == 'unstable'))
+ {
+ $io->error($this->language->lang('CLI_ERROR_INVALID_STABILITY', $stability));
+ return 3;
+ }
+ }
+
+ $ext_name = $input->getArgument('ext-name');
+ if ($ext_name != null)
+ {
+ if ($ext_name == 'all')
+ {
+ return $this->check_all_ext($io, $stability, $recheck);
+ }
+ else
+ {
+ return $this->check_ext($input, $io, $stability, $recheck, $ext_name);
+ }
+ }
+ else
+ {
+ return $this->check_core($input, $io, $stability, $recheck);
+ }
+ }
+
+ /**
+ * Check if a given extension is up to date
+ *
+ * @param InputInterface $input Input stream, used to get the options.
+ * @param SymfonyStyle $io IO handler, for formatted and unified IO
+ * @param string $stability Force a given stability
+ * @param bool $recheck Disallow the use of the cache
+ * @param string $ext_name The extension name
+ * @return int
+ */
+ protected function check_ext(InputInterface $input, SymfonyStyle $io, $stability, $recheck, $ext_name)
+ {
+ try
+ {
+ $ext_manager = $this->phpbb_container->get('ext.manager');
+ $md_manager = $ext_manager->create_extension_metadata_manager($ext_name);
+ $updates_available = $ext_manager->version_check($md_manager, $recheck, false, $stability);
+
+ $metadata = $md_manager->get_metadata('all');
+ if ($input->getOption('verbose'))
+ {
+ $io->title($md_manager->get_metadata('display-name'));
+
+ $io->note($this->language->lang('CURRENT_VERSION') . $this->language->lang('COLON') . ' ' . $metadata['version']);
+ }
+
+ if (!empty($updates_available))
+ {
+ if ($input->getOption('verbose'))
+ {
+ $io->caution($this->language->lang('NOT_UP_TO_DATE', $metadata['name']));
+
+ $this->display_versions($io, $updates_available);
+ }
+
+ return 1;
+ }
+ else
+ {
+ if ($input->getOption('verbose'))
+ {
+ $io->success($this->language->lang('UPDATE_NOT_NEEDED'));
+ }
+
+ return 0;
+ }
+ }
+ catch (\RuntimeException $e)
+ {
+ $io->error($this->language->lang('EXTENSION_NOT_INSTALLED', $ext_name));
+
+ return 1;
+ }
+ }
+
+ /**
+ * Check if the core is up to date
+ *
+ * @param InputInterface $input Input stream, used to get the options.
+ * @param SymfonyStyle $io IO handler, for formatted and unified IO
+ * @param string $stability Force a given stability
+ * @param bool $recheck Disallow the use of the cache
+ * @return int
+ */
+ protected function check_core(InputInterface $input, SymfonyStyle $io, $stability, $recheck)
+ {
+ $version_helper = $this->phpbb_container->get('version_helper');
+ $version_helper->force_stability($stability);
+
+ $updates_available = $version_helper->get_suggested_updates($recheck);
+
+ if ($input->getOption('verbose'))
+ {
+ $io->title('phpBB core');
+
+ $io->note( $this->language->lang('CURRENT_VERSION') . $this->language->lang('COLON') . ' ' . $this->config['version']);
+ }
+
+ if (!empty($updates_available))
+ {
+ $io->caution($this->language->lang('UPDATE_NEEDED'));
+
+ if ($input->getOption('verbose'))
+ {
+ $this->display_versions($io, $updates_available);
+ }
+
+ return 1;
+ }
+ else
+ {
+ if ($input->getOption('verbose'))
+ {
+ $io->success($this->language->lang('UPDATE_NOT_NEEDED'));
+ }
+
+ return 0;
+ }
+ }
+
+ /**
+ * Check if all the available extensions are up to date
+ *
+ * @param SymfonyStyle $io IO handler, for formatted and unified IO
+ * @param bool $recheck Disallow the use of the cache
+ * @return int
+ */
+ protected function check_all_ext(SymfonyStyle $io, $stability, $recheck)
+ {
+ /** @var \phpbb\extension\manager $ext_manager */
+ $ext_manager = $this->phpbb_container->get('ext.manager');
+
+ $rows = [];
+
+ foreach ($ext_manager->all_available() as $ext_name => $ext_path)
+ {
+ $row = [];
+ $row[] = sprintf("<info>%s</info>", $ext_name);
+ $md_manager = $ext_manager->create_extension_metadata_manager($ext_name);
+ try
+ {
+ $metadata = $md_manager->get_metadata('all');
+ if (isset($metadata['extra']['version-check']))
+ {
+ try {
+ $updates_available = $ext_manager->version_check($md_manager, $recheck, false, $stability);
+ if (!empty($updates_available))
+ {
+ $versions = array_map(function($entry)
+ {
+ return $entry['current'];
+ }, $updates_available);
+
+ $row[] = sprintf("<comment>%s</comment>", $metadata['version']);
+ $row[] = implode(', ', $versions);
+ }
+ else
+ {
+ $row[] = sprintf("<info>%s</info>", $metadata['version']);
+ $row[] = '';
+ }
+ } catch (\RuntimeException $e) {
+ $row[] = $metadata['version'];
+ $row[] = '';
+ }
+ }
+ else
+ {
+ $row[] = $metadata['version'];
+ $row[] = '';
+ }
+ }
+ catch (exception_interface $e)
+ {
+ $exception_message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ $row[] = '<error>' . $exception_message . '</error>';
+ }
+ catch (\RuntimeException $e)
+ {
+ $row[] = '<error>' . $e->getMessage() . '</error>';
+ }
+
+ $rows[] = $row;
+ }
+
+ $io->table([
+ $this->language->lang('EXTENSION_NAME'),
+ $this->language->lang('CURRENT_VERSION'),
+ $this->language->lang('LATEST_VERSION'),
+ ], $rows);
+
+ return 0;
+ }
+
+ /**
+ * Display the details of the available updates
+ *
+ * @param SymfonyStyle $io IO handler, for formatted and unified IO
+ * @param array $updates_available The list of the available updates
+ */
+ protected function display_versions(SymfonyStyle $io, $updates_available)
+ {
+ $io->section($this->language->lang('UPDATES_AVAILABLE'));
+
+ $rows = [];
+ foreach ($updates_available as $version_data)
+ {
+ $row = ['', '', ''];
+ $row[0] = $version_data['current'];
+
+ if (isset($version_data['announcement']))
+ {
+ $row[1] = $version_data['announcement'];
+ }
+
+ if (isset($version_data['download']))
+ {
+ $row[2] = $version_data['download'];
+ }
+
+ $rows[] = $row;
+ }
+
+ $io->table([
+ $this->language->lang('VERSION'),
+ $this->language->lang('ANNOUNCEMENT_TOPIC'),
+ $this->language->lang('DOWNLOAD_LATEST'),
+ ], $rows);
+ }
+}
diff --git a/phpBB/phpbb/console/command/user/activate.php b/phpBB/phpbb/console/command/user/activate.php
new file mode 100644
index 0000000000..9c85718b4c
--- /dev/null
+++ b/phpBB/phpbb/console/command/user/activate.php
@@ -0,0 +1,218 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\console\command\user;
+
+use phpbb\config\config;
+use phpbb\console\command\command;
+use phpbb\db\driver\driver_interface;
+use phpbb\language\language;
+use phpbb\log\log_interface;
+use phpbb\notification\manager;
+use phpbb\user;
+use phpbb\user_loader;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class activate extends command
+{
+ /** @var driver_interface */
+ protected $db;
+
+ /** @var config */
+ protected $config;
+
+ /** @var language */
+ protected $language;
+
+ /** @var log_interface */
+ protected $log;
+
+ /** @var manager */
+ protected $notifications;
+
+ /** @var user_loader */
+ protected $user_loader;
+
+ /**
+ * phpBB root path
+ *
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * PHP extension.
+ *
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Construct method
+ *
+ * @param user $user
+ * @param driver_interface $db
+ * @param config $config
+ * @param language $language
+ * @param log_interface $log
+ * @param manager $notifications
+ * @param user_loader $user_loader
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(user $user, driver_interface $db, config $config, language $language, log_interface $log, manager $notifications, user_loader $user_loader, $phpbb_root_path, $php_ext)
+ {
+ $this->db = $db;
+ $this->config = $config;
+ $this->language = $language;
+ $this->log = $log;
+ $this->notifications = $notifications;
+ $this->user_loader = $user_loader;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->language->add_lang('acp/users');
+ parent::__construct($user);
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('user:activate')
+ ->setDescription($this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE'))
+ ->setHelp($this->language->lang('CLI_HELP_USER_ACTIVATE'))
+ ->addArgument(
+ 'username',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_USERNAME')
+ )
+ ->addOption(
+ 'deactivate',
+ 'd',
+ InputOption::VALUE_NONE,
+ $this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_DEACTIVATE')
+ )
+ ->addOption(
+ 'send-email',
+ null,
+ InputOption::VALUE_NONE,
+ $this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_NOTIFY')
+ )
+ ;
+ }
+
+ /**
+ * Executes the command user:activate
+ *
+ * Activate (or deactivate) a user account
+ *
+ * @param InputInterface $input The input stream used to get the options
+ * @param OutputInterface $output The output stream, used to print messages
+ *
+ * @return int 0 if all is well, 1 if any errors occurred
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $name = $input->getArgument('username');
+ $mode = ($input->getOption('deactivate')) ? 'deactivate' : 'activate';
+
+ $user_id = $this->user_loader->load_user_by_username($name);
+ $user_row = $this->user_loader->get_user($user_id);
+
+ if ($user_row['user_id'] == ANONYMOUS)
+ {
+ $io->error($this->language->lang('NO_USER'));
+ return 1;
+ }
+
+ // Check if the user is already active (or inactive)
+ if ($mode == 'activate' && $user_row['user_type'] != USER_INACTIVE)
+ {
+ $io->error($this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_ACTIVE'));
+ return 1;
+ }
+ else if ($mode == 'deactivate' && $user_row['user_type'] == USER_INACTIVE)
+ {
+ $io->error($this->language->lang('CLI_DESCRIPTION_USER_ACTIVATE_INACTIVE'));
+ return 1;
+ }
+
+ // Activate the user account
+ if (!function_exists('user_active_flip'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+
+ user_active_flip($mode, $user_row['user_id']);
+
+ // Notify the user upon activation
+ if ($mode == 'activate' && $this->config['require_activation'] == USER_ACTIVATION_ADMIN)
+ {
+ $this->send_notification($user_row, $input);
+ }
+
+ // Log and display the result
+ $msg = ($mode == 'activate') ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED';
+ $log = ($mode == 'activate') ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE';
+
+ $this->log->add('admin', ANONYMOUS, '', $log, false, array($user_row['username']));
+ $this->log->add('user', ANONYMOUS, '', $log . '_USER', false, array(
+ 'reportee_id' => $user_row['user_id']
+ ));
+
+ $io->success($this->language->lang($msg));
+
+ return 0;
+ }
+
+ /**
+ * Send account activation notification to user
+ *
+ * @param array $user_row The user data array
+ * @param InputInterface $input The input stream used to get the options
+ * @return null
+ */
+ protected function send_notification($user_row, InputInterface $input)
+ {
+ $this->notifications->delete_notifications('notification.type.admin_activate_user', $user_row['user_id']);
+
+ if ($input->getOption('send-email'))
+ {
+ if (!class_exists('messenger'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
+ }
+
+ $messenger = new \messenger(false);
+ $messenger->template('admin_welcome_activated', $user_row['user_lang']);
+ $messenger->set_addresses($user_row);
+ $messenger->anti_abuse_headers($this->config, $this->user);
+ $messenger->assign_vars(array(
+ 'USERNAME' => htmlspecialchars_decode($user_row['username']))
+ );
+
+ $messenger->send(NOTIFY_EMAIL);
+ }
+ }
+}
diff --git a/phpBB/phpbb/console/command/user/add.php b/phpBB/phpbb/console/command/user/add.php
new file mode 100644
index 0000000000..c60a059251
--- /dev/null
+++ b/phpBB/phpbb/console/command/user/add.php
@@ -0,0 +1,334 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\console\command\user;
+
+use phpbb\config\config;
+use phpbb\console\command\command;
+use phpbb\db\driver\driver_interface;
+use phpbb\exception\runtime_exception;
+use phpbb\language\language;
+use phpbb\passwords\manager;
+use phpbb\user;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\Question;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class add extends command
+{
+ /** @var array Array of interactively acquired options */
+ protected $data;
+
+ /** @var driver_interface */
+ protected $db;
+
+ /** @var config */
+ protected $config;
+
+ /** @var language */
+ protected $language;
+
+ /** @var manager */
+ protected $password_manager;
+
+ /**
+ * phpBB root path
+ *
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * PHP extension.
+ *
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Construct method
+ *
+ * @param user $user
+ * @param driver_interface $db
+ * @param config $config
+ * @param language $language
+ * @param manager $password_manager
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(user $user, driver_interface $db, config $config, language $language, manager $password_manager, $phpbb_root_path, $php_ext)
+ {
+ $this->db = $db;
+ $this->config = $config;
+ $this->language = $language;
+ $this->password_manager = $password_manager;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->language->add_lang('ucp');
+ parent::__construct($user);
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('user:add')
+ ->setDescription($this->language->lang('CLI_DESCRIPTION_USER_ADD'))
+ ->setHelp($this->language->lang('CLI_HELP_USER_ADD'))
+ ->addOption(
+ 'username',
+ 'U',
+ InputOption::VALUE_REQUIRED,
+ $this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_USERNAME')
+ )
+ ->addOption(
+ 'password',
+ 'P',
+ InputOption::VALUE_REQUIRED,
+ $this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_PASSWORD')
+ )
+ ->addOption(
+ 'email',
+ 'E',
+ InputOption::VALUE_REQUIRED,
+ $this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_EMAIL')
+ )
+ ->addOption(
+ 'send-email',
+ null,
+ InputOption::VALUE_NONE,
+ $this->language->lang('CLI_DESCRIPTION_USER_ADD_OPTION_NOTIFY')
+ )
+ ;
+ }
+
+ /**
+ * Executes the command user:add
+ *
+ * Adds a new user to the database. If options are not provided, it will ask for the username, password and email.
+ * User is added to the registered user group. Language and timezone default to $config settings.
+ *
+ * @param InputInterface $input The input stream used to get the options
+ * @param OutputInterface $output The output stream, used to print messages
+ *
+ * @return int 0 if all is well, 1 if any errors occurred
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ try
+ {
+ $this->validate_user_data();
+ $group_id = $this->get_group_id();
+ }
+ catch (runtime_exception $e)
+ {
+ $io->error($e->getMessage());
+ return 1;
+ }
+
+ $user_row = array(
+ 'username' => $this->data['username'],
+ 'user_password' => $this->password_manager->hash($this->data['new_password']),
+ 'user_email' => $this->data['email'],
+ 'group_id' => $group_id,
+ 'user_timezone' => $this->config['board_timezone'],
+ 'user_lang' => $this->config['default_lang'],
+ 'user_type' => USER_NORMAL,
+ 'user_regdate' => time(),
+ );
+
+ $user_id = (int) user_add($user_row);
+
+ if (!$user_id)
+ {
+ $io->error($this->language->lang('AUTH_NO_PROFILE_CREATED'));
+ return 1;
+ }
+
+ if ($input->getOption('send-email') && $this->config['email_enable'])
+ {
+ $this->send_activation_email($user_id);
+ }
+
+ $io->success($this->language->lang('CLI_USER_ADD_SUCCESS', $this->data['username']));
+
+ return 0;
+ }
+
+ /**
+ * Interacts with the user.
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ */
+ protected function interact(InputInterface $input, OutputInterface $output)
+ {
+ $helper = $this->getHelper('question');
+
+ $this->data = array(
+ 'username' => $input->getOption('username'),
+ 'new_password' => $input->getOption('password'),
+ 'email' => $input->getOption('email'),
+ );
+
+ if (!$this->data['username'])
+ {
+ $question = new Question($this->ask_user('USERNAME'));
+ $this->data['username'] = $helper->ask($input, $output, $question);
+ }
+
+ if (!$this->data['new_password'])
+ {
+ $question = new Question($this->ask_user('PASSWORD'));
+ $question->setValidator(function ($value) use ($helper, $input, $output) {
+ $question = new Question($this->ask_user('CONFIRM_PASSWORD'));
+ $question->setHidden(true);
+ if ($helper->ask($input, $output, $question) != $value)
+ {
+ throw new runtime_exception($this->language->lang('NEW_PASSWORD_ERROR'));
+ }
+ return $value;
+ });
+ $question->setHidden(true);
+ $question->setMaxAttempts(5);
+
+ $this->data['new_password'] = $helper->ask($input, $output, $question);
+ }
+
+ if (!$this->data['email'])
+ {
+ $question = new Question($this->ask_user('EMAIL_ADDRESS'));
+ $this->data['email'] = $helper->ask($input, $output, $question);
+ }
+ }
+
+ /**
+ * Validate the submitted user data
+ *
+ * @throws runtime_exception if any data fails validation
+ * @return null
+ */
+ protected function validate_user_data()
+ {
+ if (!function_exists('validate_data'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+
+ $error = validate_data($this->data, array(
+ 'username' => array(
+ array('string', false, $this->config['min_name_chars'], $this->config['max_name_chars']),
+ array('username', '')),
+ 'new_password' => array(
+ array('string', false, $this->config['min_pass_chars'], $this->config['max_pass_chars']),
+ array('password')),
+ 'email' => array(
+ array('string', false, 6, 60),
+ array('user_email')),
+ ));
+
+ if ($error)
+ {
+ throw new runtime_exception(implode("\n", array_map(array($this->language, 'lang'), $error)));
+ }
+ }
+
+ /**
+ * Get the group id
+ *
+ * Go and find in the database the group_id corresponding to 'REGISTERED'
+ *
+ * @throws runtime_exception if the group id does not exist in database.
+ * @return null
+ */
+ protected function get_group_id()
+ {
+ $sql = 'SELECT group_id
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "'
+ AND group_type = " . GROUP_SPECIAL;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$row || !$row['group_id'])
+ {
+ throw new runtime_exception($this->language->lang('NO_GROUP'));
+ }
+
+ return $row['group_id'];
+ }
+
+ /**
+ * Send account activation email
+ *
+ * @param int $user_id The new user's id
+ * @return null
+ */
+ protected function send_activation_email($user_id)
+ {
+ switch ($this->config['require_activation'])
+ {
+ case USER_ACTIVATION_SELF:
+ $email_template = 'user_welcome_inactive';
+ $user_actkey = gen_rand_string(mt_rand(6, 10));
+ break;
+ case USER_ACTIVATION_ADMIN:
+ $email_template = 'admin_welcome_inactive';
+ $user_actkey = gen_rand_string(mt_rand(6, 10));
+ break;
+ default:
+ $email_template = 'user_welcome';
+ $user_actkey = '';
+ break;
+ }
+
+ if (!class_exists('messenger'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
+ }
+
+ $messenger = new \messenger(false);
+ $messenger->template($email_template, $this->user->lang_name);
+ $messenger->to($this->data['email'], $this->data['username']);
+ $messenger->anti_abuse_headers($this->config, $this->user);
+ $messenger->assign_vars(array(
+ 'WELCOME_MSG' => htmlspecialchars_decode($this->language->lang('WELCOME_SUBJECT', $this->config['sitename'])),
+ 'USERNAME' => htmlspecialchars_decode($this->data['username']),
+ 'PASSWORD' => htmlspecialchars_decode($this->data['new_password']),
+ 'U_ACTIVATE' => generate_board_url() . "/ucp.{$this->php_ext}?mode=activate&u=$user_id&k=$user_actkey")
+ );
+
+ $messenger->send(NOTIFY_EMAIL);
+ }
+
+ /**
+ * Helper to translate questions to the user
+ *
+ * @param string $key The language key
+ * @return string The language key translated with a colon and space appended
+ */
+ protected function ask_user($key)
+ {
+ return $this->language->lang($key) . $this->language->lang('COLON') . ' ';
+ }
+}
diff --git a/phpBB/phpbb/console/command/user/delete.php b/phpBB/phpbb/console/command/user/delete.php
new file mode 100644
index 0000000000..8593541c1a
--- /dev/null
+++ b/phpBB/phpbb/console/command/user/delete.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\console\command\user;
+
+use phpbb\console\command\command;
+use phpbb\db\driver\driver_interface;
+use phpbb\language\language;
+use phpbb\log\log_interface;
+use phpbb\user;
+use phpbb\user_loader;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class delete extends command
+{
+ /** @var driver_interface */
+ protected $db;
+
+ /** @var language */
+ protected $language;
+
+ /** @var log_interface */
+ protected $log;
+
+ /** @var user_loader */
+ protected $user_loader;
+
+ /**
+ * phpBB root path
+ *
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * PHP extension.
+ *
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Construct method
+ *
+ * @param user $user
+ * @param driver_interface $db
+ * @param language $language
+ * @param log_interface $log
+ * @param user_loader $user_loader
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(user $user, driver_interface $db, language $language, log_interface $log, user_loader $user_loader, $phpbb_root_path, $php_ext)
+ {
+ $this->db = $db;
+ $this->language = $language;
+ $this->log = $log;
+ $this->user_loader = $user_loader;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->language->add_lang('acp/users');
+ parent::__construct($user);
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('user:delete')
+ ->setDescription($this->language->lang('CLI_DESCRIPTION_USER_DELETE'))
+ ->addArgument(
+ 'username',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_DESCRIPTION_USER_DELETE_USERNAME')
+ )
+ ->addOption(
+ 'delete-posts',
+ null,
+ InputOption::VALUE_NONE,
+ $this->language->lang('CLI_DESCRIPTION_USER_DELETE_OPTION_POSTS')
+ )
+ ;
+ }
+
+ /**
+ * Executes the command user:delete
+ *
+ * Deletes a user from the database. An option to delete the user's posts
+ * is available, by default posts will be retained.
+ *
+ * @param InputInterface $input The input stream used to get the options
+ * @param OutputInterface $output The output stream, used to print messages
+ *
+ * @return int 0 if all is well, 1 if any errors occurred
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $name = $input->getArgument('username');
+ $mode = ($input->getOption('delete-posts')) ? 'remove' : 'retain';
+
+ if ($name)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $user_id = $this->user_loader->load_user_by_username($name);
+ $user_row = $this->user_loader->get_user($user_id);
+
+ if ($user_row['user_id'] == ANONYMOUS)
+ {
+ $io->error($this->language->lang('NO_USER'));
+ return 1;
+ }
+
+ if (!function_exists('user_delete'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+
+ user_delete($mode, $user_row['user_id'], $user_row['username']);
+
+ $this->log->add('admin', ANONYMOUS, '', 'LOG_USER_DELETED', false, array($user_row['username']));
+
+ $io->success($this->language->lang('USER_DELETED'));
+ }
+
+ return 0;
+ }
+
+ /**
+ * Interacts with the user.
+ * Confirm they really want to delete the account...last chance!
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ */
+ protected function interact(InputInterface $input, OutputInterface $output)
+ {
+ $helper = $this->getHelper('question');
+
+ $question = new ConfirmationQuestion(
+ $this->language->lang('CLI_USER_DELETE_CONFIRM', $input->getArgument('username')),
+ false
+ );
+
+ if (!$helper->ask($input, $output, $question))
+ {
+ $input->setArgument('username', false);
+ }
+ }
+}
diff --git a/phpBB/phpbb/console/command/user/reclean.php b/phpBB/phpbb/console/command/user/reclean.php
new file mode 100644
index 0000000000..1a89f13382
--- /dev/null
+++ b/phpBB/phpbb/console/command/user/reclean.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\console\command\user;
+
+use phpbb\console\command\command;
+use phpbb\db\driver\driver_interface;
+use phpbb\language\language;
+use phpbb\user;
+use Symfony\Component\Console\Helper\ProgressBar;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class reclean extends command
+{
+ /** @var driver_interface */
+ protected $db;
+
+ /** @var language */
+ protected $language;
+
+ /** @var int A count of the number of re-cleaned user names */
+ protected $processed;
+
+ /** @var ProgressBar */
+ protected $progress;
+
+ /**
+ * Construct method
+ *
+ * @param user $user
+ * @param driver_interface $db
+ * @param language $language
+ */
+ public function __construct(user $user, driver_interface $db, language $language)
+ {
+ $this->db = $db;
+ $this->language = $language;
+
+ parent::__construct($user);
+ }
+
+ /**
+ * Sets the command name and description
+ *
+ * @return null
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('user:reclean')
+ ->setDescription($this->language->lang('CLI_DESCRIPTION_USER_RECLEAN'))
+ ->setHelp($this->language->lang('CLI_HELP_USER_RECLEAN'))
+ ;
+ }
+
+ /**
+ * Executes the command user:reclean
+ *
+ * Cleans user names that are unclean.
+ *
+ * @param InputInterface $input The input stream used to get the options
+ * @param OutputInterface $output The output stream, used to print messages
+ *
+ * @return int 0 if all is well, 1 if any errors occurred
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $io = new SymfonyStyle($input, $output);
+
+ $io->section($this->language->lang('CLI_USER_RECLEAN_START'));
+
+ $this->processed = 0;
+
+ $this->progress = $this->create_progress_bar($this->get_count(), $io, $output);
+ $this->progress->setMessage($this->language->lang('CLI_USER_RECLEAN_START'));
+ $this->progress->start();
+
+ $stage = 0;
+ while ($stage !== true)
+ {
+ $stage = $this->reclean_usernames($stage);
+ }
+
+ $this->progress->finish();
+
+ $io->newLine(2);
+ $io->success($this->language->lang('CLI_USER_RECLEAN_DONE', $this->processed));
+
+ return 0;
+ }
+
+ /**
+ * Re-clean user names
+ * Only user names that are unclean will be re-cleaned
+ *
+ * @param int $start An offset index
+ * @return bool|int Return the next offset index or true if all records have been processed.
+ */
+ protected function reclean_usernames($start = 0)
+ {
+ $limit = 500;
+ $i = 0;
+
+ $this->db->sql_transaction('begin');
+
+ $sql = 'SELECT user_id, username, username_clean FROM ' . USERS_TABLE;
+ $result = $this->db->sql_query_limit($sql, $limit, $start);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $i++;
+ $username_clean = $this->db->sql_escape(utf8_clean_string($row['username']));
+
+ if ($username_clean != $row['username_clean'])
+ {
+ $sql = 'UPDATE ' . USERS_TABLE . "
+ SET username_clean = '$username_clean'
+ WHERE user_id = {$row['user_id']}";
+ $this->db->sql_query($sql);
+
+ $this->processed++;
+ }
+
+ $this->progress->advance();
+ }
+ $this->db->sql_freeresult($result);
+
+ $this->db->sql_transaction('commit');
+
+ return ($i < $limit) ? true : $start + $i;
+ }
+
+ /**
+ * Get the count of users in the database
+ *
+ * @return int
+ */
+ protected function get_count()
+ {
+ $sql = 'SELECT COUNT(user_id) AS count FROM ' . USERS_TABLE;
+ $result = $this->db->sql_query($sql);
+ $count = (int) $this->db->sql_fetchfield('count');
+ $this->db->sql_freeresult($result);
+
+ return $count;
+ }
+}
diff --git a/phpBB/phpbb/console/exception_subscriber.php b/phpBB/phpbb/console/exception_subscriber.php
new file mode 100644
index 0000000000..b240993203
--- /dev/null
+++ b/phpBB/phpbb/console/exception_subscriber.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\console;
+
+use phpbb\exception\exception_interface;
+use Symfony\Component\Console\ConsoleEvents;
+use Symfony\Component\Console\Event\ConsoleExceptionEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+class exception_subscriber implements EventSubscriberInterface
+{
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * Construct method
+ *
+ * @param \phpbb\language\language $language Language object
+ */
+ public function __construct(\phpbb\language\language $language)
+ {
+ $this->language = $language;
+ }
+
+ /**
+ * This listener is run when the ConsoleEvents::EXCEPTION event is triggered.
+ * It translate the exception message. If din debug mode the original exception is embedded.
+ *
+ * @param ConsoleExceptionEvent $event
+ */
+ public function on_exception(ConsoleExceptionEvent $event)
+ {
+ $original_exception = $event->getException();
+
+ if ($original_exception instanceof exception_interface)
+ {
+ $parameters = array_merge(array($original_exception->getMessage()), $original_exception->get_parameters());
+ $message = call_user_func_array(array($this->language, 'lang'), $parameters);
+
+ $exception = new \RuntimeException($message , $original_exception->getCode(), $original_exception);
+
+ $event->setException($exception);
+ }
+ }
+
+ static public function getSubscribedEvents()
+ {
+ return array(
+ ConsoleEvents::EXCEPTION => 'on_exception',
+ );
+ }
+}
diff --git a/phpBB/phpbb/content_visibility.php b/phpBB/phpbb/content_visibility.php
index bf7dc2c703..f023e0742c 100644
--- a/phpBB/phpbb/content_visibility.php
+++ b/phpBB/phpbb/content_visibility.php
@@ -131,6 +131,42 @@ class content_visibility
return (int) $data[$mode . '_approved'] + (int) $data[$mode . '_unapproved'] + (int) $data[$mode . '_softdeleted'];
}
+
+ /**
+ * Check topic/post visibility for a given forum ID
+ *
+ * Note: Read permissions are not checked.
+ *
+ * @param $mode string Either "topic" or "post"
+ * @param $forum_id int The forum id is used for permission checks
+ * @param $data array Array with item information to check visibility
+ * @return bool True if the item is visible, false if not
+ */
+ public function is_visible($mode, $forum_id, $data)
+ {
+ $is_visible = $this->auth->acl_get('m_approve', $forum_id) || $data[$mode . '_visibility'] == ITEM_APPROVED;
+
+ /**
+ * Allow changing the result of calling is_visible
+ *
+ * @event core.phpbb_content_visibility_is_visible
+ * @var bool is_visible Default visibility condition, to be modified by extensions if needed.
+ * @var string mode Either "topic" or "post"
+ * @var int forum_id Forum id of the current item
+ * @var array data Array of item information
+ * @since 3.2.2-RC1
+ */
+ $vars = array(
+ 'is_visible',
+ 'mode',
+ 'forum_id',
+ 'data',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.phpbb_content_visibility_is_visible', compact($vars)));
+
+ return $is_visible;
+ }
+
/**
* Create topic/post visibility SQL for a given forum ID
*
@@ -176,10 +212,14 @@ class content_visibility
if ($this->auth->acl_get('m_approve', $forum_id))
{
- return $where_sql . '1 = 1';
+ $where_sql .= '1 = 1';
+ }
+ else
+ {
+ $where_sql .= $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
}
- return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
+ return '(' . $where_sql . ')';
}
/**
@@ -195,16 +235,21 @@ class content_visibility
*/
public function get_forums_visibility_sql($mode, $forum_ids = array(), $table_alias = '')
{
- $where_sql = '(';
+ $where_sql = '';
- $approve_forums = array_intersect($forum_ids, array_keys($this->auth->acl_getf('m_approve', true)));
+ $approve_forums = array_keys($this->auth->acl_getf('m_approve', true));
+ if (!empty($forum_ids) && !empty($approve_forums))
+ {
+ $approve_forums = array_intersect($forum_ids, $approve_forums);
+ $forum_ids = array_diff($forum_ids, $approve_forums);
+ }
$get_forums_visibility_sql_overwrite = false;
/**
* Allow changing the result of calling get_forums_visibility_sql
*
* @event core.phpbb_content_visibility_get_forums_visibility_before
- * @var string where_sql The action the user tried to execute
+ * @var string where_sql Extra visibility conditions. It must end with either an SQL "AND" or an "OR"
* @var string mode Either "topic" or "post" depending on the query this is being used in
* @var array forum_ids Array of forum ids which the posts/topics are limited to
* @var string table_alias Table alias to prefix in SQL queries
@@ -229,33 +274,13 @@ class content_visibility
return $get_forums_visibility_sql_overwrite;
}
- if (sizeof($approve_forums))
- {
- // Remove moderator forums from the rest
- $forum_ids = array_diff($forum_ids, $approve_forums);
-
- if (!sizeof($forum_ids))
- {
- // The user can see all posts/topics in all specified forums
- return $where_sql . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums) . ')';
- }
- else
- {
- // Moderator can view all posts/topics in some forums
- $where_sql .= $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums) . ' OR ';
- }
- }
- else
- {
- // The user is just a normal user
- return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . '
- AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . ')';
- }
-
+ // Moderator can view all posts/topics in the moderated forums
+ $where_sql .= '(' . $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums, false, true) . ' OR ';
+ // Normal user can view approved items only
$where_sql .= '(' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . '
- AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids) . '))';
+ AND ' . $this->db->sql_in_set($table_alias . 'forum_id', $forum_ids, false, true) . '))';
- return $where_sql;
+ return '(' . $where_sql . ')';
}
/**
@@ -281,12 +306,12 @@ class content_visibility
* Allow changing the result of calling get_global_visibility_sql
*
* @event core.phpbb_content_visibility_get_global_visibility_before
- * @var array where_sqls The action the user tried to execute
+ * @var array where_sqls Array of extra visibility conditions. Will be joined by imploding with "OR".
* @var string mode Either "topic" or "post" depending on the query this is being used in
* @var array exclude_forum_ids Array of forum ids the current user doesn't have access to
* @var string table_alias Table alias to prefix in SQL queries
* @var array approve_forums Array of forums where the user has m_approve permissions
- * @var string visibility_sql_overwrite Forces the function to return an implosion of where_sqls (joined by "OR")
+ * @var string visibility_sql_overwrite If not empty, forces the function to return visibility_sql_overwrite after executing the event
* @since 3.1.3-RC1
*/
$vars = array(
@@ -304,24 +329,17 @@ class content_visibility
return $visibility_sql_overwrite;
}
- if (sizeof($exclude_forum_ids))
- {
- $where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true) . '
- AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')';
- }
- else
- {
- $where_sqls[] = $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
- }
+ // Include approved items in all forums but the excluded
+ $where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true, true) . '
+ AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')';
- if (sizeof($approve_forums))
+ // If user has moderator permissions, add everything in the moderated forums
+ if (count($approve_forums))
{
$where_sqls[] = $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums);
- return '(' . implode(' OR ', $where_sqls) . ')';
}
- // There is only one element, so we just return that one
- return $where_sqls[0];
+ return '(' . implode(' OR ', $where_sqls) . ')';
}
/**
@@ -437,12 +455,13 @@ class content_visibility
* @var int topic_id Topic of the post IDs to be modified.
* @var int forum_id Forum ID that the topic_id resides in.
* @var int user_id User ID doing this action.
- * @var int timestamp Timestamp of this action.
+ * @var int time Timestamp of this action.
* @var string reason Reason specified by the user for this change.
* @var bool is_starter Are we changing the topic's starter?
* @var bool is_latest Are we changing the topic's latest post?
* @var array data The data array for this action.
* @since 3.1.10-RC1
+ * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
*/
$vars = array(
'visibility',
@@ -450,7 +469,7 @@ class content_visibility
'topic_id',
'forum_id',
'user_id',
- 'timestamp',
+ 'time',
'reason',
'is_starter',
'is_latest',
@@ -565,7 +584,7 @@ class content_visibility
$sql_ary[$recipient_field] = " + $count_increase";
}
- if (sizeof($sql_ary))
+ if (count($sql_ary))
{
$forum_sql = array();
@@ -622,12 +641,13 @@ class content_visibility
* @var int topic_id Topic of the post IDs to be modified.
* @var int forum_id Forum ID that the topic_id resides in.
* @var int user_id User ID doing this action.
- * @var int timestamp Timestamp of this action.
+ * @var int time Timestamp of this action.
* @var string reason Reason specified by the user for this change.
* @var bool is_starter Are we changing the topic's starter?
* @var bool is_latest Are we changing the topic's latest post?
* @var array data The data array for this action.
* @since 3.1.10-RC1
+ * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
*/
$vars = array(
'visibility',
@@ -635,7 +655,7 @@ class content_visibility
'topic_id',
'forum_id',
'user_id',
- 'timestamp',
+ 'time',
'reason',
'is_starter',
'is_latest',
@@ -709,18 +729,19 @@ class content_visibility
* @var int topic_id Topic of the post IDs to be modified.
* @var int forum_id Forum ID that the topic_id resides in.
* @var int user_id User ID doing this action.
- * @var int timestamp Timestamp of this action.
+ * @var int time Timestamp of this action.
* @var string reason Reason specified by the user for this change.
* @var bool force_update_all Force an update on all posts within the topic, regardless of their current approval state.
* @var array data The data array for this action.
* @since 3.1.10-RC1
+ * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
*/
$vars = array(
'visibility',
'topic_id',
'forum_id',
'user_id',
- 'timestamp',
+ 'time',
'reason',
'force_update_all',
'data',
@@ -758,18 +779,19 @@ class content_visibility
* @var int topic_id Topic of the post IDs to be modified.
* @var int forum_id Forum ID that the topic_id resides in.
* @var int user_id User ID doing this action.
- * @var int timestamp Timestamp of this action.
+ * @var int time Timestamp of this action.
* @var string reason Reason specified by the user for this change.
* @var bool force_update_all Force an update on all posts within the topic, regardless of their current approval state.
* @var array data The data array for this action.
* @since 3.1.10-RC1
+ * @changed 3.2.2-RC1 Use time instead of non-existent timestamp
*/
$vars = array(
'visibility',
'topic_id',
'forum_id',
'user_id',
- 'timestamp',
+ 'time',
'reason',
'force_update_all',
'data',
diff --git a/phpBB/phpbb/controller/exception.php b/phpBB/phpbb/controller/exception.php
index 437558b06a..e227c7c37b 100644
--- a/phpBB/phpbb/controller/exception.php
+++ b/phpBB/phpbb/controller/exception.php
@@ -16,6 +16,6 @@ namespace phpbb\controller;
/**
* Controller exception class
*/
-class exception extends \RuntimeException
+class exception extends \phpbb\exception\runtime_exception
{
}
diff --git a/phpBB/phpbb/controller/helper.php b/phpBB/phpbb/controller/helper.php
index ce6bfba981..664b4f4e0f 100644
--- a/phpBB/phpbb/controller/helper.php
+++ b/phpBB/phpbb/controller/helper.php
@@ -15,9 +15,7 @@ namespace phpbb\controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
-use Symfony\Component\Routing\RequestContext;
/**
* Controller helper class, contains methods that do things for controllers
@@ -49,49 +47,28 @@ class helper
protected $request;
/**
- * @var \phpbb\filesystem The filesystem object
- */
- protected $filesystem;
-
- /**
- * phpBB root path
- * @var string
- */
- protected $phpbb_root_path;
-
- /**
- * PHP file extension
- * @var string
- */
- protected $php_ext;
+ * @var \phpbb\routing\helper
+ */
+ protected $routing_helper;
/**
- * Constructor
- *
- * @param \phpbb\template\template $template Template object
- * @param \phpbb\user $user User object
- * @param \phpbb\config\config $config Config object
+ * Constructor
*
- * @param \phpbb\controller\provider $provider Path provider
- * @param \phpbb\extension\manager $manager Extension manager object
- * @param \phpbb\symfony_request $symfony_request Symfony Request object
- * @param \phpbb\request\request_interface $request phpBB request object
- * @param \phpbb\filesystem $filesystem The filesystem object
- * @param string $phpbb_root_path phpBB root path
- * @param string $php_ext PHP file extension
- */
- public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext)
+ * @param \phpbb\template\template $template Template object
+ * @param \phpbb\user $user User object
+ * @param \phpbb\config\config $config Config object
+ * @param \phpbb\symfony_request $symfony_request Symfony Request object
+ * @param \phpbb\request\request_interface $request phpBB request object
+ * @param \phpbb\routing\helper $routing_helper Helper to generate the routes
+ */
+ public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\routing\helper $routing_helper)
{
$this->template = $template;
$this->user = $user;
$this->config = $config;
$this->symfony_request = $symfony_request;
$this->request = $request;
- $this->filesystem = $filesystem;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $provider->find_routing_files($manager->get_finder());
- $this->route_collection = $provider->find($phpbb_root_path)->get_routes();
+ $this->routing_helper = $routing_helper;
}
/**
@@ -134,70 +111,7 @@ class helper
*/
public function route($route, array $params = array(), $is_amp = true, $session_id = false, $reference_type = UrlGeneratorInterface::ABSOLUTE_PATH)
{
- $anchor = '';
- if (isset($params['#']))
- {
- $anchor = '#' . $params['#'];
- unset($params['#']);
- }
-
- $context = new RequestContext();
- $context->fromRequest($this->symfony_request);
-
- if ($this->config['force_server_vars'])
- {
- $context->setHost($this->config['server_name']);
- $context->setScheme(substr($this->config['server_protocol'], 0, -3));
- $context->setHttpPort($this->config['server_port']);
- $context->setHttpsPort($this->config['server_port']);
- $context->setBaseUrl(rtrim($this->config['script_path'], '/'));
- }
-
- $script_name = $this->symfony_request->getScriptName();
- $page_name = substr($script_name, -1, 1) == '/' ? '' : utf8_basename($script_name);
-
- $base_url = $context->getBaseUrl();
-
- // Append page name if base URL does not contain it
- if (!empty($page_name) && strpos($base_url, '/' . $page_name) === false)
- {
- $base_url .= '/' . $page_name;
- }
-
- // If enable_mod_rewrite is false we need to replace the current front-end by app.php, otherwise we need to remove it.
- $base_url = str_replace('/' . $page_name, empty($this->config['enable_mod_rewrite']) ? '/app.' . $this->php_ext : '', $base_url);
-
- // We need to update the base url to move to the directory of the app.php file if the current script is not app.php
- if ($page_name !== 'app.php' && !$this->config['force_server_vars'])
- {
- if (empty($this->config['enable_mod_rewrite']))
- {
- $base_url = str_replace('/app.' . $this->php_ext, '/' . $this->phpbb_root_path . 'app.' . $this->php_ext, $base_url);
- }
- else
- {
- $base_url .= preg_replace(get_preg_expression('path_remove_dot_trailing_slash'), '$2', $this->phpbb_root_path);
- }
- }
-
- $base_url = $this->request->escape($this->filesystem->clean_path($base_url), true);
-
- $context->setBaseUrl($base_url);
-
- $url_generator = new UrlGenerator($this->route_collection, $context);
- $route_url = $url_generator->generate($route, $params, $reference_type);
-
- if ($is_amp)
- {
- $route_url = str_replace(array('&amp;', '&'), array('&', '&amp;'), $route_url);
- }
-
- if ($reference_type === UrlGeneratorInterface::RELATIVE_PATH && empty($this->config['enable_mod_rewrite']))
- {
- $route_url = 'app.' . $this->php_ext . '/' . $route_url;
- }
-
- return append_sid($route_url . $anchor, false, $is_amp, $session_id, true);
+ return $this->routing_helper->route($route, $params, $is_amp, $session_id, $reference_type);
}
/**
@@ -256,6 +170,20 @@ class helper
}
/**
+ * Assigns automatic refresh time meta tag in template
+ *
+ * @param int $time time in seconds, when redirection should occur
+ * @param string $url the URL where the user should be redirected
+ * @return null
+ */
+ public function assign_meta_refresh_var($time, $url)
+ {
+ $this->template->assign_vars(array(
+ 'META' => '<meta http-equiv="refresh" content="' . $time . '; url=' . $url . '" />',
+ ));
+ }
+
+ /**
* Return the current url
*
* @return string
diff --git a/phpBB/phpbb/controller/provider.php b/phpBB/phpbb/controller/provider.php
deleted file mode 100644
index 7e26848290..0000000000
--- a/phpBB/phpbb/controller/provider.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\controller;
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Loader\YamlFileLoader;
-use Symfony\Component\Config\FileLocator;
-
-/**
-* Controller interface
-*/
-class provider
-{
- /**
- * YAML file(s) containing route information
- * @var array
- */
- protected $routing_files;
-
- /**
- * Collection of the routes in phpBB and all found extensions
- * @var RouteCollection
- */
- protected $routes;
-
- /**
- * Construct method
- *
- * @param array $routing_files Array of strings containing paths
- * to YAML files holding route information
- */
- public function __construct($routing_files = array())
- {
- $this->routing_files = $routing_files;
- }
-
- /**
- * Find the list of routing files
- *
- * @param \phpbb\finder $finder
- * @return null
- */
- public function find_routing_files(\phpbb\finder $finder)
- {
- // We hardcode the path to the core config directory
- // because the finder cannot find it
- $this->routing_files = array_merge($this->routing_files, array('config/routing.yml'), array_keys($finder
- ->directory('/config')
- ->suffix('routing.yml')
- ->find()
- ));
- }
-
- /**
- * Find a list of controllers
- *
- * @param string $base_path Base path to prepend to file paths
- * @return provider
- */
- public function find($base_path = '')
- {
- $this->routes = new RouteCollection;
- foreach ($this->routing_files as $file_path)
- {
- $loader = new YamlFileLoader(new FileLocator(phpbb_realpath($base_path)));
- $this->routes->addCollection($loader->load($file_path));
- }
-
- return $this;
- }
-
- /**
- * Get the list of routes
- *
- * @return RouteCollection Get the route collection
- */
- public function get_routes()
- {
- return $this->routes;
- }
-}
diff --git a/phpBB/phpbb/controller/resolver.php b/phpBB/phpbb/controller/resolver.php
index 948a6a218c..f8dffc12de 100644
--- a/phpBB/phpbb/controller/resolver.php
+++ b/phpBB/phpbb/controller/resolver.php
@@ -23,12 +23,6 @@ use Symfony\Component\HttpFoundation\Request;
class resolver implements ControllerResolverInterface
{
/**
- * User object
- * @var \phpbb\user
- */
- protected $user;
-
- /**
* ContainerInterface object
* @var ContainerInterface
*/
@@ -55,14 +49,12 @@ class resolver implements ControllerResolverInterface
/**
* Construct method
*
- * @param \phpbb\user $user User Object
* @param ContainerInterface $container ContainerInterface object
* @param string $phpbb_root_path Relative path to phpBB root
* @param \phpbb\template\template $template
*/
- public function __construct(\phpbb\user $user, ContainerInterface $container, $phpbb_root_path, \phpbb\template\template $template = null)
+ public function __construct(ContainerInterface $container, $phpbb_root_path, \phpbb\template\template $template = null)
{
- $this->user = $user;
$this->container = $container;
$this->template = $template;
$this->type_cast_helper = new \phpbb\request\type_cast_helper();
@@ -82,20 +74,20 @@ class resolver implements ControllerResolverInterface
if (!$controller)
{
- throw new \phpbb\controller\exception($this->user->lang['CONTROLLER_NOT_SPECIFIED']);
+ throw new \phpbb\controller\exception('CONTROLLER_NOT_SPECIFIED');
}
// Require a method name along with the service name
if (stripos($controller, ':') === false)
{
- throw new \phpbb\controller\exception($this->user->lang['CONTROLLER_METHOD_NOT_SPECIFIED']);
+ throw new \phpbb\controller\exception('CONTROLLER_METHOD_NOT_SPECIFIED');
}
list($service, $method) = explode(':', $controller);
if (!$this->container->has($service))
{
- throw new \phpbb\controller\exception($this->user->lang('CONTROLLER_SERVICE_UNDEFINED', $service));
+ throw new \phpbb\controller\exception('CONTROLLER_SERVICE_UNDEFINED', array($service));
}
$controller_object = $this->container->get($service);
@@ -134,9 +126,21 @@ class resolver implements ControllerResolverInterface
*/
public function getArguments(Request $request, $controller)
{
- // At this point, $controller contains the object and method name
- list($object, $method) = $controller;
- $mirror = new \ReflectionMethod($object, $method);
+ // At this point, $controller should be a callable
+ if (is_array($controller))
+ {
+ list($object, $method) = $controller;
+ $mirror = new \ReflectionMethod($object, $method);
+ }
+ else if (is_object($controller) && !$controller instanceof \Closure)
+ {
+ $mirror = new \ReflectionObject($controller);
+ $mirror = $mirror->getMethod('__invoke');
+ }
+ else
+ {
+ $mirror = new \ReflectionFunction($controller);
+ }
$arguments = array();
$parameters = $mirror->getParameters();
@@ -166,7 +170,7 @@ class resolver implements ControllerResolverInterface
}
else
{
- throw new \phpbb\controller\exception($this->user->lang('CONTROLLER_ARGUMENT_VALUE_MISSING', $param->getPosition() + 1, get_class($object) . ':' . $method, $param->name));
+ throw new \phpbb\controller\exception('CONTROLLER_ARGUMENT_VALUE_MISSING', array($param->getPosition() + 1, get_class($object) . ':' . $method, $param->name));
}
}
diff --git a/phpBB/phpbb/cron/task/core/prune_all_forums.php b/phpBB/phpbb/cron/task/core/prune_all_forums.php
index b47939ccbe..5005f5b894 100644
--- a/phpBB/phpbb/cron/task/core/prune_all_forums.php
+++ b/phpBB/phpbb/cron/task/core/prune_all_forums.php
@@ -55,21 +55,26 @@ class prune_all_forums extends \phpbb\cron\task\base
include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
}
- $sql = 'SELECT forum_id, prune_next, enable_prune, prune_days, prune_viewed, forum_flags, prune_freq
- FROM ' . FORUMS_TABLE . "
- WHERE enable_prune = 1
- AND prune_next < " . time();
+ $sql = 'SELECT forum_id, prune_next, enable_prune, prune_days, prune_viewed, enable_shadow_prune, prune_shadow_days, prune_shadow_freq, prune_shadow_next, forum_flags, prune_freq
+ FROM ' . FORUMS_TABLE;
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
- if ($row['prune_days'])
+ if ($row['enable_prune'] && $row['prune_next'] < time())
{
- auto_prune($row['forum_id'], 'posted', $row['forum_flags'], $row['prune_days'], $row['prune_freq']);
- }
+ if ($row['prune_days'])
+ {
+ auto_prune($row['forum_id'], 'posted', $row['forum_flags'], $row['prune_days'], $row['prune_freq']);
+ }
- if ($row['prune_viewed'])
+ if ($row['prune_viewed'])
+ {
+ auto_prune($row['forum_id'], 'viewed', $row['forum_flags'], $row['prune_viewed'], $row['prune_freq']);
+ }
+ }
+ if ($row['enable_shadow_prune'] && $row['prune_shadow_next'] < time() && $row['prune_shadow_days'])
{
- auto_prune($row['forum_id'], 'viewed', $row['forum_flags'], $row['prune_viewed'], $row['prune_freq']);
+ auto_prune($row['forum_id'], 'shadow', $row['forum_flags'], $row['prune_shadow_days'], $row['prune_shadow_freq']);
}
}
$this->db->sql_freeresult($result);
diff --git a/phpBB/phpbb/cron/task/core/prune_forum.php b/phpBB/phpbb/cron/task/core/prune_forum.php
index ba68565197..abf91aee19 100644
--- a/phpBB/phpbb/cron/task/core/prune_forum.php
+++ b/phpBB/phpbb/cron/task/core/prune_forum.php
@@ -31,7 +31,7 @@ class prune_forum extends \phpbb\cron\task\base implements \phpbb\cron\task\para
* If $forum_data is given, it is assumed to contain necessary information
* about a single forum that is to be pruned.
*
- * If $forum_data is not given, forum id will be retrieved via request_var
+ * If $forum_data is not given, forum id will be retrieved via $request->variable()
* and a database query will be performed to load the necessary information
* about the forum.
*/
diff --git a/phpBB/phpbb/cron/task/core/prune_shadow_topics.php b/phpBB/phpbb/cron/task/core/prune_shadow_topics.php
index 97a4b0ea86..0ab59f9ed5 100644
--- a/phpBB/phpbb/cron/task/core/prune_shadow_topics.php
+++ b/phpBB/phpbb/cron/task/core/prune_shadow_topics.php
@@ -33,7 +33,7 @@ class prune_shadow_topics extends \phpbb\cron\task\base implements \phpbb\cron\t
* If $forum_data is given, it is assumed to contain necessary information
* about a single forum that is to be pruned.
*
- * If $forum_data is not given, forum id will be retrieved via request_var
+ * If $forum_data is not given, forum id will be retrieved via $request->variable()
* and a database query will be performed to load the necessary information
* about the forum.
*/
diff --git a/phpBB/phpbb/cron/task/core/queue.php b/phpBB/phpbb/cron/task/core/queue.php
index a9345a44df..eca69a5041 100644
--- a/phpBB/phpbb/cron/task/core/queue.php
+++ b/phpBB/phpbb/cron/task/core/queue.php
@@ -20,20 +20,23 @@ class queue extends \phpbb\cron\task\base
{
protected $phpbb_root_path;
protected $php_ext;
+ protected $cache_dir;
protected $config;
/**
- * Constructor.
- *
- * @param string $phpbb_root_path The root path
- * @param string $php_ext PHP file extension
- * @param \phpbb\config\config $config The config
- */
- public function __construct($phpbb_root_path, $php_ext, \phpbb\config\config $config)
+ * Constructor.
+ *
+ * @param string $phpbb_root_path The root path
+ * @param string $php_ext PHP file extension
+ * @param \phpbb\config\config $config The config
+ * @param string $cache_dir phpBB cache directory
+ */
+ public function __construct($phpbb_root_path, $php_ext, \phpbb\config\config $config, $cache_dir)
{
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
$this->config = $config;
+ $this->cache_dir = $cache_dir;
}
/**
@@ -60,7 +63,7 @@ class queue extends \phpbb\cron\task\base
*/
public function is_runnable()
{
- return file_exists($this->phpbb_root_path . 'cache/queue.' . $this->php_ext);
+ return file_exists($this->cache_dir . 'queue.' . $this->php_ext);
}
/**
diff --git a/phpBB/phpbb/cron/task/core/tidy_plupload.php b/phpBB/phpbb/cron/task/core/tidy_plupload.php
index b6aeecf4b4..37d0e9b21a 100644
--- a/phpBB/phpbb/cron/task/core/tidy_plupload.php
+++ b/phpBB/phpbb/cron/task/core/tidy_plupload.php
@@ -42,6 +42,12 @@ class tidy_plupload extends \phpbb\cron\task\base
*/
protected $config;
+ /** @var \phpbb\log\log_interface */
+ protected $log;
+
+ /** @var \phpbb\user */
+ protected $user;
+
/**
* Directory where plupload stores temporary files.
* @var string
@@ -53,11 +59,15 @@ class tidy_plupload extends \phpbb\cron\task\base
*
* @param string $phpbb_root_path The root path
* @param \phpbb\config\config $config The config
+ * @param \phpbb\log\log_interface $log Log
+ * @param \phpbb\user $user User object
*/
- public function __construct($phpbb_root_path, \phpbb\config\config $config)
+ public function __construct($phpbb_root_path, \phpbb\config\config $config, \phpbb\log\log_interface $log, \phpbb\user $user)
{
$this->phpbb_root_path = $phpbb_root_path;
$this->config = $config;
+ $this->log = $log;
+ $this->user = $user;
$this->plupload_upload_path = $this->phpbb_root_path . $this->config['upload_path'] . '/plupload';
}
@@ -88,13 +98,11 @@ class tidy_plupload extends \phpbb\cron\task\base
}
catch (\UnexpectedValueException $e)
{
- add_log(
- 'critical',
- 'LOG_PLUPLOAD_TIDY_FAILED',
+ $this->log->add('critical', $this->user->data['user_id'], $this->user->ip, 'LOG_PLUPLOAD_TIDY_FAILED', false, array(
$this->plupload_upload_path,
$e->getMessage(),
$e->getTraceAsString()
- );
+ ));
}
$this->config->set('plupload_last_gc', time(), true);
diff --git a/phpBB/phpbb/cron/task/core/update_hashes.php b/phpBB/phpbb/cron/task/core/update_hashes.php
index a4fe477d99..ba095abc8b 100644
--- a/phpBB/phpbb/cron/task/core/update_hashes.php
+++ b/phpBB/phpbb/cron/task/core/update_hashes.php
@@ -111,9 +111,9 @@ class update_hashes extends \phpbb\cron\task\base
// Increase number so we know that users were selected from the database
$affected_rows++;
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_password = "' . $this->db->sql_escape($new_hash) . '"
- WHERE user_id = ' . (int) $row['user_id'];
+ $sql = 'UPDATE ' . USERS_TABLE . "
+ SET user_password = '" . $this->db->sql_escape($new_hash) . "'
+ WHERE user_id = " . (int) $row['user_id'];
$this->db->sql_query($sql);
}
diff --git a/phpBB/phpbb/cron/task/text_reparser/reparser.php b/phpBB/phpbb/cron/task/text_reparser/reparser.php
new file mode 100644
index 0000000000..fa3bc67325
--- /dev/null
+++ b/phpBB/phpbb/cron/task/text_reparser/reparser.php
@@ -0,0 +1,168 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\cron\task\text_reparser;
+
+/**
+ * Reparse text cron task
+ */
+class reparser extends \phpbb\cron\task\base
+{
+ const MIN = 1;
+ const SIZE = 100;
+
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\config\db_text
+ */
+ protected $config_text;
+
+ /**
+ * @var \phpbb\lock\db
+ */
+ protected $reparse_lock;
+
+ /**
+ * @var \phpbb\textreparser\manager
+ */
+ protected $reparser_manager;
+
+ /**
+ * @var string
+ */
+ protected $reparser_name;
+
+ /**
+ * @var \phpbb\di\service_collection
+ */
+ protected $reparsers;
+
+ /**
+ * @var array
+ */
+ protected $resume_data;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\config\config $config
+ * @param \phpbb\config\db_text $config_text
+ * @param \phpbb\lock\db $reparse_lock
+ * @param \phpbb\textreparser\manager $reparser_manager
+ * @param \phpbb\di\service_collection $reparsers
+ */
+ public function __construct(\phpbb\config\config $config, \phpbb\config\db_text $config_text, \phpbb\lock\db $reparse_lock, \phpbb\textreparser\manager $reparser_manager, \phpbb\di\service_collection $reparsers)
+ {
+ $this->config = $config;
+ $this->config_text = $config_text;
+ $this->reparse_lock = $reparse_lock;
+ $this->reparser_manager = $reparser_manager;
+ $this->reparsers = $reparsers;
+ }
+
+ /**
+ * Sets the reparser for this cron task
+ *
+ * @param string $reparser
+ */
+ public function set_reparser($reparser)
+ {
+ $this->reparser_name = !isset($this->reparsers[$reparser]) ? $this->reparser_manager->find_reparser($reparser) : $reparser;
+
+ if ($this->resume_data === null)
+ {
+ $this->resume_data = $this->reparser_manager->get_resume_data($this->reparser_name);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_runnable()
+ {
+ if ($this->resume_data === null)
+ {
+ $this->resume_data = $this->reparser_manager->get_resume_data($this->reparser_name);
+ }
+
+ if (!isset($this->resume_data['range-max']) || $this->resume_data['range-max'] >= $this->resume_data['range-min'])
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function should_run()
+ {
+ if (!empty($this->config['reparse_lock']))
+ {
+ $last_run = explode(' ', $this->config['reparse_lock']);
+
+ if ($last_run[0] + 3600 >= time())
+ {
+ return false;
+ }
+ }
+
+ if ($this->config[$this->reparser_name . '_cron_interval'])
+ {
+ return $this->config[$this->reparser_name . '_last_cron'] < time() - $this->config[$this->reparser_name . '_cron_interval'];
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ if ($this->reparse_lock->acquire())
+ {
+ if ($this->resume_data === null)
+ {
+ $this->resume_data = $this->reparser_manager->get_resume_data($this->reparser_name);
+ }
+
+ /**
+ * @var \phpbb\textreparser\reparser_interface $reparser
+ */
+ $reparser = $this->reparsers[$this->reparser_name];
+
+ $min = isset($this->resume_data['range-min']) ? $this->resume_data['range-min'] : self::MIN;
+ $current = isset($this->resume_data['range-max']) ? $this->resume_data['range-max'] : $reparser->get_max_id();
+ $size = isset($this->resume_data['range-size']) ? $this->resume_data['range-size'] : self::SIZE;
+
+ if ($current >= $min)
+ {
+ $start = max($min, $current + 1 - $size);
+ $end = max($min, $current);
+
+ $reparser->reparse_range($start, $end);
+
+ $this->reparser_manager->update_resume_data($this->reparser_name, $min, $start - 1, $size);
+ }
+
+ $this->config->set($this->reparser_name . '_last_cron', time());
+ $this->reparse_lock->release();
+ }
+ }
+}
diff --git a/phpBB/phpbb/datetime.php b/phpBB/phpbb/datetime.php
index 63cdba90fd..4b799b6219 100644
--- a/phpBB/phpbb/datetime.php
+++ b/phpBB/phpbb/datetime.php
@@ -60,6 +60,12 @@ class datetime extends \DateTime
public function format($format = '', $force_absolute = false)
{
$format = $format ? $format : $this->user->date_format;
+
+ if (substr($this->user->lang_name, 0,2) != 'en')
+ {
+ $format = preg_replace('/([^\\\])S/','$1', $format);
+ }
+
$format = self::format_cache($format, $this->user);
$relative = ($format['is_short'] && !$force_absolute);
$now = new self($this->user, 'now', $this->user->timezone);
diff --git a/phpBB/phpbb/db/driver/driver.php b/phpBB/phpbb/db/driver/driver.php
index 01dd66cd6e..a36ce8c0d7 100644
--- a/phpBB/phpbb/db/driver/driver.php
+++ b/phpBB/phpbb/db/driver/driver.php
@@ -66,6 +66,15 @@ abstract class driver implements driver_interface
*/
var $sql_server_version = false;
+ const LOGICAL_OP = 0;
+ const STATEMENTS = 1;
+ const LEFT_STMT = 0;
+ const COMPARE_OP = 1;
+ const RIGHT_STMT = 2;
+ const SUBQUERY_OP = 3;
+ const SUBQUERY_SELECT_TYPE = 4;
+ const SUBQUERY_BUILD = 5;
+
/**
* Constructor
*/
@@ -271,7 +280,7 @@ abstract class driver implements driver_interface
$query_id = $this->query_result;
}
- if ($query_id !== false)
+ if ($query_id)
{
$result = array();
while ($row = $this->sql_fetchrow($query_id))
@@ -302,7 +311,7 @@ abstract class driver implements driver_interface
return $cache->sql_rowseek($rownum, $query_id);
}
- if ($query_id === false)
+ if (!$query_id)
{
return false;
}
@@ -310,7 +319,7 @@ abstract class driver implements driver_interface
$this->sql_freeresult($query_id);
$query_id = $this->sql_query($this->last_query_text);
- if ($query_id === false)
+ if (!$query_id)
{
return false;
}
@@ -339,7 +348,7 @@ abstract class driver implements driver_interface
$query_id = $this->query_result;
}
- if ($query_id !== false)
+ if ($query_id)
{
if ($rownum !== false)
{
@@ -363,8 +372,8 @@ abstract class driver implements driver_interface
*/
function sql_like_expression($expression)
{
- $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression);
- $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
+ $expression = str_replace(array('_', '%'), array("\_", "\%"), $expression);
+ $expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\'');
}
@@ -374,8 +383,8 @@ abstract class driver implements driver_interface
*/
function sql_not_like_expression($expression)
{
- $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression);
- $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
+ $expression = str_replace(array('_', '%'), array("\_", "\%"), $expression);
+ $expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
return $this->_sql_not_like_expression('NOT LIKE \'' . $this->sql_escape($expression) . '\'');
}
@@ -528,7 +537,9 @@ abstract class driver implements driver_interface
*/
function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
{
- if (!sizeof($array))
+ $array = (array) $array;
+
+ if (!count($array))
{
if (!$allow_empty_set)
{
@@ -550,12 +561,7 @@ abstract class driver implements driver_interface
}
}
- if (!is_array($array))
- {
- $array = array($array);
- }
-
- if (sizeof($array) == 1)
+ if (count($array) == 1)
{
@reset($array);
$var = current($array);
@@ -623,7 +629,7 @@ abstract class driver implements driver_interface
*/
function sql_multi_insert($table, $sql_ary)
{
- if (!sizeof($sql_ary))
+ if (!count($sql_ary))
{
return false;
}
@@ -729,7 +735,7 @@ abstract class driver implements driver_interface
// We run the following code to determine if we need to re-order the table array. ;)
// The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison.
// DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is.
- if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false)
+ if (!empty($array['LEFT_JOIN']) && count($array['FROM']) > 1 && $used_multi_alias !== false)
{
// Take first LEFT JOIN
$join = current($array['LEFT_JOIN']);
@@ -774,7 +780,18 @@ abstract class driver implements driver_interface
if (!empty($array['WHERE']))
{
- $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']);
+ $sql .= ' WHERE ';
+
+ if (is_array($array['WHERE']))
+ {
+ $sql_where = $this->_process_boolean_tree_first($array['WHERE']);
+ }
+ else
+ {
+ $sql_where = $array['WHERE'];
+ }
+
+ $sql .= $this->_sql_custom_build('WHERE', $sql_where);
}
if (!empty($array['GROUP_BY']))
@@ -793,6 +810,131 @@ abstract class driver implements driver_interface
return $sql;
}
+
+ protected function _process_boolean_tree_first($operations_ary)
+ {
+ // In cases where an array exists but there is no head condition,
+ // it should be because there's only 1 WHERE clause. This seems the best way to deal with it.
+ if ($operations_ary[self::LOGICAL_OP] !== 'AND' &&
+ $operations_ary[self::LOGICAL_OP] !== 'OR')
+ {
+ $operations_ary = array('AND', array($operations_ary));
+ }
+ return $this->_process_boolean_tree($operations_ary) . "\n";
+ }
+
+ protected function _process_boolean_tree($operations_ary)
+ {
+ $operation = $operations_ary[self::LOGICAL_OP];
+
+ foreach ($operations_ary[self::STATEMENTS] as &$condition)
+ {
+ switch ($condition[self::LOGICAL_OP])
+ {
+ case 'AND':
+ case 'OR':
+
+ $condition = ' ( ' . $this->_process_boolean_tree($condition) . ') ';
+
+ break;
+ case 'NOT':
+
+ $condition = ' NOT (' . $this->_process_boolean_tree($condition) . ') ';
+
+ break;
+
+ default:
+
+ switch (count($condition))
+ {
+ case 3:
+
+ // Typical 3 element clause with {left hand} {operator} {right hand}
+ switch ($condition[self::COMPARE_OP])
+ {
+ case 'IN':
+ case 'NOT_IN':
+
+ // As this is used with an IN, assume it is a set of elements for sql_in_set()
+ $condition = $this->sql_in_set($condition[self::LEFT_STMT], $condition[self::RIGHT_STMT], $condition[self::COMPARE_OP] === 'NOT_IN', true);
+
+ break;
+
+ case 'LIKE':
+
+ $condition = $condition[self::LEFT_STMT] . ' ' . $this->sql_like_expression($condition[self::RIGHT_STMT]) . ' ';
+
+ break;
+
+ case 'NOT_LIKE':
+
+ $condition = $condition[self::LEFT_STMT] . ' ' . $this->sql_not_like_expression($condition[self::RIGHT_STMT]) . ' ';
+
+ break;
+
+ case 'IS_NOT':
+
+ $condition[self::COMPARE_OP] = 'IS NOT';
+
+ // no break
+ case 'IS':
+
+ // If the value is NULL, the string of it is the empty string ('') which is not the intended result.
+ // this should solve that
+ if ($condition[self::RIGHT_STMT] === null)
+ {
+ $condition[self::RIGHT_STMT] = 'NULL';
+ }
+
+ $condition = implode(' ', $condition);
+
+ break;
+
+ default:
+
+ $condition = implode(' ', $condition);
+
+ break;
+ }
+
+ break;
+
+ case 5:
+
+ // Subquery with {left hand} {operator} {compare kind} {SELECT Kind } {Sub Query}
+
+ $result = $condition[self::LEFT_STMT] . ' ' . $condition[self::COMPARE_OP] . ' ' . $condition[self::SUBQUERY_OP] . ' ( ';
+ $result .= $this->sql_build_query($condition[self::SUBQUERY_SELECT_TYPE], $condition[self::SUBQUERY_BUILD]);
+ $result .= ' )';
+ $condition = $result;
+
+ break;
+
+ default:
+ // This is an unpredicted clause setup. Just join all elements.
+ $condition = implode(' ', $condition);
+
+ break;
+ }
+
+ break;
+ }
+
+ }
+
+ if ($operation === 'NOT')
+ {
+ $operations_ary = implode("", $operations_ary[self::STATEMENTS]);
+ }
+ else
+ {
+ $operations_ary = implode(" \n $operation ", $operations_ary[self::STATEMENTS]);
+ }
+
+ return $operations_ary;
+ }
+
+
/**
* {@inheritDoc}
*/
@@ -868,7 +1010,7 @@ abstract class driver implements driver_interface
*/
function sql_report($mode, $query = '')
{
- global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper, $user;
+ global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper;
global $request;
if (is_object($request) && !$request->variable('explain', false))
@@ -994,7 +1136,7 @@ abstract class driver implements driver_interface
$html_table = func_get_arg(2);
$row = func_get_arg(3);
- if (!$html_table && sizeof($row))
+ if (!$html_table && count($row))
{
$html_table = true;
$this->html_hold .= '<table cellspacing="1"><tr>';
diff --git a/phpBB/phpbb/db/driver/mssql.php b/phpBB/phpbb/db/driver/mssql.php
deleted file mode 100644
index f9ea884ce2..0000000000
--- a/phpBB/phpbb/db/driver/mssql.php
+++ /dev/null
@@ -1,476 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\db\driver;
-
-/**
-* MSSQL Database Abstraction Layer
-* Minimum Requirement is MSSQL 2000+
-*/
-class mssql extends \phpbb\db\driver\driver
-{
- var $connect_error = '';
-
- /**
- * {@inheritDoc}
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- if (!function_exists('mssql_connect'))
- {
- $this->connect_error = 'mssql_connect function does not exist, is mssql extension installed?';
- return $this->sql_error('');
- }
-
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->dbname = $database;
-
- $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
- $this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
-
- @ini_set('mssql.charset', 'UTF-8');
- @ini_set('mssql.textlimit', 2147483647);
- @ini_set('mssql.textsize', 2147483647);
-
- $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword, $new_link) : @mssql_connect($this->server, $this->user, $sqlpassword, $new_link);
-
- if ($this->db_connect_id && $this->dbname != '')
- {
- if (!@mssql_select_db($this->dbname, $this->db_connect_id))
- {
- @mssql_close($this->db_connect_id);
- return false;
- }
- }
-
- return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false)
- {
- $result_id = @mssql_query("SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')", $this->db_connect_id);
-
- $row = false;
- if ($result_id)
- {
- $row = @mssql_fetch_assoc($result_id);
- @mssql_free_result($result_id);
- }
-
- $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0;
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('mssql_version', $this->sql_server_version);
- }
- }
-
- if ($raw)
- {
- return $this->sql_server_version;
- }
-
- return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL';
- }
-
- /**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return $expr1 . ' + ' . $expr2;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @mssql_query('BEGIN TRANSACTION', $this->db_connect_id);
- break;
-
- case 'commit':
- return @mssql_query('COMMIT TRANSACTION', $this->db_connect_id);
- break;
-
- case 'rollback':
- return @mssql_query('ROLLBACK TRANSACTION', $this->db_connect_id);
- break;
- }
-
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
- else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
- {
- $this->curtime = microtime(true);
- }
-
- $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @mssql_query($query, $this->db_connect_id)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
- else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
- {
- $this->sql_time += microtime(true) - $this->curtime;
- }
-
- if ($cache && $cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows)
- if ($total)
- {
- // We need to grab the total number of rows + the offset number of rows to get the correct result
- if (strpos($query, 'SELECT DISTINCT') === 0)
- {
- $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15);
- }
- else
- {
- $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6);
- }
- }
-
- $result = $this->sql_query($query, $cache_ttl);
-
- // Seek by $offset rows
- if ($offset)
- {
- $this->sql_rowseek($offset, $result);
- }
-
- return $result;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_affectedrows()
- {
- return ($this->db_connect_id) ? @mssql_rows_affected($this->db_connect_id) : false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache && $cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- if ($query_id === false)
- {
- return false;
- }
-
- $row = @mssql_fetch_assoc($query_id);
-
- // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug
- if ($row)
- {
- foreach ($row as $key => $value)
- {
- $row[$key] = ($value === ' ' || $value === null) ? '' : $value;
- }
- }
-
- return $row;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache && $cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- return ($query_id !== false) ? @mssql_data_seek($query_id, $rownum) : false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_nextid()
- {
- $result_id = @mssql_query('SELECT SCOPE_IDENTITY()', $this->db_connect_id);
- if ($result_id)
- {
- if ($row = @mssql_fetch_assoc($result_id))
- {
- @mssql_free_result($result_id);
- return $row['computed'];
- }
- @mssql_free_result($result_id);
- }
-
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[(int) $query_id]))
- {
- unset($this->open_queries[(int) $query_id]);
- return @mssql_free_result($query_id);
- }
-
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_lower_text($column_name)
- {
- return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))";
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
- * Build NOT LIKE expression
- * @access private
- */
- function _sql_not_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- if (function_exists('mssql_get_last_message'))
- {
- $error = array(
- 'message' => @mssql_get_last_message(),
- 'code' => '',
- );
-
- // Get error code number
- $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id);
- if ($result_id)
- {
- $row = @mssql_fetch_assoc($result_id);
- $error['code'] = $row['code'];
- @mssql_free_result($result_id);
- }
-
- // Get full error message if possible
- $sql = 'SELECT CAST(description as varchar(255)) as message
- FROM master.dbo.sysmessages
- WHERE error = ' . $error['code'];
- $result_id = @mssql_query($sql);
-
- if ($result_id)
- {
- $row = @mssql_fetch_assoc($result_id);
- if (!empty($row['message']))
- {
- $error['message'] .= '<br />' . $row['message'];
- }
- @mssql_free_result($result_id);
- }
- }
- else
- {
- $error = array(
- 'message' => $this->connect_error,
- 'code' => '',
- );
- }
-
- return $error;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @mssql_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
- $html_table = false;
- @mssql_query('SET SHOWPLAN_TEXT ON;', $this->db_connect_id);
- if ($result = @mssql_query($query, $this->db_connect_id))
- {
- @mssql_next_result($result);
- while ($row = @mssql_fetch_row($result))
- {
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @mssql_query('SET SHOWPLAN_TEXT OFF;', $this->db_connect_id);
- @mssql_free_result($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @mssql_query($query, $this->db_connect_id);
- while ($void = @mssql_fetch_assoc($result))
- {
- // Take the time spent on parsing rows into account
- }
- @mssql_free_result($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/phpbb/db/driver/mssql_base.php b/phpBB/phpbb/db/driver/mssql_base.php
index 514df9eaca..98d16ca7fc 100644
--- a/phpBB/phpbb/db/driver/mssql_base.php
+++ b/phpBB/phpbb/db/driver/mssql_base.php
@@ -61,6 +61,14 @@ abstract class mssql_base extends \phpbb\db\driver\driver
}
/**
+ * {@inheritDoc}
+ */
+ function cast_expr_to_bigint($expression)
+ {
+ return 'CONVERT(BIGINT, ' . $expression . ')';
+ }
+
+ /**
* Build db-specific query data
* @access private
*/
diff --git a/phpBB/phpbb/db/driver/mssql_odbc.php b/phpBB/phpbb/db/driver/mssql_odbc.php
index 8e5d4c7a4c..9d9ad603e0 100644
--- a/phpBB/phpbb/db/driver/mssql_odbc.php
+++ b/phpBB/phpbb/db/driver/mssql_odbc.php
@@ -98,8 +98,8 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base
$row = false;
if ($result_id)
{
- $row = @odbc_fetch_array($result_id);
- @odbc_free_result($result_id);
+ $row = odbc_fetch_array($result_id);
+ odbc_free_result($result_id);
}
$this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0;
@@ -181,12 +181,17 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base
$this->sql_time += microtime(true) - $this->curtime;
}
+ if (!$this->query_result)
+ {
+ return false;
+ }
+
if ($cache && $cache_ttl)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
}
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
+ else if (strpos($query, 'SELECT') === 0)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
}
@@ -261,7 +266,7 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base
return $cache->sql_fetchrow($query_id);
}
- return ($query_id !== false) ? @odbc_fetch_array($query_id) : false;
+ return ($query_id) ? odbc_fetch_array($query_id) : false;
}
/**
@@ -273,13 +278,13 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base
if ($result_id)
{
- if (@odbc_fetch_array($result_id))
+ if (odbc_fetch_array($result_id))
{
- $id = @odbc_result($result_id, 1);
- @odbc_free_result($result_id);
+ $id = odbc_result($result_id, 1);
+ odbc_free_result($result_id);
return $id;
}
- @odbc_free_result($result_id);
+ odbc_free_result($result_id);
}
return false;
@@ -305,7 +310,7 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base
if (isset($this->open_queries[(int) $query_id]))
{
unset($this->open_queries[(int) $query_id]);
- return @odbc_free_result($query_id);
+ return odbc_free_result($query_id);
}
return false;
@@ -360,11 +365,14 @@ class mssql_odbc extends \phpbb\db\driver\mssql_base
$endtime = $endtime[0] + $endtime[1];
$result = @odbc_exec($this->db_connect_id, $query);
- while ($void = @odbc_fetch_array($result))
+ if ($result)
{
- // Take the time spent on parsing rows into account
+ while ($void = odbc_fetch_array($result))
+ {
+ // Take the time spent on parsing rows into account
+ }
+ odbc_free_result($result);
}
- @odbc_free_result($result);
$splittime = explode(' ', microtime());
$splittime = $splittime[0] + $splittime[1];
diff --git a/phpBB/phpbb/db/driver/mssqlnative.php b/phpBB/phpbb/db/driver/mssqlnative.php
index 46a9b3a477..a4dcac5966 100644
--- a/phpBB/phpbb/db/driver/mssqlnative.php
+++ b/phpBB/phpbb/db/driver/mssqlnative.php
@@ -50,7 +50,8 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
$this->db_connect_id = sqlsrv_connect($this->server, array(
'Database' => $this->dbname,
'UID' => $this->user,
- 'PWD' => $sqlpassword
+ 'PWD' => $sqlpassword,
+ 'CharacterSet' => 'UTF-8'
));
return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
@@ -154,12 +155,17 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
$this->sql_time += microtime(true) - $this->curtime;
}
+ if (!$this->query_result)
+ {
+ return false;
+ }
+
if ($cache && $cache_ttl)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
}
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
+ else if (strpos($query, 'SELECT') === 0)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
}
@@ -242,12 +248,12 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
return $cache->sql_fetchrow($query_id);
}
- if ($query_id === false)
+ if (!$query_id)
{
return false;
}
- $row = @sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC);
+ $row = sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC);
if ($row)
{
@@ -262,7 +268,7 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
unset($row['line2'], $row['line3']);
}
}
- return (sizeof($row)) ? $row : false;
+ return ($row !== null) ? $row : false;
}
/**
@@ -272,11 +278,11 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
{
$result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY');
- if ($result_id !== false)
+ if ($result_id)
{
- $row = @sqlsrv_fetch_array($result_id);
+ $row = sqlsrv_fetch_array($result_id);
$id = $row[0];
- @sqlsrv_free_stmt($result_id);
+ sqlsrv_free_stmt($result_id);
return $id;
}
else
@@ -305,7 +311,7 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
if (isset($this->open_queries[(int) $query_id]))
{
unset($this->open_queries[(int) $query_id]);
- return @sqlsrv_free_stmt($query_id);
+ return sqlsrv_free_stmt($query_id);
}
return false;
@@ -378,14 +384,14 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
@sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;');
if ($result = @sqlsrv_query($this->db_connect_id, $query))
{
- @sqlsrv_next_result($result);
- while ($row = @sqlsrv_fetch_array($result))
+ sqlsrv_next_result($result);
+ while ($row = sqlsrv_fetch_array($result))
{
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
}
+ sqlsrv_free_stmt($result);
}
@sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;');
- @sqlsrv_free_stmt($result);
if ($html_table)
{
@@ -398,11 +404,14 @@ class mssqlnative extends \phpbb\db\driver\mssql_base
$endtime = $endtime[0] + $endtime[1];
$result = @sqlsrv_query($this->db_connect_id, $query);
- while ($void = @sqlsrv_fetch_array($result))
+ if ($result)
{
- // Take the time spent on parsing rows into account
+ while ($void = sqlsrv_fetch_array($result))
+ {
+ // Take the time spent on parsing rows into account
+ }
+ sqlsrv_free_stmt($result);
}
- @sqlsrv_free_stmt($result);
$splittime = explode(' ', microtime());
$splittime = $splittime[0] + $splittime[1];
diff --git a/phpBB/phpbb/db/driver/mysql.php b/phpBB/phpbb/db/driver/mysql.php
index e93c7239e8..a94e88b331 100644
--- a/phpBB/phpbb/db/driver/mysql.php
+++ b/phpBB/phpbb/db/driver/mysql.php
@@ -70,9 +70,16 @@ class mysql extends \phpbb\db\driver\mysql_base
if (version_compare($this->sql_server_info(true), '5.0.2', '>='))
{
$result = @mysql_query('SELECT @@session.sql_mode AS sql_mode', $this->db_connect_id);
- $row = @mysql_fetch_assoc($result);
- @mysql_free_result($result);
- $modes = array_map('trim', explode(',', $row['sql_mode']));
+ if ($result)
+ {
+ $row = mysql_fetch_assoc($result);
+ mysql_free_result($result);
+ $modes = array_map('trim', explode(',', $row['sql_mode']));
+ }
+ else
+ {
+ $modes = array();
+ }
// TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES
if (!in_array('TRADITIONAL', $modes))
@@ -114,14 +121,17 @@ class mysql extends \phpbb\db\driver\mysql_base
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false)
{
$result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id);
- $row = @mysql_fetch_assoc($result);
- @mysql_free_result($result);
+ if ($result)
+ {
+ $row = mysql_fetch_assoc($result);
+ mysql_free_result($result);
- $this->sql_server_version = $row['version'];
+ $this->sql_server_version = $row['version'];
- if (!empty($cache) && $use_cache)
- {
- $cache->put('mysql_version', $this->sql_server_version);
+ if (!empty($cache) && $use_cache)
+ {
+ $cache->put('mysql_version', $this->sql_server_version);
+ }
}
}
@@ -190,12 +200,17 @@ class mysql extends \phpbb\db\driver\mysql_base
$this->sql_time += microtime(true) - $this->curtime;
}
+ if (!$this->query_result)
+ {
+ return false;
+ }
+
if ($cache && $cache_ttl)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
}
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
+ else if (strpos($query, 'SELECT') === 0)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
}
@@ -257,7 +272,7 @@ class mysql extends \phpbb\db\driver\mysql_base
return $cache->sql_fetchrow($query_id);
}
- return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false;
+ return ($query_id) ? mysql_fetch_assoc($query_id) : false;
}
/**
@@ -308,7 +323,7 @@ class mysql extends \phpbb\db\driver\mysql_base
if (isset($this->open_queries[(int) $query_id]))
{
unset($this->open_queries[(int) $query_id]);
- return @mysql_free_result($query_id);
+ return mysql_free_result($query_id);
}
return false;
@@ -411,12 +426,12 @@ class mysql extends \phpbb\db\driver\mysql_base
if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id))
{
- while ($row = @mysql_fetch_assoc($result))
+ while ($row = mysql_fetch_assoc($result))
{
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
}
+ mysql_free_result($result);
}
- @mysql_free_result($result);
if ($html_table)
{
@@ -431,7 +446,7 @@ class mysql extends \phpbb\db\driver\mysql_base
if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id))
{
$this->html_hold .= '<br />';
- while ($row = @mysql_fetch_assoc($result))
+ while ($row = mysql_fetch_assoc($result))
{
// make <unknown> HTML safe
if (!empty($row['Source_function']))
@@ -449,8 +464,8 @@ class mysql extends \phpbb\db\driver\mysql_base
}
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
}
+ mysql_free_result($result);
}
- @mysql_free_result($result);
if ($html_table)
{
@@ -468,11 +483,14 @@ class mysql extends \phpbb\db\driver\mysql_base
$endtime = $endtime[0] + $endtime[1];
$result = @mysql_query($query, $this->db_connect_id);
- while ($void = @mysql_fetch_assoc($result))
+ if ($result)
{
- // Take the time spent on parsing rows into account
+ while ($void = mysql_fetch_assoc($result))
+ {
+ // Take the time spent on parsing rows into account
+ }
+ mysql_free_result($result);
}
- @mysql_free_result($result);
$splittime = explode(' ', microtime());
$splittime = $splittime[0] + $splittime[1];
diff --git a/phpBB/phpbb/db/driver/mysqli.php b/phpBB/phpbb/db/driver/mysqli.php
index c0ddfbf76c..b429ad97aa 100644
--- a/phpBB/phpbb/db/driver/mysqli.php
+++ b/phpBB/phpbb/db/driver/mysqli.php
@@ -68,15 +68,19 @@ class mysqli extends \phpbb\db\driver\mysql_base
if ($this->db_connect_id && $this->dbname != '')
{
+ // Disable loading local files on client side
+ @mysqli_options($this->db_connect_id, MYSQLI_OPT_LOCAL_INFILE, false);
+
@mysqli_query($this->db_connect_id, "SET NAMES 'utf8'");
// enforce strict mode on databases that support it
if (version_compare($this->sql_server_info(true), '5.0.2', '>='))
{
$result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode');
- if ($result !== null)
+ if ($result)
{
- $row = @mysqli_fetch_assoc($result);
+ $row = mysqli_fetch_assoc($result);
+ mysqli_free_result($result);
$modes = array_map('trim', explode(',', $row['sql_mode']));
}
@@ -84,7 +88,6 @@ class mysqli extends \phpbb\db\driver\mysql_base
{
$modes = array();
}
- @mysqli_free_result($result);
// TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES
if (!in_array('TRADITIONAL', $modes))
@@ -119,9 +122,10 @@ class mysqli extends \phpbb\db\driver\mysql_base
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false)
{
$result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version');
- if ($result !== null)
+ if ($result)
{
- $row = @mysqli_fetch_assoc($result);
+ $row = mysqli_fetch_assoc($result);
+ mysqli_free_result($result);
$this->sql_server_version = $row['version'];
@@ -130,7 +134,6 @@ class mysqli extends \phpbb\db\driver\mysql_base
$cache->put('mysqli_version', $this->sql_server_version);
}
}
- @mysqli_free_result($result);
}
return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version;
@@ -202,6 +205,11 @@ class mysqli extends \phpbb\db\driver\mysql_base
$this->sql_time += microtime(true) - $this->curtime;
}
+ if (!$this->query_result)
+ {
+ return false;
+ }
+
if ($cache && $cache_ttl)
{
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
@@ -245,9 +253,9 @@ class mysqli extends \phpbb\db\driver\mysql_base
return $cache->sql_fetchrow($query_id);
}
- if ($query_id !== false && $query_id !== null)
+ if ($query_id)
{
- $result = @mysqli_fetch_assoc($query_id);
+ $result = mysqli_fetch_assoc($query_id);
return $result !== null ? $result : false;
}
@@ -271,7 +279,7 @@ class mysqli extends \phpbb\db\driver\mysql_base
return $cache->sql_rowseek($rownum, $query_id);
}
- return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false;
+ return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false;
}
/**
@@ -299,7 +307,17 @@ class mysqli extends \phpbb\db\driver\mysql_base
return $cache->sql_freeresult($query_id);
}
- return @mysqli_free_result($query_id);
+ if (!$query_id)
+ {
+ return false;
+ }
+
+ if ($query_id === true)
+ {
+ return true;
+ }
+
+ return mysqli_free_result($query_id);
}
/**
@@ -398,12 +416,12 @@ class mysqli extends \phpbb\db\driver\mysql_base
if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query"))
{
- while ($row = @mysqli_fetch_assoc($result))
+ while ($row = mysqli_fetch_assoc($result))
{
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
}
+ mysqli_free_result($result);
}
- @mysqli_free_result($result);
if ($html_table)
{
@@ -418,7 +436,7 @@ class mysqli extends \phpbb\db\driver\mysql_base
if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;'))
{
$this->html_hold .= '<br />';
- while ($row = @mysqli_fetch_assoc($result))
+ while ($row = mysqli_fetch_assoc($result))
{
// make <unknown> HTML safe
if (!empty($row['Source_function']))
@@ -436,8 +454,8 @@ class mysqli extends \phpbb\db\driver\mysql_base
}
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
}
+ mysqli_free_result($result);
}
- @mysqli_free_result($result);
if ($html_table)
{
@@ -455,14 +473,14 @@ class mysqli extends \phpbb\db\driver\mysql_base
$endtime = $endtime[0] + $endtime[1];
$result = @mysqli_query($this->db_connect_id, $query);
- if ($result !== null)
+ if ($result)
{
- while ($void = @mysqli_fetch_assoc($result))
+ while ($void = mysqli_fetch_assoc($result))
{
// Take the time spent on parsing rows into account
}
+ mysqli_free_result($result);
}
- @mysqli_free_result($result);
$splittime = explode(' ', microtime());
$splittime = $splittime[0] + $splittime[1];
diff --git a/phpBB/phpbb/db/driver/oracle.php b/phpBB/phpbb/db/driver/oracle.php
index 6dcab5dd7d..5fd14709f8 100644
--- a/phpBB/phpbb/db/driver/oracle.php
+++ b/phpBB/phpbb/db/driver/oracle.php
@@ -84,8 +84,6 @@ class oracle extends \phpbb\db\driver\driver
* but I assume its because the Oracle extension provides a direct method to access it
* without a query.
*/
-
- $use_cache = false;
/*
global $cache;
@@ -138,7 +136,7 @@ class oracle extends \phpbb\db\driver\driver
*/
function _rewrite_col_compare($args)
{
- if (sizeof($args) == 4)
+ if (count($args) == 4)
{
if ($args[2] == '=')
{
@@ -292,7 +290,7 @@ class oracle extends \phpbb\db\driver\driver
and/or need the db restore script, uncomment this.
- if (sizeof($cols) !== sizeof($vals))
+ if (count($cols) !== count($vals))
{
// Try to replace some common data we know is from our restore script or from other sources
$regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]);
@@ -334,7 +332,7 @@ class oracle extends \phpbb\db\driver\driver
if ($string)
{
// New value if cols != value
- $vals[(sizeof($cols) !== sizeof($vals)) ? $i : $i - 1] .= $string;
+ $vals[(count($cols) !== count($vals)) ? $i : $i - 1] .= $string;
}
$vals = array(0 => $vals);
@@ -439,12 +437,17 @@ class oracle extends \phpbb\db\driver\driver
$this->sql_time += microtime(true) - $this->curtime;
}
+ if (!$this->query_result)
+ {
+ return false;
+ }
+
if ($cache && $cache_ttl)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
}
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
+ else if (strpos($query, 'SELECT') === 0)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
}
@@ -499,10 +502,10 @@ class oracle extends \phpbb\db\driver\driver
return $cache->sql_fetchrow($query_id);
}
- if ($query_id !== false)
+ if ($query_id)
{
$row = array();
- $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
+ $result = ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
if (!$result || !$row)
{
@@ -550,7 +553,7 @@ class oracle extends \phpbb\db\driver\driver
return $cache->sql_rowseek($rownum, $query_id);
}
- if ($query_id === false)
+ if (!$query_id)
{
return false;
}
@@ -583,18 +586,24 @@ class oracle extends \phpbb\db\driver\driver
{
$query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
$stmt = @ociparse($this->db_connect_id, $query);
- @ociexecute($stmt, OCI_DEFAULT);
+ if ($stmt)
+ {
+ $success = @ociexecute($stmt, OCI_DEFAULT);
- $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
- @ocifreestatement($stmt);
+ if ($success)
+ {
+ $temp_result = ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
+ ocifreestatement($stmt);
- if ($temp_result)
- {
- return $temp_array['CURRVAL'];
- }
- else
- {
- return false;
+ if ($temp_result)
+ {
+ return $temp_array['CURRVAL'];
+ }
+ else
+ {
+ return false;
+ }
+ }
}
}
}
@@ -622,7 +631,7 @@ class oracle extends \phpbb\db\driver\driver
if (isset($this->open_queries[(int) $query_id]))
{
unset($this->open_queries[(int) $query_id]);
- return @ocifreestatement($query_id);
+ return ocifreestatement($query_id);
}
return false;
@@ -787,14 +796,20 @@ class oracle extends \phpbb\db\driver\driver
$endtime = $endtime[0] + $endtime[1];
$result = @ociparse($this->db_connect_id, $query);
- $success = @ociexecute($result, OCI_DEFAULT);
- $row = array();
-
- while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
+ if ($result)
{
- // Take the time spent on parsing rows into account
+ $success = @ociexecute($result, OCI_DEFAULT);
+ if ($success)
+ {
+ $row = array();
+
+ while (ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
+ {
+ // Take the time spent on parsing rows into account
+ }
+ @ocifreestatement($result);
+ }
}
- @ocifreestatement($result);
$splittime = explode(' ', microtime());
$splittime = $splittime[0] + $splittime[1];
diff --git a/phpBB/phpbb/db/driver/postgres.php b/phpBB/phpbb/db/driver/postgres.php
index a3b9aa4c6b..44476612c3 100644
--- a/phpBB/phpbb/db/driver/postgres.php
+++ b/phpBB/phpbb/db/driver/postgres.php
@@ -123,14 +123,17 @@ class postgres extends \phpbb\db\driver\driver
if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false)
{
$query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version');
- $row = @pg_fetch_assoc($query_id, null);
- @pg_free_result($query_id);
+ if ($query_id)
+ {
+ $row = pg_fetch_assoc($query_id, null);
+ pg_free_result($query_id);
- $this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0;
+ $this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0;
- if (!empty($cache) && $use_cache)
- {
- $cache->put('pgsql_version', $this->sql_server_version);
+ if (!empty($cache) && $use_cache)
+ {
+ $cache->put('pgsql_version', $this->sql_server_version);
+ }
}
}
@@ -200,12 +203,17 @@ class postgres extends \phpbb\db\driver\driver
$this->sql_time += microtime(true) - $this->curtime;
}
+ if (!$this->query_result)
+ {
+ return false;
+ }
+
if ($cache && $cache_ttl)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
}
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
+ else if (strpos($query, 'SELECT') === 0)
{
$this->open_queries[(int) $this->query_result] = $this->query_result;
}
@@ -275,7 +283,7 @@ class postgres extends \phpbb\db\driver\driver
return $cache->sql_fetchrow($query_id);
}
- return ($query_id !== false) ? @pg_fetch_assoc($query_id, null) : false;
+ return ($query_id) ? pg_fetch_assoc($query_id, null) : false;
}
/**
@@ -295,7 +303,7 @@ class postgres extends \phpbb\db\driver\driver
return $cache->sql_rowseek($rownum, $query_id);
}
- return ($query_id !== false) ? @pg_result_seek($query_id, $rownum) : false;
+ return ($query_id) ? @pg_result_seek($query_id, $rownum) : false;
}
/**
@@ -317,8 +325,8 @@ class postgres extends \phpbb\db\driver\driver
return false;
}
- $temp_result = @pg_fetch_assoc($temp_q_id, null);
- @pg_free_result($query_id);
+ $temp_result = pg_fetch_assoc($temp_q_id, null);
+ pg_free_result($query_id);
return ($temp_result) ? $temp_result['last_value'] : false;
}
@@ -347,7 +355,7 @@ class postgres extends \phpbb\db\driver\driver
if (isset($this->open_queries[(int) $query_id]))
{
unset($this->open_queries[(int) $query_id]);
- return @pg_free_result($query_id);
+ return pg_free_result($query_id);
}
return false;
@@ -453,12 +461,12 @@ class postgres extends \phpbb\db\driver\driver
if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query"))
{
- while ($row = @pg_fetch_assoc($result, null))
+ while ($row = pg_fetch_assoc($result, null))
{
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
}
+ pg_free_result($result);
}
- @pg_free_result($result);
if ($html_table)
{
@@ -473,11 +481,14 @@ class postgres extends \phpbb\db\driver\driver
$endtime = $endtime[0] + $endtime[1];
$result = @pg_query($this->db_connect_id, $query);
- while ($void = @pg_fetch_assoc($result, null))
+ if ($result)
{
- // Take the time spent on parsing rows into account
+ while ($void = pg_fetch_assoc($result, null))
+ {
+ // Take the time spent on parsing rows into account
+ }
+ pg_free_result($result);
}
- @pg_free_result($result);
$splittime = explode(' ', microtime());
$splittime = $splittime[0] + $splittime[1];
diff --git a/phpBB/phpbb/db/driver/sqlite.php b/phpBB/phpbb/db/driver/sqlite.php
deleted file mode 100644
index d5da0e2438..0000000000
--- a/phpBB/phpbb/db/driver/sqlite.php
+++ /dev/null
@@ -1,378 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\db\driver;
-
-/**
-* Sqlite Database Abstraction Layer
-* Minimum Requirement: 2.8.2+
-*/
-class sqlite extends \phpbb\db\driver\driver
-{
- var $connect_error = '';
-
- /**
- * {@inheritDoc}
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->server = $sqlserver . (($port) ? ':' . $port : '');
- $this->dbname = $database;
-
- $error = '';
- if ($this->persistency)
- {
- if (!function_exists('sqlite_popen'))
- {
- $this->connect_error = 'sqlite_popen function does not exist, is sqlite extension installed?';
- return $this->sql_error('');
- }
- $this->db_connect_id = @sqlite_popen($this->server, 0666, $error);
- }
- else
- {
- if (!function_exists('sqlite_open'))
- {
- $this->connect_error = 'sqlite_open function does not exist, is sqlite extension installed?';
- return $this->sql_error('');
- }
- $this->db_connect_id = @sqlite_open($this->server, 0666, $error);
- }
-
- if ($this->db_connect_id)
- {
- @sqlite_query('PRAGMA short_column_names = 1', $this->db_connect_id);
-// @sqlite_query('PRAGMA encoding = "UTF-8"', $this->db_connect_id);
- }
-
- return ($this->db_connect_id) ? true : array('message' => $error);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false)
- {
- $result = @sqlite_query('SELECT sqlite_version() AS version', $this->db_connect_id);
- $row = @sqlite_fetch_array($result, SQLITE_ASSOC);
-
- $this->sql_server_version = (!empty($row['version'])) ? $row['version'] : 0;
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('sqlite_version', $this->sql_server_version);
- }
- }
-
- return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @sqlite_query('BEGIN', $this->db_connect_id);
- break;
-
- case 'commit':
- return @sqlite_query('COMMIT', $this->db_connect_id);
- break;
-
- case 'rollback':
- return @sqlite_query('ROLLBACK', $this->db_connect_id);
- break;
- }
-
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
- else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
- {
- $this->curtime = microtime(true);
- }
-
- $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @sqlite_query($query, $this->db_connect_id)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
- else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
- {
- $this->sql_time += microtime(true) - $this->curtime;
- }
-
- if ($cache && $cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // if $total is set to 0 we do not want to limit the number of rows
- if ($total == 0)
- {
- $total = -1;
- }
-
- $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_affectedrows()
- {
- return ($this->db_connect_id) ? @sqlite_changes($this->db_connect_id) : false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache && $cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- return ($query_id !== false) ? @sqlite_fetch_array($query_id, SQLITE_ASSOC) : false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache && $cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- return ($query_id !== false) ? @sqlite_seek($query_id, $rownum) : false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_nextid()
- {
- return ($this->db_connect_id) ? @sqlite_last_insert_rowid($this->db_connect_id) : false;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_escape($msg)
- {
- return @sqlite_escape_string($msg);
- }
-
- /**
- * {@inheritDoc}
- *
- * For SQLite an underscore is a not-known character... this may change with SQLite3
- */
- function sql_like_expression($expression)
- {
- // Unlike LIKE, GLOB is unfortunately case sensitive.
- // We only catch * and ? here, not the character map possible on file globbing.
- $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression);
-
- $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression);
- $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression);
-
- return 'GLOB \'' . $this->sql_escape($expression) . '\'';
- }
-
- /**
- * {@inheritDoc}
- *
- * For SQLite an underscore is a not-known character...
- */
- function sql_not_like_expression($expression)
- {
- // Unlike NOT LIKE, NOT GLOB is unfortunately case sensitive.
- // We only catch * and ? here, not the character map possible on file globbing.
- $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression);
-
- $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression);
- $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression);
-
- return 'NOT GLOB \'' . $this->sql_escape($expression) . '\'';
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- if (function_exists('sqlite_error_string'))
- {
- $error = array(
- 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)),
- 'code' => @sqlite_last_error($this->db_connect_id),
- );
- }
- else
- {
- $error = array(
- 'message' => $this->connect_error,
- 'code' => '',
- );
- }
-
- return $error;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @sqlite_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @sqlite_query($query, $this->db_connect_id);
- while ($void = @sqlite_fetch_array($result, SQLITE_ASSOC))
- {
- // Take the time spent on parsing rows into account
- }
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/phpbb/db/driver/sqlite3.php b/phpBB/phpbb/db/driver/sqlite3.php
index cc3352af34..0508500c52 100644
--- a/phpBB/phpbb/db/driver/sqlite3.php
+++ b/phpBB/phpbb/db/driver/sqlite3.php
@@ -102,7 +102,7 @@ class sqlite3 extends \phpbb\db\driver\driver
break;
case 'rollback':
- return $this->dbo->exec('ROLLBACK');
+ return @$this->dbo->exec('ROLLBACK');
break;
}
@@ -134,9 +134,26 @@ class sqlite3 extends \phpbb\db\driver\driver
if ($this->query_result === false)
{
+ if ($this->transaction === true && strpos($query, 'INSERT') === 0)
+ {
+ $query = preg_replace('/^INSERT INTO/', 'INSERT OR ROLLBACK INTO', $query);
+ }
+
if (($this->query_result = @$this->dbo->query($query)) === false)
{
- $this->sql_error($query);
+ // Try to recover a lost database connection
+ if ($this->dbo && !@$this->dbo->lastErrorMsg())
+ {
+ if ($this->sql_connect($this->server, $this->user, '', $this->dbname))
+ {
+ $this->query_result = @$this->dbo->query($query);
+ }
+ }
+
+ if ($this->query_result === false)
+ {
+ $this->sql_error($query);
+ }
}
if (defined('DEBUG'))
@@ -148,6 +165,11 @@ class sqlite3 extends \phpbb\db\driver\driver
$this->sql_time += microtime(true) - $this->curtime;
}
+ if (!$this->query_result)
+ {
+ return false;
+ }
+
if ($cache && $cache_ttl)
{
$this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
@@ -208,6 +230,7 @@ class sqlite3 extends \phpbb\db\driver\driver
if ($query_id === false)
{
+ /** @var \SQLite3Result $query_id */
$query_id = $this->query_result;
}
@@ -216,7 +239,7 @@ class sqlite3 extends \phpbb\db\driver\driver
return $cache->sql_fetchrow($query_id);
}
- return is_object($query_id) ? $query_id->fetchArray(SQLITE3_ASSOC) : false;
+ return is_object($query_id) ? @$query_id->fetchArray(SQLITE3_ASSOC) : false;
}
/**
@@ -389,9 +412,12 @@ class sqlite3 extends \phpbb\db\driver\driver
$endtime = $endtime[0] + $endtime[1];
$result = $this->dbo->query($query);
- while ($void = $result->fetchArray(SQLITE3_ASSOC))
+ if ($result)
{
- // Take the time spent on parsing rows into account
+ while ($void = $result->fetchArray(SQLITE3_ASSOC))
+ {
+ // Take the time spent on parsing rows into account
+ }
}
$splittime = explode(' ', microtime());
diff --git a/phpBB/phpbb/db/extractor/base_extractor.php b/phpBB/phpbb/db/extractor/base_extractor.php
new file mode 100644
index 0000000000..547c85f066
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/base_extractor.php
@@ -0,0 +1,252 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+use phpbb\db\extractor\exception\invalid_format_exception;
+use phpbb\db\extractor\exception\extractor_not_initialized_exception;
+
+/**
+ * Abstract base class for database extraction
+ */
+abstract class base_extractor implements extractor_interface
+{
+ /**
+ * @var string phpBB root path
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var \phpbb\request\request_interface
+ */
+ protected $request;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var bool
+ */
+ protected $download;
+
+ /**
+ * @var bool
+ */
+ protected $store;
+
+ /**
+ * @var int
+ */
+ protected $time;
+
+ /**
+ * @var string
+ */
+ protected $format;
+
+ /**
+ * @var resource
+ */
+ protected $fp;
+
+ /**
+ * @var string
+ */
+ protected $write;
+
+ /**
+ * @var string
+ */
+ protected $close;
+
+ /**
+ * @var bool
+ */
+ protected $run_comp;
+
+ /**
+ * @var bool
+ */
+ protected $is_initialized;
+
+ /**
+ * Constructor
+ *
+ * @param string $phpbb_root_path
+ * @param \phpbb\request\request_interface $request
+ * @param \phpbb\db\driver\driver_interface $db
+ */
+ public function __construct($phpbb_root_path, \phpbb\request\request_interface $request, \phpbb\db\driver\driver_interface $db)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->request = $request;
+ $this->db = $db;
+ $this->fp = null;
+
+ $this->is_initialized = false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init_extractor($format, $filename, $time, $download = false, $store = false)
+ {
+ $this->download = $download;
+ $this->store = $store;
+ $this->time = $time;
+ $this->format = $format;
+
+ switch ($format)
+ {
+ case 'text':
+ $ext = '.sql';
+ $open = 'fopen';
+ $this->write = 'fwrite';
+ $this->close = 'fclose';
+ $mimetype = 'text/x-sql';
+ break;
+ case 'bzip2':
+ $ext = '.sql.bz2';
+ $open = 'bzopen';
+ $this->write = 'bzwrite';
+ $this->close = 'bzclose';
+ $mimetype = 'application/x-bzip2';
+ break;
+ case 'gzip':
+ $ext = '.sql.gz';
+ $open = 'gzopen';
+ $this->write = 'gzwrite';
+ $this->close = 'gzclose';
+ $mimetype = 'application/x-gzip';
+ break;
+ default:
+ throw new invalid_format_exception();
+ break;
+ }
+
+ if ($download === true)
+ {
+ $name = $filename . $ext;
+ header('Cache-Control: private, no-cache');
+ header("Content-Type: $mimetype; name=\"$name\"");
+ header("Content-disposition: attachment; filename=$name");
+
+ switch ($format)
+ {
+ case 'bzip2':
+ ob_start();
+ break;
+
+ case 'gzip':
+ if (strpos($this->request->header('Accept-Encoding'), 'gzip') !== false && strpos(strtolower($this->request->header('User-Agent')), 'msie') === false)
+ {
+ ob_start('ob_gzhandler');
+ }
+ else
+ {
+ $this->run_comp = true;
+ }
+ break;
+ }
+ }
+
+ if ($store === true)
+ {
+ $file = $this->phpbb_root_path . 'store/' . $filename . $ext;
+
+ $this->fp = $open($file, 'w');
+
+ if (!$this->fp)
+ {
+ trigger_error('FILE_WRITE_FAIL', E_USER_ERROR);
+ }
+ }
+
+ $this->is_initialized = true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_end()
+ {
+ static $close;
+
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ if ($this->store)
+ {
+ if ($close === null)
+ {
+ $close = $this->close;
+ }
+ $close($this->fp);
+ }
+
+ // bzip2 must be written all the way at the end
+ if ($this->download && $this->format === 'bzip2')
+ {
+ $c = ob_get_clean();
+ echo bzcompress($c);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function flush($data)
+ {
+ static $write;
+
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ if ($this->store === true)
+ {
+ if ($write === null)
+ {
+ $write = $this->write;
+ }
+ $write($this->fp, $data);
+ }
+
+ if ($this->download === true)
+ {
+ if ($this->format === 'bzip2' || $this->format === 'text' || ($this->format === 'gzip' && !$this->run_comp))
+ {
+ echo $data;
+ }
+
+ // we can write the gzip data as soon as we get it
+ if ($this->format === 'gzip')
+ {
+ if ($this->run_comp)
+ {
+ echo gzencode($data);
+ }
+ else
+ {
+ ob_flush();
+ flush();
+ }
+ }
+ }
+ }
+}
diff --git a/phpBB/phpbb/db/extractor/exception/extractor_not_initialized_exception.php b/phpBB/phpbb/db/extractor/exception/extractor_not_initialized_exception.php
new file mode 100644
index 0000000000..62eb434be1
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/exception/extractor_not_initialized_exception.php
@@ -0,0 +1,24 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor\exception;
+
+use phpbb\exception\runtime_exception;
+
+/**
+* This exception is thrown when invalid format is given to the extractor
+*/
+class extractor_not_initialized_exception extends runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/db/extractor/exception/invalid_format_exception.php b/phpBB/phpbb/db/extractor/exception/invalid_format_exception.php
new file mode 100644
index 0000000000..6be24cb5dc
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/exception/invalid_format_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor\exception;
+
+/**
+* This exception is thrown when invalid format is given to the extractor
+*/
+class invalid_format_exception extends \InvalidArgumentException
+{
+
+}
diff --git a/phpBB/phpbb/db/extractor/extractor_interface.php b/phpBB/phpbb/db/extractor/extractor_interface.php
new file mode 100644
index 0000000000..ff45df9bb7
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/extractor_interface.php
@@ -0,0 +1,80 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+/**
+* Database extractor interface
+*/
+interface extractor_interface
+{
+ /**
+ * Start the extraction of the database
+ *
+ * This function initialize the database extraction. It is required to call this
+ * function before calling any other extractor functions.
+ *
+ * @param string $format
+ * @param string $filename
+ * @param int $time
+ * @param bool $download
+ * @param bool $store
+ * @return null
+ * @throws \phpbb\db\extractor\exception\invalid_format_exception when $format is invalid
+ */
+ public function init_extractor($format, $filename, $time, $download = false, $store = false);
+
+ /**
+ * Writes header comments to the database backup
+ *
+ * @param string $table_prefix prefix of phpBB database tables
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function write_start($table_prefix);
+
+ /**
+ * Closes file and/or dumps download data
+ *
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function write_end();
+
+ /**
+ * Extracts database table structure
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function write_table($table_name);
+
+ /**
+ * Extracts data from database table
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function write_data($table_name);
+
+ /**
+ * Writes data to file/download content
+ *
+ * @param string $data
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function flush($data);
+}
diff --git a/phpBB/phpbb/db/extractor/factory.php b/phpBB/phpbb/db/extractor/factory.php
new file mode 100644
index 0000000000..f27aae720f
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/factory.php
@@ -0,0 +1,75 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+/**
+* A factory which serves the suitable extractor instance for the given dbal
+*/
+class factory
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \Symfony\Component\DependencyInjection\ContainerInterface
+ */
+ protected $container;
+
+ /**
+ * Extractor factory constructor
+ *
+ * @param \phpbb\db\driver\driver_interface $db
+ * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, \Symfony\Component\DependencyInjection\ContainerInterface $container)
+ {
+ $this->db = $db;
+ $this->container = $container;
+ }
+
+ /**
+ * DB extractor factory getter
+ *
+ * @return \phpbb\db\extractor\extractor_interface an appropriate instance of the database extractor for the used database driver
+ * @throws \InvalidArgumentException when the database driver is unknown
+ */
+ public function get()
+ {
+ // Return the appropriate DB extractor
+ if ($this->db instanceof \phpbb\db\driver\mssql_base)
+ {
+ return $this->container->get('dbal.extractor.extractors.mssql_extractor');
+ }
+ else if ($this->db instanceof \phpbb\db\driver\mysql_base)
+ {
+ return $this->container->get('dbal.extractor.extractors.mysql_extractor');
+ }
+ else if ($this->db instanceof \phpbb\db\driver\oracle)
+ {
+ return $this->container->get('dbal.extractor.extractors.oracle_extractor');
+ }
+ else if ($this->db instanceof \phpbb\db\driver\postgres)
+ {
+ return $this->container->get('dbal.extractor.extractors.postgres_extractor');
+ }
+ else if ($this->db instanceof \phpbb\db\driver\sqlite3)
+ {
+ return $this->container->get('dbal.extractor.extractors.sqlite3_extractor');
+ }
+
+ throw new \InvalidArgumentException('Invalid database driver given');
+ }
+}
diff --git a/phpBB/phpbb/db/extractor/mssql_extractor.php b/phpBB/phpbb/db/extractor/mssql_extractor.php
new file mode 100644
index 0000000000..4eeab4780e
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/mssql_extractor.php
@@ -0,0 +1,415 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+use phpbb\db\extractor\exception\extractor_not_initialized_exception;
+
+class mssql_extractor extends base_extractor
+{
+ /**
+ * Writes closing line(s) to database backup
+ *
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function write_end()
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $this->flush("COMMIT\nGO\n");
+ parent::write_end();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_start($table_prefix)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = "--\n";
+ $sql_data .= "-- phpBB Backup Script\n";
+ $sql_data .= "-- Dump of tables for $table_prefix\n";
+ $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
+ $sql_data .= "--\n";
+ $sql_data .= "BEGIN TRANSACTION\n";
+ $sql_data .= "GO\n";
+ $this->flush($sql_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_table($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = '-- Table: ' . $table_name . "\n";
+ $sql_data .= "IF OBJECT_ID(N'$table_name', N'U') IS NOT NULL\n";
+ $sql_data .= "DROP TABLE $table_name;\n";
+ $sql_data .= "GO\n";
+ $sql_data .= "\nCREATE TABLE [$table_name] (\n";
+ $rows = array();
+
+ $text_flag = false;
+
+ $sql = "SELECT COLUMN_NAME, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as IS_IDENTITY
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE TABLE_NAME = '$table_name'";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $line = "\t[{$row['COLUMN_NAME']}] [{$row['DATA_TYPE']}]";
+
+ if ($row['DATA_TYPE'] == 'text')
+ {
+ $text_flag = true;
+ }
+
+ if ($row['IS_IDENTITY'])
+ {
+ $line .= ' IDENTITY (1 , 1)';
+ }
+
+ if ($row['CHARACTER_MAXIMUM_LENGTH'] && $row['DATA_TYPE'] !== 'text')
+ {
+ $line .= ' (' . $row['CHARACTER_MAXIMUM_LENGTH'] . ')';
+ }
+
+ if ($row['IS_NULLABLE'] == 'YES')
+ {
+ $line .= ' NULL';
+ }
+ else
+ {
+ $line .= ' NOT NULL';
+ }
+
+ if ($row['COLUMN_DEFAULT'])
+ {
+ $line .= ' DEFAULT ' . $row['COLUMN_DEFAULT'];
+ }
+
+ $rows[] = $line;
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql_data .= implode(",\n", $rows);
+ $sql_data .= "\n) ON [PRIMARY]";
+
+ if ($text_flag)
+ {
+ $sql_data .= " TEXTIMAGE_ON [PRIMARY]";
+ }
+
+ $sql_data .= "\nGO\n\n";
+ $rows = array();
+
+ $sql = "SELECT CONSTRAINT_NAME, COLUMN_NAME
+ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
+ WHERE TABLE_NAME = '$table_name'";
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (!count($rows))
+ {
+ $sql_data .= "ALTER TABLE [$table_name] WITH NOCHECK ADD\n";
+ $sql_data .= "\tCONSTRAINT [{$row['CONSTRAINT_NAME']}] PRIMARY KEY CLUSTERED \n\t(\n";
+ }
+ $rows[] = "\t\t[{$row['COLUMN_NAME']}]";
+ }
+ if (count($rows))
+ {
+ $sql_data .= implode(",\n", $rows);
+ $sql_data .= "\n\t) ON [PRIMARY] \nGO\n";
+ }
+ $this->db->sql_freeresult($result);
+
+ $index = array();
+ $sql = "EXEC sp_statistics '$table_name'";
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if ($row['TYPE'] == 3)
+ {
+ $index[$row['INDEX_NAME']][] = '[' . $row['COLUMN_NAME'] . ']';
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ foreach ($index as $index_name => $column_name)
+ {
+ $index[$index_name] = implode(', ', $column_name);
+ }
+
+ foreach ($index as $index_name => $columns)
+ {
+ $sql_data .= "\nCREATE INDEX [$index_name] ON [$table_name]($columns) ON [PRIMARY]\nGO\n";
+ }
+ $this->flush($sql_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_data($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ if ($this->db->get_sql_layer() === 'mssqlnative')
+ {
+ $this->write_data_mssqlnative($table_name);
+ }
+ else
+ {
+ $this->write_data_odbc($table_name);
+ }
+ }
+
+ /**
+ * Extracts data from database table (for MSSQL Native driver)
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ protected function write_data_mssqlnative($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $ary_type = $ary_name = array();
+ $ident_set = false;
+ $sql_data = '';
+
+ // Grab all of the data from current table.
+ $sql = "SELECT * FROM $table_name";
+ $this->db->mssqlnative_set_query_options(array('Scrollable' => SQLSRV_CURSOR_STATIC));
+ $result = $this->db->sql_query($sql);
+
+ $retrieved_data = $this->db->mssqlnative_num_rows($result);
+
+ if (!$retrieved_data)
+ {
+ $this->db->sql_freeresult($result);
+ return;
+ }
+
+ $sql = "SELECT COLUMN_NAME, DATA_TYPE
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE INFORMATION_SCHEMA.COLUMNS.TABLE_NAME = '" . $this->db->sql_escape($table_name) . "'";
+ $result_fields = $this->db->sql_query($sql);
+
+ $i_num_fields = 0;
+ while ($row = $this->db->sql_fetchrow($result_fields))
+ {
+ $ary_type[$i_num_fields] = $row['DATA_TYPE'];
+ $ary_name[$i_num_fields] = $row['COLUMN_NAME'];
+ $i_num_fields++;
+ }
+ $this->db->sql_freeresult($result_fields);
+
+ $sql = "SELECT 1 as has_identity
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
+ $result2 = $this->db->sql_query($sql);
+ $row2 = $this->db->sql_fetchrow($result2);
+
+ if (!empty($row2['has_identity']))
+ {
+ $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
+ $ident_set = true;
+ }
+ $this->db->sql_freeresult($result2);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $schema_vals = $schema_fields = array();
+
+ // Build the SQL statement to recreate the data.
+ for ($i = 0; $i < $i_num_fields; $i++)
+ {
+ $str_val = $row[$ary_name[$i]];
+
+ // defaults to type number - better quote just to be safe, so check for is_int too
+ if (is_int($ary_type[$i]) || preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
+ {
+ $str_quote = '';
+ $str_empty = "''";
+ $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
+ }
+ else if (preg_match('#date|timestamp#i', $ary_type[$i]))
+ {
+ if (empty($str_val))
+ {
+ $str_quote = '';
+ }
+ else
+ {
+ $str_quote = "'";
+ }
+ }
+ else
+ {
+ $str_quote = '';
+ $str_empty = 'NULL';
+ }
+
+ if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
+ {
+ $str_val = $str_empty;
+ }
+
+ $schema_vals[$i] = $str_quote . $str_val . $str_quote;
+ $schema_fields[$i] = $ary_name[$i];
+ }
+
+ // Take the ordered fields and their associated data and build it
+ // into a valid sql statement to recreate that field in the data.
+ $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
+
+ $this->flush($sql_data);
+ $sql_data = '';
+ }
+ $this->db->sql_freeresult($result);
+
+ if ($ident_set)
+ {
+ $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
+ }
+ $this->flush($sql_data);
+ }
+
+ /**
+ * Extracts data from database table (for ODBC driver)
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ protected function write_data_odbc($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $ary_type = $ary_name = array();
+ $ident_set = false;
+ $sql_data = '';
+
+ // Grab all of the data from current table.
+ $sql = "SELECT *
+ FROM $table_name";
+ $result = $this->db->sql_query($sql);
+
+ $retrieved_data = odbc_num_rows($result);
+
+ if ($retrieved_data)
+ {
+ $sql = "SELECT 1 as has_identity
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1";
+ $result2 = $this->db->sql_query($sql);
+ $row2 = $this->db->sql_fetchrow($result2);
+ if (!empty($row2['has_identity']))
+ {
+ $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n";
+ $ident_set = true;
+ }
+ $this->db->sql_freeresult($result2);
+ }
+
+ $i_num_fields = odbc_num_fields($result);
+
+ for ($i = 0; $i < $i_num_fields; $i++)
+ {
+ $ary_type[$i] = odbc_field_type($result, $i + 1);
+ $ary_name[$i] = odbc_field_name($result, $i + 1);
+ }
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $schema_vals = $schema_fields = array();
+
+ // Build the SQL statement to recreate the data.
+ for ($i = 0; $i < $i_num_fields; $i++)
+ {
+ $str_val = $row[$ary_name[$i]];
+
+ if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i]))
+ {
+ $str_quote = '';
+ $str_empty = "''";
+ $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val));
+ }
+ else if (preg_match('#date|timestamp#i', $ary_type[$i]))
+ {
+ if (empty($str_val))
+ {
+ $str_quote = '';
+ }
+ else
+ {
+ $str_quote = "'";
+ }
+ }
+ else
+ {
+ $str_quote = '';
+ $str_empty = 'NULL';
+ }
+
+ if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val)))
+ {
+ $str_val = $str_empty;
+ }
+
+ $schema_vals[$i] = $str_quote . $str_val . $str_quote;
+ $schema_fields[$i] = $ary_name[$i];
+ }
+
+ // Take the ordered fields and their associated data and build it
+ // into a valid sql statement to recreate that field in the data.
+ $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n";
+
+ $this->flush($sql_data);
+
+ $sql_data = '';
+
+ }
+ $this->db->sql_freeresult($result);
+
+ if ($retrieved_data && $ident_set)
+ {
+ $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n";
+ }
+ $this->flush($sql_data);
+ }
+}
diff --git a/phpBB/phpbb/db/extractor/mysql_extractor.php b/phpBB/phpbb/db/extractor/mysql_extractor.php
new file mode 100644
index 0000000000..34e309c19e
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/mysql_extractor.php
@@ -0,0 +1,403 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+use phpbb\db\extractor\exception\extractor_not_initialized_exception;
+
+class mysql_extractor extends base_extractor
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function write_start($table_prefix)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = "#\n";
+ $sql_data .= "# phpBB Backup Script\n";
+ $sql_data .= "# Dump of tables for $table_prefix\n";
+ $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
+ $sql_data .= "#\n";
+ $this->flush($sql_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_table($table_name)
+ {
+ static $new_extract;
+
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ if ($new_extract === null)
+ {
+ if ($this->db->get_sql_layer() === 'mysqli' || version_compare($this->db->sql_server_info(true), '3.23.20', '>='))
+ {
+ $new_extract = true;
+ }
+ else
+ {
+ $new_extract = false;
+ }
+ }
+
+ if ($new_extract)
+ {
+ $this->new_write_table($table_name);
+ }
+ else
+ {
+ $this->old_write_table($table_name);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_data($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ if ($this->db->get_sql_layer() === 'mysqli')
+ {
+ $this->write_data_mysqli($table_name);
+ }
+ else
+ {
+ $this->write_data_mysql($table_name);
+ }
+ }
+
+ /**
+ * Extracts data from database table (for MySQLi driver)
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ protected function write_data_mysqli($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql = "SELECT *
+ FROM $table_name";
+ $result = mysqli_query($this->db->get_db_connect_id(), $sql, MYSQLI_USE_RESULT);
+ if ($result != false)
+ {
+ $fields_cnt = mysqli_num_fields($result);
+
+ // Get field information
+ $field = mysqli_fetch_fields($result);
+ $field_set = array();
+
+ for ($j = 0; $j < $fields_cnt; $j++)
+ {
+ $field_set[] = $field[$j]->name;
+ }
+
+ $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
+ $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
+ $fields = implode(', ', $field_set);
+ $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
+ $first_set = true;
+ $query_len = 0;
+ $max_len = get_usable_memory();
+
+ while ($row = mysqli_fetch_row($result))
+ {
+ $values = array();
+ if ($first_set)
+ {
+ $query = $sql_data . '(';
+ }
+ else
+ {
+ $query .= ',(';
+ }
+
+ for ($j = 0; $j < $fields_cnt; $j++)
+ {
+ if (!isset($row[$j]) || is_null($row[$j]))
+ {
+ $values[$j] = 'NULL';
+ }
+ else if (($field[$j]->flags & 32768) && !($field[$j]->flags & 1024))
+ {
+ $values[$j] = $row[$j];
+ }
+ else
+ {
+ $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
+ }
+ }
+ $query .= implode(', ', $values) . ')';
+
+ $query_len += strlen($query);
+ if ($query_len > $max_len)
+ {
+ $this->flush($query . ";\n\n");
+ $query = '';
+ $query_len = 0;
+ $first_set = true;
+ }
+ else
+ {
+ $first_set = false;
+ }
+ }
+ mysqli_free_result($result);
+
+ // check to make sure we have nothing left to flush
+ if (!$first_set && $query)
+ {
+ $this->flush($query . ";\n\n");
+ }
+ }
+ }
+
+ /**
+ * Extracts data from database table (for MySQL driver)
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ protected function write_data_mysql($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql = "SELECT *
+ FROM $table_name";
+ $result = mysql_unbuffered_query($sql, $this->db->get_db_connect_id());
+
+ if ($result != false)
+ {
+ $fields_cnt = mysql_num_fields($result);
+
+ // Get field information
+ $field = array();
+ for ($i = 0; $i < $fields_cnt; $i++)
+ {
+ $field[] = mysql_fetch_field($result, $i);
+ }
+ $field_set = array();
+
+ for ($j = 0; $j < $fields_cnt; $j++)
+ {
+ $field_set[] = $field[$j]->name;
+ }
+
+ $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"');
+ $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"');
+ $fields = implode(', ', $field_set);
+ $sql_data = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ';
+ $first_set = true;
+ $query_len = 0;
+ $max_len = get_usable_memory();
+
+ while ($row = mysql_fetch_row($result))
+ {
+ $values = array();
+ if ($first_set)
+ {
+ $query = $sql_data . '(';
+ }
+ else
+ {
+ $query .= ',(';
+ }
+
+ for ($j = 0; $j < $fields_cnt; $j++)
+ {
+ if (!isset($row[$j]) || is_null($row[$j]))
+ {
+ $values[$j] = 'NULL';
+ }
+ else if ($field[$j]->numeric && ($field[$j]->type !== 'timestamp'))
+ {
+ $values[$j] = $row[$j];
+ }
+ else
+ {
+ $values[$j] = "'" . str_replace($search, $replace, $row[$j]) . "'";
+ }
+ }
+ $query .= implode(', ', $values) . ')';
+
+ $query_len += strlen($query);
+ if ($query_len > $max_len)
+ {
+ $this->flush($query . ";\n\n");
+ $query = '';
+ $query_len = 0;
+ $first_set = true;
+ }
+ else
+ {
+ $first_set = false;
+ }
+ }
+ mysql_free_result($result);
+
+ // check to make sure we have nothing left to flush
+ if (!$first_set && $query)
+ {
+ $this->flush($query . ";\n\n");
+ }
+ }
+ }
+
+ /**
+ * Extracts database table structure (for MySQLi or MySQL 3.23.20+)
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ protected function new_write_table($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql = 'SHOW CREATE TABLE ' . $table_name;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+
+ $sql_data = '# Table: ' . $table_name . "\n";
+ $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
+ $this->flush($sql_data . $row['Create Table'] . ";\n\n");
+
+ $this->db->sql_freeresult($result);
+ }
+
+ /**
+ * Extracts database table structure (for MySQL verisons older than 3.23.20)
+ *
+ * @param string $table_name name of the database table
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ protected function old_write_table($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = '# Table: ' . $table_name . "\n";
+ $sql_data .= "DROP TABLE IF EXISTS $table_name;\n";
+ $sql_data .= "CREATE TABLE $table_name(\n";
+ $rows = array();
+
+ $sql = "SHOW FIELDS
+ FROM $table_name";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $line = ' ' . $row['Field'] . ' ' . $row['Type'];
+
+ if (!is_null($row['Default']))
+ {
+ $line .= " DEFAULT '{$row['Default']}'";
+ }
+
+ if ($row['Null'] != 'YES')
+ {
+ $line .= ' NOT NULL';
+ }
+
+ if ($row['Extra'] != '')
+ {
+ $line .= ' ' . $row['Extra'];
+ }
+
+ $rows[] = $line;
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql = "SHOW KEYS
+ FROM $table_name";
+
+ $result = $this->db->sql_query($sql);
+
+ $index = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $kname = $row['Key_name'];
+
+ if ($kname != 'PRIMARY')
+ {
+ if ($row['Non_unique'] == 0)
+ {
+ $kname = "UNIQUE|$kname";
+ }
+ }
+
+ if ($row['Sub_part'])
+ {
+ $row['Column_name'] .= '(' . $row['Sub_part'] . ')';
+ }
+ $index[$kname][] = $row['Column_name'];
+ }
+ $this->db->sql_freeresult($result);
+
+ foreach ($index as $key => $columns)
+ {
+ $line = ' ';
+
+ if ($key == 'PRIMARY')
+ {
+ $line .= 'PRIMARY KEY (' . implode(', ', $columns) . ')';
+ }
+ else if (strpos($key, 'UNIQUE') === 0)
+ {
+ $line .= 'UNIQUE ' . substr($key, 7) . ' (' . implode(', ', $columns) . ')';
+ }
+ else if (strpos($key, 'FULLTEXT') === 0)
+ {
+ $line .= 'FULLTEXT ' . substr($key, 9) . ' (' . implode(', ', $columns) . ')';
+ }
+ else
+ {
+ $line .= "KEY $key (" . implode(', ', $columns) . ')';
+ }
+
+ $rows[] = $line;
+ }
+
+ $sql_data .= implode(",\n", $rows);
+ $sql_data .= "\n);\n\n";
+
+ $this->flush($sql_data);
+ }
+}
diff --git a/phpBB/phpbb/db/extractor/oracle_extractor.php b/phpBB/phpbb/db/extractor/oracle_extractor.php
new file mode 100644
index 0000000000..bc43a37b10
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/oracle_extractor.php
@@ -0,0 +1,263 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+use phpbb\db\extractor\exception\extractor_not_initialized_exception;
+
+class oracle_extractor extends base_extractor
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function write_table($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = '-- Table: ' . $table_name . "\n";
+ $sql_data .= "DROP TABLE $table_name\n/\n";
+ $sql_data .= "\nCREATE TABLE $table_name (\n";
+
+ $sql = "SELECT COLUMN_NAME, DATA_TYPE, DATA_PRECISION, DATA_LENGTH, NULLABLE, DATA_DEFAULT
+ FROM ALL_TAB_COLS
+ WHERE table_name = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+
+ $rows = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $line = ' "' . $row['column_name'] . '" ' . $row['data_type'];
+
+ if ($row['data_type'] !== 'CLOB')
+ {
+ if ($row['data_type'] !== 'VARCHAR2' && $row['data_type'] !== 'CHAR')
+ {
+ $line .= '(' . $row['data_precision'] . ')';
+ }
+ else
+ {
+ $line .= '(' . $row['data_length'] . ')';
+ }
+ }
+
+ if (!empty($row['data_default']))
+ {
+ $line .= ' DEFAULT ' . $row['data_default'];
+ }
+
+ if ($row['nullable'] == 'N')
+ {
+ $line .= ' NOT NULL';
+ }
+ $rows[] = $line;
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
+ FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
+ WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
+ AND B.CONSTRAINT_TYPE = 'P'
+ AND A.TABLE_NAME = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+
+ $primary_key = array();
+ $constraint_name = '';
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $constraint_name = '"' . $row['constraint_name'] . '"';
+ $primary_key[] = '"' . $row['column_name'] . '"';
+ }
+ $this->db->sql_freeresult($result);
+
+ if (count($primary_key))
+ {
+ $rows[] = " CONSTRAINT {$constraint_name} PRIMARY KEY (" . implode(', ', $primary_key) . ')';
+ }
+
+ $sql = "SELECT A.CONSTRAINT_NAME, A.COLUMN_NAME
+ FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
+ WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
+ AND B.CONSTRAINT_TYPE = 'U'
+ AND A.TABLE_NAME = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+
+ $unique = array();
+ $constraint_name = '';
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $constraint_name = '"' . $row['constraint_name'] . '"';
+ $unique[] = '"' . $row['column_name'] . '"';
+ }
+ $this->db->sql_freeresult($result);
+
+ if (count($unique))
+ {
+ $rows[] = " CONSTRAINT {$constraint_name} UNIQUE (" . implode(', ', $unique) . ')';
+ }
+
+ $sql_data .= implode(",\n", $rows);
+ $sql_data .= "\n)\n/\n";
+
+ $sql = "SELECT A.REFERENCED_NAME, C.*
+ FROM USER_DEPENDENCIES A, USER_TRIGGERS B, USER_SEQUENCES C
+ WHERE A.REFERENCED_TYPE = 'SEQUENCE'
+ AND A.NAME = B.TRIGGER_NAME
+ AND B.TABLE_NAME = '{$table_name}'
+ AND C.SEQUENCE_NAME = A.REFERENCED_NAME";
+ $result = $this->db->sql_query($sql);
+
+ $type = $this->request->variable('type', '');
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $sql_data .= "\nDROP SEQUENCE \"{$row['referenced_name']}\"\n/\n";
+ $sql_data .= "\nCREATE SEQUENCE \"{$row['referenced_name']}\"";
+
+ if ($type == 'full')
+ {
+ $sql_data .= ' START WITH ' . $row['last_number'];
+ }
+
+ $sql_data .= "\n/\n";
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql = "SELECT DESCRIPTION, WHEN_CLAUSE, TRIGGER_BODY
+ FROM USER_TRIGGERS
+ WHERE TABLE_NAME = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $sql_data .= "\nCREATE OR REPLACE TRIGGER {$row['description']}WHEN ({$row['when_clause']})\n{$row['trigger_body']}\n/\n";
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql = "SELECT A.INDEX_NAME, B.COLUMN_NAME
+ FROM USER_INDEXES A, USER_IND_COLUMNS B
+ WHERE A.UNIQUENESS = 'NONUNIQUE'
+ AND A.INDEX_NAME = B.INDEX_NAME
+ AND B.TABLE_NAME = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+
+ $index = array();
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $index[$row['index_name']][] = $row['column_name'];
+ }
+
+ foreach ($index as $index_name => $column_names)
+ {
+ $sql_data .= "\nCREATE INDEX $index_name ON $table_name(" . implode(', ', $column_names) . ")\n/\n";
+ }
+ $this->db->sql_freeresult($result);
+ $this->flush($sql_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_data($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $ary_type = $ary_name = array();
+
+ // Grab all of the data from current table.
+ $sql = "SELECT *
+ FROM $table_name";
+ $result = $this->db->sql_query($sql);
+
+ $i_num_fields = ocinumcols($result);
+
+ for ($i = 0; $i < $i_num_fields; $i++)
+ {
+ $ary_type[$i] = ocicolumntype($result, $i + 1);
+ $ary_name[$i] = ocicolumnname($result, $i + 1);
+ }
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $schema_vals = $schema_fields = array();
+
+ // Build the SQL statement to recreate the data.
+ for ($i = 0; $i < $i_num_fields; $i++)
+ {
+ // Oracle uses uppercase - we use lowercase
+ $str_val = $row[strtolower($ary_name[$i])];
+
+ if (preg_match('#char|text|bool|raw|clob#i', $ary_type[$i]))
+ {
+ $str_quote = '';
+ $str_empty = "''";
+ $str_val = sanitize_data_oracle($str_val);
+ }
+ else if (preg_match('#date|timestamp#i', $ary_type[$i]))
+ {
+ if (empty($str_val))
+ {
+ $str_quote = '';
+ }
+ else
+ {
+ $str_quote = "'";
+ }
+ }
+ else
+ {
+ $str_quote = '';
+ $str_empty = 'NULL';
+ }
+
+ if (empty($str_val) && $str_val !== '0')
+ {
+ $str_val = $str_empty;
+ }
+
+ $schema_vals[$i] = $str_quote . $str_val . $str_quote;
+ $schema_fields[$i] = '"' . $ary_name[$i] . '"';
+ }
+
+ // Take the ordered fields and their associated data and build it
+ // into a valid sql statement to recreate that field in the data.
+ $sql_data = "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ")\n/\n";
+
+ $this->flush($sql_data);
+ }
+ $this->db->sql_freeresult($result);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_start($table_prefix)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = "--\n";
+ $sql_data .= "-- phpBB Backup Script\n";
+ $sql_data .= "-- Dump of tables for $table_prefix\n";
+ $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
+ $sql_data .= "--\n";
+ $this->flush($sql_data);
+ }
+}
diff --git a/phpBB/phpbb/db/extractor/postgres_extractor.php b/phpBB/phpbb/db/extractor/postgres_extractor.php
new file mode 100644
index 0000000000..0219d2ac8d
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/postgres_extractor.php
@@ -0,0 +1,339 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+use phpbb\db\extractor\exception\extractor_not_initialized_exception;
+
+class postgres_extractor extends base_extractor
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function write_start($table_prefix)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = "--\n";
+ $sql_data .= "-- phpBB Backup Script\n";
+ $sql_data .= "-- Dump of tables for $table_prefix\n";
+ $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
+ $sql_data .= "--\n";
+ $sql_data .= "BEGIN TRANSACTION;\n";
+ $this->flush($sql_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_table($table_name)
+ {
+ static $domains_created = array();
+
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql = "SELECT a.domain_name, a.data_type, a.character_maximum_length, a.domain_default
+ FROM INFORMATION_SCHEMA.domains a, INFORMATION_SCHEMA.column_domain_usage b
+ WHERE a.domain_name = b.domain_name
+ AND b.table_name = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (empty($domains_created[$row['domain_name']]))
+ {
+ $domains_created[$row['domain_name']] = true;
+ //$sql_data = "DROP DOMAIN {$row['domain_name']};\n";
+ $sql_data = "CREATE DOMAIN {$row['domain_name']} as {$row['data_type']}";
+ if (!empty($row['character_maximum_length']))
+ {
+ $sql_data .= '(' . $row['character_maximum_length'] . ')';
+ }
+ $sql_data .= ' NOT NULL';
+ if (!empty($row['domain_default']))
+ {
+ $sql_data .= ' DEFAULT ' . $row['domain_default'];
+ }
+ $this->flush($sql_data . ";\n");
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql_data = '-- Table: ' . $table_name . "\n";
+ $sql_data .= "DROP TABLE $table_name;\n";
+ // PGSQL does not "tightly" bind sequences and tables, we must guess...
+ $sql = "SELECT relname
+ FROM pg_class
+ WHERE relkind = 'S'
+ AND relname = '{$table_name}_seq'";
+ $result = $this->db->sql_query($sql);
+ // We don't even care about storing the results. We already know the answer if we get rows back.
+ if ($this->db->sql_fetchrow($result))
+ {
+ $sql_data .= "DROP SEQUENCE IF EXISTS {$table_name}_seq;\n";
+ $sql_data .= "CREATE SEQUENCE {$table_name}_seq;\n";
+ }
+ $this->db->sql_freeresult($result);
+
+ $field_query = "SELECT a.attnum, a.attname as field, t.typname as type, a.attlen as length, a.atttypmod as lengthvar, a.attnotnull as notnull
+ FROM pg_class c, pg_attribute a, pg_type t
+ WHERE c.relname = '" . $this->db->sql_escape($table_name) . "'
+ AND a.attnum > 0
+ AND a.attrelid = c.oid
+ AND a.atttypid = t.oid
+ ORDER BY a.attnum";
+ $result = $this->db->sql_query($field_query);
+
+ $sql_data .= "CREATE TABLE $table_name(\n";
+ $lines = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // Get the data from the table
+ $sql_get_default = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
+ FROM pg_attrdef d, pg_class c
+ WHERE (c.relname = '" . $this->db->sql_escape($table_name) . "')
+ AND (c.oid = d.adrelid)
+ AND d.adnum = " . $row['attnum'];
+ $def_res = $this->db->sql_query($sql_get_default);
+ $def_row = $this->db->sql_fetchrow($def_res);
+ $this->db->sql_freeresult($def_res);
+
+ if (empty($def_row))
+ {
+ unset($row['rowdefault']);
+ }
+ else
+ {
+ $row['rowdefault'] = $def_row['rowdefault'];
+ }
+
+ if ($row['type'] == 'bpchar')
+ {
+ // Internally stored as bpchar, but isn't accepted in a CREATE TABLE statement.
+ $row['type'] = 'char';
+ }
+
+ $line = ' ' . $row['field'] . ' ' . $row['type'];
+
+ if (strpos($row['type'], 'char') !== false)
+ {
+ if ($row['lengthvar'] > 0)
+ {
+ $line .= '(' . ($row['lengthvar'] - 4) . ')';
+ }
+ }
+
+ if (strpos($row['type'], 'numeric') !== false)
+ {
+ $line .= '(';
+ $line .= sprintf("%s,%s", (($row['lengthvar'] >> 16) & 0xffff), (($row['lengthvar'] - 4) & 0xffff));
+ $line .= ')';
+ }
+
+ if (isset($row['rowdefault']))
+ {
+ $line .= ' DEFAULT ' . $row['rowdefault'];
+ }
+
+ if ($row['notnull'] == 't')
+ {
+ $line .= ' NOT NULL';
+ }
+
+ $lines[] = $line;
+ }
+ $this->db->sql_freeresult($result);
+
+ // Get the listing of primary keys.
+ $sql_pri_keys = "SELECT ic.relname as index_name, bc.relname as tab_name, ta.attname as column_name, i.indisunique as unique_key, i.indisprimary as primary_key
+ FROM pg_class bc, pg_class ic, pg_index i, pg_attribute ta, pg_attribute ia
+ WHERE (bc.oid = i.indrelid)
+ AND (ic.oid = i.indexrelid)
+ AND (ia.attrelid = i.indexrelid)
+ AND (ta.attrelid = bc.oid)
+ AND (bc.relname = '" . $this->db->sql_escape($table_name) . "')
+ AND (ta.attrelid = i.indrelid)
+ AND (ta.attnum = i.indkey[ia.attnum-1])
+ ORDER BY index_name, tab_name, column_name";
+
+ $result = $this->db->sql_query($sql_pri_keys);
+
+ $index_create = $index_rows = $primary_key = array();
+
+ // We do this in two steps. It makes placing the comma easier
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if ($row['primary_key'] == 't')
+ {
+ $primary_key[] = $row['column_name'];
+ $primary_key_name = $row['index_name'];
+ }
+ else
+ {
+ // We have to store this all this info because it is possible to have a multi-column key...
+ // we can loop through it again and build the statement
+ $index_rows[$row['index_name']]['table'] = $table_name;
+ $index_rows[$row['index_name']]['unique'] = ($row['unique_key'] == 't') ? true : false;
+ $index_rows[$row['index_name']]['column_names'][] = $row['column_name'];
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if (!empty($index_rows))
+ {
+ foreach ($index_rows as $idx_name => $props)
+ {
+ $index_create[] = 'CREATE ' . ($props['unique'] ? 'UNIQUE ' : '') . "INDEX $idx_name ON $table_name (" . implode(', ', $props['column_names']) . ");";
+ }
+ }
+
+ if (!empty($primary_key))
+ {
+ $lines[] = " CONSTRAINT $primary_key_name PRIMARY KEY (" . implode(', ', $primary_key) . ")";
+ }
+
+ // Generate constraint clauses for CHECK constraints
+ $sql_checks = "SELECT conname as index_name, consrc
+ FROM pg_constraint, pg_class bc
+ WHERE conrelid = bc.oid
+ AND bc.relname = '" . $this->db->sql_escape($table_name) . "'
+ AND NOT EXISTS (
+ SELECT *
+ FROM pg_constraint as c, pg_inherits as i
+ WHERE i.inhrelid = pg_constraint.conrelid
+ AND c.conname = pg_constraint.conname
+ AND c.consrc = pg_constraint.consrc
+ AND c.conrelid = i.inhparent
+ )";
+ $result = $this->db->sql_query($sql_checks);
+
+ // Add the constraints to the sql file.
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (!is_null($row['consrc']))
+ {
+ $lines[] = ' CONSTRAINT ' . $row['index_name'] . ' CHECK ' . $row['consrc'];
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql_data .= implode(", \n", $lines);
+ $sql_data .= "\n);\n";
+
+ if (!empty($index_create))
+ {
+ $sql_data .= implode("\n", $index_create) . "\n\n";
+ }
+ $this->flush($sql_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_data($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ // Grab all of the data from current table.
+ $sql = "SELECT *
+ FROM $table_name";
+ $result = $this->db->sql_query($sql);
+
+ $i_num_fields = pg_num_fields($result);
+ $seq = '';
+
+ for ($i = 0; $i < $i_num_fields; $i++)
+ {
+ $ary_type[] = pg_field_type($result, $i);
+ $ary_name[] = pg_field_name($result, $i);
+
+ $sql = "SELECT pg_get_expr(d.adbin, d.adrelid) as rowdefault
+ FROM pg_attrdef d, pg_class c
+ WHERE (c.relname = '{$table_name}')
+ AND (c.oid = d.adrelid)
+ AND d.adnum = " . strval($i + 1);
+ $result2 = $this->db->sql_query($sql);
+ if ($row = $this->db->sql_fetchrow($result2))
+ {
+ // Determine if we must reset the sequences
+ if (strpos($row['rowdefault'], "nextval('") === 0)
+ {
+ $seq .= "SELECT SETVAL('{$table_name}_seq',(select case when max({$ary_name[$i]})>0 then max({$ary_name[$i]})+1 else 1 end FROM {$table_name}));\n";
+ }
+ }
+ }
+
+ $this->flush("COPY $table_name (" . implode(', ', $ary_name) . ') FROM stdin;' . "\n");
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $schema_vals = array();
+
+ // Build the SQL statement to recreate the data.
+ for ($i = 0; $i < $i_num_fields; $i++)
+ {
+ $str_val = $row[$ary_name[$i]];
+
+ if (preg_match('#char|text|bool|bytea#i', $ary_type[$i]))
+ {
+ $str_val = str_replace(array("\n", "\t", "\r", "\b", "\f", "\v"), array('\n', '\t', '\r', '\b', '\f', '\v'), addslashes($str_val));
+ $str_empty = '';
+ }
+ else
+ {
+ $str_empty = '\N';
+ }
+
+ if (empty($str_val) && $str_val !== '0')
+ {
+ $str_val = $str_empty;
+ }
+
+ $schema_vals[] = $str_val;
+ }
+
+ // Take the ordered fields and their associated data and build it
+ // into a valid sql statement to recreate that field in the data.
+ $this->flush(implode("\t", $schema_vals) . "\n");
+ }
+ $this->db->sql_freeresult($result);
+ $this->flush("\\.\n");
+
+ // Write out the sequence statements
+ $this->flush($seq);
+ }
+
+ /**
+ * Writes closing line(s) to database backup
+ *
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function write_end()
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $this->flush("COMMIT;\n");
+ parent::write_end();
+ }
+}
diff --git a/phpBB/phpbb/db/extractor/sqlite3_extractor.php b/phpBB/phpbb/db/extractor/sqlite3_extractor.php
new file mode 100644
index 0000000000..ce8da6a652
--- /dev/null
+++ b/phpBB/phpbb/db/extractor/sqlite3_extractor.php
@@ -0,0 +1,151 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\extractor;
+
+use phpbb\db\extractor\exception\extractor_not_initialized_exception;
+
+class sqlite3_extractor extends base_extractor
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function write_start($table_prefix)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = "--\n";
+ $sql_data .= "-- phpBB Backup Script\n";
+ $sql_data .= "-- Dump of tables for $table_prefix\n";
+ $sql_data .= "-- DATE : " . gmdate("d-m-Y H:i:s", $this->time) . " GMT\n";
+ $sql_data .= "--\n";
+ $sql_data .= "BEGIN TRANSACTION;\n";
+ $this->flush($sql_data);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_table($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $sql_data = '-- Table: ' . $table_name . "\n";
+ $sql_data .= "DROP TABLE $table_name;\n";
+
+ $sql = "SELECT sql
+ FROM sqlite_master
+ WHERE type = 'table'
+ AND name = '" . $this->db->sql_escape($table_name) . "'
+ ORDER BY name ASC;";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ // Create Table
+ $sql_data .= $row['sql'] . ";\n";
+
+ $result = $this->db->sql_query("PRAGMA index_list('" . $this->db->sql_escape($table_name) . "');");
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (strpos($row['name'], 'autoindex') !== false)
+ {
+ continue;
+ }
+
+ $result2 = $this->db->sql_query("PRAGMA index_info('" . $this->db->sql_escape($row['name']) . "');");
+
+ $fields = array();
+ while ($row2 = $this->db->sql_fetchrow($result2))
+ {
+ $fields[] = $row2['name'];
+ }
+ $this->db->sql_freeresult($result2);
+
+ $sql_data .= 'CREATE ' . ($row['unique'] ? 'UNIQUE ' : '') . 'INDEX ' . $row['name'] . ' ON ' . $table_name . ' (' . implode(', ', $fields) . ");\n";
+ }
+ $this->db->sql_freeresult($result);
+
+ $this->flush($sql_data . "\n");
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write_data($table_name)
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $result = $this->db->sql_query("PRAGMA table_info('" . $this->db->sql_escape($table_name) . "');");
+
+ $col_types = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $col_types[$row['name']] = $row['type'];
+ }
+ $this->db->sql_freeresult($result);
+
+ $sql_insert = 'INSERT INTO ' . $table_name . ' (' . implode(', ', array_keys($col_types)) . ') VALUES (';
+
+ $sql = "SELECT *
+ FROM $table_name";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ foreach ($row as $column_name => $column_data)
+ {
+ if (is_null($column_data))
+ {
+ $row[$column_name] = 'NULL';
+ }
+ else if ($column_data === '')
+ {
+ $row[$column_name] = "''";
+ }
+ else if (stripos($col_types[$column_name], 'text') !== false || stripos($col_types[$column_name], 'char') !== false || stripos($col_types[$column_name], 'blob') !== false)
+ {
+ $row[$column_name] = sanitize_data_generic(str_replace("'", "''", $column_data));
+ }
+ }
+ $this->flush($sql_insert . implode(', ', $row) . ");\n");
+ }
+ }
+
+ /**
+ * Writes closing line(s) to database backup
+ *
+ * @return null
+ * @throws \phpbb\db\extractor\exception\extractor_not_initialized_exception when calling this function before init_extractor()
+ */
+ public function write_end()
+ {
+ if (!$this->is_initialized)
+ {
+ throw new extractor_not_initialized_exception();
+ }
+
+ $this->flush("COMMIT;\n");
+ parent::write_end();
+ }
+}
diff --git a/phpBB/phpbb/db/html_migrator_output_handler.php b/phpBB/phpbb/db/html_migrator_output_handler.php
deleted file mode 100644
index e37c667463..0000000000
--- a/phpBB/phpbb/db/html_migrator_output_handler.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\db;
-
-use phpbb\user;
-
-class html_migrator_output_handler implements migrator_output_handler_interface
-{
- /**
- * User object.
- *
- * @var user
- */
- private $user;
-
- /**
- * Constructor
- *
- * @param user $user User object
- */
- public function __construct(user $user)
- {
- $this->user = $user;
- }
-
- /**
- * {@inheritdoc}
- */
- public function write($message, $verbosity)
- {
- if ($verbosity <= migrator_output_handler_interface::VERBOSITY_VERBOSE)
- {
- $final_message = call_user_func_array(array($this->user, 'lang'), $message);
- echo $final_message . "<br />\n";
- }
- }
-}
diff --git a/phpBB/phpbb/db/log_wrapper_migrator_output_handler.php b/phpBB/phpbb/db/log_wrapper_migrator_output_handler.php
deleted file mode 100644
index 94c293dc45..0000000000
--- a/phpBB/phpbb/db/log_wrapper_migrator_output_handler.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\db;
-
-use phpbb\user;
-
-class log_wrapper_migrator_output_handler implements migrator_output_handler_interface
-{
- /**
- * User object.
- *
- * @var user
- */
- protected $user;
-
- /**
- * A migrator output handler
- *
- * @var migrator_output_handler_interface
- */
- protected $migrator;
-
- /**
- * Log file handle
- * @var resource
- */
- protected $file_handle = false;
-
- /**
- * Constructor
- *
- * @param user $user User object
- * @param migrator_output_handler_interface $migrator Migrator output handler
- * @param string $log_file File to log to
- */
- public function __construct(user $user, migrator_output_handler_interface $migrator, $log_file)
- {
- $this->user = $user;
- $this->migrator = $migrator;
- $this->file_open($log_file);
- }
-
- /**
- * Open file for logging
- *
- * @param string $file File to open
- */
- protected function file_open($file)
- {
- if (phpbb_is_writable(dirname($file)))
- {
- $this->file_handle = fopen($file, 'w');
- }
- else
- {
- throw new \RuntimeException('Unable to write to migrator log file');
- }
- }
-
- /**
- * {@inheritdoc}
- */
- public function write($message, $verbosity)
- {
- $this->migrator->write($message, $verbosity);
-
- if ($this->file_handle !== false)
- {
- $translated_message = call_user_func_array(array($this->user, 'lang'), $message) . "\n";
-
- if ($verbosity <= migrator_output_handler_interface::VERBOSITY_NORMAL)
- {
- $translated_message = '[INFO] ' . $translated_message;
- }
- else
- {
- $translated_message = '[DEBUG] ' . $translated_message;
- }
-
- fwrite($this->file_handle, $translated_message);
- fflush($this->file_handle);
- }
- }
-}
diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php
index 003ccf8f18..084d00a13a 100644
--- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php
+++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_5_rc1.php
@@ -57,7 +57,9 @@ class release_3_0_5_rc1 extends container_aware_migration
public function hash_old_passwords()
{
+ /* @var $passwords_manager \phpbb\passwords\manager */
$passwords_manager = $this->container->get('passwords.manager');
+
$sql = 'SELECT user_id, user_password
FROM ' . $this->table_prefix . 'users
WHERE user_pass_convert = 1';
@@ -116,7 +118,7 @@ class release_3_0_5_rc1 extends container_aware_migration
$result = $this->db->sql_query($sql);
// Skip first row, this is our original auth option we want to preserve
- $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_fetchrow($result);
while ($row = $this->db->sql_fetchrow($result))
{
diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_6_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_6_rc1.php
index faef68121d..40bb58c10d 100644
--- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_6_rc1.php
+++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_6_rc1.php
@@ -153,7 +153,10 @@ class release_3_0_6_rc1 extends \phpbb\db\migration\migration
'ACP_BOARD_CONFIGURATION',
array(
'module_basename' => 'acp_board',
- 'modes' => array('feed'),
+ 'module_langname' => 'ACP_FEED_SETTINGS',
+ 'module_mode' => 'feed',
+ 'module_auth' => 'acl_a_board',
+ 'after' => array('signature', 'ACP_SIGNATURE_SETTINGS'),
),
)),
array('module.add', array(
@@ -161,7 +164,11 @@ class release_3_0_6_rc1 extends \phpbb\db\migration\migration
'ACP_CAT_USERS',
array(
'module_basename' => 'acp_users',
- 'modes' => array('warnings'),
+ 'module_langname' => 'ACP_USER_WARNINGS',
+ 'module_mode' => 'warnings',
+ 'module_auth' => 'acl_a_user',
+ 'module_display' => false,
+ 'after' => array('feedback', 'ACP_USER_FEEDBACK'),
),
)),
array('module.add', array(
@@ -169,7 +176,9 @@ class release_3_0_6_rc1 extends \phpbb\db\migration\migration
'ACP_SERVER_CONFIGURATION',
array(
'module_basename' => 'acp_send_statistics',
- 'modes' => array('send_statistics'),
+ 'module_langname' => 'ACP_SEND_STATISTICS',
+ 'module_mode' => 'send_statistics',
+ 'module_auth' => 'acl_a_server',
),
)),
array('module.add', array(
@@ -177,7 +186,10 @@ class release_3_0_6_rc1 extends \phpbb\db\migration\migration
'ACP_FORUM_BASED_PERMISSIONS',
array(
'module_basename' => 'acp_permissions',
- 'modes' => array('setting_forum_copy'),
+ 'module_langname' => 'ACP_FORUM_PERMISSIONS_COPY',
+ 'module_mode' => 'setting_forum_copy',
+ 'module_auth' => 'acl_a_fauth && acl_a_authusers && acl_a_authgroups && acl_a_mauth',
+ 'after' => array('setting_forum_local', 'ACP_FORUM_PERMISSIONS'),
),
)),
array('module.add', array(
@@ -185,7 +197,29 @@ class release_3_0_6_rc1 extends \phpbb\db\migration\migration
'MCP_REPORTS',
array(
'module_basename' => 'mcp_pm_reports',
- 'modes' => array('pm_reports','pm_reports_closed','pm_report_details'),
+ 'module_langname' => 'MCP_PM_REPORTS_OPEN',
+ 'module_mode' => 'pm_reports',
+ 'module_auth' => 'acl_m_pm_report',
+ ),
+ )),
+ array('module.add', array(
+ 'mcp',
+ 'MCP_REPORTS',
+ array(
+ 'module_basename' => 'mcp_pm_reports',
+ 'module_langname' => 'MCP_PM_REPORTS_CLOSED',
+ 'module_mode' => 'pm_reports_closed',
+ 'module_auth' => 'acl_m_pm_report',
+ ),
+ )),
+ array('module.add', array(
+ 'mcp',
+ 'MCP_REPORTS',
+ array(
+ 'module_basename' => 'mcp_pm_reports',
+ 'module_langname' => 'MCP_PM_REPORT_DETAILS',
+ 'module_mode' => 'pm_report_details',
+ 'module_auth' => 'acl_m_pm_report',
),
)),
array('custom', array(array(&$this, 'add_newly_registered_group'))),
diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php
index 22fd51543b..836cb4577a 100644
--- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php
+++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_8_rc1.php
@@ -36,7 +36,10 @@ class release_3_0_8_rc1 extends \phpbb\db\migration\migration
'ACP_MESSAGES',
array(
'module_basename' => 'acp_board',
- 'modes' => array('post'),
+ 'module_langname' => 'ACP_POST_SETTINGS',
+ 'module_mode' => 'post',
+ 'module_auth' => 'acl_a_board',
+ 'after' => array('message', 'ACP_MESSAGE_SETTINGS'),
),
)),
array('config.add', array('load_unreads_search', 1)),
@@ -55,9 +58,14 @@ class release_3_0_8_rc1 extends \phpbb\db\migration\migration
$result = $this->db->sql_query($sql);
$extension_groups_updated = array();
- while ($lang_dir = $this->db->sql_fetchfield('lang_dir'))
+ while ($row = $this->db->sql_fetchrow($result))
{
- $lang_dir = basename($lang_dir);
+ if (empty($row['lang_dir']))
+ {
+ continue;
+ }
+
+ $lang_dir = basename($row['lang_dir']);
// The language strings we need are either in language/.../acp/attachments.php
// in the update package if we're updating to 3.0.8-RC1 or later,
diff --git a/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php b/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php
index 06e46d522f..5f928df47c 100644
--- a/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php
+++ b/phpBB/phpbb/db/migration/data/v30x/release_3_0_9_rc1.php
@@ -34,7 +34,7 @@ class release_3_0_9_rc1 extends \phpbb\db\migration\migration
// this column was removed from the database updater
// after 3.0.9-RC3 was released. It might still exist
// in 3.0.9-RCX installations and has to be dropped as
- // soon as the db_tools class is capable of properly
+ // soon as the \phpbb\db\tools\tools class is capable of properly
// removing a primary key.
// 'attempt_id' => array('UINT', NULL, 'auto_increment'),
'attempt_ip' => array('VCHAR:40', ''),
diff --git a/phpBB/phpbb/db/migration/data/v310/acp_prune_users_module.php b/phpBB/phpbb/db/migration/data/v310/acp_prune_users_module.php
index 0ca4f2f19c..725c57ca86 100644
--- a/phpBB/phpbb/db/migration/data/v310/acp_prune_users_module.php
+++ b/phpBB/phpbb/db/migration/data/v310/acp_prune_users_module.php
@@ -13,7 +13,7 @@
namespace phpbb\db\migration\data\v310;
-class acp_prune_users_module extends \phpbb\db\migration\migration
+class acp_prune_users_module extends \phpbb\db\migration\container_aware_migration
{
public function effectively_installed()
{
@@ -70,12 +70,7 @@ class acp_prune_users_module extends \phpbb\db\migration\migration
$acp_cat_users_id = (int) $this->db->sql_fetchfield('module_id');
$this->db->sql_freeresult($result);
- if (!class_exists('\acp_modules'))
- {
- include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
- }
- $module_manager = new \acp_modules();
- $module_manager->module_class = 'acp';
- $module_manager->move_module($acp_prune_users_id, $acp_cat_users_id);
+ $module_manager = $this->container->get('module.manager');
+ $module_manager->move_module($acp_prune_users_id, $acp_cat_users_id, 'acp');
}
}
diff --git a/phpBB/phpbb/db/migration/data/v310/auth_provider_oauth.php b/phpBB/phpbb/db/migration/data/v310/auth_provider_oauth.php
index 2d51bd53e4..1e2024a071 100644
--- a/phpBB/phpbb/db/migration/data/v310/auth_provider_oauth.php
+++ b/phpBB/phpbb/db/migration/data/v310/auth_provider_oauth.php
@@ -17,7 +17,12 @@ class auth_provider_oauth extends \phpbb\db\migration\migration
{
public function effectively_installed()
{
- return $this->db_tools->sql_table_exists($this->table_prefix . 'auth_provider_oauth');
+ return $this->db_tools->sql_table_exists($this->table_prefix . 'oauth_tokens');
+ }
+
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v30x\release_3_0_0');
}
public function update_schema()
@@ -69,7 +74,9 @@ class auth_provider_oauth extends \phpbb\db\migration\migration
'UCP_PROFILE',
array(
'module_basename' => 'ucp_auth_link',
- 'modes' => array('auth_link'),
+ 'module_langname' => 'UCP_AUTH_LINK_MANAGE',
+ 'module_mode' => 'auth_link',
+ 'module_auth' => 'authmethod_oauth',
),
)),
);
diff --git a/phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php b/phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php
index 20bd547ac3..e48a9a1d3d 100644
--- a/phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php
+++ b/phpBB/phpbb/db/migration/data/v310/contact_admin_acp_module.php
@@ -23,7 +23,9 @@ class contact_admin_acp_module extends \phpbb\db\migration\migration
'ACP_BOARD_CONFIGURATION',
array(
'module_basename' => 'acp_contact',
- 'modes' => array('contact'),
+ 'module_langname' => 'ACP_CONTACT_SETTINGS',
+ 'module_mode' => 'contact',
+ 'module_auth' => 'acl_a_board',
),
)),
);
diff --git a/phpBB/phpbb/db/migration/data/v310/dev.php b/phpBB/phpbb/db/migration/data/v310/dev.php
index f037191c2a..9cc953ad8d 100644
--- a/phpBB/phpbb/db/migration/data/v310/dev.php
+++ b/phpBB/phpbb/db/migration/data/v310/dev.php
@@ -13,7 +13,7 @@
namespace phpbb\db\migration\data\v310;
-class dev extends \phpbb\db\migration\migration
+class dev extends \phpbb\db\migration\container_aware_migration
{
public function effectively_installed()
{
@@ -125,7 +125,9 @@ class dev extends \phpbb\db\migration\migration
'ACP_GROUPS',
array(
'module_basename' => 'acp_groups',
- 'modes' => array('position'),
+ 'module_langname' => 'ACP_GROUPS_POSITION',
+ 'module_mode' => 'position',
+ 'module_auth' => 'acl_a_group',
),
)),
array('module.add', array(
@@ -133,7 +135,9 @@ class dev extends \phpbb\db\migration\migration
'ACP_ATTACHMENTS',
array(
'module_basename' => 'acp_attachments',
- 'modes' => array('manage'),
+ 'module_langname' => 'ACP_MANAGE_ATTACHMENTS',
+ 'module_mode' => 'manage',
+ 'module_auth' => 'acl_a_attach',
),
)),
array('module.add', array(
@@ -141,7 +145,19 @@ class dev extends \phpbb\db\migration\migration
'ACP_STYLE_MANAGEMENT',
array(
'module_basename' => 'acp_styles',
- 'modes' => array('install', 'cache'),
+ 'module_langname' => 'ACP_STYLES_INSTALL',
+ 'module_mode' => 'install',
+ 'module_auth' => 'acl_a_styles',
+ ),
+ )),
+ array('module.add', array(
+ 'acp',
+ 'ACP_STYLE_MANAGEMENT',
+ array(
+ 'module_basename' => 'acp_styles',
+ 'module_langname' => 'ACP_STYLES_CACHE',
+ 'module_mode' => 'cache',
+ 'module_auth' => 'acl_a_styles',
),
)),
array('module.add', array(
@@ -149,7 +165,8 @@ class dev extends \phpbb\db\migration\migration
'UCP_PROFILE',
array(
'module_basename' => 'ucp_profile',
- 'modes' => array('autologin_keys'),
+ 'module_langname' => 'UCP_PROFILE_AUTOLOGIN_KEYS',
+ 'module_mode' => 'autologin_keys',
),
)),
// Module will be renamed later
@@ -204,18 +221,13 @@ class dev extends \phpbb\db\migration\migration
$language_management_module_id = $this->db->sql_fetchfield('module_id');
$this->db->sql_freeresult($result);
- if (!class_exists('acp_modules'))
- {
- include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
- }
// acp_modules calls adm_back_link, which is undefined at this point
if (!function_exists('adm_back_link'))
{
include($this->phpbb_root_path . 'includes/functions_acp.' . $this->php_ext);
}
- $module_manager = new \acp_modules();
- $module_manager->module_class = 'acp';
- $module_manager->move_module($language_module_id, $language_management_module_id);
+ $module_manager = $this->container->get('module.manager');
+ $module_manager->move_module($language_module_id, $language_management_module_id, 'acp');
}
public function update_ucp_pm_basename()
diff --git a/phpBB/phpbb/db/migration/data/v310/extensions.php b/phpBB/phpbb/db/migration/data/v310/extensions.php
index 3171435482..2e7c5c5316 100644
--- a/phpBB/phpbb/db/migration/data/v310/extensions.php
+++ b/phpBB/phpbb/db/migration/data/v310/extensions.php
@@ -66,7 +66,9 @@ class extensions extends \phpbb\db\migration\migration
'ACP_EXTENSION_MANAGEMENT',
array(
'module_basename' => 'acp_extensions',
- 'modes' => array('main'),
+ 'module_langname' => 'ACP_EXTENSIONS',
+ 'module_mode' => 'main',
+ 'module_auth' => 'acl_a_extensions',
),
)),
array('permission.add', array('a_extensions', true, 'a_styles')),
diff --git a/phpBB/phpbb/db/migration/data/v310/notifications.php b/phpBB/phpbb/db/migration/data/v310/notifications.php
index f4d012b5ac..789aaa3ba9 100644
--- a/phpBB/phpbb/db/migration/data/v310/notifications.php
+++ b/phpBB/phpbb/db/migration/data/v310/notifications.php
@@ -85,7 +85,9 @@ class notifications extends \phpbb\db\migration\migration
'UCP_MAIN',
array(
'module_basename' => 'ucp_notifications',
- 'modes' => array('notification_list'),
+ 'module_langname' => 'UCP_NOTIFICATION_LIST',
+ 'module_mode' => 'notification_list',
+ 'module_auth' => 'cfg_allow_board_notifications',
),
)),
array('module.add', array(
@@ -93,7 +95,8 @@ class notifications extends \phpbb\db\migration\migration
'UCP_PREFS',
array(
'module_basename' => 'ucp_notifications',
- 'modes' => array('notification_options'),
+ 'module_langname' => 'UCP_NOTIFICATION_OPTIONS',
+ 'module_mode' => 'notification_options',
),
)),
array('config.add', array('load_notifications', 1)),
diff --git a/phpBB/phpbb/db/migration/data/v310/softdelete_mcp_modules.php b/phpBB/phpbb/db/migration/data/v310/softdelete_mcp_modules.php
index 5e68db5889..90dab991e1 100644
--- a/phpBB/phpbb/db/migration/data/v310/softdelete_mcp_modules.php
+++ b/phpBB/phpbb/db/migration/data/v310/softdelete_mcp_modules.php
@@ -45,7 +45,9 @@ class softdelete_mcp_modules extends \phpbb\db\migration\migration
'MCP_QUEUE',
array(
'module_basename' => 'mcp_queue',
- 'modes' => array('deleted_topics'),
+ 'module_langname' => 'MCP_QUEUE_DELETED_TOPICS',
+ 'module_mode' => 'deleted_topics',
+ 'module_auth' => 'aclf_m_approve',
),
)),
array('module.add', array(
@@ -53,7 +55,9 @@ class softdelete_mcp_modules extends \phpbb\db\migration\migration
'MCP_QUEUE',
array(
'module_basename' => 'mcp_queue',
- 'modes' => array('deleted_posts'),
+ 'module_langname' => 'MCP_QUEUE_DELETED_POSTS',
+ 'module_mode' => 'deleted_posts',
+ 'module_auth' => 'aclf_m_approve',
),
)),
);
diff --git a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php
index 2c7b7edf2e..a7e30a9cb7 100644
--- a/phpBB/phpbb/db/migration/data/v310/style_update_p1.php
+++ b/phpBB/phpbb/db/migration/data/v310/style_update_p1.php
@@ -133,7 +133,7 @@ class style_update_p1 extends \phpbb\db\migration\migration
}
// Remove old entries from styles table
- if (!sizeof($valid_styles))
+ if (!count($valid_styles))
{
// No valid styles: remove everything and add prosilver
$this->sql_query('DELETE FROM ' . STYLES_TABLE);
@@ -160,12 +160,12 @@ class style_update_p1 extends \phpbb\db\migration\migration
FROM ' . STYLES_TABLE . "
WHERE style_name = 'prosilver'";
$result = $this->sql_query($sql);
- $default_style = $this->db->sql_fetchfield('style_id');
+ $default_style = (int) $this->db->sql_fetchfield('style_id');
$this->db->sql_freeresult($result);
$this->config->set('default_style', $default_style);
- $sql = 'UPDATE ' . USERS_TABLE . ' SET user_style = 0';
+ $sql = 'UPDATE ' . USERS_TABLE . ' SET user_style = ' . (int) $default_style;
$this->sql_query($sql);
}
else
@@ -183,9 +183,9 @@ class style_update_p1 extends \phpbb\db\migration\migration
}
// Reset styles for users
- $this->sql_query('UPDATE ' . USERS_TABLE . '
- SET user_style = 0
- WHERE ' . $this->db->sql_in_set('user_style', $valid_styles, true));
+ $this->sql_query('UPDATE ' . USERS_TABLE . "
+ SET user_style = '" . (int) $valid_styles[0] . "'
+ WHERE " . $this->db->sql_in_set('user_style', $valid_styles, true));
}
}
}
diff --git a/phpBB/phpbb/db/migration/data/v310/teampage.php b/phpBB/phpbb/db/migration/data/v310/teampage.php
index f8edbc3492..3a37b17e97 100644
--- a/phpBB/phpbb/db/migration/data/v310/teampage.php
+++ b/phpBB/phpbb/db/migration/data/v310/teampage.php
@@ -93,13 +93,13 @@ class teampage extends \phpbb\db\migration\migration
$teampage_entries[] = array(
'group_id' => (int) $row['group_id'],
'teampage_name' => '',
- 'teampage_position' => sizeof($teampage_entries) + 1,
+ 'teampage_position' => count($teampage_entries) + 1,
'teampage_parent' => 0,
);
}
$this->db->sql_freeresult($result);
- if (sizeof($teampage_entries))
+ if (count($teampage_entries))
{
$this->db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_entries);
}
diff --git a/phpBB/phpbb/db/migration/data/v310/timezone.php b/phpBB/phpbb/db/migration/data/v310/timezone.php
index 1f6b47ad50..03a8d1ab34 100644
--- a/phpBB/phpbb/db/migration/data/v310/timezone.php
+++ b/phpBB/phpbb/db/migration/data/v310/timezone.php
@@ -103,7 +103,7 @@ class timezone extends \phpbb\db\migration\migration
*/
public function convert_phpbb30_timezone($timezone, $dst)
{
- $offset = $timezone + $dst;
+ $offset = (float) $timezone + (int) $dst;
switch ($timezone)
{
diff --git a/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php
index 854ed1f568..14b7b7b0f6 100644
--- a/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php
+++ b/phpBB/phpbb/db/migration/data/v31x/update_custom_bbcodes_with_idn.php
@@ -45,7 +45,6 @@ class update_custom_bbcodes_with_idn extends \phpbb\db\migration\migration
$sql_ary = array();
while ($row = $this->db->sql_fetchrow($result))
{
- $data = array();
if (preg_match('/(URL|LOCAL_URL|RELATIVE_URL)/', $row['bbcode_match']))
{
$data = $bbcodes->build_regexp($row['bbcode_match'], $row['bbcode_tpl']);
diff --git a/phpBB/phpbb/db/migration/data/v31x/v3112.php b/phpBB/phpbb/db/migration/data/v31x/v3112.php
new file mode 100644
index 0000000000..0d75d35184
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v31x/v3112.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v31x;
+
+class v3112 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.1.12', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v3111',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.1.12')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/.htaccess b/phpBB/phpbb/db/migration/data/v320/.htaccess
new file mode 100644
index 0000000000..44242b5418
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/.htaccess
@@ -0,0 +1,33 @@
+# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from
+# module mod_authz_host to a new module called mod_access_compat (which may be
+# disabled) and a new "Require" syntax has been introduced to mod_authz_host.
+# We could just conditionally provide both versions, but unfortunately Apache
+# does not explicitly tell us its version if the module mod_version is not
+# available. In this case, we check for the availability of module
+# mod_authz_core (which should be on 2.4 or higher only) as a best guess.
+<IfModule mod_version.c>
+ <IfVersion < 2.4>
+ <Files "*">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ </IfVersion>
+ <IfVersion >= 2.4>
+ <Files "*">
+ Require all denied
+ </Files>
+ </IfVersion>
+</IfModule>
+<IfModule !mod_version.c>
+ <IfModule !mod_authz_core.c>
+ <Files "*">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ </IfModule>
+ <IfModule mod_authz_core.c>
+ <Files "*">
+ Require all denied
+ </Files>
+ </IfModule>
+</IfModule>
diff --git a/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php b/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php
new file mode 100644
index 0000000000..804adc4490
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/add_help_phpbb.php
@@ -0,0 +1,48 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class add_help_phpbb extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320rc1',
+ );
+ }
+
+ public function effectively_installed()
+ {
+ return isset($this->config['help_send_statistics']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('help_send_statistics', true)),
+ array('config.add', array('help_send_statistics_time', 0)),
+ array('module.remove', array('acp', false, 'ACP_SEND_STATISTICS')),
+ array('module.add', array(
+ 'acp',
+ 'ACP_SERVER_CONFIGURATION',
+ array(
+ 'module_basename' => 'acp_help_phpbb',
+ 'module_langname' => 'ACP_HELP_PHPBB',
+ 'module_mode' => 'help_phpbb',
+ 'module_auth' => 'acl_a_server',
+ ),
+ )),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/allowed_schemes_links.php b/phpBB/phpbb/db/migration/data/v320/allowed_schemes_links.php
new file mode 100644
index 0000000000..726822bc71
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/allowed_schemes_links.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class allowed_schemes_links extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('allowed_schemes_links', 'http,https,ftp')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/announce_global_permission.php b/phpBB/phpbb/db/migration/data/v320/announce_global_permission.php
new file mode 100644
index 0000000000..7afecb884b
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/announce_global_permission.php
@@ -0,0 +1,43 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class announce_global_permission extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ $sql = 'SELECT auth_option_id
+ FROM ' . ACL_OPTIONS_TABLE . "
+ WHERE auth_option = 'f_announce_global'";
+ $result = $this->db->sql_query($sql);
+ $auth_option_id = $this->db->sql_fetchfield('auth_option_id');
+ $this->db->sql_freeresult($result);
+
+ return $auth_option_id !== false;
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('permission.add', array('f_announce_global', false, 'f_announce')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/cookie_notice.php b/phpBB/phpbb/db/migration/data/v320/cookie_notice.php
new file mode 100644
index 0000000000..75cb03b3ef
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/cookie_notice.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class cookie_notice extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320rc2',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('cookie_notice', false)),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/default_data_type_ids.php b/phpBB/phpbb/db/migration/data/v320/default_data_type_ids.php
new file mode 100644
index 0000000000..65e5b3fa73
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/default_data_type_ids.php
@@ -0,0 +1,361 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class default_data_type_ids extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320a2',
+ '\phpbb\db\migration\data\v320\oauth_states',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'acl_users' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'attachments' => array(
+ 'attach_id' => array('ULINT', null, 'auto_increment'),
+ 'post_msg_id' => array('ULINT', 0),
+ 'poster_id' => array('ULINT', 0),
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'banlist' => array(
+ 'ban_id' => array('ULINT', null, 'auto_increment'),
+ 'ban_userid' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'bookmarks' => array(
+ 'topic_id' => array('ULINT', 0),
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'bots' => array(
+ 'bot_id' => array('ULINT', null, 'auto_increment'),
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'drafts' => array(
+ 'draft_id' => array('ULINT', null, 'auto_increment'),
+ 'user_id' => array('ULINT', 0),
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'forums' => array(
+ 'forum_last_post_id' => array('ULINT', 0),
+ 'forum_last_poster_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'forums_access' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'forums_track' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'forums_watch' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'log' => array(
+ 'log_id' => array('ULINT', null, 'auto_increment'),
+ 'post_id' => array('ULINT', 0),
+ 'reportee_id' => array('ULINT', 0),
+ 'user_id' => array('ULINT', 0),
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'login_attempts' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'moderator_cache' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'notifications' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'oauth_accounts' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'oauth_states' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'oauth_tokens' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'poll_options' => array(
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'poll_votes' => array(
+ 'topic_id' => array('ULINT', 0),
+ 'vote_user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'posts' => array(
+ 'post_id' => array('ULINT', null, 'auto_increment'),
+ 'poster_id' => array('ULINT', 0),
+ 'post_delete_user' => array('ULINT', 0),
+ 'post_edit_user' => array('ULINT', 0),
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'privmsgs' => array(
+ 'author_id' => array('ULINT', 0),
+ 'message_edit_user' => array('ULINT', 0),
+ 'msg_id' => array('ULINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'privmsgs_folder' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'privmsgs_rules' => array(
+ 'rule_user_id' => array('ULINT', 0),
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'privmsgs_to' => array(
+ 'author_id' => array('ULINT', 0),
+ 'msg_id' => array('ULINT', 0),
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'profile_fields_data' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'reports' => array(
+ 'report_id' => array('ULINT', 0),
+ 'pm_id' => array('ULINT', 0),
+ 'post_id' => array('ULINT', 0),
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'search_wordlist' => array(
+ 'word_id' => array('ULINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'search_wordmatch' => array(
+ 'post_id' => array('ULINT', 0),
+ 'word_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'sessions' => array(
+ 'session_user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'sessions_keys' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'topics' => array(
+ 'topic_id' => array('ULINT', null, 'auto_increment'),
+ 'topic_poster' => array('ULINT', 0),
+ 'topic_first_post_id' => array('ULINT', 0),
+ 'topic_last_post_id' => array('ULINT', 0),
+ 'topic_last_poster_id' => array('ULINT', 0),
+ 'topic_moved_id' => array('ULINT', 0),
+ 'topic_delete_user' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'topics_track' => array(
+ 'user_id' => array('ULINT', 0),
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'topics_posted' => array(
+ 'user_id' => array('ULINT', 0),
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'topics_watch' => array(
+ 'user_id' => array('ULINT', 0),
+ 'topic_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'user_notifications' => array(
+ 'item_id' => array('ULINT', 0),
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'user_group' => array(
+ 'user_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'users' => array(
+ 'user_id' => array('ULINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'warnings' => array(
+ 'log_id' => array('ULINT', 0),
+ 'user_id' => array('ULINT', 0),
+ 'post_id' => array('ULINT', 0),
+ ),
+ $this->table_prefix . 'words' => array(
+ 'word_id' => array('ULINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'zebra' => array(
+ 'user_id' => array('ULINT', 0),
+ 'zebra_id' => array('ULINT', 0),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'acl_users' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'attachments' => array(
+ 'attach_id' => array('UINT', null, 'auto_increment'),
+ 'post_msg_id' => array('UINT', 0),
+ 'poster_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'banlist' => array(
+ 'ban_id' => array('UINT', null, 'auto_increment'),
+ 'ban_userid' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'bookmarks' => array(
+ 'topic_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'bots' => array(
+ 'bot_id' => array('UINT', null, 'auto_increment'),
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'drafts' => array(
+ 'draft_id' => array('UINT', null, 'auto_increment'),
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'forums' => array(
+ 'forum_last_post_id' => array('UINT', 0),
+ 'forum_last_poster_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'forums_access' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'forums_track' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'forums_watch' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'log' => array(
+ 'log_id' => array('UINT', null, 'auto_increment'),
+ 'post_id' => array('UINT', 0),
+ 'reportee_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'login_attempts' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'moderator_cache' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'notifications' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'oauth_accounts' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'oauth_states' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'oauth_tokens' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'poll_options' => array(
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'poll_votes' => array(
+ 'topic_id' => array('UINT', 0),
+ 'vote_user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'posts' => array(
+ 'post_id' => array('UINT', null, 'auto_increment'),
+ 'poster_id' => array('UINT', 0),
+ 'post_delete_user' => array('UINT', 0),
+ 'post_edit_user' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'privmsgs' => array(
+ 'author_id' => array('UINT', 0),
+ 'message_edit_user' => array('UINT', 0),
+ 'msg_id' => array('UINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'privmsgs_folder' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'privmsgs_rules' => array(
+ 'rule_user_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'privmsgs_to' => array(
+ 'author_id' => array('UINT', 0),
+ 'msg_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'profile_fields_data' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'reports' => array(
+ 'report_id' => array('UINT', 0),
+ 'pm_id' => array('UINT', 0),
+ 'post_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'search_wordlist' => array(
+ 'word_id' => array('UINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'search_wordmatch' => array(
+ 'post_id' => array('UINT', 0),
+ 'word_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'sessions' => array(
+ 'session_user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'sessions_keys' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'topics' => array(
+ 'topic_id' => array('UINT', null, 'auto_increment'),
+ 'topic_poster' => array('UINT', 0),
+ 'topic_first_post_id' => array('UINT', 0),
+ 'topic_last_post_id' => array('UINT', 0),
+ 'topic_last_poster_id' => array('UINT', 0),
+ 'topic_moved_id' => array('UINT', 0),
+ 'topic_delete_user' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'topics_track' => array(
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'topics_posted' => array(
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'topics_watch' => array(
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'user_notifications' => array(
+ 'item_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'user_group' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'users' => array(
+ 'user_id' => array('UINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'warnings' => array(
+ 'log_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'post_id' => array('UINT', 0),
+ ),
+ $this->table_prefix . 'words' => array(
+ 'word_id' => array('UINT', null, 'auto_increment'),
+ ),
+ $this->table_prefix . 'zebra' => array(
+ 'user_id' => array('UINT', 0),
+ 'zebra_id' => array('UINT', 0),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/dev.php b/phpBB/phpbb/db/migration/data/v320/dev.php
new file mode 100644
index 0000000000..ad2da3c1f4
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/dev.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class dev extends \phpbb\db\migration\container_aware_migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0-dev', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v316',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0-dev')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/font_awesome_update.php b/phpBB/phpbb/db/migration/data/v320/font_awesome_update.php
new file mode 100644
index 0000000000..817b638037
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/font_awesome_update.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class font_awesome_update extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function effectively_installed()
+ {
+ return isset($this->config['load_font_awesome_url']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('load_font_awesome_url', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/icons_alt.php b/phpBB/phpbb/db/migration/data/v320/icons_alt.php
new file mode 100644
index 0000000000..80132e579e
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/icons_alt.php
@@ -0,0 +1,46 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class icons_alt extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_columns' => array(
+ $this->table_prefix . 'icons' => array(
+ 'icons_alt' => array('VCHAR', '', 'after' => 'icons_height'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_columns' => array(
+ $this->table_prefix . 'icons' => array(
+ 'icons_alt',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/log_post_id.php b/phpBB/phpbb/db/migration/data/v320/log_post_id.php
new file mode 100644
index 0000000000..ead53c8138
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/log_post_id.php
@@ -0,0 +1,46 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class log_post_id extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_columns' => array(
+ $this->table_prefix . 'log' => array(
+ 'post_id' => array('UINT', 0, 'after' => 'topic_id'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_columns' => array(
+ $this->table_prefix . 'log' => array(
+ 'post_id',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/notifications_board.php b/phpBB/phpbb/db/migration/data/v320/notifications_board.php
new file mode 100644
index 0000000000..ac1b3a0f2c
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/notifications_board.php
@@ -0,0 +1,75 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class notifications_board extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('allow_board_notifications', 1)),
+ array('custom', array(array($this, 'update_user_subscriptions'))),
+ array('custom', array(array($this, 'update_module'))),
+ );
+ }
+
+ public function update_module()
+ {
+ $sql = 'UPDATE ' . MODULES_TABLE . "
+ SET module_auth = 'cfg_allow_board_notifications'
+ WHERE module_basename = 'ucp_notifications'
+ AND module_mode = 'notification_list'";
+ $this->sql_query($sql);
+ }
+
+ public function update_user_subscriptions()
+ {
+ $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . "
+ SET method = 'notification.method.board'
+ WHERE method = ''";
+ $this->sql_query($sql);
+ }
+
+ public function revert_data()
+ {
+ return array(
+ array('custom', array(array($this, 'revert_user_subscriptions'))),
+ array('custom', array(array($this, 'revert_module'))),
+ );
+ }
+
+ public function revert_user_subscriptions()
+ {
+ $sql = 'UPDATE ' . USER_NOTIFICATIONS_TABLE . "
+ SET method = ''
+ WHERE method = 'notification.method.board'";
+ $this->sql_query($sql);
+ }
+
+ public function revert_module()
+ {
+ $sql = 'UPDATE ' . MODULES_TABLE . "
+ SET auth = ''
+ WHERE module_basename = 'ucp_notifications'
+ AND module_mode = 'notification_list'";
+ $this->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/oauth_states.php b/phpBB/phpbb/db/migration/data/v320/oauth_states.php
new file mode 100644
index 0000000000..22ab2dabb3
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/oauth_states.php
@@ -0,0 +1,56 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class oauth_states extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v310\auth_provider_oauth');
+ }
+
+ public function effectively_installed()
+ {
+ return $this->db_tools->sql_table_exists($this->table_prefix . 'oauth_states');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_tables' => array(
+ $this->table_prefix . 'oauth_states' => array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', 0),
+ 'session_id' => array('CHAR:32', ''),
+ 'provider' => array('VCHAR', ''),
+ 'oauth_state' => array('VCHAR', ''),
+ ),
+ 'KEYS' => array(
+ 'user_id' => array('INDEX', 'user_id'),
+ 'provider' => array('INDEX', 'provider'),
+ ),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'oauth_states',
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/remote_upload_validation.php b/phpBB/phpbb/db/migration/data/v320/remote_upload_validation.php
new file mode 100644
index 0000000000..d61f6b96fd
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/remote_upload_validation.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class remote_upload_validation extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320a2',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('remote_upload_verify', '0')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/remove_outdated_media.php b/phpBB/phpbb/db/migration/data/v320/remove_outdated_media.php
new file mode 100644
index 0000000000..88fe59ccc9
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/remove_outdated_media.php
@@ -0,0 +1,95 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class remove_outdated_media extends \phpbb\db\migration\migration
+{
+ // Following constants were deprecated in 3.2
+ // and moved from constants.php to compatibility_globals.php,
+ // thus define them as class constants
+ const ATTACHMENT_CATEGORY_WM = 2;
+ const ATTACHMENT_CATEGORY_RM = 3;
+ const ATTACHMENT_CATEGORY_QUICKTIME = 6;
+
+ protected $cat_id = array(
+ self::ATTACHMENT_CATEGORY_WM,
+ self::ATTACHMENT_CATEGORY_RM,
+ self::ATTACHMENT_CATEGORY_QUICKTIME,
+ );
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'change_extension_group'))),
+ );
+ }
+
+ public function change_extension_group()
+ {
+ // select group ids of outdated media
+ $sql = 'SELECT group_id
+ FROM ' . EXTENSION_GROUPS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('cat_id', $this->cat_id);
+ $result = $this->db->sql_query($sql);
+
+ $group_ids = array();
+ while ($group_id = (int) $this->db->sql_fetchfield('group_id'))
+ {
+ $group_ids[] = $group_id;
+ }
+ $this->db->sql_freeresult($result);
+
+ // nothing to do, admin has removed all the outdated media extension groups
+ if (empty($group_ids))
+ {
+ return true;
+ }
+
+ // get the group id of downloadable files
+ $sql = 'SELECT group_id
+ FROM ' . EXTENSION_GROUPS_TABLE . "
+ WHERE group_name = 'DOWNLOADABLE_FILES'";
+ $result = $this->db->sql_query($sql);
+ $download_id = (int) $this->db->sql_fetchfield('group_id');
+ $this->db->sql_freeresult($result);
+
+ if (empty($download_id))
+ {
+ $sql = 'UPDATE ' . EXTENSIONS_TABLE . '
+ SET group_id = 0
+ WHERE ' . $this->db->sql_in_set('group_id', $group_ids);
+ }
+ else
+ {
+ // move outdated media extensions to downloadable files
+ $sql = 'UPDATE ' . EXTENSIONS_TABLE . "
+ SET group_id = $download_id" . '
+ WHERE ' . $this->db->sql_in_set('group_id', $group_ids);
+ }
+
+ $this->db->sql_query($sql);
+
+ // delete the now empty, outdated media extension groups
+ $sql = 'DELETE FROM ' . EXTENSION_GROUPS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('group_id', $group_ids);
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/remove_profilefield_wlm.php b/phpBB/phpbb/db/migration/data/v320/remove_profilefield_wlm.php
new file mode 100644
index 0000000000..1cb9070bf9
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/remove_profilefield_wlm.php
@@ -0,0 +1,152 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class remove_profilefield_wlm extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'drop_columns' => array(
+ $this->table_prefix . 'profile_fields_data' => array(
+ 'pf_phpbb_wlm',
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'add_columns' => array(
+ $this->table_prefix . 'profile_fields_data' => array(
+ 'pf_phpbb_wlm' => array('VCHAR', ''),
+ ),
+ ),
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'delete_custom_profile_field_data'))),
+ );
+ }
+
+ public function revert_data()
+ {
+ return array(
+ array('custom', array(array($this, 'create_custom_field'))),
+ );
+ }
+
+ public function delete_custom_profile_field_data()
+ {
+ $field_id = $this->get_custom_profile_field_id();
+
+ $sql = 'DELETE FROM ' . PROFILE_FIELDS_TABLE . '
+ WHERE field_id = ' . (int) $field_id;
+ $this->db->sql_query($sql);
+
+ $sql = 'DELETE FROM ' . PROFILE_LANG_TABLE . '
+ WHERE field_id = ' . (int) $field_id;
+ $this->db->sql_query($sql);
+
+ $sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . '
+ WHERE field_id = ' . (int) $field_id;
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Get custom profile field id
+ * @return int custom profile filed id
+ */
+ public function get_custom_profile_field_id()
+ {
+ $sql = 'SELECT field_id
+ FROM ' . PROFILE_FIELDS_TABLE . "
+ WHERE field_name = 'phpbb_wlm'";
+ $result = $this->db->sql_query($sql);
+ $field_id = (int) $this->db->sql_fetchfield('field_id');
+ $this->db->sql_freeresult($result);
+
+ return $field_id;
+ }
+
+ public function create_custom_field()
+ {
+ $sql = 'SELECT MAX(field_order) as max_field_order
+ FROM ' . PROFILE_FIELDS_TABLE;
+ $result = $this->db->sql_query($sql);
+ $max_field_order = (int) $this->db->sql_fetchfield('max_field_order');
+ $this->db->sql_freeresult($result);
+
+ $sql_ary = array(
+ 'field_name' => 'phpbb_wlm',
+ 'field_type' => 'profilefields.type.string',
+ 'field_ident' => 'phpbb_wlm',
+ 'field_length' => '40',
+ 'field_minlen' => '5',
+ 'field_maxlen' => '255',
+ 'field_novalue' => '',
+ 'field_default_value' => '',
+ 'field_validation' => '.*',
+ 'field_required' => 0,
+ 'field_show_novalue' => 0,
+ 'field_show_on_reg' => 0,
+ 'field_show_on_pm' => 1,
+ 'field_show_on_vt' => 1,
+ 'field_show_on_ml' => 0,
+ 'field_show_profile' => 1,
+ 'field_hide' => 0,
+ 'field_no_view' => 0,
+ 'field_active' => 1,
+ 'field_is_contact' => 1,
+ 'field_contact_desc' => '',
+ 'field_contact_url' => '',
+ 'field_order' => $max_field_order + 1,
+ );
+
+ $sql = 'INSERT INTO ' . PROFILE_FIELDS_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
+ $this->db->sql_query($sql);
+ $field_id = (int) $this->db->sql_nextid();
+
+ $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, PROFILE_LANG_TABLE);
+
+ $sql = 'SELECT lang_id
+ FROM ' . LANG_TABLE;
+ $result = $this->db->sql_query($sql);
+ $lang_name = 'WLM';
+ while ($lang_id = (int) $this->db->sql_fetchfield('lang_id'))
+ {
+ $insert_buffer->insert(array(
+ 'field_id' => (int) $field_id,
+ 'lang_id' => (int) $lang_id,
+ 'lang_name' => $lang_name,
+ 'lang_explain' => '',
+ 'lang_default_value' => '',
+ ));
+ }
+ $this->db->sql_freeresult($result);
+
+ $insert_buffer->flush();
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/report_id_auto_increment.php b/phpBB/phpbb/db/migration/data/v320/report_id_auto_increment.php
new file mode 100644
index 0000000000..6e81baefb9
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/report_id_auto_increment.php
@@ -0,0 +1,46 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class report_id_auto_increment extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\default_data_type_ids',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'reports' => array(
+ 'report_id' => array('ULINT', null, 'auto_increment'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'reports' => array(
+ 'report_id' => array('ULINT', 0),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/text_reparser.php b/phpBB/phpbb/db/migration/data/v320/text_reparser.php
new file mode 100644
index 0000000000..6b8cf93cc9
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/text_reparser.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v320;
+
+use phpbb\textreparser\manager;
+use phpbb\textreparser\reparser_interface;
+
+class text_reparser extends \phpbb\db\migration\container_aware_migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v310\contact_admin_form',
+ '\phpbb\db\migration\data\v320\allowed_schemes_links',
+ );
+ }
+
+ public function effectively_installed()
+ {
+ return isset($this->config['reparse_lock']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('reparse_lock', 0, true)),
+ array('config.add', array('text_reparser.pm_text_cron_interval', 10)),
+ array('config.add', array('text_reparser.pm_text_last_cron', 0)),
+ array('config.add', array('text_reparser.poll_option_cron_interval', 10)),
+ array('config.add', array('text_reparser.poll_option_last_cron', 0)),
+ array('config.add', array('text_reparser.poll_title_cron_interval', 10)),
+ array('config.add', array('text_reparser.poll_title_last_cron', 0)),
+ array('config.add', array('text_reparser.post_text_cron_interval', 10)),
+ array('config.add', array('text_reparser.post_text_last_cron', 0)),
+ array('config.add', array('text_reparser.user_signature_cron_interval', 10)),
+ array('config.add', array('text_reparser.user_signature_last_cron', 0)),
+ array('custom', array(array($this, 'reparse'))),
+ );
+ }
+
+ public function reparse($resume_data)
+ {
+ /** @var manager $reparser_manager */
+ $reparser_manager = $this->container->get('text_reparser.manager');
+
+ if (!is_array($resume_data))
+ {
+ /** @var reparser_interface[] $reparsers */
+ $reparsers = $this->container->get('text_reparser_collection');
+
+ // Initialize all reparsers
+ foreach ($reparsers as $name => $reparser)
+ {
+ $reparser_manager->update_resume_data($name, 1, $reparser->get_max_id(), 100);
+ }
+ }
+
+ // Sometimes a cron job is too much
+ $limit = 100;
+ $fast_reparsers = array(
+ 'text_reparser.contact_admin_info',
+ 'text_reparser.forum_description',
+ 'text_reparser.forum_rules',
+ 'text_reparser.group_description',
+ );
+
+ if (!is_array($resume_data))
+ {
+ $resume_data = array(
+ 'reparser' => 0,
+ 'current' => $this->container->get($fast_reparsers[0])->get_max_id(),
+ );
+ }
+
+ $fast_reparsers_size = count($fast_reparsers);
+ $processed_records = 0;
+ while ($processed_records < $limit && $resume_data['reparser'] < $fast_reparsers_size)
+ {
+ $reparser = $this->container->get($fast_reparsers[$resume_data['reparser']]);
+
+ // New reparser
+ if ($resume_data['current'] === 0)
+ {
+ $resume_data['current'] = $reparser->get_max_id();
+ }
+
+ $start = max(1, $resume_data['current'] + 1 - ($limit - $processed_records));
+ $end = max(1, $resume_data['current']);
+ $reparser->reparse_range($start, $end);
+
+ $processed_records += $end - $start + 1;
+ $resume_data['current'] = $start - 1;
+
+ if ($start === 1)
+ {
+ // Prevent CLI command from running these reparsers again
+ $reparser_manager->update_resume_data($fast_reparsers[$resume_data['reparser']], 1, 0, $limit);
+
+ $resume_data['reparser']++;
+ }
+ }
+
+ if ($resume_data['reparser'] === $fast_reparsers_size)
+ {
+ return true;
+ }
+
+ return $resume_data;
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/v320.php b/phpBB/phpbb/db/migration/data/v320/v320.php
new file mode 100644
index 0000000000..20e741cb8b
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/v320.php
@@ -0,0 +1,40 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+use phpbb\db\migration\migration;
+
+class v320 extends migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\increase_size_of_emotion',
+ '\phpbb\db\migration\data\v320\cookie_notice',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/v320a1.php b/phpBB/phpbb/db/migration/data/v320/v320a1.php
new file mode 100644
index 0000000000..d7ecb36f90
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/v320a1.php
@@ -0,0 +1,44 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class v320a1 extends \phpbb\db\migration\container_aware_migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0-a1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\dev',
+ '\phpbb\db\migration\data\v320\allowed_schemes_links',
+ '\phpbb\db\migration\data\v320\announce_global_permission',
+ '\phpbb\db\migration\data\v320\remove_profilefield_wlm',
+ '\phpbb\db\migration\data\v320\font_awesome_update',
+ '\phpbb\db\migration\data\v320\icons_alt',
+ '\phpbb\db\migration\data\v320\log_post_id',
+ '\phpbb\db\migration\data\v320\remove_outdated_media',
+ '\phpbb\db\migration\data\v320\notifications_board',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0-dev')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/v320a2.php b/phpBB/phpbb/db/migration/data/v320/v320a2.php
new file mode 100644
index 0000000000..ae53a73210
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/v320a2.php
@@ -0,0 +1,38 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class v320a2 extends \phpbb\db\migration\container_aware_migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0-a2', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v317rc1',
+ '\phpbb\db\migration\data\v320\text_reparser',
+ '\phpbb\db\migration\data\v320\v320a1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0-a2')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/v320b1.php b/phpBB/phpbb/db/migration/data/v320/v320b1.php
new file mode 100644
index 0000000000..5c3a3797cd
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/v320b1.php
@@ -0,0 +1,39 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+class v320b1 extends \phpbb\db\migration\container_aware_migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0-b1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v317pl1',
+ '\phpbb\db\migration\data\v320\v320a2',
+ '\phpbb\db\migration\data\v31x\increase_size_of_dateformat',
+ '\phpbb\db\migration\data\v320\default_data_type_ids',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0-b1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/v320b2.php b/phpBB/phpbb/db/migration/data/v320/v320b2.php
new file mode 100644
index 0000000000..007f7588e6
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/v320b2.php
@@ -0,0 +1,40 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+use phpbb\db\migration\migration;
+
+class v320b2 extends migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0-b2', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v318',
+ '\phpbb\db\migration\data\v320\v320b1',
+ '\phpbb\db\migration\data\v320\remote_upload_validation',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0-b2')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/v320rc1.php b/phpBB/phpbb/db/migration/data/v320/v320rc1.php
new file mode 100644
index 0000000000..a04a2abb19
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/v320rc1.php
@@ -0,0 +1,40 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+use phpbb\db\migration\migration;
+
+class v320rc1 extends migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v319',
+ '\phpbb\db\migration\data\v320\report_id_auto_increment',
+ '\phpbb\db\migration\data\v320\v320b2',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v320/v320rc2.php b/phpBB/phpbb/db/migration/data/v320/v320rc2.php
new file mode 100644
index 0000000000..ec9bb62732
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v320/v320rc2.php
@@ -0,0 +1,40 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v320;
+
+use phpbb\db\migration\migration;
+
+class v320rc2 extends migration
+{
+ public function effectively_installed()
+ {
+ return version_compare($this->config['version'], '3.2.0-RC2', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\remove_duplicate_migrations',
+ '\phpbb\db\migration\data\v31x\add_log_time_index',
+ '\phpbb\db\migration\data\v320\add_help_phpbb',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.0-RC2')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/.htaccess b/phpBB/phpbb/db/migration/data/v32x/.htaccess
new file mode 100644
index 0000000000..44242b5418
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/.htaccess
@@ -0,0 +1,33 @@
+# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from
+# module mod_authz_host to a new module called mod_access_compat (which may be
+# disabled) and a new "Require" syntax has been introduced to mod_authz_host.
+# We could just conditionally provide both versions, but unfortunately Apache
+# does not explicitly tell us its version if the module mod_version is not
+# available. In this case, we check for the availability of module
+# mod_authz_core (which should be on 2.4 or higher only) as a best guess.
+<IfModule mod_version.c>
+ <IfVersion < 2.4>
+ <Files "*">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ </IfVersion>
+ <IfVersion >= 2.4>
+ <Files "*">
+ Require all denied
+ </Files>
+ </IfVersion>
+</IfModule>
+<IfModule !mod_version.c>
+ <IfModule !mod_authz_core.c>
+ <Files "*">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ </IfModule>
+ <IfModule mod_authz_core.c>
+ <Files "*">
+ Require all denied
+ </Files>
+ </IfModule>
+</IfModule>
diff --git a/phpBB/phpbb/db/migration/data/v32x/cookie_notice_p2.php b/phpBB/phpbb/db/migration/data/v32x/cookie_notice_p2.php
new file mode 100644
index 0000000000..1a83175705
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/cookie_notice_p2.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class cookie_notice_p2 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320',
+ );
+ }
+
+ public function effectively_installed()
+ {
+ return isset($this->config['cookie_notice']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('cookie_notice', '0')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/disable_remote_avatar.php b/phpBB/phpbb/db/migration/data/v32x/disable_remote_avatar.php
new file mode 100644
index 0000000000..b08833fad4
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/disable_remote_avatar.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+use phpbb\db\migration\migration;
+
+class disable_remote_avatar extends migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v325',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('allow_avatar_remote', '0')),
+ array('config.update', array('allow_avatar_remote_upload', '0')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/email_force_sender.php b/phpBB/phpbb/db/migration/data/v32x/email_force_sender.php
new file mode 100644
index 0000000000..5319b7f76e
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/email_force_sender.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class email_force_sender extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v321',
+ );
+ }
+
+ public function effectively_installed()
+ {
+ return isset($this->config['email_force_sender']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('email_force_sender', '0')),
+ array('config.remove', array('email_function_name')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/enable_accurate_pm_button.php b/phpBB/phpbb/db/migration/data/v32x/enable_accurate_pm_button.php
new file mode 100644
index 0000000000..a7b99606f7
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/enable_accurate_pm_button.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class enable_accurate_pm_button extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v322',
+ );
+ }
+
+ public function effectively_installed()
+ {
+ return isset($this->config['enable_accurate_pm_button']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('enable_accurate_pm_button', '1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/f_list_topics_permission_add.php b/phpBB/phpbb/db/migration/data/v32x/f_list_topics_permission_add.php
new file mode 100644
index 0000000000..49727e5a62
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/f_list_topics_permission_add.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class f_list_topics_permission_add extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v321',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('permission.add', array('f_list_topics', false, 'f_read')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/fix_user_styles.php b/phpBB/phpbb/db/migration/data/v32x/fix_user_styles.php
new file mode 100644
index 0000000000..16fbdbc77b
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/fix_user_styles.php
@@ -0,0 +1,54 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class fix_user_styles extends \phpbb\db\migration\migration
+{
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'styles_fix'))),
+ );
+ }
+
+ public function styles_fix()
+ {
+ $default_style = (int) $this->config['default_style'];
+ $enabled_styles = array();
+
+ // Get enabled styles
+ $sql = 'SELECT style_id
+ FROM ' . STYLES_TABLE . '
+ WHERE style_active = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $enabled_styles[] = (int) $row['style_id'];
+ }
+ $this->db->sql_freeresult($result);
+
+ // Set the default style to users who have an invalid style
+ $this->sql_query('UPDATE ' . USERS_TABLE . '
+ SET user_style = ' . (int) $default_style . '
+ WHERE ' . $this->db->sql_in_set('user_style', $enabled_styles, true));
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/forum_topics_per_page_type.php b/phpBB/phpbb/db/migration/data/v32x/forum_topics_per_page_type.php
new file mode 100644
index 0000000000..afcecf2ef0
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/forum_topics_per_page_type.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class forum_topics_per_page_type extends \phpbb\db\migration\migration
+{
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v323',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'forums' => array(
+ 'forum_topics_per_page' => array('USINT', 0),
+ ),
+ ),
+ );
+ }
+
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/jquery_update.php b/phpBB/phpbb/db/migration/data/v32x/jquery_update.php
new file mode 100644
index 0000000000..6dc58ec638
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/jquery_update.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class jquery_update extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return $this->config['load_jquery_url'] === '//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js';
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v325rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js')),
+ );
+ }
+
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/load_user_activity_limit.php b/phpBB/phpbb/db/migration/data/v32x/load_user_activity_limit.php
new file mode 100644
index 0000000000..71bb6c00bf
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/load_user_activity_limit.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class load_user_activity_limit extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320',
+ );
+ }
+
+ public function effectively_installed()
+ {
+ return isset($this->config['load_user_activity_limit']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('load_user_activity_limit', '5000')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php b/phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php
new file mode 100644
index 0000000000..71ee19e3dd
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/merge_duplicate_bbcodes.php
@@ -0,0 +1,84 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class merge_duplicate_bbcodes extends \phpbb\db\migration\container_aware_migration
+{
+ public function update_data()
+ {
+ return [
+ ['custom', [[$this, 'update_bbcodes_table']]],
+ ];
+ }
+
+ public function update_bbcodes_table()
+ {
+ $sql = 'SELECT bbcode_id, bbcode_tag, bbcode_helpline, bbcode_match, bbcode_tpl FROM ' . BBCODES_TABLE;
+ $result = $this->sql_query($sql);
+ $bbcodes = [];
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $variant = (substr($row['bbcode_tag'], -1) === '=') ? 'with': 'without';
+ $bbcode_name = strtolower(rtrim($row['bbcode_tag'], '='));
+ $bbcodes[$bbcode_name][$variant] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ foreach ($bbcodes as $bbcode_name => $variants)
+ {
+ if (count($variants) === 2)
+ {
+ $this->merge_bbcodes($variants['without'], $variants['with']);
+ }
+ }
+ }
+
+ protected function merge_bbcodes(array $without, array $with)
+ {
+ try
+ {
+ $merged = $this->container->get('text_formatter.s9e.bbcode_merger')->merge_bbcodes(
+ [
+ 'usage' => $without['bbcode_match'],
+ 'template' => $without['bbcode_tpl']
+ ],
+ [
+ 'usage' => $with['bbcode_match'],
+ 'template' => $with['bbcode_tpl']
+ ]
+ );
+ }
+ catch (\Exception $e)
+ {
+ // Ignore the pair and move on. The BBCodes would have to be fixed manually
+ return;
+ }
+
+ $bbcode_data = [
+ 'bbcode_tag' => $without['bbcode_tag'],
+ 'bbcode_helpline' => $without['bbcode_helpline'] . ' | ' . $with['bbcode_helpline'],
+ 'bbcode_match' => $merged['usage'],
+ 'bbcode_tpl' => $merged['template']
+ ];
+
+ $sql = 'UPDATE ' . BBCODES_TABLE . '
+ SET ' . $this->db->sql_build_array('UPDATE', $bbcode_data) . '
+ WHERE bbcode_id = ' . (int) $without['bbcode_id'];
+ $this->sql_query($sql);
+
+ $sql = 'DELETE FROM ' . BBCODES_TABLE . '
+ WHERE bbcode_id = ' . (int) $with['bbcode_id'];
+ $this->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/remove_imagick.php b/phpBB/phpbb/db/migration/data/v32x/remove_imagick.php
new file mode 100644
index 0000000000..7ad396f8e8
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/remove_imagick.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class remove_imagick extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v324rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.remove', array('img_imagick')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/smtp_dynamic_data.php b/phpBB/phpbb/db/migration/data/v32x/smtp_dynamic_data.php
new file mode 100644
index 0000000000..aeaa3e8979
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/smtp_dynamic_data.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class smtp_dynamic_data extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v326rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'set_smtp_dynamic'))),
+ );
+ }
+
+ public function set_smtp_dynamic()
+ {
+ $smtp_auth_entries = [
+ 'smtp_password',
+ 'smtp_username',
+ ];
+ $this->sql_query('UPDATE ' . CONFIG_TABLE . '
+ SET is_dynamic = 1
+ WHERE ' . $this->db->sql_in_set('config_name', $smtp_auth_entries));
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/timezone_p3.php b/phpBB/phpbb/db/migration/data/v32x/timezone_p3.php
new file mode 100644
index 0000000000..433f62ace9
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/timezone_p3.php
@@ -0,0 +1,29 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class timezone_p3 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array('\phpbb\db\migration\data\v310\timezone');
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.remove', array('board_dst')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php b/phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php
new file mode 100644
index 0000000000..6e51a01834
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/update_prosilver_bitfield.php
@@ -0,0 +1,39 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class update_prosilver_bitfield extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v321',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'update_bbcode_bitfield'))),
+ );
+ }
+
+ public function update_bbcode_bitfield()
+ {
+ $sql = 'UPDATE ' . STYLES_TABLE . "
+ SET bbcode_bitfield = '//g='
+ WHERE style_path = 'prosilver'";
+ $this->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_emoji_permission.php b/phpBB/phpbb/db/migration/data/v32x/user_emoji_permission.php
new file mode 100644
index 0000000000..98759c78ee
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_emoji_permission.php
@@ -0,0 +1,44 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_emoji_permission extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ $sql = 'SELECT auth_option_id
+ FROM ' . ACL_OPTIONS_TABLE . "
+ WHERE auth_option = 'u_emoji'";
+ $result = $this->db->sql_query($sql);
+ $auth_option_id = $this->db->sql_fetchfield('auth_option_id');
+ $this->db->sql_freeresult($result);
+
+ return $auth_option_id !== false;
+ }
+
+ static public function depends_on()
+ {
+ return [
+ '\phpbb\db\migration\data\v32x\v329rc1',
+ ];
+ }
+
+ public function update_data()
+ {
+ return [
+ ['permission.add', ['u_emoji']],
+ ['permission.permission_set', ['REGISTERED', 'u_emoji', 'group']],
+ ];
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p1.php b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p1.php
new file mode 100644
index 0000000000..93ff31ec6c
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p1.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_notifications_table_index_p1 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\cookie_notice_p2',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_index' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'user_id' => array('user_id'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_keys' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'user_id',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p2.php b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p2.php
new file mode 100644
index 0000000000..0a471766a0
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p2.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_notifications_table_index_p2 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\user_notifications_table_index_p1',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_index' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'uid_itm_id' => array('user_id', 'item_id'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_keys' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'uid_itm_id',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p3.php b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p3.php
new file mode 100644
index 0000000000..1636b3024a
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_index_p3.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_notifications_table_index_p3 extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\user_notifications_table_index_p2',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_index' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'usr_itm_tpe' => array('user_id', 'item_type', 'item_id'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_keys' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'usr_itm_tpe',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_reduce_column_sizes.php b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_reduce_column_sizes.php
new file mode 100644
index 0000000000..e0a107782e
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_reduce_column_sizes.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_notifications_table_reduce_column_sizes extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\user_notifications_table_index_p3',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'item_type' => array('VCHAR:165', ''),
+ 'method' => array('VCHAR:165', ''),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'item_type' => array('VCHAR:255', ''),
+ 'method' => array('VCHAR:255', ''),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_remove_duplicates.php b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_remove_duplicates.php
new file mode 100644
index 0000000000..50d0642056
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_remove_duplicates.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_notifications_table_remove_duplicates extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\user_notifications_table_temp_index',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'remove_duplicates'))),
+ );
+ }
+
+ public function remove_duplicates()
+ {
+ $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->table_prefix . 'user_notifications');
+
+ $sql = "SELECT item_type, item_id, user_id, method, MAX(notify) AS notify
+ FROM {$this->table_prefix}user_notifications
+ GROUP BY item_type, item_id, user_id, method
+ HAVING COUNT(item_type) > 1";
+
+ $result = $this->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // Delete the duplicate entries
+ $this->sql_query("DELETE FROM {$this->table_prefix}user_notifications
+ WHERE user_id = {$row['user_id']}
+ AND item_type = '{$row['item_type']}'
+ AND method = '{$row['method']}'");
+
+ // And re-insert as a single one
+ $insert_buffer->insert($row);
+ }
+ $this->db->sql_freeresult($result);
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_temp_index.php b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_temp_index.php
new file mode 100644
index 0000000000..80256a0e0a
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_temp_index.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_notifications_table_temp_index extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\user_notifications_table_reduce_column_sizes',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_index' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'itm_usr_mthd' => array('item_type', 'item_id', 'user_id', 'method'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_keys' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'itm_usr_mthd',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_unique_index.php b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_unique_index.php
new file mode 100644
index 0000000000..51cf90c8a0
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/user_notifications_table_unique_index.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration\data\v32x;
+
+class user_notifications_table_unique_index extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\user_notifications_table_remove_duplicates',
+ );
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'drop_keys' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'itm_usr_mthd',
+ ),
+ ),
+ 'add_unique_index' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'itm_usr_mthd' => array('item_type', 'item_id', 'user_id', 'method'),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_keys' => array(
+ $this->table_prefix . 'user_notifications' => array(
+ 'itm_usr_mthd',
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v321.php b/phpBB/phpbb/db/migration/data/v32x/v321.php
new file mode 100644
index 0000000000..fdbb5cff19
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v321.php
@@ -0,0 +1,38 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v321 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v3111',
+ '\phpbb\db\migration\data\v32x\v321rc1',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v321rc1.php b/phpBB/phpbb/db/migration/data/v32x/v321rc1.php
new file mode 100644
index 0000000000..653a16f327
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v321rc1.php
@@ -0,0 +1,39 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v321rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.1-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v320\v320',
+ '\phpbb\db\migration\data\v31x\v3111rc1',
+ '\phpbb\db\migration\data\v32x\load_user_activity_limit',
+ '\phpbb\db\migration\data\v32x\user_notifications_table_unique_index',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.1-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v322.php b/phpBB/phpbb/db/migration/data/v32x/v322.php
new file mode 100644
index 0000000000..7ecbbb3e79
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v322.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v322 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.2', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v31x\v3112',
+ '\phpbb\db\migration\data\v32x\v322rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.2')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v322rc1.php b/phpBB/phpbb/db/migration/data/v32x/v322rc1.php
new file mode 100644
index 0000000000..4fd6270132
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v322rc1.php
@@ -0,0 +1,41 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v322rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.2-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v321',
+ '\phpbb\db\migration\data\v32x\fix_user_styles',
+ '\phpbb\db\migration\data\v32x\update_prosilver_bitfield',
+ '\phpbb\db\migration\data\v32x\email_force_sender',
+ '\phpbb\db\migration\data\v32x\f_list_topics_permission_add',
+ '\phpbb\db\migration\data\v32x\merge_duplicate_bbcodes',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.2-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v323.php b/phpBB/phpbb/db/migration/data/v32x/v323.php
new file mode 100644
index 0000000000..1ec28ceb37
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v323.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v323 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.3', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v323rc2',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.3')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v323rc1.php b/phpBB/phpbb/db/migration/data/v32x/v323rc1.php
new file mode 100644
index 0000000000..c3fcd1ab0b
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v323rc1.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v323rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.3-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v322',
+ '\phpbb\db\migration\data\v32x\enable_accurate_pm_button',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.3-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v323rc2.php b/phpBB/phpbb/db/migration/data/v32x/v323rc2.php
new file mode 100644
index 0000000000..32235ee067
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v323rc2.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v323rc2 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.3-RC2', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v323rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.3-RC2')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v324.php b/phpBB/phpbb/db/migration/data/v32x/v324.php
new file mode 100644
index 0000000000..cd7783fdee
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v324.php
@@ -0,0 +1,38 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v324 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.4', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v324rc1',
+ '\phpbb\db\migration\data\v32x\remove_imagick',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.4')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v324rc1.php b/phpBB/phpbb/db/migration/data/v32x/v324rc1.php
new file mode 100644
index 0000000000..0221e2621a
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v324rc1.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v324rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.4-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v323',
+ '\phpbb\db\migration\data\v32x\forum_topics_per_page_type',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.4-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v325.php b/phpBB/phpbb/db/migration/data/v32x/v325.php
new file mode 100644
index 0000000000..59de4916df
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v325.php
@@ -0,0 +1,38 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v325 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.5', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v325rc1',
+ '\phpbb\db\migration\data\v32x\jquery_update',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.5')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v325rc1.php b/phpBB/phpbb/db/migration/data/v32x/v325rc1.php
new file mode 100644
index 0000000000..2d0de0a432
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v325rc1.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v325rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.5-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v324',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.5-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v326.php b/phpBB/phpbb/db/migration/data/v32x/v326.php
new file mode 100644
index 0000000000..2d511b9ed8
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v326.php
@@ -0,0 +1,39 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v326 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.6', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v326rc1',
+ '\phpbb\db\migration\data\v32x\disable_remote_avatar',
+ '\phpbb\db\migration\data\v32x\smtp_dynamic_data',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.6')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v326rc1.php b/phpBB/phpbb/db/migration/data/v32x/v326rc1.php
new file mode 100644
index 0000000000..092700d3db
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v326rc1.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v326rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.6-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v325',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.6-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v327.php b/phpBB/phpbb/db/migration/data/v32x/v327.php
new file mode 100644
index 0000000000..f9ea11f4b9
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v327.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v327 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.7', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v327rc1',
+ );
+
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.7')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v327rc1.php b/phpBB/phpbb/db/migration/data/v32x/v327rc1.php
new file mode 100644
index 0000000000..c8169105af
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v327rc1.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v327rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.7-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v326',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.7-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v328.php b/phpBB/phpbb/db/migration/data/v32x/v328.php
new file mode 100644
index 0000000000..28ff2c7033
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v328.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v328 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.8', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v328rc1',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.8')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v328rc1.php b/phpBB/phpbb/db/migration/data/v32x/v328rc1.php
new file mode 100644
index 0000000000..fa43cf33a7
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v328rc1.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v328rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.8-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\timezone_p3',
+ '\phpbb\db\migration\data\v32x\v327',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.8-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v329.php b/phpBB/phpbb/db/migration/data/v32x/v329.php
new file mode 100644
index 0000000000..e88e264aef
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v329.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v329 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.9', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v329rc1',
+ '\phpbb\db\migration\data\v32x\user_emoji_permission',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.9')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/data/v32x/v329rc1.php b/phpBB/phpbb/db/migration/data/v32x/v329rc1.php
new file mode 100644
index 0000000000..271bf62859
--- /dev/null
+++ b/phpBB/phpbb/db/migration/data/v32x/v329rc1.php
@@ -0,0 +1,36 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\migration\data\v32x;
+
+class v329rc1 extends \phpbb\db\migration\migration
+{
+ public function effectively_installed()
+ {
+ return phpbb_version_compare($this->config['version'], '3.2.9-RC1', '>=');
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ '\phpbb\db\migration\data\v32x\v328',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('version', '3.2.9-RC1')),
+ );
+ }
+}
diff --git a/phpBB/phpbb/db/migration/migration.php b/phpBB/phpbb/db/migration/migration.php
index 5f120333e1..4e218344f4 100644
--- a/phpBB/phpbb/db/migration/migration.php
+++ b/phpBB/phpbb/db/migration/migration.php
@@ -20,7 +20,7 @@ namespace phpbb\db\migration;
* in a subclass. This class provides various utility methods to simplify editing
* a phpBB.
*/
-abstract class migration
+abstract class migration implements migration_interface
{
/** @var \phpbb\config\config */
protected $config;
@@ -28,7 +28,7 @@ abstract class migration
/** @var \phpbb\db\driver\driver_interface */
protected $db;
- /** @var \phpbb\db\tools */
+ /** @var \phpbb\db\tools\tools_interface */
protected $db_tools;
/** @var string */
@@ -51,12 +51,12 @@ abstract class migration
*
* @param \phpbb\config\config $config
* @param \phpbb\db\driver\driver_interface $db
- * @param \phpbb\db\tools $db_tools
+ * @param \phpbb\db\tools\tools_interface $db_tools
* @param string $phpbb_root_path
* @param string $php_ext
* @param string $table_prefix
*/
- public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $phpbb_root_path, $php_ext, $table_prefix)
+ public function __construct(\phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools\tools_interface $db_tools, $phpbb_root_path, $php_ext, $table_prefix)
{
$this->config = $config;
$this->db = $db;
@@ -70,9 +70,7 @@ abstract class migration
}
/**
- * Defines other migrations to be applied first
- *
- * @return array An array of migration class names
+ * {@inheritdoc}
*/
static public function depends_on()
{
@@ -80,14 +78,7 @@ abstract class migration
}
/**
- * Allows you to check if the migration is effectively installed (entirely optional)
- *
- * This is checked when a migration is installed. If true is returned, the migration will be set as
- * installed without performing the database changes.
- * This function is intended to help moving to migrations from a previous database updater, where some
- * migrations may have been installed already even though they are not yet listed in the migrations table.
- *
- * @return bool True if this migration is installed, False if this migration is not installed (checked on install)
+ * {@inheritdoc}
*/
public function effectively_installed()
{
@@ -95,9 +86,7 @@ abstract class migration
}
/**
- * Updates the database schema by providing a set of change instructions
- *
- * @return array Array of schema changes (compatible with db_tools->perform_schema_changes())
+ * {@inheritdoc}
*/
public function update_schema()
{
@@ -105,9 +94,7 @@ abstract class migration
}
/**
- * Reverts the database schema by providing a set of change instructions
- *
- * @return array Array of schema changes (compatible with db_tools->perform_schema_changes())
+ * {@inheritdoc}
*/
public function revert_schema()
{
@@ -115,9 +102,7 @@ abstract class migration
}
/**
- * Updates data by returning a list of instructions to be executed
- *
- * @return array Array of data update instructions
+ * {@inheritdoc}
*/
public function update_data()
{
@@ -125,12 +110,7 @@ abstract class migration
}
/**
- * Reverts data by returning a list of instructions to be executed
- *
- * @return array Array of data instructions that will be performed on revert
- * NOTE: calls to tools (such as config.add) are automatically reverted when
- * possible, so you should not attempt to revert those, this is mostly for
- * otherwise unrevertable calls (custom functions for example)
+ * {@inheritdoc}
*/
public function revert_data()
{
diff --git a/phpBB/phpbb/db/migration/migration_interface.php b/phpBB/phpbb/db/migration/migration_interface.php
new file mode 100644
index 0000000000..2aba5ec608
--- /dev/null
+++ b/phpBB/phpbb/db/migration/migration_interface.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\migration;
+
+/**
+ * Base class interface for database migrations
+ */
+interface migration_interface
+{
+ /**
+ * Defines other migrations to be applied first
+ *
+ * @return array An array of migration class names
+ */
+ static public function depends_on();
+
+ /**
+ * Allows you to check if the migration is effectively installed (entirely optional)
+ *
+ * This is checked when a migration is installed. If true is returned, the migration will be set as
+ * installed without performing the database changes.
+ * This function is intended to help moving to migrations from a previous database updater, where some
+ * migrations may have been installed already even though they are not yet listed in the migrations table.
+ *
+ * @return bool True if this migration is installed, False if this migration is not installed (checked on install)
+ */
+ public function effectively_installed();
+
+ /**
+ * Updates the database schema by providing a set of change instructions
+ *
+ * @return array Array of schema changes (compatible with db_tools->perform_schema_changes())
+ */
+ public function update_schema();
+
+ /**
+ * Reverts the database schema by providing a set of change instructions
+ *
+ * @return array Array of schema changes (compatible with db_tools->perform_schema_changes())
+ */
+ public function revert_schema();
+
+ /**
+ * Updates data by returning a list of instructions to be executed
+ *
+ * @return array Array of data update instructions
+ */
+ public function update_data();
+
+ /**
+ * Reverts data by returning a list of instructions to be executed
+ *
+ * @return array Array of data instructions that will be performed on revert
+ * NOTE: calls to tools (such as config.add) are automatically reverted when
+ * possible, so you should not attempt to revert those, this is mostly for
+ * otherwise unrevertable calls (custom functions for example)
+ */
+ public function revert_data();
+}
diff --git a/phpBB/phpbb/db/migration/profilefield_base_migration.php b/phpBB/phpbb/db/migration/profilefield_base_migration.php
index b20ca874be..bc542a8fed 100644
--- a/phpBB/phpbb/db/migration/profilefield_base_migration.php
+++ b/phpBB/phpbb/db/migration/profilefield_base_migration.php
@@ -238,6 +238,7 @@ abstract class profilefield_base_migration extends container_aware_migration
if ($profile_row === null)
{
+ /* @var $manager \phpbb\profilefields\manager */
$manager = $this->container->get('profilefields.manager');
$profile_row = $manager->build_insert_sql_array(array());
}
diff --git a/phpBB/phpbb/db/migration/schema_generator.php b/phpBB/phpbb/db/migration/schema_generator.php
index 91d8307d91..c579e25824 100644
--- a/phpBB/phpbb/db/migration/schema_generator.php
+++ b/phpBB/phpbb/db/migration/schema_generator.php
@@ -24,7 +24,7 @@ class schema_generator
/** @var \phpbb\db\driver\driver_interface */
protected $db;
- /** @var \phpbb\db\tools */
+ /** @var \phpbb\db\tools\tools_interface */
protected $db_tools;
/** @var array */
@@ -48,7 +48,7 @@ class schema_generator
/**
* Constructor
*/
- public function __construct(array $class_names, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $phpbb_root_path, $php_ext, $table_prefix)
+ public function __construct(array $class_names, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools\tools_interface $db_tools, $phpbb_root_path, $php_ext, $table_prefix)
{
$this->config = $config;
$this->db = $db;
@@ -77,8 +77,15 @@ class schema_generator
$check_dependencies = true;
while (!empty($migrations))
{
- foreach ($migrations as $migration_class)
+ foreach ($migrations as $key => $migration_class)
{
+ // Unset classes that are not a valid migration
+ if (\phpbb\db\migrator::is_migration($migration_class) === false)
+ {
+ unset($migrations[$key]);
+ continue;
+ }
+
$open_dependencies = array_diff($migration_class::depends_on(), $tree);
if (empty($open_dependencies))
diff --git a/phpBB/phpbb/db/migration/tool/config.php b/phpBB/phpbb/db/migration/tool/config.php
index 33aa8ff026..a351c4858e 100644
--- a/phpBB/phpbb/db/migration/tool/config.php
+++ b/phpBB/phpbb/db/migration/tool/config.php
@@ -134,7 +134,7 @@ class config implements \phpbb\db\migration\tool\tool_interface
case 'remove':
$call = 'add';
- if (sizeof($arguments) == 1)
+ if (count($arguments) == 1)
{
$arguments[] = '';
}
diff --git a/phpBB/phpbb/db/migration/tool/config_text.php b/phpBB/phpbb/db/migration/tool/config_text.php
index 54b45f6f6d..5fe9a25b70 100644
--- a/phpBB/phpbb/db/migration/tool/config_text.php
+++ b/phpBB/phpbb/db/migration/tool/config_text.php
@@ -110,7 +110,7 @@ class config_text implements \phpbb\db\migration\tool\tool_interface
case 'remove':
$call = 'add';
- if (sizeof($arguments) == 1)
+ if (count($arguments) == 1)
{
$arguments[] = '';
}
diff --git a/phpBB/phpbb/db/migration/tool/module.php b/phpBB/phpbb/db/migration/tool/module.php
index 7ea7d1dac1..e5133c8152 100644
--- a/phpBB/phpbb/db/migration/tool/module.php
+++ b/phpBB/phpbb/db/migration/tool/module.php
@@ -13,6 +13,8 @@
namespace phpbb\db\migration\tool;
+use phpbb\module\exception\module_exception;
+
/**
* Migration module management tool
*/
@@ -27,6 +29,9 @@ class module implements \phpbb\db\migration\tool\tool_interface
/** @var \phpbb\user */
protected $user;
+ /** @var \phpbb\module\module_manager */
+ protected $module_manager;
+
/** @var string */
protected $phpbb_root_path;
@@ -45,15 +50,17 @@ class module implements \phpbb\db\migration\tool\tool_interface
* @param \phpbb\db\driver\driver_interface $db
* @param \phpbb\cache\service $cache
* @param \phpbb\user $user
+ * @param \phpbb\module\module_manager $module_manager
* @param string $phpbb_root_path
* @param string $php_ext
* @param string $modules_table
*/
- public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, $phpbb_root_path, $php_ext, $modules_table)
+ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, \phpbb\module\module_manager $module_manager, $phpbb_root_path, $php_ext, $modules_table)
{
$this->db = $db;
$this->cache = $cache;
$this->user = $user;
+ $this->module_manager = $module_manager;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
$this->modules_table = $modules_table;
@@ -77,9 +84,12 @@ class module implements \phpbb\db\migration\tool\tool_interface
* Use false to ignore the parent check and check class wide.
* @param int|string $module The module_id|module_langname you would like to
* check for to see if it exists
- * @return bool true/false if module exists
+ * @param bool $lazy Checks lazily if the module exists. Returns true if it exists in at
+ * least one given parent.
+ * @return bool true if module exists in *all* given parents, false if not in any given parent;
+ * true if ignoring parent check and module exists class wide, false if not found at all.
*/
- public function exists($class, $parent, $module)
+ public function exists($class, $parent, $module, $lazy = false)
{
// the main root directory should return true
if (!$module)
@@ -87,33 +97,48 @@ class module implements \phpbb\db\migration\tool\tool_interface
return true;
}
- $parent_sql = '';
+ $parent_sqls = [];
if ($parent !== false)
{
- $parent = $this->get_parent_module_id($parent, $module, false);
- if ($parent === false)
+ $parents = $this->get_parent_module_id($parent, $module, false);
+ if ($parents === false)
{
return false;
}
- $parent_sql = 'AND parent_id = ' . (int) $parent;
+ foreach ((array) $parents as $parent_id)
+ {
+ $parent_sqls[] = 'AND parent_id = ' . (int) $parent_id;
+ }
+ }
+ else
+ {
+ $parent_sqls[] = '';
}
- $sql = 'SELECT module_id
- FROM ' . $this->modules_table . "
- WHERE module_class = '" . $this->db->sql_escape($class) . "'
- $parent_sql
- AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'");
- $result = $this->db->sql_query($sql);
- $module_id = $this->db->sql_fetchfield('module_id');
- $this->db->sql_freeresult($result);
-
- if ($module_id)
+ foreach ($parent_sqls as $parent_sql)
{
- return true;
+ $sql = 'SELECT module_id
+ FROM ' . $this->modules_table . "
+ WHERE module_class = '" . $this->db->sql_escape($class) . "'
+ $parent_sql
+ AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'");
+ $result = $this->db->sql_query($sql);
+ $module_id = $this->db->sql_fetchfield('module_id');
+ $this->db->sql_freeresult($result);
+
+ if (!$lazy && !$module_id)
+ {
+ return false;
+ }
+ if ($lazy && $module_id)
+ {
+ return true;
+ }
}
- return false;
+ // Returns true, if modules exist in all parents and false otherwise
+ return !$lazy;
}
/**
@@ -157,13 +182,15 @@ class module implements \phpbb\db\migration\tool\tool_interface
*/
public function add($class, $parent = 0, $data = array())
{
+ global $user, $phpbb_log;
+
// allow sending the name as a string in $data to create a category
if (!is_array($data))
{
$data = array('module_langname' => $data);
}
- $parent = $data['parent_id'] = $this->get_parent_module_id($parent, $data);
+ $parents = (array) $this->get_parent_module_id($parent, $data);
if (!isset($data['module_langname']))
{
@@ -171,7 +198,6 @@ class module implements \phpbb\db\migration\tool\tool_interface
$basename = (isset($data['module_basename'])) ? $data['module_basename'] : '';
$module = $this->get_module_info($class, $basename);
- $result = '';
foreach ($module['modes'] as $mode => $module_info)
{
if (!isset($data['modes']) || in_array($mode, $data['modes']))
@@ -187,106 +213,135 @@ class module implements \phpbb\db\migration\tool\tool_interface
);
// Run the "manual" way with the data we've collected.
- $this->add($class, $parent, $new_module);
+ foreach ($parents as $parent)
+ {
+ $this->add($class, $parent, $new_module);
+ }
}
}
return;
}
- // The "manual" way
- if (!$this->exists($class, false, $parent))
+ foreach ($parents as $parent)
{
- throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
- }
+ $data['parent_id'] = $parent;
- if ($this->exists($class, $parent, $data['module_langname']))
- {
- throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']);
- }
+ // The "manual" way
+ if (!$this->exists($class, false, $parent))
+ {
+ throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
+ }
- if (!class_exists('acp_modules'))
- {
- include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
- $this->user->add_lang('acp/modules');
- }
- $acp_modules = new \acp_modules();
-
- $module_data = array(
- 'module_enabled' => (isset($data['module_enabled'])) ? $data['module_enabled'] : 1,
- 'module_display' => (isset($data['module_display'])) ? $data['module_display'] : 1,
- 'module_basename' => (isset($data['module_basename'])) ? $data['module_basename'] : '',
- 'module_class' => $class,
- 'parent_id' => (int) $parent,
- 'module_langname' => (isset($data['module_langname'])) ? $data['module_langname'] : '',
- 'module_mode' => (isset($data['module_mode'])) ? $data['module_mode'] : '',
- 'module_auth' => (isset($data['module_auth'])) ? $data['module_auth'] : '',
- );
- $result = $acp_modules->update_module_data($module_data, true);
-
- // update_module_data can either return a string or an empty array...
- if (is_string($result))
- {
- // Error
- throw new \phpbb\db\migration\exception('MODULE_ERROR', $result);
- }
- else
- {
- // Success
- $module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']);
- add_log('admin', 'LOG_MODULE_ADD', $module_log_name);
+ if ($this->exists($class, $parent, $data['module_langname']))
+ {
+ throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']);
+ }
- // Move the module if requested above/below an existing one
- if (isset($data['before']) && $data['before'])
+ $module_data = array(
+ 'module_enabled' => (isset($data['module_enabled'])) ? $data['module_enabled'] : 1,
+ 'module_display' => (isset($data['module_display'])) ? $data['module_display'] : 1,
+ 'module_basename' => (isset($data['module_basename'])) ? $data['module_basename'] : '',
+ 'module_class' => $class,
+ 'parent_id' => (int) $parent,
+ 'module_langname' => (isset($data['module_langname'])) ? $data['module_langname'] : '',
+ 'module_mode' => (isset($data['module_mode'])) ? $data['module_mode'] : '',
+ 'module_auth' => (isset($data['module_auth'])) ? $data['module_auth'] : '',
+ );
+
+ try
{
- $sql = 'SELECT left_id
+ $this->module_manager->update_module_data($module_data);
+
+ // Success
+ $module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']);
+ $phpbb_log->add('admin', (isset($user->data['user_id'])) ? $user->data['user_id'] : ANONYMOUS, $user->ip, 'LOG_MODULE_ADD', false, array($module_log_name));
+
+ // Move the module if requested above/below an existing one
+ if (isset($data['before']) && $data['before'])
+ {
+ $before_mode = $before_langname = '';
+ if (is_array($data['before']))
+ {
+ // Restore legacy-legacy behaviour from phpBB 3.0
+ list($before_mode, $before_langname) = $data['before'];
+ }
+ else
+ {
+ // Legacy behaviour from phpBB 3.1+
+ $before_langname = $data['before'];
+ }
+
+ $sql = 'SELECT left_id
FROM ' . $this->modules_table . "
WHERE module_class = '" . $this->db->sql_escape($class) . "'
AND parent_id = " . (int) $parent . "
- AND module_langname = '" . $this->db->sql_escape($data['before']) . "'";
- $this->db->sql_query($sql);
- $to_left = (int) $this->db->sql_fetchfield('left_id');
+ AND module_langname = '" . $this->db->sql_escape($before_langname) . "'"
+ . (($before_mode) ? " AND module_mode = '" . $this->db->sql_escape($before_mode) . "'" : '');
+ $result = $this->db->sql_query($sql);
+ $to_left = (int) $this->db->sql_fetchfield('left_id');
+ $this->db->sql_freeresult($result);
- $sql = 'UPDATE ' . $this->modules_table . "
+ $sql = 'UPDATE ' . $this->modules_table . "
SET left_id = left_id + 2, right_id = right_id + 2
WHERE module_class = '" . $this->db->sql_escape($class) . "'
AND left_id >= $to_left
AND left_id < {$module_data['left_id']}";
- $this->db->sql_query($sql);
+ $this->db->sql_query($sql);
- $sql = 'UPDATE ' . $this->modules_table . "
+ $sql = 'UPDATE ' . $this->modules_table . "
SET left_id = $to_left, right_id = " . ($to_left + 1) . "
WHERE module_class = '" . $this->db->sql_escape($class) . "'
AND module_id = {$module_data['module_id']}";
- $this->db->sql_query($sql);
- }
- else if (isset($data['after']) && $data['after'])
- {
- $sql = 'SELECT right_id
+ $this->db->sql_query($sql);
+ }
+ else if (isset($data['after']) && $data['after'])
+ {
+ $after_mode = $after_langname = '';
+ if (is_array($data['after']))
+ {
+ // Restore legacy-legacy behaviour from phpBB 3.0
+ list($after_mode, $after_langname) = $data['after'];
+ }
+ else
+ {
+ // Legacy behaviour from phpBB 3.1+
+ $after_langname = $data['after'];
+ }
+
+ $sql = 'SELECT right_id
FROM ' . $this->modules_table . "
WHERE module_class = '" . $this->db->sql_escape($class) . "'
AND parent_id = " . (int) $parent . "
- AND module_langname = '" . $this->db->sql_escape($data['after']) . "'";
- $this->db->sql_query($sql);
- $to_right = (int) $this->db->sql_fetchfield('right_id');
+ AND module_langname = '" . $this->db->sql_escape($after_langname) . "'"
+ . (($after_mode) ? " AND module_mode = '" . $this->db->sql_escape($after_mode) . "'" : '');
+ $result = $this->db->sql_query($sql);
+ $to_right = (int) $this->db->sql_fetchfield('right_id');
+ $this->db->sql_freeresult($result);
- $sql = 'UPDATE ' . $this->modules_table . "
+ $sql = 'UPDATE ' . $this->modules_table . "
SET left_id = left_id + 2, right_id = right_id + 2
WHERE module_class = '" . $this->db->sql_escape($class) . "'
AND left_id >= $to_right
AND left_id < {$module_data['left_id']}";
- $this->db->sql_query($sql);
+ $this->db->sql_query($sql);
- $sql = 'UPDATE ' . $this->modules_table . '
+ $sql = 'UPDATE ' . $this->modules_table . '
SET left_id = ' . ($to_right + 1) . ', right_id = ' . ($to_right + 2) . "
WHERE module_class = '" . $this->db->sql_escape($class) . "'
AND module_id = {$module_data['module_id']}";
- $this->db->sql_query($sql);
+ $this->db->sql_query($sql);
+ }
+ }
+ catch (module_exception $e)
+ {
+ // Error
+ throw new \phpbb\db\migration\exception('MODULE_ERROR', $e->getMessage());
}
}
// Clear the Modules Cache
- $this->cache->destroy("_modules_$class");
+ $this->module_manager->remove_cache_file($class);
}
/**
@@ -333,7 +388,7 @@ class module implements \phpbb\db\migration\tool\tool_interface
}
else
{
- if (!$this->exists($class, $parent, $module))
+ if (!$this->exists($class, $parent, $module, true))
{
return;
}
@@ -341,8 +396,8 @@ class module implements \phpbb\db\migration\tool\tool_interface
$parent_sql = '';
if ($parent !== false)
{
- $parent = $this->get_parent_module_id($parent, $module);
- $parent_sql = 'AND parent_id = ' . (int) $parent;
+ $parents = (array) $this->get_parent_module_id($parent, $module);
+ $parent_sql = 'AND ' . $this->db->sql_in_set('parent_id', $parents);
}
$module_ids = array();
@@ -365,24 +420,12 @@ class module implements \phpbb\db\migration\tool\tool_interface
$module_ids[] = (int) $module;
}
- if (!class_exists('acp_modules'))
- {
- include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
- $this->user->add_lang('acp/modules');
- }
- $acp_modules = new \acp_modules();
- $acp_modules->module_class = $class;
-
foreach ($module_ids as $module_id)
{
- $result = $acp_modules->delete_module($module_id);
- if (!empty($result))
- {
- return;
- }
+ $this->module_manager->delete_module($module_id, $class);
}
- $this->cache->destroy("_modules_$class");
+ $this->module_manager->remove_cache_file($class);
}
}
@@ -427,13 +470,7 @@ class module implements \phpbb\db\migration\tool\tool_interface
*/
protected function get_module_info($class, $basename)
{
- if (!class_exists('acp_modules'))
- {
- include($this->phpbb_root_path . 'includes/acp/acp_modules.' . $this->php_ext);
- $this->user->add_lang('acp/modules');
- }
- $acp_modules = new \acp_modules();
- $module = $acp_modules->get_module_infos($basename, $class, true);
+ $module = $this->module_manager->get_module_infos($class, $basename, true);
if (empty($module))
{
@@ -474,23 +511,14 @@ class module implements \phpbb\db\migration\tool\tool_interface
* @param string|int $parent_id The parent module_id|module_langname
* @param int|string|array $data The module_id, module_langname for existance checking or module data array for adding
* @param bool $throw_exception The flag indicating if exception should be thrown on error
- * @return mixed The int parent module_id or false
+ * @return mixed The int parent module_id, an array of int parent module_id values or false
* @throws \phpbb\db\migration\exception
*/
public function get_parent_module_id($parent_id, $data = '', $throw_exception = true)
{
- // Initialize exception object placeholder
- $exception = false;
-
// Allow '' to be sent as 0
$parent_id = $parent_id ?: 0;
- // If automatic adding is in action, convert array back to string to simplify things
- if (is_array($data) && sizeof($data) == 1)
- {
- $data = $data['module_langname'];
- }
-
if (!is_numeric($parent_id))
{
// Refresh the $module_categories array
@@ -499,65 +527,30 @@ class module implements \phpbb\db\migration\tool\tool_interface
// Search for the parent module_langname
$ids = array_keys($this->module_categories, $parent_id);
- switch (sizeof($ids))
+ switch (count($ids))
{
// No parent with the given module_langname exist
case 0:
- $exception = new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
+ if ($throw_exception)
+ {
+ throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
+ }
+
+ return false;
break;
// Return the module id
case 1:
- $parent_id = (int) $ids[0];
+ return (int) $ids[0];
break;
- // Several modules with the given module_langname were found
- // Try to determine the parent_id by the neighbour module parent
default:
- if (is_array($data) && (isset($data['before']) || isset($data['after'])))
- {
- $neighbour_module_langname = isset($data['before']) ? $data['before'] : $data['after'];
- $sql = 'SELECT parent_id
- FROM ' . $this->modules_table . "
- WHERE module_langname = '" . $this->db->sql_escape($neighbour_module_langname) . "'
- AND " . $this->db->sql_in_set('parent_id', $ids);
- $result = $this->db->sql_query($sql);
- $parent_id = (int) $this->db->sql_fetchfield('parent_id');
- if (!$parent_id)
- {
- $exception = new \phpbb\db\migration\exception('PARENT_MODULE_FIND_ERROR', $data['parent_id']);
- }
- }
- else if (!empty($data) && !is_array($data))
- {
- // The module_langname is set, checking for the module existance
- // As more than 1 parents were found already, there's no way for null parent_id here
- $sql = 'SELECT m2.module_id as module_parent_id
- FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
- WHERE " . ((is_numeric($data)) ? 'm1.module_id = ' . (int) $data : "m1.module_langname = '" . $this->db->sql_escape($data)) . "'
- AND m2.module_id = m1.parent_id
- AND " . $this->db->sql_in_set('m2.module_id', $ids);
- $result = $this->db->sql_query($sql);
- $parent_id = (int) $this->db->sql_fetchfield('module_parent_id');
- }
- else
- {
- //Unable to get the parent module id, throwing an exception
- $exception = new \phpbb\db\migration\exception('MODULE_EXIST_MULTIPLE', $parent_id);
- }
+ // This represents the old behaviour of phpBB 3.0
+ return $ids;
break;
}
}
- if ($exception !== false)
- {
- if ($throw_exception)
- {
- throw $exception;
- }
- return false;
- }
-
return $parent_id;
}
}
diff --git a/phpBB/phpbb/db/migration/tool/permission.php b/phpBB/phpbb/db/migration/tool/permission.php
index 9688420025..4b53aa32a7 100644
--- a/phpBB/phpbb/db/migration/tool/permission.php
+++ b/phpBB/phpbb/db/migration/tool/permission.php
@@ -442,7 +442,7 @@ class permission implements \phpbb\db\migration\tool\tool_interface
}
);
- if (sizeof($auth_option))
+ if (count($auth_option))
{
return $this->permission_set($role_name, $auth_option, 'role', $has_permission);
}
diff --git a/phpBB/phpbb/db/migrator.php b/phpBB/phpbb/db/migrator.php
index 45a333ac94..2b0c66fc58 100644
--- a/phpBB/phpbb/db/migrator.php
+++ b/phpBB/phpbb/db/migrator.php
@@ -13,6 +13,8 @@
namespace phpbb\db;
+use phpbb\db\output_handler\migrator_output_handler_interface;
+use phpbb\db\output_handler\null_migrator_output_handler;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -32,7 +34,7 @@ class migrator
/** @var \phpbb\db\driver\driver_interface */
protected $db;
- /** @var \phpbb\db\tools */
+ /** @var \phpbb\db\tools\tools_interface */
protected $db_tools;
/** @var \phpbb\db\migration\helper */
@@ -92,7 +94,7 @@ class migrator
/**
* Constructor of the database migrator
*/
- public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools $db_tools, $migrations_table, $phpbb_root_path, $php_ext, $table_prefix, $tools, \phpbb\db\migration\helper $helper)
+ public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db, \phpbb\db\tools\tools_interface $db_tools, $migrations_table, $phpbb_root_path, $php_ext, $table_prefix, $tools, \phpbb\db\migration\helper $helper)
{
$this->container = $container;
$this->config = $config;
@@ -122,7 +124,7 @@ class migrator
/**
* Set the output handler.
*
- * @param migrator_output_handler $handler The output handler
+ * @param migrator_output_handler_interface $handler The output handler
*/
public function set_output_handler(migrator_output_handler_interface $handler)
{
@@ -182,10 +184,50 @@ class migrator
*/
public function set_migrations($class_names)
{
+ foreach ($class_names as $key => $class)
+ {
+ if (!self::is_migration($class))
+ {
+ unset($class_names[$key]);
+ }
+ }
+
$this->migrations = $class_names;
}
/**
+ * Get the list of available migration class names
+ *
+ * @return array Array of all migrations available to be run
+ */
+ public function get_migrations()
+ {
+ return $this->migrations;
+ }
+
+ /**
+ * Get the list of available and not installed migration class names
+ *
+ * @return array
+ */
+ public function get_installable_migrations()
+ {
+ $unfinished_migrations = array();
+
+ foreach ($this->migrations as $name)
+ {
+ if (!isset($this->migration_state[$name]) ||
+ !$this->migration_state[$name]['migration_schema_done'] ||
+ !$this->migration_state[$name]['migration_data_done'])
+ {
+ $unfinished_migrations[] = $name;
+ }
+ }
+
+ return $unfinished_migrations;
+ }
+
+ /**
* Runs a single update step from the next migration to be applied.
*
* The update step can either be a schema or a (partial) data update. To
@@ -461,11 +503,14 @@ class migrator
return;
}
- foreach ($this->migration_state as $name => $state)
+ foreach ($this->migrations as $name)
{
- if (!empty($state['migration_depends_on']) && in_array($migration, $state['migration_depends_on']))
+ $state = $this->migration_state($name);
+
+ if ($state && in_array($migration, $state['migration_depends_on']) && ($state['migration_schema_done'] || $state['migration_data_done']))
{
$this->revert_do($name);
+ return;
}
}
@@ -497,19 +542,60 @@ class migrator
if ($state['migration_data_done'])
{
+ $verbosity = empty($state['migration_data_state']) ?
+ migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG;
+ $this->output_handler->write(array('MIGRATION_REVERT_DATA_RUNNING', $name), $verbosity);
+
+ $total_time = (is_array($state['migration_data_state']) && isset($state['migration_data_state']['_total_time'])) ?
+ $state['migration_data_state']['_total_time'] : 0.0;
+ $elapsed_time = microtime(true);
+
$steps = array_merge($this->helper->reverse_update_data($migration->update_data()), $migration->revert_data());
$result = $this->process_data_step($steps, $state['migration_data_state']);
+ $elapsed_time = microtime(true) - $elapsed_time;
+ $total_time += $elapsed_time;
+
+ if (is_array($result))
+ {
+ $result['_total_time'] = $total_time;
+ }
+
$state['migration_data_state'] = ($result === true) ? '' : $result;
$state['migration_data_done'] = ($result === true) ? false : true;
$this->set_migration_state($name, $state);
+
+ if (!$state['migration_data_done'])
+ {
+ $this->output_handler->write(array('MIGRATION_REVERT_DATA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
+ }
+ else
+ {
+ $this->output_handler->write(array('MIGRATION_REVERT_DATA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE);
+ }
}
else if ($state['migration_schema_done'])
{
+ $verbosity = empty($state['migration_data_state']) ?
+ migrator_output_handler_interface::VERBOSITY_VERBOSE : migrator_output_handler_interface::VERBOSITY_DEBUG;
+ $this->output_handler->write(array('MIGRATION_REVERT_SCHEMA_RUNNING', $name), $verbosity);
+
+ $total_time = (is_array($state['migration_data_state']) && isset($state['migration_data_state']['_total_time'])) ?
+ $state['migration_data_state']['_total_time'] : 0.0;
+ $elapsed_time = microtime(true);
+
$steps = $this->helper->get_schema_steps($migration->revert_schema());
$result = $this->process_data_step($steps, $state['migration_data_state']);
+ $elapsed_time = microtime(true) - $elapsed_time;
+ $total_time += $elapsed_time;
+
+ if (is_array($result))
+ {
+ $result['_total_time'] = $total_time;
+ }
+
$state['migration_data_state'] = ($result === true) ? '' : $result;
$state['migration_schema_done'] = ($result === true) ? false : true;
@@ -521,10 +607,14 @@ class migrator
$this->last_run_migration = false;
unset($this->migration_state[$name]);
+
+ $this->output_handler->write(array('MIGRATION_REVERT_SCHEMA_DONE', $name, $total_time), migrator_output_handler_interface::VERBOSITY_NORMAL);
}
else
{
$this->set_migration_state($name, $state);
+
+ $this->output_handler->write(array('MIGRATION_REVERT_SCHEMA_IN_PROGRESS', $name, $elapsed_time), migrator_output_handler_interface::VERBOSITY_VERY_VERBOSE);
}
}
@@ -542,7 +632,7 @@ class migrator
*/
protected function process_data_step($steps, $state, $revert = false)
{
- if (sizeof($steps) === 0)
+ if (count($steps) === 0)
{
return true;
}
@@ -569,7 +659,7 @@ class migrator
// Result will be null or true if everything completed correctly
// Stop after each update step, to let the updater control the script runtime
$result = $this->run_step($steps[$step], $last_result, $revert);
- if (($result !== null && $result !== true) || $step + 1 < sizeof($steps))
+ if (($result !== null && $result !== true) || $step + 1 < count($steps))
{
return array(
'result' => $result,
@@ -670,7 +760,7 @@ class migrator
$condition = $parameters[0];
- if (!$condition)
+ if (!$condition || (is_array($condition) && !$this->run_step($condition, $last_result, $reverse)))
{
return false;
}
@@ -921,4 +1011,27 @@ class migrator
));
}
}
+
+ /**
+ * Check if a class is a migration.
+ *
+ * @param string $migration A migration class name
+ * @return bool Return true if class is a migration, false otherwise
+ */
+ static public function is_migration($migration)
+ {
+ if (class_exists($migration))
+ {
+ // Migration classes should extend the abstract class
+ // phpbb\db\migration\migration (which implements the
+ // migration_interface) and be instantiable.
+ $reflector = new \ReflectionClass($migration);
+ if ($reflector->implementsInterface('\phpbb\db\migration\migration_interface') && $reflector->isInstantiable())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/phpBB/phpbb/db/migrator_output_handler_interface.php b/phpBB/phpbb/db/migrator_output_handler_interface.php
deleted file mode 100644
index 9947b51dcc..0000000000
--- a/phpBB/phpbb/db/migrator_output_handler_interface.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\db;
-
-interface migrator_output_handler_interface
-{
- const VERBOSITY_QUIET = 16;
- const VERBOSITY_NORMAL = 32;
- const VERBOSITY_VERBOSE = 64;
- const VERBOSITY_VERY_VERBOSE = 128;
- const VERBOSITY_DEBUG = 256;
-
- /**
- * Write output using the configured closure.
- *
- * @param string|array $message The message to write or an array containing the language key and all of its parameters.
- * @param int $verbosity The verbosity of the message.
- */
- public function write($message, $verbosity);
-}
diff --git a/phpBB/phpbb/db/null_migrator_output_handler.php b/phpBB/phpbb/db/null_migrator_output_handler.php
deleted file mode 100644
index 0e8cfbb049..0000000000
--- a/phpBB/phpbb/db/null_migrator_output_handler.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\db;
-
-class null_migrator_output_handler implements migrator_output_handler_interface
-{
- /**
- * {@inheritdoc}
- */
- public function write($message, $verbosity)
- {
- }
-}
diff --git a/phpBB/phpbb/db/output_handler/html_migrator_output_handler.php b/phpBB/phpbb/db/output_handler/html_migrator_output_handler.php
new file mode 100644
index 0000000000..67309649c9
--- /dev/null
+++ b/phpBB/phpbb/db/output_handler/html_migrator_output_handler.php
@@ -0,0 +1,46 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\output_handler;
+
+class html_migrator_output_handler implements migrator_output_handler_interface
+{
+ /**
+ * Language object.
+ *
+ * @var \phpbb\language\language
+ */
+ private $language;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\language\language $language Language object
+ */
+ public function __construct(\phpbb\language\language $language)
+ {
+ $this->language = $language;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($message, $verbosity)
+ {
+ if ($verbosity <= migrator_output_handler_interface::VERBOSITY_VERBOSE)
+ {
+ $final_message = $this->language->lang_array(array_shift($message), $message);
+ echo $final_message . "<br />\n";
+ }
+ }
+}
diff --git a/phpBB/phpbb/db/output_handler/installer_migrator_output_handler.php b/phpBB/phpbb/db/output_handler/installer_migrator_output_handler.php
new file mode 100644
index 0000000000..56d5cf49a1
--- /dev/null
+++ b/phpBB/phpbb/db/output_handler/installer_migrator_output_handler.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\output_handler;
+
+use phpbb\install\helper\iohandler\iohandler_interface;
+
+class installer_migrator_output_handler implements migrator_output_handler_interface
+{
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * Constructor
+ *
+ * @param iohandler_interface $iohandler Installer's IO-handler
+ */
+ public function __construct(iohandler_interface $iohandler)
+ {
+ $this->iohandler = $iohandler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($message, $verbosity)
+ {
+ if ($verbosity <= migrator_output_handler_interface::VERBOSITY_VERBOSE)
+ {
+ $this->iohandler->add_log_message($message);
+ $this->iohandler->send_response();
+ }
+ }
+}
diff --git a/phpBB/phpbb/db/output_handler/log_wrapper_migrator_output_handler.php b/phpBB/phpbb/db/output_handler/log_wrapper_migrator_output_handler.php
new file mode 100644
index 0000000000..e4bd3ac8e0
--- /dev/null
+++ b/phpBB/phpbb/db/output_handler/log_wrapper_migrator_output_handler.php
@@ -0,0 +1,101 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\output_handler;
+
+class log_wrapper_migrator_output_handler implements migrator_output_handler_interface
+{
+ /**
+ * Language object.
+ *
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * A migrator output handler
+ *
+ * @var migrator_output_handler_interface
+ */
+ protected $migrator;
+
+ /**
+ * Log file handle
+ * @var resource
+ */
+ protected $file_handle = false;
+
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\language\language $language Language object
+ * @param migrator_output_handler_interface $migrator Migrator output handler
+ * @param string $log_file File to log to
+ * @param \phpbb\filesystem\filesystem_interface $filesystem phpBB filesystem object
+ */
+ public function __construct(\phpbb\language\language $language, migrator_output_handler_interface $migrator, $log_file, \phpbb\filesystem\filesystem_interface $filesystem)
+ {
+ $this->language = $language;
+ $this->migrator = $migrator;
+ $this->filesystem = $filesystem;
+ $this->file_open($log_file);
+ }
+
+ /**
+ * Open file for logging
+ *
+ * @param string $file File to open
+ */
+ protected function file_open($file)
+ {
+ if ($this->filesystem->is_writable(dirname($file)))
+ {
+ $this->file_handle = fopen($file, 'w');
+ }
+ else
+ {
+ throw new \RuntimeException('Unable to write to migrator log file');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($message, $verbosity)
+ {
+ $this->migrator->write($message, $verbosity);
+
+ if ($this->file_handle !== false)
+ {
+
+ $translated_message = $this->language->lang_array(array_shift($message), $message);
+
+ if ($verbosity <= migrator_output_handler_interface::VERBOSITY_NORMAL)
+ {
+ $translated_message = '[INFO] ' . $translated_message;
+ }
+ else
+ {
+ $translated_message = '[DEBUG] ' . $translated_message;
+ }
+
+ fwrite($this->file_handle, $translated_message . "\n");
+ fflush($this->file_handle);
+ }
+ }
+}
diff --git a/phpBB/phpbb/db/output_handler/migrator_output_handler_interface.php b/phpBB/phpbb/db/output_handler/migrator_output_handler_interface.php
new file mode 100644
index 0000000000..455d8aabbb
--- /dev/null
+++ b/phpBB/phpbb/db/output_handler/migrator_output_handler_interface.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\output_handler;
+
+interface migrator_output_handler_interface
+{
+ const VERBOSITY_QUIET = 16;
+ const VERBOSITY_NORMAL = 32;
+ const VERBOSITY_VERBOSE = 64;
+ const VERBOSITY_VERY_VERBOSE = 128;
+ const VERBOSITY_DEBUG = 256;
+
+ /**
+ * Write output using the configured closure.
+ *
+ * @param string|array $message The message to write or an array containing the language key and all of its parameters.
+ * @param int $verbosity The verbosity of the message.
+ */
+ public function write($message, $verbosity);
+}
diff --git a/phpBB/phpbb/db/output_handler/null_migrator_output_handler.php b/phpBB/phpbb/db/output_handler/null_migrator_output_handler.php
new file mode 100644
index 0000000000..5fc2a52577
--- /dev/null
+++ b/phpBB/phpbb/db/output_handler/null_migrator_output_handler.php
@@ -0,0 +1,24 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\output_handler;
+
+class null_migrator_output_handler implements migrator_output_handler_interface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function write($message, $verbosity)
+ {
+ }
+}
diff --git a/phpBB/phpbb/db/sql_insert_buffer.php b/phpBB/phpbb/db/sql_insert_buffer.php
index 18e4814a77..30e807b154 100644
--- a/phpBB/phpbb/db/sql_insert_buffer.php
+++ b/phpBB/phpbb/db/sql_insert_buffer.php
@@ -92,7 +92,7 @@ class sql_insert_buffer
// Flush buffer if it is full or when DB does not support multi inserts.
// In the later case, the buffer will always only contain one row.
- if (!$this->db->get_multi_insert() || sizeof($this->buffer) >= $this->max_buffered_rows)
+ if (!$this->db->get_multi_insert() || count($this->buffer) >= $this->max_buffered_rows)
{
return $this->flush();
}
@@ -104,7 +104,7 @@ class sql_insert_buffer
* Inserts a row set, i.e. an array of rows, by calling insert().
*
* Please note that it is in most cases better to use insert() instead of
- * first building a huge rowset. Or at least sizeof($rows) should be kept
+ * first building a huge rowset. Or at least count($rows) should be kept
* small.
*
* @param array $rows
diff --git a/phpBB/phpbb/db/tools.php b/phpBB/phpbb/db/tools.php
index 832a0c510c..4d1b91f7b4 100644
--- a/phpBB/phpbb/db/tools.php
+++ b/phpBB/phpbb/db/tools.php
@@ -14,2827 +14,8 @@
namespace phpbb\db;
/**
-* Database Tools for handling cross-db actions such as altering columns, etc.
-* Currently not supported is returning SQL for creating tables.
-*/
-class tools
+ * @deprecated 3.2.0-dev (To be removed 3.3.0) use \phpbb\db\tools\tools instead
+ */
+class tools extends \phpbb\db\tools\tools
{
- /**
- * Current sql layer
- */
- var $sql_layer = '';
-
- /**
- * @var object DB object
- */
- var $db = null;
-
- /**
- * The Column types for every database we support
- * @var array
- */
- var $dbms_type_map = array();
-
- /**
- * Is the used MS SQL Server a SQL Server 2000?
- * @var bool
- */
- protected $is_sql_server_2000;
-
- /**
- * Get the column types for every database we support
- *
- * @return array
- */
- public static function get_dbms_type_map()
- {
- return array(
- 'mysql_41' => array(
- 'INT:' => 'int(%d)',
- 'BINT' => 'bigint(20)',
- 'UINT' => 'mediumint(8) UNSIGNED',
- 'UINT:' => 'int(%d) UNSIGNED',
- 'TINT:' => 'tinyint(%d)',
- 'USINT' => 'smallint(4) UNSIGNED',
- 'BOOL' => 'tinyint(1) UNSIGNED',
- 'VCHAR' => 'varchar(255)',
- 'VCHAR:' => 'varchar(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'text',
- 'XSTEXT_UNI'=> 'varchar(100)',
- 'STEXT' => 'text',
- 'STEXT_UNI' => 'varchar(255)',
- 'TEXT' => 'text',
- 'TEXT_UNI' => 'text',
- 'MTEXT' => 'mediumtext',
- 'MTEXT_UNI' => 'mediumtext',
- 'TIMESTAMP' => 'int(11) UNSIGNED',
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'varchar(255)',
- 'VCHAR_UNI:'=> 'varchar(%d)',
- 'VCHAR_CI' => 'varchar(255)',
- 'VARBINARY' => 'varbinary(255)',
- ),
-
- 'mysql_40' => array(
- 'INT:' => 'int(%d)',
- 'BINT' => 'bigint(20)',
- 'UINT' => 'mediumint(8) UNSIGNED',
- 'UINT:' => 'int(%d) UNSIGNED',
- 'TINT:' => 'tinyint(%d)',
- 'USINT' => 'smallint(4) UNSIGNED',
- 'BOOL' => 'tinyint(1) UNSIGNED',
- 'VCHAR' => 'varbinary(255)',
- 'VCHAR:' => 'varbinary(%d)',
- 'CHAR:' => 'binary(%d)',
- 'XSTEXT' => 'blob',
- 'XSTEXT_UNI'=> 'blob',
- 'STEXT' => 'blob',
- 'STEXT_UNI' => 'blob',
- 'TEXT' => 'blob',
- 'TEXT_UNI' => 'blob',
- 'MTEXT' => 'mediumblob',
- 'MTEXT_UNI' => 'mediumblob',
- 'TIMESTAMP' => 'int(11) UNSIGNED',
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'blob',
- 'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')),
- 'VCHAR_CI' => 'blob',
- 'VARBINARY' => 'varbinary(255)',
- ),
-
- 'mssql' => array(
- 'INT:' => '[int]',
- 'BINT' => '[float]',
- 'UINT' => '[int]',
- 'UINT:' => '[int]',
- 'TINT:' => '[int]',
- 'USINT' => '[int]',
- 'BOOL' => '[int]',
- 'VCHAR' => '[varchar] (255)',
- 'VCHAR:' => '[varchar] (%d)',
- 'CHAR:' => '[char] (%d)',
- 'XSTEXT' => '[varchar] (1000)',
- 'STEXT' => '[varchar] (3000)',
- 'TEXT' => '[varchar] (8000)',
- 'MTEXT' => '[text]',
- 'XSTEXT_UNI'=> '[varchar] (100)',
- 'STEXT_UNI' => '[varchar] (255)',
- 'TEXT_UNI' => '[varchar] (4000)',
- 'MTEXT_UNI' => '[text]',
- 'TIMESTAMP' => '[int]',
- 'DECIMAL' => '[float]',
- 'DECIMAL:' => '[float]',
- 'PDECIMAL' => '[float]',
- 'PDECIMAL:' => '[float]',
- 'VCHAR_UNI' => '[varchar] (255)',
- 'VCHAR_UNI:'=> '[varchar] (%d)',
- 'VCHAR_CI' => '[varchar] (255)',
- 'VARBINARY' => '[varchar] (255)',
- ),
-
- 'mssqlnative' => array(
- 'INT:' => '[int]',
- 'BINT' => '[float]',
- 'UINT' => '[int]',
- 'UINT:' => '[int]',
- 'TINT:' => '[int]',
- 'USINT' => '[int]',
- 'BOOL' => '[int]',
- 'VCHAR' => '[varchar] (255)',
- 'VCHAR:' => '[varchar] (%d)',
- 'CHAR:' => '[char] (%d)',
- 'XSTEXT' => '[varchar] (1000)',
- 'STEXT' => '[varchar] (3000)',
- 'TEXT' => '[varchar] (8000)',
- 'MTEXT' => '[text]',
- 'XSTEXT_UNI'=> '[varchar] (100)',
- 'STEXT_UNI' => '[varchar] (255)',
- 'TEXT_UNI' => '[varchar] (4000)',
- 'MTEXT_UNI' => '[text]',
- 'TIMESTAMP' => '[int]',
- 'DECIMAL' => '[float]',
- 'DECIMAL:' => '[float]',
- 'PDECIMAL' => '[float]',
- 'PDECIMAL:' => '[float]',
- 'VCHAR_UNI' => '[varchar] (255)',
- 'VCHAR_UNI:'=> '[varchar] (%d)',
- 'VCHAR_CI' => '[varchar] (255)',
- 'VARBINARY' => '[varchar] (255)',
- ),
-
- 'oracle' => array(
- 'INT:' => 'number(%d)',
- 'BINT' => 'number(20)',
- 'UINT' => 'number(8)',
- 'UINT:' => 'number(%d)',
- 'TINT:' => 'number(%d)',
- 'USINT' => 'number(4)',
- 'BOOL' => 'number(1)',
- 'VCHAR' => 'varchar2(255)',
- 'VCHAR:' => 'varchar2(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'varchar2(1000)',
- 'STEXT' => 'varchar2(3000)',
- 'TEXT' => 'clob',
- 'MTEXT' => 'clob',
- 'XSTEXT_UNI'=> 'varchar2(300)',
- 'STEXT_UNI' => 'varchar2(765)',
- 'TEXT_UNI' => 'clob',
- 'MTEXT_UNI' => 'clob',
- 'TIMESTAMP' => 'number(11)',
- 'DECIMAL' => 'number(5, 2)',
- 'DECIMAL:' => 'number(%d, 2)',
- 'PDECIMAL' => 'number(6, 3)',
- 'PDECIMAL:' => 'number(%d, 3)',
- 'VCHAR_UNI' => 'varchar2(765)',
- 'VCHAR_UNI:'=> array('varchar2(%d)', 'limit' => array('mult', 3, 765, 'clob')),
- 'VCHAR_CI' => 'varchar2(255)',
- 'VARBINARY' => 'raw(255)',
- ),
-
- 'sqlite' => array(
- 'INT:' => 'int(%d)',
- 'BINT' => 'bigint(20)',
- 'UINT' => 'INTEGER UNSIGNED', //'mediumint(8) UNSIGNED',
- 'UINT:' => 'INTEGER UNSIGNED', // 'int(%d) UNSIGNED',
- 'TINT:' => 'tinyint(%d)',
- 'USINT' => 'INTEGER UNSIGNED', //'mediumint(4) UNSIGNED',
- 'BOOL' => 'INTEGER UNSIGNED', //'tinyint(1) UNSIGNED',
- 'VCHAR' => 'varchar(255)',
- 'VCHAR:' => 'varchar(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'text(65535)',
- 'STEXT' => 'text(65535)',
- 'TEXT' => 'text(65535)',
- 'MTEXT' => 'mediumtext(16777215)',
- 'XSTEXT_UNI'=> 'text(65535)',
- 'STEXT_UNI' => 'text(65535)',
- 'TEXT_UNI' => 'text(65535)',
- 'MTEXT_UNI' => 'mediumtext(16777215)',
- 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED',
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'varchar(255)',
- 'VCHAR_UNI:'=> 'varchar(%d)',
- 'VCHAR_CI' => 'varchar(255)',
- 'VARBINARY' => 'blob',
- ),
-
- 'sqlite3' => array(
- 'INT:' => 'INT(%d)',
- 'BINT' => 'BIGINT(20)',
- 'UINT' => 'INTEGER UNSIGNED',
- 'UINT:' => 'INTEGER UNSIGNED',
- 'TINT:' => 'TINYINT(%d)',
- 'USINT' => 'INTEGER UNSIGNED',
- 'BOOL' => 'INTEGER UNSIGNED',
- 'VCHAR' => 'VARCHAR(255)',
- 'VCHAR:' => 'VARCHAR(%d)',
- 'CHAR:' => 'CHAR(%d)',
- 'XSTEXT' => 'TEXT(65535)',
- 'STEXT' => 'TEXT(65535)',
- 'TEXT' => 'TEXT(65535)',
- 'MTEXT' => 'MEDIUMTEXT(16777215)',
- 'XSTEXT_UNI'=> 'TEXT(65535)',
- 'STEXT_UNI' => 'TEXT(65535)',
- 'TEXT_UNI' => 'TEXT(65535)',
- 'MTEXT_UNI' => 'MEDIUMTEXT(16777215)',
- 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED',
- 'DECIMAL' => 'DECIMAL(5,2)',
- 'DECIMAL:' => 'DECIMAL(%d,2)',
- 'PDECIMAL' => 'DECIMAL(6,3)',
- 'PDECIMAL:' => 'DECIMAL(%d,3)',
- 'VCHAR_UNI' => 'VARCHAR(255)',
- 'VCHAR_UNI:'=> 'VARCHAR(%d)',
- 'VCHAR_CI' => 'VARCHAR(255)',
- 'VARBINARY' => 'BLOB',
- ),
-
- 'postgres' => array(
- 'INT:' => 'INT4',
- 'BINT' => 'INT8',
- 'UINT' => 'INT4', // unsigned
- 'UINT:' => 'INT4', // unsigned
- 'USINT' => 'INT2', // unsigned
- 'BOOL' => 'INT2', // unsigned
- 'TINT:' => 'INT2',
- 'VCHAR' => 'varchar(255)',
- 'VCHAR:' => 'varchar(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'varchar(1000)',
- 'STEXT' => 'varchar(3000)',
- 'TEXT' => 'varchar(8000)',
- 'MTEXT' => 'TEXT',
- 'XSTEXT_UNI'=> 'varchar(100)',
- 'STEXT_UNI' => 'varchar(255)',
- 'TEXT_UNI' => 'varchar(4000)',
- 'MTEXT_UNI' => 'TEXT',
- 'TIMESTAMP' => 'INT4', // unsigned
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'varchar(255)',
- 'VCHAR_UNI:'=> 'varchar(%d)',
- 'VCHAR_CI' => 'varchar_ci',
- 'VARBINARY' => 'bytea',
- ),
- );
- }
-
- /**
- * A list of types being unsigned for better reference in some db's
- * @var array
- */
- var $unsigned_types = array('UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP');
-
- /**
- * A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules.
- * @var array
- */
- var $supported_dbms = array('mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite', 'sqlite3');
-
- /**
- * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array).
- * This mode has no effect on some methods (inserting of data for example). This is expressed within the methods command.
- */
- var $return_statements = false;
-
- /**
- * Constructor. Set DB Object and set {@link $return_statements return_statements}.
- *
- * @param \phpbb\db\driver\driver_interface $db Database connection
- * @param bool $return_statements True if only statements should be returned and no SQL being executed
- */
- public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
- {
- $this->db = $db;
- $this->return_statements = $return_statements;
-
- $this->dbms_type_map = self::get_dbms_type_map();
-
- // Determine mapping database type
- switch ($this->db->get_sql_layer())
- {
- case 'mysql':
- $this->sql_layer = 'mysql_40';
- break;
-
- case 'mysql4':
- if (version_compare($this->db->sql_server_info(true), '4.1.3', '>='))
- {
- $this->sql_layer = 'mysql_41';
- }
- else
- {
- $this->sql_layer = 'mysql_40';
- }
- break;
-
- case 'mysqli':
- $this->sql_layer = 'mysql_41';
- break;
-
- case 'mssql':
- case 'mssql_odbc':
- $this->sql_layer = 'mssql';
- break;
-
- case 'mssqlnative':
- $this->sql_layer = 'mssqlnative';
- break;
-
- default:
- $this->sql_layer = $this->db->get_sql_layer();
- break;
- }
- }
-
- /**
- * Setter for {@link $return_statements return_statements}.
- *
- * @param bool $return_statements True if SQL should not be executed but returned as strings
- * @return null
- */
- public function set_return_statements($return_statements)
- {
- $this->return_statements = $return_statements;
- }
-
- /**
- * Gets a list of tables in the database.
- *
- * @return array Array of table names (all lower case)
- */
- function sql_list_tables()
- {
- switch ($this->db->get_sql_layer())
- {
- case 'mysql':
- case 'mysql4':
- case 'mysqli':
- $sql = 'SHOW TABLES';
- break;
-
- case 'sqlite':
- $sql = 'SELECT name
- FROM sqlite_master
- WHERE type = "table"';
- break;
-
- case 'sqlite3':
- $sql = 'SELECT name
- FROM sqlite_master
- WHERE type = "table"
- AND name <> "sqlite_sequence"';
- break;
-
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
- $sql = "SELECT name
- FROM sysobjects
- WHERE type='U'";
- break;
-
- case 'postgres':
- $sql = 'SELECT relname
- FROM pg_stat_user_tables';
- break;
-
- case 'oracle':
- $sql = 'SELECT table_name
- FROM USER_TABLES';
- break;
- }
-
- $result = $this->db->sql_query($sql);
-
- $tables = array();
- while ($row = $this->db->sql_fetchrow($result))
- {
- $name = current($row);
- $tables[$name] = $name;
- }
- $this->db->sql_freeresult($result);
-
- return $tables;
- }
-
- /**
- * Check if table exists
- *
- *
- * @param string $table_name The table name to check for
- * @return bool true if table exists, else false
- */
- function sql_table_exists($table_name)
- {
- $this->db->sql_return_on_error(true);
- $result = $this->db->sql_query_limit('SELECT * FROM ' . $table_name, 1);
- $this->db->sql_return_on_error(false);
-
- if ($result)
- {
- $this->db->sql_freeresult($result);
- return true;
- }
-
- return false;
- }
-
- /**
- * Create SQL Table
- *
- * @param string $table_name The table name to create
- * @param array $table_data Array containing table data.
- * @return array Statements if $return_statements is true.
- */
- function sql_create_table($table_name, $table_data)
- {
- // holds the DDL for a column
- $columns = $statements = array();
-
- if ($this->sql_table_exists($table_name))
- {
- return $this->_sql_run_sql($statements);
- }
-
- // Begin transaction
- $statements[] = 'begin';
-
- // Determine if we have created a PRIMARY KEY in the earliest
- $primary_key_gen = false;
-
- // Determine if the table requires a sequence
- $create_sequence = false;
-
- // Begin table sql statement
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n";
- break;
-
- default:
- $table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n";
- break;
- }
-
- if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
- {
- if (!isset($table_data['PRIMARY_KEY']))
- {
- $table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment');
- $table_data['PRIMARY_KEY'] = 'mssqlindex';
- }
- }
-
- // Iterate through the columns to create a table
- foreach ($table_data['COLUMNS'] as $column_name => $column_data)
- {
- // here lies an array, filled with information compiled on the column's data
- $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
-
- if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
- {
- trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
- }
-
- // here we add the definition of the new column to the list of columns
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default'];
- break;
-
- default:
- $columns[] = "\t {$column_name} " . $prepared_column['column_type_sql'];
- break;
- }
-
- // see if we have found a primary key set due to a column definition if we have found it, we can stop looking
- if (!$primary_key_gen)
- {
- $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
- }
-
- // create sequence DDL based off of the existance of auto incrementing columns
- if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
- {
- $create_sequence = $column_name;
- }
- }
-
- // this makes up all the columns in the create table statement
- $table_sql .= implode(",\n", $columns);
-
- // Close the table for two DBMS and add to the statements
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $table_sql .= "\n);";
- $statements[] = $table_sql;
- break;
- }
-
- // we have yet to create a primary key for this table,
- // this means that we can add the one we really wanted instead
- if (!$primary_key_gen)
- {
- // Write primary key
- if (isset($table_data['PRIMARY_KEY']))
- {
- if (!is_array($table_data['PRIMARY_KEY']))
- {
- $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
- }
-
- switch ($this->sql_layer)
- {
- case 'mysql_40':
- case 'mysql_41':
- case 'postgres':
- case 'sqlite':
- case 'sqlite3':
- $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- // We need the data here
- $old_return_statements = $this->return_statements;
- $this->return_statements = true;
-
- $primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']);
- foreach ($primary_key_stmts as $pk_stmt)
- {
- $statements[] = $pk_stmt;
- }
-
- $this->return_statements = $old_return_statements;
- break;
-
- case 'oracle':
- $table_sql .= ",\n\t CONSTRAINT pk_{$table_name} PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
- break;
- }
- }
- }
-
- // close the table
- switch ($this->sql_layer)
- {
- case 'mysql_41':
- // make sure the table is in UTF-8 mode
- $table_sql .= "\n) CHARACTER SET `utf8` COLLATE `utf8_bin`;";
- $statements[] = $table_sql;
- break;
-
- case 'mysql_40':
- case 'sqlite':
- case 'sqlite3':
- $table_sql .= "\n);";
- $statements[] = $table_sql;
- break;
-
- case 'postgres':
- // do we need to add a sequence for auto incrementing columns?
- if ($create_sequence)
- {
- $statements[] = "CREATE SEQUENCE {$table_name}_seq;";
- }
-
- $table_sql .= "\n);";
- $statements[] = $table_sql;
- break;
-
- case 'oracle':
- $table_sql .= "\n)";
- $statements[] = $table_sql;
-
- // do we need to add a sequence and a tigger for auto incrementing columns?
- if ($create_sequence)
- {
- // create the actual sequence
- $statements[] = "CREATE SEQUENCE {$table_name}_seq";
-
- // the trigger is the mechanism by which we increment the counter
- $trigger = "CREATE OR REPLACE TRIGGER t_{$table_name}\n";
- $trigger .= "BEFORE INSERT ON {$table_name}\n";
- $trigger .= "FOR EACH ROW WHEN (\n";
- $trigger .= "\tnew.{$create_sequence} IS NULL OR new.{$create_sequence} = 0\n";
- $trigger .= ")\n";
- $trigger .= "BEGIN\n";
- $trigger .= "\tSELECT {$table_name}_seq.nextval\n";
- $trigger .= "\tINTO :new.{$create_sequence}\n";
- $trigger .= "\tFROM dual;\n";
- $trigger .= "END;";
-
- $statements[] = $trigger;
- }
- break;
- }
-
- // Write Keys
- if (isset($table_data['KEYS']))
- {
- foreach ($table_data['KEYS'] as $key_name => $key_data)
- {
- if (!is_array($key_data[1]))
- {
- $key_data[1] = array($key_data[1]);
- }
-
- $old_return_statements = $this->return_statements;
- $this->return_statements = true;
-
- $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
-
- foreach ($key_stmts as $key_stmt)
- {
- $statements[] = $key_stmt;
- }
-
- $this->return_statements = $old_return_statements;
- }
- }
-
- // Commit Transaction
- $statements[] = 'commit';
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Handle passed database update array.
- * Expected structure...
- * Key being one of the following
- * drop_tables: Drop tables
- * add_tables: Add tables
- * change_columns: Column changes (only type, not name)
- * add_columns: Add columns to a table
- * drop_keys: Dropping keys
- * drop_columns: Removing/Dropping columns
- * add_primary_keys: adding primary keys
- * add_unique_index: adding an unique index
- * add_index: adding an index (can be column:index_size if you need to provide size)
- *
- * The values are in this format:
- * {TABLE NAME} => array(
- * {COLUMN NAME} => array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}),
- * {KEY/INDEX NAME} => array({COLUMN NAMES}),
- * )
- *
- * For more information have a look at /develop/create_schema_files.php (only available through SVN)
- */
- function perform_schema_changes($schema_changes)
- {
- if (empty($schema_changes))
- {
- return;
- }
-
- $statements = array();
- $sqlite = false;
-
- // For SQLite we need to perform the schema changes in a much more different way
- if (($this->db->get_sql_layer() == 'sqlite' || $this->db->get_sql_layer() == 'sqlite3') && $this->return_statements)
- {
- $sqlite_data = array();
- $sqlite = true;
- }
-
- // Drop tables?
- if (!empty($schema_changes['drop_tables']))
- {
- foreach ($schema_changes['drop_tables'] as $table)
- {
- // only drop table if it exists
- if ($this->sql_table_exists($table))
- {
- $result = $this->sql_table_drop($table);
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Add tables?
- if (!empty($schema_changes['add_tables']))
- {
- foreach ($schema_changes['add_tables'] as $table => $table_data)
- {
- $result = $this->sql_create_table($table, $table_data);
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
-
- // Change columns?
- if (!empty($schema_changes['change_columns']))
- {
- foreach ($schema_changes['change_columns'] as $table => $columns)
- {
- foreach ($columns as $column_name => $column_data)
- {
- // If the column exists we change it, else we add it ;)
- if ($column_exists = $this->sql_column_exists($table, $column_name))
- {
- $result = $this->sql_column_change($table, $column_name, $column_data, true);
- }
- else
- {
- $result = $this->sql_column_add($table, $column_name, $column_data, true);
- }
-
- if ($sqlite)
- {
- if ($column_exists)
- {
- $sqlite_data[$table]['change_columns'][] = $result;
- }
- else
- {
- $sqlite_data[$table]['add_columns'][] = $result;
- }
- }
- else if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Add columns?
- if (!empty($schema_changes['add_columns']))
- {
- foreach ($schema_changes['add_columns'] as $table => $columns)
- {
- foreach ($columns as $column_name => $column_data)
- {
- // Only add the column if it does not exist yet
- if ($column_exists = $this->sql_column_exists($table, $column_name))
- {
- continue;
- // This is commented out here because it can take tremendous time on updates
-// $result = $this->sql_column_change($table, $column_name, $column_data, true);
- }
- else
- {
- $result = $this->sql_column_add($table, $column_name, $column_data, true);
- }
-
- if ($sqlite)
- {
- if ($column_exists)
- {
- continue;
-// $sqlite_data[$table]['change_columns'][] = $result;
- }
- else
- {
- $sqlite_data[$table]['add_columns'][] = $result;
- }
- }
- else if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Remove keys?
- if (!empty($schema_changes['drop_keys']))
- {
- foreach ($schema_changes['drop_keys'] as $table => $indexes)
- {
- foreach ($indexes as $index_name)
- {
- if (!$this->sql_index_exists($table, $index_name))
- {
- continue;
- }
-
- $result = $this->sql_index_drop($table, $index_name);
-
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Drop columns?
- if (!empty($schema_changes['drop_columns']))
- {
- foreach ($schema_changes['drop_columns'] as $table => $columns)
- {
- foreach ($columns as $column)
- {
- // Only remove the column if it exists...
- if ($this->sql_column_exists($table, $column))
- {
- $result = $this->sql_column_remove($table, $column, true);
-
- if ($sqlite)
- {
- $sqlite_data[$table]['drop_columns'][] = $result;
- }
- else if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
- }
-
- // Add primary keys?
- if (!empty($schema_changes['add_primary_keys']))
- {
- foreach ($schema_changes['add_primary_keys'] as $table => $columns)
- {
- $result = $this->sql_create_primary_key($table, $columns, true);
-
- if ($sqlite)
- {
- $sqlite_data[$table]['primary_key'] = $result;
- }
- else if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
-
- // Add unique indexes?
- if (!empty($schema_changes['add_unique_index']))
- {
- foreach ($schema_changes['add_unique_index'] as $table => $index_array)
- {
- foreach ($index_array as $index_name => $column)
- {
- if ($this->sql_unique_index_exists($table, $index_name))
- {
- continue;
- }
-
- $result = $this->sql_create_unique_index($table, $index_name, $column);
-
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Add indexes?
- if (!empty($schema_changes['add_index']))
- {
- foreach ($schema_changes['add_index'] as $table => $index_array)
- {
- foreach ($index_array as $index_name => $column)
- {
- if ($this->sql_index_exists($table, $index_name))
- {
- continue;
- }
-
- $result = $this->sql_create_index($table, $index_name, $column);
-
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- if ($sqlite)
- {
- foreach ($sqlite_data as $table_name => $sql_schema_changes)
- {
- // Create temporary table with original data
- $statements[] = 'begin';
-
- $sql = "SELECT sql
- FROM sqlite_master
- WHERE type = 'table'
- AND name = '{$table_name}'
- ORDER BY type DESC, name;";
- $result = $this->db->sql_query($sql);
-
- if (!$result)
- {
- continue;
- }
-
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- // Create a backup table and populate it, destroy the existing one
- $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']);
- $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
- $statements[] = 'DROP TABLE ' . $table_name;
-
- // Get the columns...
- preg_match('#\((.*)\)#s', $row['sql'], $matches);
-
- $plain_table_cols = trim($matches[1]);
- $new_table_cols = preg_split('/,(?![\s\w]+\))/m', $plain_table_cols);
- $column_list = array();
-
- foreach ($new_table_cols as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- continue;
- }
- $column_list[] = $entities[0];
- }
-
- // note down the primary key notation because sqlite only supports adding it to the end for the new table
- $primary_key = false;
- $_new_cols = array();
-
- foreach ($new_table_cols as $key => $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- $primary_key = $declaration;
- continue;
- }
- $_new_cols[] = $declaration;
- }
-
- $new_table_cols = $_new_cols;
-
- // First of all... change columns
- if (!empty($sql_schema_changes['change_columns']))
- {
- foreach ($sql_schema_changes['change_columns'] as $column_sql)
- {
- foreach ($new_table_cols as $key => $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if (strpos($column_sql, $entities[0] . ' ') === 0)
- {
- $new_table_cols[$key] = $column_sql;
- }
- }
- }
- }
-
- if (!empty($sql_schema_changes['add_columns']))
- {
- foreach ($sql_schema_changes['add_columns'] as $column_sql)
- {
- $new_table_cols[] = $column_sql;
- }
- }
-
- // Now drop them...
- if (!empty($sql_schema_changes['drop_columns']))
- {
- foreach ($sql_schema_changes['drop_columns'] as $column_name)
- {
- // Remove from column list...
- $new_column_list = array();
- foreach ($column_list as $key => $value)
- {
- if ($value === $column_name)
- {
- continue;
- }
-
- $new_column_list[] = $value;
- }
-
- $column_list = $new_column_list;
-
- // Remove from table...
- $_new_cols = array();
- foreach ($new_table_cols as $key => $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if (strpos($column_name . ' ', $entities[0] . ' ') === 0)
- {
- continue;
- }
- $_new_cols[] = $declaration;
- }
- $new_table_cols = $_new_cols;
- }
- }
-
- // Primary key...
- if (!empty($sql_schema_changes['primary_key']))
- {
- $new_table_cols[] = 'PRIMARY KEY (' . implode(', ', $sql_schema_changes['primary_key']) . ')';
- }
- // Add a new one or the old primary key
- else if ($primary_key !== false)
- {
- $new_table_cols[] = $primary_key;
- }
-
- $columns = implode(',', $column_list);
-
- // create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $new_table_cols) . ');';
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
- }
- }
-
- if ($this->return_statements)
- {
- return $statements;
- }
- }
-
- /**
- * Gets a list of columns of a table.
- *
- * @param string $table Table name
- *
- * @return array Array of column names (all lower case)
- */
- function sql_list_columns($table)
- {
- $columns = array();
-
- switch ($this->sql_layer)
- {
- case 'mysql_40':
- case 'mysql_41':
- $sql = "SHOW COLUMNS FROM $table";
- break;
-
- // PostgreSQL has a way of doing this in a much simpler way but would
- // not allow us to support all versions of PostgreSQL
- case 'postgres':
- $sql = "SELECT a.attname
- FROM pg_class c, pg_attribute a
- WHERE c.relname = '{$table}'
- AND a.attnum > 0
- AND a.attrelid = c.oid";
- break;
-
- // same deal with PostgreSQL, we must perform more complex operations than
- // we technically could
- case 'mssql':
- case 'mssqlnative':
- $sql = "SELECT c.name
- FROM syscolumns c
- LEFT JOIN sysobjects o ON c.id = o.id
- WHERE o.name = '{$table}'";
- break;
-
- case 'oracle':
- $sql = "SELECT column_name
- FROM user_tab_columns
- WHERE LOWER(table_name) = '" . strtolower($table) . "'";
- break;
-
- case 'sqlite':
- case 'sqlite3':
- $sql = "SELECT sql
- FROM sqlite_master
- WHERE type = 'table'
- AND name = '{$table}'";
-
- $result = $this->db->sql_query($sql);
-
- if (!$result)
- {
- return false;
- }
-
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- preg_match('#\((.*)\)#s', $row['sql'], $matches);
-
- $cols = trim($matches[1]);
- $col_array = preg_split('/,(?![\s\w]+\))/m', $cols);
-
- foreach ($col_array as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- continue;
- }
-
- $column = strtolower($entities[0]);
- $columns[$column] = $column;
- }
-
- return $columns;
- break;
- }
-
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $column = strtolower(current($row));
- $columns[$column] = $column;
- }
- $this->db->sql_freeresult($result);
-
- return $columns;
- }
-
- /**
- * Check whether a specified column exist in a table
- *
- * @param string $table Table to check
- * @param string $column_name Column to check
- *
- * @return bool True if column exists, false otherwise
- */
- function sql_column_exists($table, $column_name)
- {
- $columns = $this->sql_list_columns($table);
-
- return isset($columns[$column_name]);
- }
-
- /**
- * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes.
- *
- * @param string $table_name Table to check the index at
- * @param string $index_name The index name to check
- *
- * @return bool True if index exists, else false
- */
- function sql_index_exists($table_name, $index_name)
- {
- if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
- {
- $sql = "EXEC sp_statistics '$table_name'";
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- if ($row['TYPE'] == 3)
- {
- if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- }
- $this->db->sql_freeresult($result);
-
- return false;
- }
-
- switch ($this->sql_layer)
- {
- case 'postgres':
- $sql = "SELECT ic.relname as index_name
- FROM pg_class bc, pg_class ic, pg_index i
- WHERE (bc.oid = i.indrelid)
- AND (ic.oid = i.indexrelid)
- AND (bc.relname = '" . $table_name . "')
- AND (i.indisunique != 't')
- AND (i.indisprimary != 't')";
- $col = 'index_name';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql = 'SHOW KEYS
- FROM ' . $table_name;
- $col = 'Key_name';
- break;
-
- case 'oracle':
- $sql = "SELECT index_name
- FROM user_indexes
- WHERE table_name = '" . strtoupper($table_name) . "'
- AND generated = 'N'
- AND uniqueness = 'NONUNIQUE'";
- $col = 'index_name';
- break;
-
- case 'sqlite':
- case 'sqlite3':
- $sql = "PRAGMA index_list('" . $table_name . "');";
- $col = 'name';
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
- {
- continue;
- }
-
- // These DBMS prefix index name with the table name
- switch ($this->sql_layer)
- {
- case 'oracle':
- case 'postgres':
- case 'sqlite':
- case 'sqlite3':
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- break;
- }
-
- if (strtolower($row[$col]) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- $this->db->sql_freeresult($result);
-
- return false;
- }
-
- /**
- * Check if a specified index exists in table. Does not return PRIMARY KEY indexes.
- *
- * @param string $table_name Table to check the index at
- * @param string $index_name The index name to check
- *
- * @return bool True if index exists, else false
- */
- function sql_unique_index_exists($table_name, $index_name)
- {
- if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
- {
- $sql = "EXEC sp_statistics '$table_name'";
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- // Usually NON_UNIQUE is the column we want to check, but we allow for both
- if ($row['TYPE'] == 3)
- {
- if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- }
- $this->db->sql_freeresult($result);
- return false;
- }
-
- switch ($this->sql_layer)
- {
- case 'postgres':
- $sql = "SELECT ic.relname as index_name, i.indisunique
- FROM pg_class bc, pg_class ic, pg_index i
- WHERE (bc.oid = i.indrelid)
- AND (ic.oid = i.indexrelid)
- AND (bc.relname = '" . $table_name . "')
- AND (i.indisprimary != 't')";
- $col = 'index_name';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql = 'SHOW KEYS
- FROM ' . $table_name;
- $col = 'Key_name';
- break;
-
- case 'oracle':
- $sql = "SELECT index_name, table_owner
- FROM user_indexes
- WHERE table_name = '" . strtoupper($table_name) . "'
- AND generated = 'N'
- AND uniqueness = 'UNIQUE'";
- $col = 'index_name';
- break;
-
- case 'sqlite':
- case 'sqlite3':
- $sql = "PRAGMA index_list('" . $table_name . "');";
- $col = 'name';
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY'))
- {
- continue;
- }
-
- if (($this->sql_layer == 'sqlite' || $this->sql_layer == 'sqlite3') && !$row['unique'])
- {
- continue;
- }
-
- if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't')
- {
- continue;
- }
-
- // These DBMS prefix index name with the table name
- switch ($this->sql_layer)
- {
- case 'oracle':
- // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name
- if (strpos($row[$col], 'U_') === 0)
- {
- $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1);
- }
- else if (strpos($row[$col], strtoupper($table_name)) === 0)
- {
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- }
- break;
-
- case 'postgres':
- case 'sqlite':
- case 'sqlite3':
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- break;
- }
-
- if (strtolower($row[$col]) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- $this->db->sql_freeresult($result);
-
- return false;
- }
-
- /**
- * Private method for performing sql statements (either execute them or return them)
- * @access private
- */
- function _sql_run_sql($statements)
- {
- if ($this->return_statements)
- {
- return $statements;
- }
-
- // We could add error handling here...
- foreach ($statements as $sql)
- {
- if ($sql === 'begin')
- {
- $this->db->sql_transaction('begin');
- }
- else if ($sql === 'commit')
- {
- $this->db->sql_transaction('commit');
- }
- else
- {
- $this->db->sql_query($sql);
- }
- }
-
- return true;
- }
-
- /**
- * Function to prepare some column information for better usage
- * @access private
- */
- function sql_prepare_column_data($table_name, $column_name, $column_data)
- {
- if (strlen($column_name) > 30)
- {
- trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
- }
-
- // Get type
- list($column_type, $orig_column_type) = $this->get_column_type($column_data[0]);
-
- // Adjust default value if db-dependent specified
- if (is_array($column_data[1]))
- {
- $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
- }
-
- $sql = '';
-
- $return_array = array();
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $sql .= " {$column_type} ";
- $sql_default = " {$column_type} ";
-
- // For adding columns we need the default definition
- if (!is_null($column_data[1]))
- {
- // For hexadecimal values do not use single quotes
- if (strpos($column_data[1], '0x') === 0)
- {
- $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') ';
- $sql_default .= $return_array['default'];
- }
- else
- {
- $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') ';
- $sql_default .= $return_array['default'];
- }
- }
-
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
-// $sql .= 'IDENTITY (1, 1) ';
- $sql_default .= 'IDENTITY (1, 1) ';
- }
-
- $return_array['textimage'] = $column_type === '[text]';
-
- if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment'))
- {
- $sql .= 'NOT NULL';
- $sql_default .= 'NOT NULL';
- }
- else
- {
- $sql .= 'NULL';
- $sql_default .= 'NULL';
- }
-
- $return_array['column_type_sql_default'] = $sql_default;
-
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql .= " {$column_type} ";
-
- // For hexadecimal values do not use single quotes
- if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob')
- {
- $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' ";
- }
-
- if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment'))
- {
- $sql .= 'NOT NULL';
- }
- else
- {
- $sql .= 'NULL';
- }
-
- if (isset($column_data[2]))
- {
- if ($column_data[2] == 'auto_increment')
- {
- $sql .= ' auto_increment';
- }
- else if ($this->sql_layer === 'mysql_41' && $column_data[2] == 'true_sort')
- {
- $sql .= ' COLLATE utf8_unicode_ci';
- }
- }
-
- if (isset($column_data['after']))
- {
- $return_array['after'] = $column_data['after'];
- }
-
- break;
-
- case 'oracle':
- $sql .= " {$column_type} ";
- $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}' " : '';
-
- // In Oracle empty strings ('') are treated as NULL.
- // Therefore in oracle we allow NULL's for all DEFAULT '' entries
- // Oracle does not like setting NOT NULL on a column that is already NOT NULL (this happens only on number fields)
- if (!preg_match('/number/i', $column_type))
- {
- $sql .= ($column_data[1] === '' || $column_data[1] === null) ? '' : 'NOT NULL';
- }
-
- $return_array['auto_increment'] = false;
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
- $return_array['auto_increment'] = true;
- }
-
- break;
-
- case 'postgres':
- $return_array['column_type'] = $column_type;
-
- $sql .= " {$column_type} ";
-
- $return_array['auto_increment'] = false;
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
- $default_val = "nextval('{$table_name}_seq')";
- $return_array['auto_increment'] = true;
- }
- else if (!is_null($column_data[1]))
- {
- $default_val = "'" . $column_data[1] . "'";
- $return_array['null'] = 'NOT NULL';
- $sql .= 'NOT NULL ';
- }
- else
- {
- // Integers need to have 0 instead of empty string as default
- if (strpos($column_type, 'INT') === 0)
- {
- $default_val = '0';
- }
- else
- {
- $default_val = "'" . $column_data[1] . "'";
- }
- $return_array['null'] = 'NULL';
- $sql .= 'NULL ';
- }
-
- $return_array['default'] = $default_val;
-
- $sql .= "DEFAULT {$default_val}";
-
- // Unsigned? Then add a CHECK contraint
- if (in_array($orig_column_type, $this->unsigned_types))
- {
- $return_array['constraint'] = "CHECK ({$column_name} >= 0)";
- $sql .= " CHECK ({$column_name} >= 0)";
- }
-
- break;
-
- case 'sqlite':
- case 'sqlite3':
- $return_array['primary_key_set'] = false;
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
- $sql .= ' INTEGER PRIMARY KEY';
- $return_array['primary_key_set'] = true;
-
- if ($this->sql_layer === 'sqlite3')
- {
- $sql .= ' AUTOINCREMENT';
- }
- }
- else
- {
- $sql .= ' ' . $column_type;
- }
-
- if (!is_null($column_data[1]))
- {
- $sql .= ' NOT NULL ';
- $sql .= "DEFAULT '{$column_data[1]}'";
- }
-
- break;
- }
-
- $return_array['column_type_sql'] = $sql;
-
- return $return_array;
- }
-
- /**
- * Get the column's database type from the type map
- *
- * @param string $column_map_type
- * @return array column type for this database
- * and map type without length
- */
- function get_column_type($column_map_type)
- {
- if (strpos($column_map_type, ':') !== false)
- {
- list($orig_column_type, $column_length) = explode(':', $column_map_type);
- if (!is_array($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']))
- {
- $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'], $column_length);
- }
- else
- {
- if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule']))
- {
- switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][0])
- {
- case 'div':
- $column_length /= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][1];
- $column_length = ceil($column_length);
- $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
- break;
- }
- }
-
- if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit']))
- {
- switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][0])
- {
- case 'mult':
- $column_length *= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][1];
- if ($column_length > $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][2])
- {
- $column_type = $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][3];
- }
- else
- {
- $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
- }
- break;
- }
- }
- }
- $orig_column_type .= ':';
- }
- else
- {
- $orig_column_type = $column_map_type;
- $column_type = $this->dbms_type_map[$this->sql_layer][$column_map_type];
- }
-
- return array($column_type, $orig_column_type);
- }
-
- /**
- * Add new column
- */
- function sql_column_add($table_name, $column_name, $column_data, $inline = false)
- {
- $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- // Does not support AFTER, only through temporary table
- $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : '';
- $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after;
- break;
-
- case 'oracle':
- // Does not support AFTER, only through temporary table
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
- break;
-
- case 'postgres':
- // Does not support AFTER, only through temporary table
- if (version_compare($this->db->sql_server_info(true), '8.0', '>='))
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
- }
- else
- {
- // old versions cannot add columns with default and null information
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint'];
-
- if (isset($column_data['null']))
- {
- if ($column_data['null'] == 'NOT NULL')
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL';
- }
- }
-
- if (isset($column_data['default']))
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
- }
- }
-
- break;
-
- case 'sqlite':
- if ($inline && $this->return_statements)
- {
- return $column_name . ' ' . $column_data['column_type_sql'];
- }
-
- $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name);
- if (empty($recreate_queries))
- {
- break;
- }
-
- $statements[] = 'begin';
-
- $sql_create_table = array_shift($recreate_queries);
-
- // Create a backup table and populate it, destroy the existing one
- $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table);
- $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
- $statements[] = 'DROP TABLE ' . $table_name;
-
- preg_match('#\((.*)\)#s', $sql_create_table, $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- continue;
- }
- $column_list[] = $entities[0];
- }
-
- $columns = implode(',', $column_list);
-
- $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols;
-
- // create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');';
- $statements = array_merge($statements, $recreate_queries);
-
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
- break;
-
- case 'sqlite3':
- if ($inline && $this->return_statements)
- {
- return $column_name . ' ' . $column_data['column_type_sql'];
- }
-
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Drop column
- */
- function sql_column_remove($table_name, $column_name, $inline = false)
- {
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- // We need the data here
- $old_return_statements = $this->return_statements;
- $this->return_statements = true;
-
- $indexes = $this->get_existing_indexes($table_name, $column_name);
- $indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true));
-
- // Drop any indexes
- $recreate_indexes = array();
- if (!empty($indexes))
- {
- foreach ($indexes as $index_name => $index_data)
- {
- $result = $this->sql_index_drop($table_name, $index_name);
- $statements = array_merge($statements, $result);
- if (sizeof($index_data) > 1)
- {
- // Remove this column from the index and recreate it
- $recreate_indexes[$index_name] = array_diff($index_data, array($column_name));
- }
- }
- }
-
- // Drop default value constraint
- $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
- $statements = array_merge($statements, $result);
-
- // Remove the column
- $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']';
-
- if (!empty($recreate_indexes))
- {
- // Recreate indexes after we removed the column
- foreach ($recreate_indexes as $index_name => $index_data)
- {
- $result = $this->sql_create_index($table_name, $index_name, $index_data);
- $statements = array_merge($statements, $result);
- }
- }
-
- $this->return_statements = $old_return_statements;
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`';
- break;
-
- case 'oracle':
- $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name;
- break;
-
- case 'postgres':
- $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"';
- break;
-
- case 'sqlite':
- case 'sqlite3':
-
- if ($inline && $this->return_statements)
- {
- return $column_name;
- }
-
- $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name, $column_name);
- if (empty($recreate_queries))
- {
- break;
- }
-
- $statements[] = 'begin';
-
- $sql_create_table = array_shift($recreate_queries);
-
- // Create a backup table and populate it, destroy the existing one
- $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table);
- $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
- $statements[] = 'DROP TABLE ' . $table_name;
-
- preg_match('#\((.*)\)#s', $sql_create_table, $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name)
- {
- continue;
- }
- $column_list[] = $entities[0];
- }
-
- $columns = implode(',', $column_list);
-
- $new_table_cols = trim(preg_replace('/' . $column_name . '\b[^,]+(?:,|$)/m', '', $new_table_cols));
- if (substr($new_table_cols, -1) === ',')
- {
- // Remove the comma from the last entry again
- $new_table_cols = substr($new_table_cols, 0, -1);
- }
-
- // create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');';
- $statements = array_merge($statements, $recreate_queries);
-
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Drop Index
- */
- function sql_index_drop($table_name, $index_name)
- {
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name;
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name;
- break;
-
- case 'oracle':
- case 'postgres':
- case 'sqlite':
- case 'sqlite3':
- $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name;
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Drop Table
- */
- function sql_table_drop($table_name)
- {
- $statements = array();
-
- if (!$this->sql_table_exists($table_name))
- {
- return $this->_sql_run_sql($statements);
- }
-
- // the most basic operation, get rid of the table
- $statements[] = 'DROP TABLE ' . $table_name;
-
- switch ($this->sql_layer)
- {
- case 'oracle':
- $sql = 'SELECT A.REFERENCED_NAME
- FROM USER_DEPENDENCIES A, USER_TRIGGERS B
- WHERE A.REFERENCED_TYPE = \'SEQUENCE\'
- AND A.NAME = B.TRIGGER_NAME
- AND B.TABLE_NAME = \'' . strtoupper($table_name) . "'";
- $result = $this->db->sql_query($sql);
-
- // any sequences ref'd to this table's triggers?
- while ($row = $this->db->sql_fetchrow($result))
- {
- $statements[] = "DROP SEQUENCE {$row['referenced_name']}";
- }
- $this->db->sql_freeresult($result);
- break;
-
- case 'postgres':
- // PGSQL does not "tightly" bind sequences and tables, we must guess...
- $sql = "SELECT relname
- FROM pg_class
- WHERE relkind = 'S'
- AND relname = '{$table_name}_seq'";
- $result = $this->db->sql_query($sql);
-
- // We don't even care about storing the results. We already know the answer if we get rows back.
- if ($this->db->sql_fetchrow($result))
- {
- $statements[] = "DROP SEQUENCE {$table_name}_seq;\n";
- }
- $this->db->sql_freeresult($result);
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Add primary key
- */
- function sql_create_primary_key($table_name, $column, $inline = false)
- {
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'postgres':
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD ";
- $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED (";
- $sql .= '[' . implode("],\n\t\t[", $column) . ']';
- $sql .= ')';
-
- $statements[] = $sql;
- break;
-
- case 'oracle':
- $statements[] = 'ALTER TABLE ' . $table_name . ' add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')';
- break;
-
- case 'sqlite':
- case 'sqlite3':
-
- if ($inline && $this->return_statements)
- {
- return $column;
- }
-
- $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name);
- if (empty($recreate_queries))
- {
- break;
- }
-
- $statements[] = 'begin';
-
- $sql_create_table = array_shift($recreate_queries);
-
- // Create a backup table and populate it, destroy the existing one
- $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table);
- $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
- $statements[] = 'DROP TABLE ' . $table_name;
-
- preg_match('#\((.*)\)#s', $sql_create_table, $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- continue;
- }
- $column_list[] = $entities[0];
- }
-
- $columns = implode(',', $column_list);
-
- // create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));';
- $statements = array_merge($statements, $recreate_queries);
-
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Add unique index
- */
- function sql_create_unique_index($table_name, $index_name, $column)
- {
- $statements = array();
-
- $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
- if (strlen($table_name . '_' . $index_name) - strlen($table_prefix) > 24)
- {
- $max_length = strlen($table_prefix) + 24;
- trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR);
- }
-
- switch ($this->sql_layer)
- {
- case 'postgres':
- case 'oracle':
- case 'sqlite':
- case 'sqlite3':
- $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Add index
- */
- function sql_create_index($table_name, $index_name, $column)
- {
- $statements = array();
-
- $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
- if (strlen($table_name . $index_name) - strlen($table_prefix) > 24)
- {
- $max_length = strlen($table_prefix) + 24;
- trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR);
- }
-
- // remove index length unless MySQL4
- if ('mysql_40' != $this->sql_layer)
- {
- $column = preg_replace('#:.*$#', '', $column);
- }
-
- switch ($this->sql_layer)
- {
- case 'postgres':
- case 'oracle':
- case 'sqlite':
- case 'sqlite3':
- $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
- break;
-
- case 'mysql_40':
- // add index size to definition as required by MySQL4
- foreach ($column as $i => $col)
- {
- if (false !== strpos($col, ':'))
- {
- list($col, $index_size) = explode(':', $col);
- $column[$i] = "$col($index_size)";
- }
- }
- // no break
- case 'mysql_41':
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . ' (' . implode(', ', $column) . ')';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'CREATE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * List all of the indices that belong to a table,
- * does not count:
- * * UNIQUE indices
- * * PRIMARY keys
- */
- function sql_list_index($table_name)
- {
- $index_array = array();
-
- if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
- {
- $sql = "EXEC sp_statistics '$table_name'";
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if ($row['TYPE'] == 3)
- {
- $index_array[] = $row['INDEX_NAME'];
- }
- }
- $this->db->sql_freeresult($result);
- }
- else
- {
- switch ($this->sql_layer)
- {
- case 'postgres':
- $sql = "SELECT ic.relname as index_name
- FROM pg_class bc, pg_class ic, pg_index i
- WHERE (bc.oid = i.indrelid)
- AND (ic.oid = i.indexrelid)
- AND (bc.relname = '" . $table_name . "')
- AND (i.indisunique != 't')
- AND (i.indisprimary != 't')";
- $col = 'index_name';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql = 'SHOW KEYS
- FROM ' . $table_name;
- $col = 'Key_name';
- break;
-
- case 'oracle':
- $sql = "SELECT index_name
- FROM user_indexes
- WHERE table_name = '" . strtoupper($table_name) . "'
- AND generated = 'N'
- AND uniqueness = 'NONUNIQUE'";
- $col = 'index_name';
- break;
-
- case 'sqlite':
- case 'sqlite3':
- $sql = "PRAGMA index_info('" . $table_name . "');";
- $col = 'name';
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
- {
- continue;
- }
-
- switch ($this->sql_layer)
- {
- case 'oracle':
- case 'postgres':
- case 'sqlite':
- case 'sqlite3':
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- break;
- }
-
- $index_array[] = $row[$col];
- }
- $this->db->sql_freeresult($result);
- }
-
- return array_map('strtolower', $index_array);
- }
-
- /**
- * Removes table_name from the index_name if it is at the beginning
- *
- * @param $table_name
- * @param $index_name
- * @return string
- */
- protected function strip_table_name_from_index_name($table_name, $index_name)
- {
- return (strpos(strtoupper($index_name), strtoupper($table_name)) === 0) ? substr($index_name, strlen($table_name) + 1) : $index_name;
- }
-
- /**
- * Change column type (not name!)
- */
- function sql_column_change($table_name, $column_name, $column_data, $inline = false)
- {
- $original_column_data = $column_data;
- $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- // We need the data here
- $old_return_statements = $this->return_statements;
- $this->return_statements = true;
-
- $indexes = $this->get_existing_indexes($table_name, $column_name);
- $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true);
-
- // Drop any indexes
- if (!empty($indexes) || !empty($unique_indexes))
- {
- $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes));
- foreach ($drop_indexes as $index_name)
- {
- $result = $this->sql_index_drop($table_name, $index_name);
- $statements = array_merge($statements, $result);
- }
- }
-
- // Drop default value constraint
- $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
- $statements = array_merge($statements, $result);
-
- // Change the column
- $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql'];
-
- if (!empty($column_data['default']))
- {
- // Add new default value constraint
- $statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $column_data['default'] . ' FOR [' . $column_name . ']';
- }
-
- if (!empty($indexes))
- {
- // Recreate indexes after we changed the column
- foreach ($indexes as $index_name => $index_data)
- {
- $result = $this->sql_create_index($table_name, $index_name, $index_data);
- $statements = array_merge($statements, $result);
- }
- }
-
- if (!empty($unique_indexes))
- {
- // Recreate unique indexes after we changed the column
- foreach ($unique_indexes as $index_name => $index_data)
- {
- $result = $this->sql_create_unique_index($table_name, $index_name, $index_data);
- $statements = array_merge($statements, $result);
- }
- }
-
- $this->return_statements = $old_return_statements;
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql'];
- break;
-
- case 'oracle':
- // We need the data here
- $old_return_statements = $this->return_statements;
- $this->return_statements = true;
-
- // Get list of existing indexes
- $indexes = $this->get_existing_indexes($table_name, $column_name);
- $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true);
-
- // Drop any indexes
- if (!empty($indexes) || !empty($unique_indexes))
- {
- $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes));
- foreach ($drop_indexes as $index_name)
- {
- $result = $this->sql_index_drop($table_name, $this->strip_table_name_from_index_name($table_name, $index_name));
- $statements = array_merge($statements, $result);
- }
- }
-
- $temp_column_name = 'temp_' . substr(md5($column_name), 0, 25);
- // Add a temporary table with the new type
- $result = $this->sql_column_add($table_name, $temp_column_name, $original_column_data);
- $statements = array_merge($statements, $result);
-
- // Copy the data to the new column
- $statements[] = 'UPDATE ' . $table_name . ' SET ' . $temp_column_name . ' = ' . $column_name;
-
- // Drop the original column
- $result = $this->sql_column_remove($table_name, $column_name);
- $statements = array_merge($statements, $result);
-
- // Recreate the original column with the new type
- $result = $this->sql_column_add($table_name, $column_name, $original_column_data);
- $statements = array_merge($statements, $result);
-
- if (!empty($indexes))
- {
- // Recreate indexes after we changed the column
- foreach ($indexes as $index_name => $index_data)
- {
- $result = $this->sql_create_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data);
- $statements = array_merge($statements, $result);
- }
- }
-
- if (!empty($unique_indexes))
- {
- // Recreate unique indexes after we changed the column
- foreach ($unique_indexes as $index_name => $index_data)
- {
- $result = $this->sql_create_unique_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data);
- $statements = array_merge($statements, $result);
- }
- }
-
- // Copy the data to the original column
- $statements[] = 'UPDATE ' . $table_name . ' SET ' . $column_name . ' = ' . $temp_column_name;
-
- // Drop the temporary column again
- $result = $this->sql_column_remove($table_name, $temp_column_name);
- $statements = array_merge($statements, $result);
-
- $this->return_statements = $old_return_statements;
- break;
-
- case 'postgres':
- $sql = 'ALTER TABLE ' . $table_name . ' ';
-
- $sql_array = array();
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type'];
-
- if (isset($column_data['null']))
- {
- if ($column_data['null'] == 'NOT NULL')
- {
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL';
- }
- else if ($column_data['null'] == 'NULL')
- {
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL';
- }
- }
-
- if (isset($column_data['default']))
- {
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
- }
-
- // we don't want to double up on constraints if we change different number data types
- if (isset($column_data['constraint']))
- {
- $constraint_sql = "SELECT consrc as constraint_data
- FROM pg_constraint, pg_class bc
- WHERE conrelid = bc.oid
- AND bc.relname = '{$table_name}'
- AND NOT EXISTS (
- SELECT *
- FROM pg_constraint as c, pg_inherits as i
- WHERE i.inhrelid = pg_constraint.conrelid
- AND c.conname = pg_constraint.conname
- AND c.consrc = pg_constraint.consrc
- AND c.conrelid = i.inhparent
- )";
-
- $constraint_exists = false;
-
- $result = $this->db->sql_query($constraint_sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (trim($row['constraint_data']) == trim($column_data['constraint']))
- {
- $constraint_exists = true;
- break;
- }
- }
- $this->db->sql_freeresult($result);
-
- if (!$constraint_exists)
- {
- $sql_array[] = 'ADD ' . $column_data['constraint'];
- }
- }
-
- $sql .= implode(', ', $sql_array);
-
- $statements[] = $sql;
- break;
-
- case 'sqlite':
- case 'sqlite3':
-
- if ($inline && $this->return_statements)
- {
- return $column_name . ' ' . $column_data['column_type_sql'];
- }
-
- $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name);
- if (empty($recreate_queries))
- {
- break;
- }
-
- $statements[] = 'begin';
-
- $sql_create_table = array_shift($recreate_queries);
-
- // Create a temp table and populate it, destroy the existing one
- $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table);
- $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
- $statements[] = 'DROP TABLE ' . $table_name;
-
- preg_match('#\((.*)\)#s', $sql_create_table, $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $key => $declaration)
- {
- $declaration = trim($declaration);
-
- // Check for the beginning of the constraint section and stop
- if (preg_match('/[^\(]*\s*PRIMARY KEY\s+\(/', $declaration) ||
- preg_match('/[^\(]*\s*UNIQUE\s+\(/', $declaration) ||
- preg_match('/[^\(]*\s*FOREIGN KEY\s+\(/', $declaration) ||
- preg_match('/[^\(]*\s*CHECK\s+\(/', $declaration))
- {
- break;
- }
-
- $entities = preg_split('#\s+#', $declaration);
- $column_list[] = $entities[0];
- if ($entities[0] == $column_name)
- {
- $old_table_cols[$key] = $column_name . ' ' . $column_data['column_type_sql'];
- }
- }
-
- $columns = implode(',', $column_list);
-
- // Create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');';
- $statements = array_merge($statements, $recreate_queries);
-
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
-
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Get queries to drop the default constraints of a column
- *
- * We need to drop the default constraints of a column,
- * before being able to change their type or deleting them.
- *
- * @param string $table_name
- * @param string $column_name
- * @return array Array with SQL statements
- */
- protected function mssql_get_drop_default_constraints_queries($table_name, $column_name)
- {
- $statements = array();
- if ($this->mssql_is_sql_server_2000())
- {
- // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
- // Deprecated in SQL Server 2005
- $sql = "SELECT so.name AS def_name
- FROM sysobjects so
- JOIN sysconstraints sc ON so.id = sc.constid
- WHERE object_name(so.parent_obj) = '{$table_name}'
- AND so.xtype = 'D'
- AND sc.colid = (SELECT colid FROM syscolumns
- WHERE id = object_id('{$table_name}')
- AND name = '{$column_name}')";
- }
- else
- {
- $sql = "SELECT dobj.name AS def_name
- FROM sys.columns col
- LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D')
- WHERE col.object_id = object_id('{$table_name}')
- AND col.name = '{$column_name}'
- AND dobj.name IS NOT NULL";
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- $statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']';
- }
- $this->db->sql_freeresult($result);
-
- return $statements;
- }
-
- /**
- * Get a list with existing indexes for the column
- *
- * @param string $table_name
- * @param string $column_name
- * @param bool $unique Should we get unique indexes or normal ones
- * @return array Array with Index name => columns
- */
- public function get_existing_indexes($table_name, $column_name, $unique = false)
- {
- switch ($this->sql_layer)
- {
- case 'mysql_40':
- case 'mysql_41':
- case 'postgres':
- case 'sqlite':
- case 'sqlite3':
- // Not supported
- throw new \Exception('DBMS is not supported');
- break;
- }
-
- $sql = '';
- $existing_indexes = array();
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- if ($this->mssql_is_sql_server_2000())
- {
- // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
- // Deprecated in SQL Server 2005
- $sql = "SELECT DISTINCT ix.name AS phpbb_index_name
- FROM sysindexes ix
- INNER JOIN sysindexkeys ixc
- ON ixc.id = ix.id
- AND ixc.indid = ix.indid
- INNER JOIN syscolumns cols
- ON cols.colid = ixc.colid
- AND cols.id = ix.id
- WHERE ix.id = object_id('{$table_name}')
- AND cols.name = '{$column_name}'
- AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0');
- }
- else
- {
- $sql = "SELECT DISTINCT ix.name AS phpbb_index_name
- FROM sys.indexes ix
- INNER JOIN sys.index_columns ixc
- ON ixc.object_id = ix.object_id
- AND ixc.index_id = ix.index_id
- INNER JOIN sys.columns cols
- ON cols.column_id = ixc.column_id
- AND cols.object_id = ix.object_id
- WHERE ix.object_id = object_id('{$table_name}')
- AND cols.name = '{$column_name}'
- AND ix.is_unique = " . ($unique ? '1' : '0');
- }
- break;
-
- case 'oracle':
- $sql = "SELECT ix.index_name AS phpbb_index_name, ix.uniqueness AS is_unique
- FROM all_ind_columns ixc, all_indexes ix
- WHERE ix.index_name = ixc.index_name
- AND ixc.table_name = '" . strtoupper($table_name) . "'
- AND ixc.column_name = '" . strtoupper($column_name) . "'";
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE'))
- {
- $existing_indexes[$row['phpbb_index_name']] = array();
- }
- }
- $this->db->sql_freeresult($result);
-
- if (empty($existing_indexes))
- {
- return array();
- }
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- if ($this->mssql_is_sql_server_2000())
- {
- $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
- FROM sysindexes ix
- INNER JOIN sysindexkeys ixc
- ON ixc.id = ix.id
- AND ixc.indid = ix.indid
- INNER JOIN syscolumns cols
- ON cols.colid = ixc.colid
- AND cols.id = ix.id
- WHERE ix.id = object_id('{$table_name}')
- AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
- }
- else
- {
- $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
- FROM sys.indexes ix
- INNER JOIN sys.index_columns ixc
- ON ixc.object_id = ix.object_id
- AND ixc.index_id = ix.index_id
- INNER JOIN sys.columns cols
- ON cols.column_id = ixc.column_id
- AND cols.object_id = ix.object_id
- WHERE ix.object_id = object_id('{$table_name}')
- AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
- }
- break;
-
- case 'oracle':
- $sql = "SELECT index_name AS phpbb_index_name, column_name AS phpbb_column_name
- FROM all_ind_columns
- WHERE table_name = '" . strtoupper($table_name) . "'
- AND " . $this->db->sql_in_set('index_name', array_keys($existing_indexes));
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- $existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name'];
- }
- $this->db->sql_freeresult($result);
-
- return $existing_indexes;
- }
-
- /**
- * Is the used MS SQL Server a SQL Server 2000?
- *
- * @return bool
- */
- protected function mssql_is_sql_server_2000()
- {
- if ($this->is_sql_server_2000 === null)
- {
- $sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version";
- $result = $this->db->sql_query($sql);
- $properties = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
- $this->is_sql_server_2000 = $properties['mssql_version'][0] == '8';
- }
-
- return $this->is_sql_server_2000;
- }
-
- /**
- * Returns the Queries which are required to recreate a table including indexes
- *
- * @param string $table_name
- * @param string $remove_column When we drop a column, we remove the column
- * from all indexes. If the index has no other
- * column, we drop it completly.
- * @return array
- */
- protected function sqlite_get_recreate_table_queries($table_name, $remove_column = '')
- {
- $queries = array();
-
- $sql = "SELECT sql
- FROM sqlite_master
- WHERE type = 'table'
- AND name = '{$table_name}'";
- $result = $this->db->sql_query($sql);
- $sql_create_table = $this->db->sql_fetchfield('sql');
- $this->db->sql_freeresult($result);
-
- if (!$sql_create_table)
- {
- return array();
- }
- $queries[] = $sql_create_table;
-
- $sql = "SELECT sql
- FROM sqlite_master
- WHERE type = 'index'
- AND tbl_name = '{$table_name}'";
- $result = $this->db->sql_query($sql);
- while ($sql_create_index = $this->db->sql_fetchfield('sql'))
- {
- if ($remove_column)
- {
- $match = array();
- preg_match('#(?:[\w ]+)\((.*)\)#', $sql_create_index, $match);
- if (!isset($match[1]))
- {
- continue;
- }
-
- // Find and remove $remove_column from the index
- $columns = explode(', ', $match[1]);
- $found_column = array_search($remove_column, $columns);
- if ($found_column !== false)
- {
- unset($columns[$found_column]);
-
- // If the column list is not empty add the index to the list
- if (!empty($columns))
- {
- $queries[] = str_replace($match[1], implode(', ', $columns), $sql_create_index);
- }
- }
- else
- {
- $queries[] = $sql_create_index;
- }
- }
- else
- {
- $queries[] = $sql_create_index;
- }
- }
- $this->db->sql_freeresult($result);
-
- return $queries;
- }
}
diff --git a/phpBB/phpbb/db/tools/factory.php b/phpBB/phpbb/db/tools/factory.php
new file mode 100644
index 0000000000..96471c3408
--- /dev/null
+++ b/phpBB/phpbb/db/tools/factory.php
@@ -0,0 +1,43 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\tools;
+
+/**
+ * A factory which serves the suitable tools instance for the given dbal
+ */
+class factory
+{
+ /**
+ * @param mixed $db_driver
+ * @param bool $return_statements
+ * @return \phpbb\db\tools\tools_interface
+ */
+ public function get($db_driver, $return_statements = false)
+ {
+ if ($db_driver instanceof \phpbb\db\driver\mssql_base)
+ {
+ return new \phpbb\db\tools\mssql($db_driver, $return_statements);
+ }
+ else if ($db_driver instanceof \phpbb\db\driver\postgres)
+ {
+ return new \phpbb\db\tools\postgres($db_driver, $return_statements);
+ }
+ else if ($db_driver instanceof \phpbb\db\driver\driver_interface)
+ {
+ return new \phpbb\db\tools\tools($db_driver, $return_statements);
+ }
+
+ throw new \InvalidArgumentException('Invalid database driver given');
+ }
+}
diff --git a/phpBB/phpbb/db/tools/mssql.php b/phpBB/phpbb/db/tools/mssql.php
new file mode 100644
index 0000000000..cbedf9a5c4
--- /dev/null
+++ b/phpBB/phpbb/db/tools/mssql.php
@@ -0,0 +1,880 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\tools;
+
+/**
+ * Database Tools for handling cross-db actions such as altering columns, etc.
+ * Currently not supported is returning SQL for creating tables.
+ */
+class mssql extends tools
+{
+ /**
+ * Is the used MS SQL Server a SQL Server 2000?
+ * @var bool
+ */
+ protected $is_sql_server_2000;
+
+ /**
+ * Get the column types for mssql based databases
+ *
+ * @return array
+ */
+ public static function get_dbms_type_map()
+ {
+ return array(
+ 'mssql' => array(
+ 'INT:' => '[int]',
+ 'BINT' => '[float]',
+ 'ULINT' => '[int]',
+ 'UINT' => '[int]',
+ 'UINT:' => '[int]',
+ 'TINT:' => '[int]',
+ 'USINT' => '[int]',
+ 'BOOL' => '[int]',
+ 'VCHAR' => '[varchar] (255)',
+ 'VCHAR:' => '[varchar] (%d)',
+ 'CHAR:' => '[char] (%d)',
+ 'XSTEXT' => '[varchar] (1000)',
+ 'STEXT' => '[varchar] (3000)',
+ 'TEXT' => '[varchar] (8000)',
+ 'MTEXT' => '[text]',
+ 'XSTEXT_UNI'=> '[nvarchar] (100)',
+ 'STEXT_UNI' => '[nvarchar] (255)',
+ 'TEXT_UNI' => '[nvarchar] (4000)',
+ 'MTEXT_UNI' => '[ntext]',
+ 'TIMESTAMP' => '[int]',
+ 'DECIMAL' => '[float]',
+ 'DECIMAL:' => '[float]',
+ 'PDECIMAL' => '[float]',
+ 'PDECIMAL:' => '[float]',
+ 'VCHAR_UNI' => '[nvarchar] (255)',
+ 'VCHAR_UNI:'=> '[nvarchar] (%d)',
+ 'VCHAR_CI' => '[nvarchar] (255)',
+ 'VARBINARY' => '[varchar] (255)',
+ ),
+
+ 'mssqlnative' => array(
+ 'INT:' => '[int]',
+ 'BINT' => '[float]',
+ 'ULINT' => '[int]',
+ 'UINT' => '[int]',
+ 'UINT:' => '[int]',
+ 'TINT:' => '[int]',
+ 'USINT' => '[int]',
+ 'BOOL' => '[int]',
+ 'VCHAR' => '[varchar] (255)',
+ 'VCHAR:' => '[varchar] (%d)',
+ 'CHAR:' => '[char] (%d)',
+ 'XSTEXT' => '[varchar] (1000)',
+ 'STEXT' => '[varchar] (3000)',
+ 'TEXT' => '[varchar] (8000)',
+ 'MTEXT' => '[text]',
+ 'XSTEXT_UNI'=> '[nvarchar] (100)',
+ 'STEXT_UNI' => '[nvarchar] (255)',
+ 'TEXT_UNI' => '[nvarchar] (4000)',
+ 'MTEXT_UNI' => '[ntext]',
+ 'TIMESTAMP' => '[int]',
+ 'DECIMAL' => '[float]',
+ 'DECIMAL:' => '[float]',
+ 'PDECIMAL' => '[float]',
+ 'PDECIMAL:' => '[float]',
+ 'VCHAR_UNI' => '[nvarchar] (255)',
+ 'VCHAR_UNI:'=> '[nvarchar] (%d)',
+ 'VCHAR_CI' => '[nvarchar] (255)',
+ 'VARBINARY' => '[varchar] (255)',
+ ),
+ );
+ }
+
+ /**
+ * Constructor. Set DB Object and set {@link $return_statements return_statements}.
+ *
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param bool $return_statements True if only statements should be returned and no SQL being executed
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
+ {
+ parent::__construct($db, $return_statements);
+
+ // Determine mapping database type
+ switch ($this->db->get_sql_layer())
+ {
+ case 'mssql_odbc':
+ $this->sql_layer = 'mssql';
+ break;
+
+ case 'mssqlnative':
+ $this->sql_layer = 'mssqlnative';
+ break;
+ }
+
+ $this->dbms_type_map = self::get_dbms_type_map();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_tables()
+ {
+ $sql = "SELECT name
+ FROM sysobjects
+ WHERE type='U'";
+ $result = $this->db->sql_query($sql);
+
+ $tables = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $name = current($row);
+ $tables[$name] = $name;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $tables;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_table($table_name, $table_data)
+ {
+ // holds the DDL for a column
+ $columns = $statements = array();
+
+ if ($this->sql_table_exists($table_name))
+ {
+ return $this->_sql_run_sql($statements);
+ }
+
+ // Begin transaction
+ $statements[] = 'begin';
+
+ // Determine if we have created a PRIMARY KEY in the earliest
+ $primary_key_gen = false;
+
+ // Determine if the table requires a sequence
+ $create_sequence = false;
+
+ // Begin table sql statement
+ $table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n";
+
+ if (!isset($table_data['PRIMARY_KEY']))
+ {
+ $table_data['COLUMNS']['mssqlindex'] = array('UINT', null, 'auto_increment');
+ $table_data['PRIMARY_KEY'] = 'mssqlindex';
+ }
+
+ // Iterate through the columns to create a table
+ foreach ($table_data['COLUMNS'] as $column_name => $column_data)
+ {
+ // here lies an array, filled with information compiled on the column's data
+ $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+
+ if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
+ {
+ trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
+ }
+
+ // here we add the definition of the new column to the list of columns
+ $columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default'];
+
+ // see if we have found a primary key set due to a column definition if we have found it, we can stop looking
+ if (!$primary_key_gen)
+ {
+ $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
+ }
+
+ // create sequence DDL based off of the existance of auto incrementing columns
+ if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
+ {
+ $create_sequence = $column_name;
+ }
+ }
+
+ // this makes up all the columns in the create table statement
+ $table_sql .= implode(",\n", $columns);
+
+ // Close the table for two DBMS and add to the statements
+ $table_sql .= "\n);";
+ $statements[] = $table_sql;
+
+ // we have yet to create a primary key for this table,
+ // this means that we can add the one we really wanted instead
+ if (!$primary_key_gen)
+ {
+ // Write primary key
+ if (isset($table_data['PRIMARY_KEY']))
+ {
+ if (!is_array($table_data['PRIMARY_KEY']))
+ {
+ $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
+ }
+
+ // We need the data here
+ $old_return_statements = $this->return_statements;
+ $this->return_statements = true;
+
+ $primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']);
+ foreach ($primary_key_stmts as $pk_stmt)
+ {
+ $statements[] = $pk_stmt;
+ }
+
+ $this->return_statements = $old_return_statements;
+ }
+ }
+
+ // Write Keys
+ if (isset($table_data['KEYS']))
+ {
+ foreach ($table_data['KEYS'] as $key_name => $key_data)
+ {
+ if (!is_array($key_data[1]))
+ {
+ $key_data[1] = array($key_data[1]);
+ }
+
+ $old_return_statements = $this->return_statements;
+ $this->return_statements = true;
+
+ $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
+
+ foreach ($key_stmts as $key_stmt)
+ {
+ $statements[] = $key_stmt;
+ }
+
+ $this->return_statements = $old_return_statements;
+ }
+ }
+
+ // Commit Transaction
+ $statements[] = 'commit';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_columns($table_name)
+ {
+ $columns = array();
+
+ $sql = "SELECT c.name
+ FROM syscolumns c
+ LEFT JOIN sysobjects o ON c.id = o.id
+ WHERE o.name = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $column = strtolower(current($row));
+ $columns[$column] = $column;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $columns;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_index_exists($table_name, $index_name)
+ {
+ $sql = "EXEC sp_statistics '$table_name'";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if ($row['TYPE'] == 3)
+ {
+ if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_unique_index_exists($table_name, $index_name)
+ {
+ $sql = "EXEC sp_statistics '$table_name'";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // Usually NON_UNIQUE is the column we want to check, but we allow for both
+ if ($row['TYPE'] == 3)
+ {
+ if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_prepare_column_data($table_name, $column_name, $column_data)
+ {
+ if (strlen($column_name) > 30)
+ {
+ trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
+ }
+
+ // Get type
+ list($column_type, ) = $this->get_column_type($column_data[0]);
+
+ // Adjust default value if db-dependent specified
+ if (is_array($column_data[1]))
+ {
+ $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
+ }
+
+ $sql = '';
+
+ $return_array = array();
+
+ $sql .= " {$column_type} ";
+ $sql_default = " {$column_type} ";
+
+ // For adding columns we need the default definition
+ if (!is_null($column_data[1]))
+ {
+ // For hexadecimal values do not use single quotes
+ if (strpos($column_data[1], '0x') === 0)
+ {
+ $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') ';
+ $sql_default .= $return_array['default'];
+ }
+ else
+ {
+ $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') ';
+ $sql_default .= $return_array['default'];
+ }
+ }
+
+ if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
+ {
+ // $sql .= 'IDENTITY (1, 1) ';
+ $sql_default .= 'IDENTITY (1, 1) ';
+ }
+
+ $return_array['textimage'] = $column_type === '[text]';
+
+ if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment'))
+ {
+ $sql .= 'NOT NULL';
+ $sql_default .= 'NOT NULL';
+ }
+ else
+ {
+ $sql .= 'NULL';
+ $sql_default .= 'NULL';
+ }
+
+ $return_array['column_type_sql_default'] = $sql_default;
+
+ $return_array['column_type_sql'] = $sql;
+
+ return $return_array;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_add($table_name, $column_name, $column_data, $inline = false)
+ {
+ $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+ $statements = array();
+
+ // Does not support AFTER, only through temporary table
+ $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default'];
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_remove($table_name, $column_name, $inline = false)
+ {
+ $statements = array();
+
+ // We need the data here
+ $old_return_statements = $this->return_statements;
+ $this->return_statements = true;
+
+ $indexes = $this->get_existing_indexes($table_name, $column_name);
+ $indexes = array_merge($indexes, $this->get_existing_indexes($table_name, $column_name, true));
+
+ // Drop any indexes
+ $recreate_indexes = array();
+ if (!empty($indexes))
+ {
+ foreach ($indexes as $index_name => $index_data)
+ {
+ $result = $this->sql_index_drop($table_name, $index_name);
+ $statements = array_merge($statements, $result);
+ if (count($index_data) > 1)
+ {
+ // Remove this column from the index and recreate it
+ $recreate_indexes[$index_name] = array_diff($index_data, array($column_name));
+ }
+ }
+ }
+
+ // Drop primary keys depending on this column
+ $result = $this->mssql_get_drop_default_primary_key_queries($table_name, $column_name);
+ $statements = array_merge($statements, $result);
+
+ // Drop default value constraint
+ $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
+ $statements = array_merge($statements, $result);
+
+ // Remove the column
+ $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']';
+
+ if (!empty($recreate_indexes))
+ {
+ // Recreate indexes after we removed the column
+ foreach ($recreate_indexes as $index_name => $index_data)
+ {
+ $result = $this->sql_create_index($table_name, $index_name, $index_data);
+ $statements = array_merge($statements, $result);
+ }
+ }
+
+ $this->return_statements = $old_return_statements;
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_index_drop($table_name, $index_name)
+ {
+ $statements = array();
+
+ $statements[] = 'DROP INDEX [' . $table_name . '].[' . $index_name . ']';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_table_drop($table_name)
+ {
+ $statements = array();
+
+ if (!$this->sql_table_exists($table_name))
+ {
+ return $this->_sql_run_sql($statements);
+ }
+
+ // the most basic operation, get rid of the table
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_primary_key($table_name, $column, $inline = false)
+ {
+ $statements = array();
+
+ $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD ";
+ $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED (";
+ $sql .= '[' . implode("],\n\t\t[", $column) . ']';
+ $sql .= ')';
+
+ $statements[] = $sql;
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_unique_index($table_name, $index_name, $column)
+ {
+ $statements = array();
+
+ if ($this->mssql_is_sql_server_2000())
+ {
+ $this->check_index_name_length($table_name, $index_name);
+ }
+
+ $statements[] = 'CREATE UNIQUE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_index($table_name, $index_name, $column)
+ {
+ $statements = array();
+
+ $this->check_index_name_length($table_name, $index_name);
+
+ // remove index length
+ $column = preg_replace('#:.*$#', '', $column);
+
+ $statements[] = 'CREATE INDEX [' . $index_name . '] ON [' . $table_name . ']([' . implode('], [', $column) . '])';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_max_index_name_length()
+ {
+ if ($this->mssql_is_sql_server_2000())
+ {
+ return parent::get_max_index_name_length();
+ }
+ else
+ {
+ return 128;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_index($table_name)
+ {
+ $index_array = array();
+ $sql = "EXEC sp_statistics '$table_name'";
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if ($row['TYPE'] == 3)
+ {
+ $index_array[] = strtolower($row['INDEX_NAME']);
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return $index_array;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_change($table_name, $column_name, $column_data, $inline = false)
+ {
+ $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+ $statements = array();
+
+ // We need the data here
+ $old_return_statements = $this->return_statements;
+ $this->return_statements = true;
+
+ $indexes = $this->get_existing_indexes($table_name, $column_name);
+ $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true);
+
+ // Drop any indexes
+ if (!empty($indexes) || !empty($unique_indexes))
+ {
+ $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes));
+ foreach ($drop_indexes as $index_name)
+ {
+ $result = $this->sql_index_drop($table_name, $index_name);
+ $statements = array_merge($statements, $result);
+ }
+ }
+
+ // Drop default value constraint
+ $result = $this->mssql_get_drop_default_constraints_queries($table_name, $column_name);
+ $statements = array_merge($statements, $result);
+
+ // Change the column
+ $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql'];
+
+ if (!empty($column_data['default']) && !$this->mssql_is_column_identity($table_name, $column_name))
+ {
+ // Add new default value constraint
+ $statements[] = 'ALTER TABLE [' . $table_name . '] ADD CONSTRAINT [DF_' . $table_name . '_' . $column_name . '_1] ' . $column_data['default'] . ' FOR [' . $column_name . ']';
+ }
+
+ if (!empty($indexes))
+ {
+ // Recreate indexes after we changed the column
+ foreach ($indexes as $index_name => $index_data)
+ {
+ $result = $this->sql_create_index($table_name, $index_name, $index_data);
+ $statements = array_merge($statements, $result);
+ }
+ }
+
+ if (!empty($unique_indexes))
+ {
+ // Recreate unique indexes after we changed the column
+ foreach ($unique_indexes as $index_name => $index_data)
+ {
+ $result = $this->sql_create_unique_index($table_name, $index_name, $index_data);
+ $statements = array_merge($statements, $result);
+ }
+ }
+
+ $this->return_statements = $old_return_statements;
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * Get queries to drop the default constraints of a column
+ *
+ * We need to drop the default constraints of a column,
+ * before being able to change their type or deleting them.
+ *
+ * @param string $table_name
+ * @param string $column_name
+ * @return array Array with SQL statements
+ */
+ protected function mssql_get_drop_default_constraints_queries($table_name, $column_name)
+ {
+ $statements = array();
+ if ($this->mssql_is_sql_server_2000())
+ {
+ // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
+ // Deprecated in SQL Server 2005
+ $sql = "SELECT so.name AS def_name
+ FROM sysobjects so
+ JOIN sysconstraints sc ON so.id = sc.constid
+ WHERE object_name(so.parent_obj) = '{$table_name}'
+ AND so.xtype = 'D'
+ AND sc.colid = (SELECT colid FROM syscolumns
+ WHERE id = object_id('{$table_name}')
+ AND name = '{$column_name}')";
+ }
+ else
+ {
+ $sql = "SELECT dobj.name AS def_name
+ FROM sys.columns col
+ LEFT OUTER JOIN sys.objects dobj ON (dobj.object_id = col.default_object_id AND dobj.type = 'D')
+ WHERE col.object_id = object_id('{$table_name}')
+ AND col.name = '{$column_name}'
+ AND dobj.name IS NOT NULL";
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $row['def_name'] . ']';
+ }
+ $this->db->sql_freeresult($result);
+
+ return $statements;
+ }
+
+ /**
+ * Get queries to drop the primary keys depending on the specified column
+ *
+ * We need to drop primary keys depending on this column before being able
+ * to delete them.
+ *
+ * @param string $table_name
+ * @param string $column_name
+ * @return array Array with SQL statements
+ */
+ protected function mssql_get_drop_default_primary_key_queries($table_name, $column_name)
+ {
+ $statements = array();
+
+ $sql = "SELECT ccu.CONSTRAINT_NAME, ccu.COLUMN_NAME
+ FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
+ JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu ON tc.CONSTRAINT_NAME = ccu.Constraint_name
+ WHERE tc.TABLE_NAME = '{$table_name}'
+ AND tc.CONSTRAINT_TYPE = 'Primary Key'
+ AND ccu.COLUMN_NAME = '{$column_name}'";
+
+ $result = $this->db->sql_query($sql);
+
+ while ($primary_key = $this->db->sql_fetchrow($result))
+ {
+ $statements[] = 'ALTER TABLE [' . $table_name . '] DROP CONSTRAINT [' . $primary_key['CONSTRAINT_NAME'] . ']';
+ }
+ $this->db->sql_freeresult($result);
+
+ return $statements;
+ }
+
+ /**
+ * Checks to see if column is an identity column
+ *
+ * Identity columns cannot have defaults set for them.
+ *
+ * @param string $table_name
+ * @param string $column_name
+ * @return bool true if identity, false if not
+ */
+ protected function mssql_is_column_identity($table_name, $column_name)
+ {
+ if ($this->mssql_is_sql_server_2000())
+ {
+ // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
+ // Deprecated in SQL Server 2005
+ $sql = "SELECT COLUMNPROPERTY(object_id('{$table_name}'), '{$column_name}', 'IsIdentity') AS is_identity";
+ }
+ else
+ {
+ $sql = "SELECT is_identity FROM sys.columns
+ WHERE object_id = object_id('{$table_name}')
+ AND name = '{$column_name}'";
+ }
+
+ $result = $this->db->sql_query($sql);
+ $is_identity = $this->db->sql_fetchfield('is_identity');
+ $this->db->sql_freeresult($result);
+
+ return (bool) $is_identity;
+ }
+
+ /**
+ * Get a list with existing indexes for the column
+ *
+ * @param string $table_name
+ * @param string $column_name
+ * @param bool $unique Should we get unique indexes or normal ones
+ * @return array Array with Index name => columns
+ */
+ public function get_existing_indexes($table_name, $column_name, $unique = false)
+ {
+ $existing_indexes = array();
+ if ($this->mssql_is_sql_server_2000())
+ {
+ // http://msdn.microsoft.com/en-us/library/aa175912%28v=sql.80%29.aspx
+ // Deprecated in SQL Server 2005
+ $sql = "SELECT DISTINCT ix.name AS phpbb_index_name
+ FROM sysindexes ix
+ INNER JOIN sysindexkeys ixc
+ ON ixc.id = ix.id
+ AND ixc.indid = ix.indid
+ INNER JOIN syscolumns cols
+ ON cols.colid = ixc.colid
+ AND cols.id = ix.id
+ WHERE ix.id = object_id('{$table_name}')
+ AND cols.name = '{$column_name}'
+ AND INDEXPROPERTY(ix.id, ix.name, 'IsUnique') = " . ($unique ? '1' : '0');
+ }
+ else
+ {
+ $sql = "SELECT DISTINCT ix.name AS phpbb_index_name
+ FROM sys.indexes ix
+ INNER JOIN sys.index_columns ixc
+ ON ixc.object_id = ix.object_id
+ AND ixc.index_id = ix.index_id
+ INNER JOIN sys.columns cols
+ ON cols.column_id = ixc.column_id
+ AND cols.object_id = ix.object_id
+ WHERE ix.object_id = object_id('{$table_name}')
+ AND cols.name = '{$column_name}'
+ AND ix.is_primary_key = 0
+ AND ix.is_unique = " . ($unique ? '1' : '0');
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE'))
+ {
+ $existing_indexes[$row['phpbb_index_name']] = array();
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if (empty($existing_indexes))
+ {
+ return array();
+ }
+
+ if ($this->mssql_is_sql_server_2000())
+ {
+ $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
+ FROM sysindexes ix
+ INNER JOIN sysindexkeys ixc
+ ON ixc.id = ix.id
+ AND ixc.indid = ix.indid
+ INNER JOIN syscolumns cols
+ ON cols.colid = ixc.colid
+ AND cols.id = ix.id
+ WHERE ix.id = object_id('{$table_name}')
+ AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
+ }
+ else
+ {
+ $sql = "SELECT DISTINCT ix.name AS phpbb_index_name, cols.name AS phpbb_column_name
+ FROM sys.indexes ix
+ INNER JOIN sys.index_columns ixc
+ ON ixc.object_id = ix.object_id
+ AND ixc.index_id = ix.index_id
+ INNER JOIN sys.columns cols
+ ON cols.column_id = ixc.column_id
+ AND cols.object_id = ix.object_id
+ WHERE ix.object_id = object_id('{$table_name}')
+ AND " . $this->db->sql_in_set('ix.name', array_keys($existing_indexes));
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name'];
+ }
+ $this->db->sql_freeresult($result);
+
+ return $existing_indexes;
+ }
+
+ /**
+ * Is the used MS SQL Server a SQL Server 2000?
+ *
+ * @return bool
+ */
+ protected function mssql_is_sql_server_2000()
+ {
+ if ($this->is_sql_server_2000 === null)
+ {
+ $sql = "SELECT CAST(SERVERPROPERTY('productversion') AS VARCHAR(25)) AS mssql_version";
+ $result = $this->db->sql_query($sql);
+ $properties = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+ $this->is_sql_server_2000 = $properties['mssql_version'][0] == '8';
+ }
+
+ return $this->is_sql_server_2000;
+ }
+
+}
diff --git a/phpBB/phpbb/db/tools/postgres.php b/phpBB/phpbb/db/tools/postgres.php
new file mode 100644
index 0000000000..077d6e06f9
--- /dev/null
+++ b/phpBB/phpbb/db/tools/postgres.php
@@ -0,0 +1,614 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\db\tools;
+
+/**
+ * Database Tools for handling cross-db actions such as altering columns, etc.
+ * Currently not supported is returning SQL for creating tables.
+ */
+class postgres extends tools
+{
+ /**
+ * Get the column types for postgres only
+ *
+ * @return array
+ */
+ public static function get_dbms_type_map()
+ {
+ return array(
+ 'postgres' => array(
+ 'INT:' => 'INT4',
+ 'BINT' => 'INT8',
+ 'ULINT' => 'INT4', // unsigned
+ 'UINT' => 'INT4', // unsigned
+ 'UINT:' => 'INT4', // unsigned
+ 'USINT' => 'INT2', // unsigned
+ 'BOOL' => 'INT2', // unsigned
+ 'TINT:' => 'INT2',
+ 'VCHAR' => 'varchar(255)',
+ 'VCHAR:' => 'varchar(%d)',
+ 'CHAR:' => 'char(%d)',
+ 'XSTEXT' => 'varchar(1000)',
+ 'STEXT' => 'varchar(3000)',
+ 'TEXT' => 'varchar(8000)',
+ 'MTEXT' => 'TEXT',
+ 'XSTEXT_UNI'=> 'varchar(100)',
+ 'STEXT_UNI' => 'varchar(255)',
+ 'TEXT_UNI' => 'varchar(4000)',
+ 'MTEXT_UNI' => 'TEXT',
+ 'TIMESTAMP' => 'INT4', // unsigned
+ 'DECIMAL' => 'decimal(5,2)',
+ 'DECIMAL:' => 'decimal(%d,2)',
+ 'PDECIMAL' => 'decimal(6,3)',
+ 'PDECIMAL:' => 'decimal(%d,3)',
+ 'VCHAR_UNI' => 'varchar(255)',
+ 'VCHAR_UNI:'=> 'varchar(%d)',
+ 'VCHAR_CI' => 'varchar_ci',
+ 'VARBINARY' => 'bytea',
+ ),
+ );
+ }
+
+ /**
+ * Constructor. Set DB Object and set {@link $return_statements return_statements}.
+ *
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param bool $return_statements True if only statements should be returned and no SQL being executed
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
+ {
+ parent::__construct($db, $return_statements);
+
+ // Determine mapping database type
+ $this->sql_layer = 'postgres';
+
+ $this->dbms_type_map = self::get_dbms_type_map();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_tables()
+ {
+ $sql = 'SELECT relname
+ FROM pg_stat_user_tables';
+ $result = $this->db->sql_query($sql);
+
+ $tables = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $name = current($row);
+ $tables[$name] = $name;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $tables;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_table($table_name, $table_data)
+ {
+ // holds the DDL for a column
+ $columns = $statements = array();
+
+ if ($this->sql_table_exists($table_name))
+ {
+ return $this->_sql_run_sql($statements);
+ }
+
+ // Begin transaction
+ $statements[] = 'begin';
+
+ // Determine if we have created a PRIMARY KEY in the earliest
+ $primary_key_gen = false;
+
+ // Determine if the table requires a sequence
+ $create_sequence = false;
+
+ // Begin table sql statement
+ $table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n";
+
+ // Iterate through the columns to create a table
+ foreach ($table_data['COLUMNS'] as $column_name => $column_data)
+ {
+ // here lies an array, filled with information compiled on the column's data
+ $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+
+ if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
+ {
+ trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
+ }
+
+ // here we add the definition of the new column to the list of columns
+ $columns[] = "\t {$column_name} " . $prepared_column['column_type_sql'];
+
+ // see if we have found a primary key set due to a column definition if we have found it, we can stop looking
+ if (!$primary_key_gen)
+ {
+ $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
+ }
+
+ // create sequence DDL based off of the existance of auto incrementing columns
+ if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
+ {
+ $create_sequence = $column_name;
+ }
+ }
+
+ // this makes up all the columns in the create table statement
+ $table_sql .= implode(",\n", $columns);
+
+ // we have yet to create a primary key for this table,
+ // this means that we can add the one we really wanted instead
+ if (!$primary_key_gen)
+ {
+ // Write primary key
+ if (isset($table_data['PRIMARY_KEY']))
+ {
+ if (!is_array($table_data['PRIMARY_KEY']))
+ {
+ $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
+ }
+
+ $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
+ }
+ }
+
+ // do we need to add a sequence for auto incrementing columns?
+ if ($create_sequence)
+ {
+ $statements[] = "CREATE SEQUENCE {$table_name}_seq;";
+ }
+
+ // close the table
+ $table_sql .= "\n);";
+ $statements[] = $table_sql;
+
+ // Write Keys
+ if (isset($table_data['KEYS']))
+ {
+ foreach ($table_data['KEYS'] as $key_name => $key_data)
+ {
+ if (!is_array($key_data[1]))
+ {
+ $key_data[1] = array($key_data[1]);
+ }
+
+ $old_return_statements = $this->return_statements;
+ $this->return_statements = true;
+
+ $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
+
+ foreach ($key_stmts as $key_stmt)
+ {
+ $statements[] = $key_stmt;
+ }
+
+ $this->return_statements = $old_return_statements;
+ }
+ }
+
+ // Commit Transaction
+ $statements[] = 'commit';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_columns($table_name)
+ {
+ $columns = array();
+
+ $sql = "SELECT a.attname
+ FROM pg_class c, pg_attribute a
+ WHERE c.relname = '{$table_name}'
+ AND a.attnum > 0
+ AND a.attrelid = c.oid";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $column = strtolower(current($row));
+ $columns[$column] = $column;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $columns;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_index_exists($table_name, $index_name)
+ {
+ $sql = "SELECT ic.relname as index_name
+ FROM pg_class bc, pg_class ic, pg_index i
+ WHERE (bc.oid = i.indrelid)
+ AND (ic.oid = i.indexrelid)
+ AND (bc.relname = '" . $table_name . "')
+ AND (i.indisunique != 't')
+ AND (i.indisprimary != 't')";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // This DBMS prefixes index names with the table name
+ $row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
+
+ if (strtolower($row['index_name']) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_unique_index_exists($table_name, $index_name)
+ {
+ $sql = "SELECT ic.relname as index_name, i.indisunique
+ FROM pg_class bc, pg_class ic, pg_index i
+ WHERE (bc.oid = i.indrelid)
+ AND (ic.oid = i.indexrelid)
+ AND (bc.relname = '" . $table_name . "')
+ AND (i.indisprimary != 't')";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if ($row['indisunique'] != 't')
+ {
+ continue;
+ }
+
+ // This DBMS prefixes index names with the table name
+ $row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
+
+ if (strtolower($row['index_name']) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
+ * Function to prepare some column information for better usage
+ * @access private
+ */
+ function sql_prepare_column_data($table_name, $column_name, $column_data)
+ {
+ if (strlen($column_name) > 30)
+ {
+ trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
+ }
+
+ // Get type
+ list($column_type, $orig_column_type) = $this->get_column_type($column_data[0]);
+
+ // Adjust default value if db-dependent specified
+ if (is_array($column_data[1]))
+ {
+ $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
+ }
+
+ $sql = " {$column_type} ";
+
+ $return_array = array(
+ 'column_type' => $column_type,
+ 'auto_increment' => false,
+ );
+
+ if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
+ {
+ $default_val = "nextval('{$table_name}_seq')";
+ $return_array['auto_increment'] = true;
+ }
+ else if (!is_null($column_data[1]))
+ {
+ $default_val = "'" . $column_data[1] . "'";
+ $return_array['null'] = 'NOT NULL';
+ $sql .= 'NOT NULL ';
+ }
+ else
+ {
+ // Integers need to have 0 instead of empty string as default
+ if (strpos($column_type, 'INT') === 0)
+ {
+ $default_val = '0';
+ }
+ else
+ {
+ $default_val = "'" . $column_data[1] . "'";
+ }
+ $return_array['null'] = 'NULL';
+ $sql .= 'NULL ';
+ }
+
+ $return_array['default'] = $default_val;
+
+ $sql .= "DEFAULT {$default_val}";
+
+ // Unsigned? Then add a CHECK contraint
+ if (in_array($orig_column_type, $this->unsigned_types))
+ {
+ $return_array['constraint'] = "CHECK ({$column_name} >= 0)";
+ $sql .= " CHECK ({$column_name} >= 0)";
+ }
+
+ $return_array['column_type_sql'] = $sql;
+
+ return $return_array;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_add($table_name, $column_name, $column_data, $inline = false)
+ {
+ $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+ $statements = array();
+
+ // Does not support AFTER, only through temporary table
+ if (version_compare($this->db->sql_server_info(true), '8.0', '>='))
+ {
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
+ }
+ else
+ {
+ // old versions cannot add columns with default and null information
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint'];
+
+ if (isset($column_data['null']))
+ {
+ if ($column_data['null'] == 'NOT NULL')
+ {
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL';
+ }
+ }
+
+ if (isset($column_data['default']))
+ {
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
+ }
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_remove($table_name, $column_name, $inline = false)
+ {
+ $statements = array();
+
+ $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_index_drop($table_name, $index_name)
+ {
+ $statements = array();
+
+ $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name;
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_table_drop($table_name)
+ {
+ $statements = array();
+
+ if (!$this->sql_table_exists($table_name))
+ {
+ return $this->_sql_run_sql($statements);
+ }
+
+ // the most basic operation, get rid of the table
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ // PGSQL does not "tightly" bind sequences and tables, we must guess...
+ $sql = "SELECT relname
+ FROM pg_class
+ WHERE relkind = 'S'
+ AND relname = '{$table_name}_seq'";
+ $result = $this->db->sql_query($sql);
+
+ // We don't even care about storing the results. We already know the answer if we get rows back.
+ if ($this->db->sql_fetchrow($result))
+ {
+ $statements[] = "DROP SEQUENCE IF EXISTS {$table_name}_seq;\n";
+ }
+ $this->db->sql_freeresult($result);
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_primary_key($table_name, $column, $inline = false)
+ {
+ $statements = array();
+
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_unique_index($table_name, $index_name, $column)
+ {
+ $statements = array();
+
+ $this->check_index_name_length($table_name, $index_name);
+
+ $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_index($table_name, $index_name, $column)
+ {
+ $statements = array();
+
+ $this->check_index_name_length($table_name, $index_name);
+
+ // remove index length
+ $column = preg_replace('#:.*$#', '', $column);
+
+ $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_index($table_name)
+ {
+ $index_array = array();
+
+ $sql = "SELECT ic.relname as index_name
+ FROM pg_class bc, pg_class ic, pg_index i
+ WHERE (bc.oid = i.indrelid)
+ AND (ic.oid = i.indexrelid)
+ AND (bc.relname = '" . $table_name . "')
+ AND (i.indisunique != 't')
+ AND (i.indisprimary != 't')";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $row['index_name'] = $this->strip_table_name_from_index_name($table_name, $row['index_name']);
+
+ $index_array[] = $row['index_name'];
+ }
+ $this->db->sql_freeresult($result);
+
+ return array_map('strtolower', $index_array);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_change($table_name, $column_name, $column_data, $inline = false)
+ {
+ $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+ $statements = array();
+
+ $sql = 'ALTER TABLE ' . $table_name . ' ';
+
+ $sql_array = array();
+ $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type'];
+
+ if (isset($column_data['null']))
+ {
+ if ($column_data['null'] == 'NOT NULL')
+ {
+ $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL';
+ }
+ else if ($column_data['null'] == 'NULL')
+ {
+ $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL';
+ }
+ }
+
+ if (isset($column_data['default']))
+ {
+ $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
+ }
+
+ // we don't want to double up on constraints if we change different number data types
+ if (isset($column_data['constraint']))
+ {
+ $constraint_sql = "SELECT consrc as constraint_data
+ FROM pg_constraint, pg_class bc
+ WHERE conrelid = bc.oid
+ AND bc.relname = '{$table_name}'
+ AND NOT EXISTS (
+ SELECT *
+ FROM pg_constraint as c, pg_inherits as i
+ WHERE i.inhrelid = pg_constraint.conrelid
+ AND c.conname = pg_constraint.conname
+ AND c.consrc = pg_constraint.consrc
+ AND c.conrelid = i.inhparent
+ )";
+
+ $constraint_exists = false;
+
+ $result = $this->db->sql_query($constraint_sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (trim($row['constraint_data']) == trim($column_data['constraint']))
+ {
+ $constraint_exists = true;
+ break;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if (!$constraint_exists)
+ {
+ $sql_array[] = 'ADD ' . $column_data['constraint'];
+ }
+ }
+
+ $sql .= implode(', ', $sql_array);
+
+ $statements[] = $sql;
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * Get a list with existing indexes for the column
+ *
+ * @param string $table_name
+ * @param string $column_name
+ * @param bool $unique Should we get unique indexes or normal ones
+ * @return array Array with Index name => columns
+ */
+ public function get_existing_indexes($table_name, $column_name, $unique = false)
+ {
+ // Not supported
+ throw new \Exception('DBMS is not supported');
+ }
+}
diff --git a/phpBB/phpbb/db/tools/tools.php b/phpBB/phpbb/db/tools/tools.php
new file mode 100644
index 0000000000..c3352a1f66
--- /dev/null
+++ b/phpBB/phpbb/db/tools/tools.php
@@ -0,0 +1,1956 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\tools;
+
+/**
+* Database Tools for handling cross-db actions such as altering columns, etc.
+* Currently not supported is returning SQL for creating tables.
+*/
+class tools implements tools_interface
+{
+ /**
+ * Current sql layer
+ */
+ var $sql_layer = '';
+
+ /**
+ * @var object DB object
+ */
+ var $db = null;
+
+ /**
+ * The Column types for every database we support
+ * @var array
+ */
+ var $dbms_type_map = array();
+
+ /**
+ * Get the column types for every database we support
+ *
+ * @return array
+ */
+ static public function get_dbms_type_map()
+ {
+ return array(
+ 'mysql_41' => array(
+ 'INT:' => 'int(%d)',
+ 'BINT' => 'bigint(20)',
+ 'ULINT' => 'INT(10) UNSIGNED',
+ 'UINT' => 'mediumint(8) UNSIGNED',
+ 'UINT:' => 'int(%d) UNSIGNED',
+ 'TINT:' => 'tinyint(%d)',
+ 'USINT' => 'smallint(4) UNSIGNED',
+ 'BOOL' => 'tinyint(1) UNSIGNED',
+ 'VCHAR' => 'varchar(255)',
+ 'VCHAR:' => 'varchar(%d)',
+ 'CHAR:' => 'char(%d)',
+ 'XSTEXT' => 'text',
+ 'XSTEXT_UNI'=> 'varchar(100)',
+ 'STEXT' => 'text',
+ 'STEXT_UNI' => 'varchar(255)',
+ 'TEXT' => 'text',
+ 'TEXT_UNI' => 'text',
+ 'MTEXT' => 'mediumtext',
+ 'MTEXT_UNI' => 'mediumtext',
+ 'TIMESTAMP' => 'int(11) UNSIGNED',
+ 'DECIMAL' => 'decimal(5,2)',
+ 'DECIMAL:' => 'decimal(%d,2)',
+ 'PDECIMAL' => 'decimal(6,3)',
+ 'PDECIMAL:' => 'decimal(%d,3)',
+ 'VCHAR_UNI' => 'varchar(255)',
+ 'VCHAR_UNI:'=> 'varchar(%d)',
+ 'VCHAR_CI' => 'varchar(255)',
+ 'VARBINARY' => 'varbinary(255)',
+ ),
+
+ 'mysql_40' => array(
+ 'INT:' => 'int(%d)',
+ 'BINT' => 'bigint(20)',
+ 'ULINT' => 'INT(10) UNSIGNED',
+ 'UINT' => 'mediumint(8) UNSIGNED',
+ 'UINT:' => 'int(%d) UNSIGNED',
+ 'TINT:' => 'tinyint(%d)',
+ 'USINT' => 'smallint(4) UNSIGNED',
+ 'BOOL' => 'tinyint(1) UNSIGNED',
+ 'VCHAR' => 'varbinary(255)',
+ 'VCHAR:' => 'varbinary(%d)',
+ 'CHAR:' => 'binary(%d)',
+ 'XSTEXT' => 'blob',
+ 'XSTEXT_UNI'=> 'blob',
+ 'STEXT' => 'blob',
+ 'STEXT_UNI' => 'blob',
+ 'TEXT' => 'blob',
+ 'TEXT_UNI' => 'blob',
+ 'MTEXT' => 'mediumblob',
+ 'MTEXT_UNI' => 'mediumblob',
+ 'TIMESTAMP' => 'int(11) UNSIGNED',
+ 'DECIMAL' => 'decimal(5,2)',
+ 'DECIMAL:' => 'decimal(%d,2)',
+ 'PDECIMAL' => 'decimal(6,3)',
+ 'PDECIMAL:' => 'decimal(%d,3)',
+ 'VCHAR_UNI' => 'blob',
+ 'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')),
+ 'VCHAR_CI' => 'blob',
+ 'VARBINARY' => 'varbinary(255)',
+ ),
+
+ 'oracle' => array(
+ 'INT:' => 'number(%d)',
+ 'BINT' => 'number(20)',
+ 'ULINT' => 'number(10)',
+ 'UINT' => 'number(8)',
+ 'UINT:' => 'number(%d)',
+ 'TINT:' => 'number(%d)',
+ 'USINT' => 'number(4)',
+ 'BOOL' => 'number(1)',
+ 'VCHAR' => 'varchar2(255)',
+ 'VCHAR:' => 'varchar2(%d)',
+ 'CHAR:' => 'char(%d)',
+ 'XSTEXT' => 'varchar2(1000)',
+ 'STEXT' => 'varchar2(3000)',
+ 'TEXT' => 'clob',
+ 'MTEXT' => 'clob',
+ 'XSTEXT_UNI'=> 'varchar2(300)',
+ 'STEXT_UNI' => 'varchar2(765)',
+ 'TEXT_UNI' => 'clob',
+ 'MTEXT_UNI' => 'clob',
+ 'TIMESTAMP' => 'number(11)',
+ 'DECIMAL' => 'number(5, 2)',
+ 'DECIMAL:' => 'number(%d, 2)',
+ 'PDECIMAL' => 'number(6, 3)',
+ 'PDECIMAL:' => 'number(%d, 3)',
+ 'VCHAR_UNI' => 'varchar2(765)',
+ 'VCHAR_UNI:'=> array('varchar2(%d)', 'limit' => array('mult', 3, 765, 'clob')),
+ 'VCHAR_CI' => 'varchar2(255)',
+ 'VARBINARY' => 'raw(255)',
+ ),
+
+ 'sqlite3' => array(
+ 'INT:' => 'INT(%d)',
+ 'BINT' => 'BIGINT(20)',
+ 'ULINT' => 'INTEGER UNSIGNED',
+ 'UINT' => 'INTEGER UNSIGNED',
+ 'UINT:' => 'INTEGER UNSIGNED',
+ 'TINT:' => 'TINYINT(%d)',
+ 'USINT' => 'INTEGER UNSIGNED',
+ 'BOOL' => 'INTEGER UNSIGNED',
+ 'VCHAR' => 'VARCHAR(255)',
+ 'VCHAR:' => 'VARCHAR(%d)',
+ 'CHAR:' => 'CHAR(%d)',
+ 'XSTEXT' => 'TEXT(65535)',
+ 'STEXT' => 'TEXT(65535)',
+ 'TEXT' => 'TEXT(65535)',
+ 'MTEXT' => 'MEDIUMTEXT(16777215)',
+ 'XSTEXT_UNI'=> 'TEXT(65535)',
+ 'STEXT_UNI' => 'TEXT(65535)',
+ 'TEXT_UNI' => 'TEXT(65535)',
+ 'MTEXT_UNI' => 'MEDIUMTEXT(16777215)',
+ 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED',
+ 'DECIMAL' => 'DECIMAL(5,2)',
+ 'DECIMAL:' => 'DECIMAL(%d,2)',
+ 'PDECIMAL' => 'DECIMAL(6,3)',
+ 'PDECIMAL:' => 'DECIMAL(%d,3)',
+ 'VCHAR_UNI' => 'VARCHAR(255)',
+ 'VCHAR_UNI:'=> 'VARCHAR(%d)',
+ 'VCHAR_CI' => 'VARCHAR(255)',
+ 'VARBINARY' => 'BLOB',
+ ),
+ );
+ }
+
+ /**
+ * A list of types being unsigned for better reference in some db's
+ * @var array
+ */
+ var $unsigned_types = array('ULINT', 'UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP');
+
+ /**
+ * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array).
+ * This mode has no effect on some methods (inserting of data for example). This is expressed within the methods command.
+ */
+ var $return_statements = false;
+
+ /**
+ * Constructor. Set DB Object and set {@link $return_statements return_statements}.
+ *
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param bool $return_statements True if only statements should be returned and no SQL being executed
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, $return_statements = false)
+ {
+ $this->db = $db;
+ $this->return_statements = $return_statements;
+
+ $this->dbms_type_map = self::get_dbms_type_map();
+
+ // Determine mapping database type
+ switch ($this->db->get_sql_layer())
+ {
+ case 'mysql':
+ $this->sql_layer = 'mysql_40';
+ break;
+
+ case 'mysql4':
+ if (version_compare($this->db->sql_server_info(true), '4.1.3', '>='))
+ {
+ $this->sql_layer = 'mysql_41';
+ }
+ else
+ {
+ $this->sql_layer = 'mysql_40';
+ }
+ break;
+
+ case 'mysqli':
+ $this->sql_layer = 'mysql_41';
+ break;
+
+ default:
+ $this->sql_layer = $this->db->get_sql_layer();
+ break;
+ }
+ }
+
+ /**
+ * Setter for {@link $return_statements return_statements}.
+ *
+ * @param bool $return_statements True if SQL should not be executed but returned as strings
+ * @return null
+ */
+ public function set_return_statements($return_statements)
+ {
+ $this->return_statements = $return_statements;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_tables()
+ {
+ switch ($this->db->get_sql_layer())
+ {
+ case 'mysql':
+ case 'mysql4':
+ case 'mysqli':
+ $sql = 'SHOW TABLES';
+ break;
+
+ case 'sqlite3':
+ $sql = 'SELECT name
+ FROM sqlite_master
+ WHERE type = "table"
+ AND name <> "sqlite_sequence"';
+ break;
+
+ case 'oracle':
+ $sql = 'SELECT table_name
+ FROM USER_TABLES';
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+
+ $tables = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $name = current($row);
+ $tables[$name] = $name;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $tables;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_table_exists($table_name)
+ {
+ $this->db->sql_return_on_error(true);
+ $result = $this->db->sql_query_limit('SELECT * FROM ' . $table_name, 1);
+ $this->db->sql_return_on_error(false);
+
+ if ($result)
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_table($table_name, $table_data)
+ {
+ // holds the DDL for a column
+ $columns = $statements = array();
+
+ if ($this->sql_table_exists($table_name))
+ {
+ return $this->_sql_run_sql($statements);
+ }
+
+ // Begin transaction
+ $statements[] = 'begin';
+
+ // Determine if we have created a PRIMARY KEY in the earliest
+ $primary_key_gen = false;
+
+ // Determine if the table requires a sequence
+ $create_sequence = false;
+
+ // Begin table sql statement
+ $table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n";
+
+ // Iterate through the columns to create a table
+ foreach ($table_data['COLUMNS'] as $column_name => $column_data)
+ {
+ // here lies an array, filled with information compiled on the column's data
+ $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+
+ if (isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'] && strlen($column_name) > 26) // "${column_name}_gen"
+ {
+ trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
+ }
+
+ // here we add the definition of the new column to the list of columns
+ $columns[] = "\t {$column_name} " . $prepared_column['column_type_sql'];
+
+ // see if we have found a primary key set due to a column definition if we have found it, we can stop looking
+ if (!$primary_key_gen)
+ {
+ $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
+ }
+
+ // create sequence DDL based off of the existance of auto incrementing columns
+ if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
+ {
+ $create_sequence = $column_name;
+ }
+ }
+
+ // this makes up all the columns in the create table statement
+ $table_sql .= implode(",\n", $columns);
+
+ // we have yet to create a primary key for this table,
+ // this means that we can add the one we really wanted instead
+ if (!$primary_key_gen)
+ {
+ // Write primary key
+ if (isset($table_data['PRIMARY_KEY']))
+ {
+ if (!is_array($table_data['PRIMARY_KEY']))
+ {
+ $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
+ }
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ case 'sqlite3':
+ $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
+ break;
+
+ case 'oracle':
+ $table_sql .= ",\n\t CONSTRAINT pk_{$table_name} PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
+ break;
+ }
+ }
+ }
+
+ // close the table
+ switch ($this->sql_layer)
+ {
+ case 'mysql_41':
+ // make sure the table is in UTF-8 mode
+ $table_sql .= "\n) CHARACTER SET `utf8` COLLATE `utf8_bin`;";
+ $statements[] = $table_sql;
+ break;
+
+ case 'mysql_40':
+ case 'sqlite3':
+ $table_sql .= "\n);";
+ $statements[] = $table_sql;
+ break;
+
+ case 'oracle':
+ $table_sql .= "\n)";
+ $statements[] = $table_sql;
+
+ // do we need to add a sequence and a tigger for auto incrementing columns?
+ if ($create_sequence)
+ {
+ // create the actual sequence
+ $statements[] = "CREATE SEQUENCE {$table_name}_seq";
+
+ // the trigger is the mechanism by which we increment the counter
+ $trigger = "CREATE OR REPLACE TRIGGER t_{$table_name}\n";
+ $trigger .= "BEFORE INSERT ON {$table_name}\n";
+ $trigger .= "FOR EACH ROW WHEN (\n";
+ $trigger .= "\tnew.{$create_sequence} IS NULL OR new.{$create_sequence} = 0\n";
+ $trigger .= ")\n";
+ $trigger .= "BEGIN\n";
+ $trigger .= "\tSELECT {$table_name}_seq.nextval\n";
+ $trigger .= "\tINTO :new.{$create_sequence}\n";
+ $trigger .= "\tFROM dual;\n";
+ $trigger .= "END;";
+
+ $statements[] = $trigger;
+ }
+ break;
+ }
+
+ // Write Keys
+ if (isset($table_data['KEYS']))
+ {
+ foreach ($table_data['KEYS'] as $key_name => $key_data)
+ {
+ if (!is_array($key_data[1]))
+ {
+ $key_data[1] = array($key_data[1]);
+ }
+
+ $old_return_statements = $this->return_statements;
+ $this->return_statements = true;
+
+ $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
+
+ foreach ($key_stmts as $key_stmt)
+ {
+ $statements[] = $key_stmt;
+ }
+
+ $this->return_statements = $old_return_statements;
+ }
+ }
+
+ // Commit Transaction
+ $statements[] = 'commit';
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function perform_schema_changes($schema_changes)
+ {
+ if (empty($schema_changes))
+ {
+ return;
+ }
+
+ $statements = array();
+ $sqlite = false;
+
+ // For SQLite we need to perform the schema changes in a much more different way
+ if ($this->db->get_sql_layer() == 'sqlite3' && $this->return_statements)
+ {
+ $sqlite_data = array();
+ $sqlite = true;
+ }
+
+ // Drop tables?
+ if (!empty($schema_changes['drop_tables']))
+ {
+ foreach ($schema_changes['drop_tables'] as $table)
+ {
+ // only drop table if it exists
+ if ($this->sql_table_exists($table))
+ {
+ $result = $this->sql_table_drop($table);
+ if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+ }
+
+ // Add tables?
+ if (!empty($schema_changes['add_tables']))
+ {
+ foreach ($schema_changes['add_tables'] as $table => $table_data)
+ {
+ $result = $this->sql_create_table($table, $table_data);
+ if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+
+ // Change columns?
+ if (!empty($schema_changes['change_columns']))
+ {
+ foreach ($schema_changes['change_columns'] as $table => $columns)
+ {
+ foreach ($columns as $column_name => $column_data)
+ {
+ // If the column exists we change it, else we add it ;)
+ if ($column_exists = $this->sql_column_exists($table, $column_name))
+ {
+ $result = $this->sql_column_change($table, $column_name, $column_data, true);
+ }
+ else
+ {
+ $result = $this->sql_column_add($table, $column_name, $column_data, true);
+ }
+
+ if ($sqlite)
+ {
+ if ($column_exists)
+ {
+ $sqlite_data[$table]['change_columns'][] = $result;
+ }
+ else
+ {
+ $sqlite_data[$table]['add_columns'][] = $result;
+ }
+ }
+ else if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+ }
+
+ // Add columns?
+ if (!empty($schema_changes['add_columns']))
+ {
+ foreach ($schema_changes['add_columns'] as $table => $columns)
+ {
+ foreach ($columns as $column_name => $column_data)
+ {
+ // Only add the column if it does not exist yet
+ if ($column_exists = $this->sql_column_exists($table, $column_name))
+ {
+ continue;
+ // This is commented out here because it can take tremendous time on updates
+// $result = $this->sql_column_change($table, $column_name, $column_data, true);
+ }
+ else
+ {
+ $result = $this->sql_column_add($table, $column_name, $column_data, true);
+ }
+
+ if ($sqlite)
+ {
+ if ($column_exists)
+ {
+ continue;
+// $sqlite_data[$table]['change_columns'][] = $result;
+ }
+ else
+ {
+ $sqlite_data[$table]['add_columns'][] = $result;
+ }
+ }
+ else if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+ }
+
+ // Remove keys?
+ if (!empty($schema_changes['drop_keys']))
+ {
+ foreach ($schema_changes['drop_keys'] as $table => $indexes)
+ {
+ foreach ($indexes as $index_name)
+ {
+ if (!$this->sql_index_exists($table, $index_name) && !$this->sql_unique_index_exists($table, $index_name))
+ {
+ continue;
+ }
+
+ $result = $this->sql_index_drop($table, $index_name);
+
+ if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+ }
+
+ // Drop columns?
+ if (!empty($schema_changes['drop_columns']))
+ {
+ foreach ($schema_changes['drop_columns'] as $table => $columns)
+ {
+ foreach ($columns as $column)
+ {
+ // Only remove the column if it exists...
+ if ($this->sql_column_exists($table, $column))
+ {
+ $result = $this->sql_column_remove($table, $column, true);
+
+ if ($sqlite)
+ {
+ $sqlite_data[$table]['drop_columns'][] = $result;
+ }
+ else if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+ }
+ }
+
+ // Add primary keys?
+ if (!empty($schema_changes['add_primary_keys']))
+ {
+ foreach ($schema_changes['add_primary_keys'] as $table => $columns)
+ {
+ $result = $this->sql_create_primary_key($table, $columns, true);
+
+ if ($sqlite)
+ {
+ $sqlite_data[$table]['primary_key'] = $result;
+ }
+ else if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+
+ // Add unique indexes?
+ if (!empty($schema_changes['add_unique_index']))
+ {
+ foreach ($schema_changes['add_unique_index'] as $table => $index_array)
+ {
+ foreach ($index_array as $index_name => $column)
+ {
+ if ($this->sql_unique_index_exists($table, $index_name))
+ {
+ continue;
+ }
+
+ $result = $this->sql_create_unique_index($table, $index_name, $column);
+
+ if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+ }
+
+ // Add indexes?
+ if (!empty($schema_changes['add_index']))
+ {
+ foreach ($schema_changes['add_index'] as $table => $index_array)
+ {
+ foreach ($index_array as $index_name => $column)
+ {
+ if ($this->sql_index_exists($table, $index_name))
+ {
+ continue;
+ }
+
+ $result = $this->sql_create_index($table, $index_name, $column);
+
+ if ($this->return_statements)
+ {
+ $statements = array_merge($statements, $result);
+ }
+ }
+ }
+ }
+
+ if ($sqlite)
+ {
+ foreach ($sqlite_data as $table_name => $sql_schema_changes)
+ {
+ // Create temporary table with original data
+ $statements[] = 'begin';
+
+ $sql = "SELECT sql
+ FROM sqlite_master
+ WHERE type = 'table'
+ AND name = '{$table_name}'
+ ORDER BY type DESC, name;";
+ $result = $this->db->sql_query($sql);
+
+ if (!$result)
+ {
+ continue;
+ }
+
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ // Create a backup table and populate it, destroy the existing one
+ $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']);
+ $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ // Get the columns...
+ preg_match('#\((.*)\)#s', $row['sql'], $matches);
+
+ $plain_table_cols = trim($matches[1]);
+ $new_table_cols = preg_split('/,(?![\s\w]+\))/m', $plain_table_cols);
+ $column_list = array();
+
+ foreach ($new_table_cols as $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if ($entities[0] == 'PRIMARY')
+ {
+ continue;
+ }
+ $column_list[] = $entities[0];
+ }
+
+ // note down the primary key notation because sqlite only supports adding it to the end for the new table
+ $primary_key = false;
+ $_new_cols = array();
+
+ foreach ($new_table_cols as $key => $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if ($entities[0] == 'PRIMARY')
+ {
+ $primary_key = $declaration;
+ continue;
+ }
+ $_new_cols[] = $declaration;
+ }
+
+ $new_table_cols = $_new_cols;
+
+ // First of all... change columns
+ if (!empty($sql_schema_changes['change_columns']))
+ {
+ foreach ($sql_schema_changes['change_columns'] as $column_sql)
+ {
+ foreach ($new_table_cols as $key => $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if (strpos($column_sql, $entities[0] . ' ') === 0)
+ {
+ $new_table_cols[$key] = $column_sql;
+ }
+ }
+ }
+ }
+
+ if (!empty($sql_schema_changes['add_columns']))
+ {
+ foreach ($sql_schema_changes['add_columns'] as $column_sql)
+ {
+ $new_table_cols[] = $column_sql;
+ }
+ }
+
+ // Now drop them...
+ if (!empty($sql_schema_changes['drop_columns']))
+ {
+ foreach ($sql_schema_changes['drop_columns'] as $column_name)
+ {
+ // Remove from column list...
+ $new_column_list = array();
+ foreach ($column_list as $key => $value)
+ {
+ if ($value === $column_name)
+ {
+ continue;
+ }
+
+ $new_column_list[] = $value;
+ }
+
+ $column_list = $new_column_list;
+
+ // Remove from table...
+ $_new_cols = array();
+ foreach ($new_table_cols as $key => $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if (strpos($column_name . ' ', $entities[0] . ' ') === 0)
+ {
+ continue;
+ }
+ $_new_cols[] = $declaration;
+ }
+ $new_table_cols = $_new_cols;
+ }
+ }
+
+ // Primary key...
+ if (!empty($sql_schema_changes['primary_key']))
+ {
+ $new_table_cols[] = 'PRIMARY KEY (' . implode(', ', $sql_schema_changes['primary_key']) . ')';
+ }
+ // Add a new one or the old primary key
+ else if ($primary_key !== false)
+ {
+ $new_table_cols[] = $primary_key;
+ }
+
+ $columns = implode(',', $column_list);
+
+ // create a new table and fill it up. destroy the temp one
+ $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $new_table_cols) . ');';
+ $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
+ $statements[] = 'DROP TABLE ' . $table_name . '_temp';
+
+ $statements[] = 'commit';
+ }
+ }
+
+ if ($this->return_statements)
+ {
+ return $statements;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_columns($table_name)
+ {
+ $columns = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $sql = "SHOW COLUMNS FROM $table_name";
+ break;
+
+ case 'oracle':
+ $sql = "SELECT column_name
+ FROM user_tab_columns
+ WHERE LOWER(table_name) = '" . strtolower($table_name) . "'";
+ break;
+
+ case 'sqlite3':
+ $sql = "SELECT sql
+ FROM sqlite_master
+ WHERE type = 'table'
+ AND name = '{$table_name}'";
+
+ $result = $this->db->sql_query($sql);
+
+ if (!$result)
+ {
+ return false;
+ }
+
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ preg_match('#\((.*)\)#s', $row['sql'], $matches);
+
+ $cols = trim($matches[1]);
+ $col_array = preg_split('/,(?![\s\w]+\))/m', $cols);
+
+ foreach ($col_array as $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if ($entities[0] == 'PRIMARY')
+ {
+ continue;
+ }
+
+ $column = strtolower($entities[0]);
+ $columns[$column] = $column;
+ }
+
+ return $columns;
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $column = strtolower(current($row));
+ $columns[$column] = $column;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $columns;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_exists($table_name, $column_name)
+ {
+ $columns = $this->sql_list_columns($table_name);
+
+ return isset($columns[$column_name]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_index_exists($table_name, $index_name)
+ {
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $sql = 'SHOW KEYS
+ FROM ' . $table_name;
+ $col = 'Key_name';
+ break;
+
+ case 'oracle':
+ $sql = "SELECT index_name
+ FROM user_indexes
+ WHERE table_name = '" . strtoupper($table_name) . "'
+ AND generated = 'N'
+ AND uniqueness = 'NONUNIQUE'";
+ $col = 'index_name';
+ break;
+
+ case 'sqlite3':
+ $sql = "PRAGMA index_list('" . $table_name . "');";
+ $col = 'name';
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
+ {
+ continue;
+ }
+
+ switch ($this->sql_layer)
+ {
+ // These DBMS prefix index name with the table name
+ case 'oracle':
+ case 'sqlite3':
+ $new_index_name = $this->check_index_name_length($table_name, $table_name . '_' . $index_name, false);
+ break;
+ default:
+ $new_index_name = $this->check_index_name_length($table_name, $index_name, false);
+ break;
+ }
+
+ if (strtolower($row[$col]) == strtolower($new_index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_unique_index_exists($table_name, $index_name)
+ {
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $sql = 'SHOW KEYS
+ FROM ' . $table_name;
+ $col = 'Key_name';
+ break;
+
+ case 'oracle':
+ $sql = "SELECT index_name, table_owner
+ FROM user_indexes
+ WHERE table_name = '" . strtoupper($table_name) . "'
+ AND generated = 'N'
+ AND uniqueness = 'UNIQUE'";
+ $col = 'index_name';
+ break;
+
+ case 'sqlite3':
+ $sql = "PRAGMA index_list('" . $table_name . "');";
+ $col = 'name';
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY'))
+ {
+ continue;
+ }
+
+ if ($this->sql_layer == 'sqlite3' && !$row['unique'])
+ {
+ continue;
+ }
+
+ // These DBMS prefix index name with the table name
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name
+ if (strpos($row[$col], 'U_') === 0)
+ {
+ $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1);
+ }
+ else if (strpos($row[$col], strtoupper($table_name)) === 0)
+ {
+ $row[$col] = substr($row[$col], strlen($table_name) + 1);
+ }
+ break;
+
+ case 'sqlite3':
+ $row[$col] = substr($row[$col], strlen($table_name) + 1);
+ break;
+ }
+
+ if (strtolower($row[$col]) == strtolower($index_name))
+ {
+ $this->db->sql_freeresult($result);
+ return true;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return false;
+ }
+
+ /**
+ * Private method for performing sql statements (either execute them or return them)
+ * @access private
+ */
+ function _sql_run_sql($statements)
+ {
+ if ($this->return_statements)
+ {
+ return $statements;
+ }
+
+ // We could add error handling here...
+ foreach ($statements as $sql)
+ {
+ if ($sql === 'begin')
+ {
+ $this->db->sql_transaction('begin');
+ }
+ else if ($sql === 'commit')
+ {
+ $this->db->sql_transaction('commit');
+ }
+ else
+ {
+ $this->db->sql_query($sql);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Function to prepare some column information for better usage
+ * @access private
+ */
+ function sql_prepare_column_data($table_name, $column_name, $column_data)
+ {
+ if (strlen($column_name) > 30)
+ {
+ trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
+ }
+
+ // Get type
+ list($column_type) = $this->get_column_type($column_data[0]);
+
+ // Adjust default value if db-dependent specified
+ if (is_array($column_data[1]))
+ {
+ $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
+ }
+
+ $sql = '';
+
+ $return_array = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $sql .= " {$column_type} ";
+
+ // For hexadecimal values do not use single quotes
+ if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob')
+ {
+ $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' ";
+ }
+
+ if (!is_null($column_data[1]) || (isset($column_data[2]) && $column_data[2] == 'auto_increment'))
+ {
+ $sql .= 'NOT NULL';
+ }
+ else
+ {
+ $sql .= 'NULL';
+ }
+
+ if (isset($column_data[2]))
+ {
+ if ($column_data[2] == 'auto_increment')
+ {
+ $sql .= ' auto_increment';
+ }
+ else if ($this->sql_layer === 'mysql_41' && $column_data[2] == 'true_sort')
+ {
+ $sql .= ' COLLATE utf8_unicode_ci';
+ }
+ }
+
+ if (isset($column_data['after']))
+ {
+ $return_array['after'] = $column_data['after'];
+ }
+
+ break;
+
+ case 'oracle':
+ $sql .= " {$column_type} ";
+ $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}' " : '';
+
+ // In Oracle empty strings ('') are treated as NULL.
+ // Therefore in oracle we allow NULL's for all DEFAULT '' entries
+ // Oracle does not like setting NOT NULL on a column that is already NOT NULL (this happens only on number fields)
+ if (!preg_match('/number/i', $column_type))
+ {
+ $sql .= ($column_data[1] === '' || $column_data[1] === null) ? '' : 'NOT NULL';
+ }
+
+ $return_array['auto_increment'] = false;
+ if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
+ {
+ $return_array['auto_increment'] = true;
+ }
+
+ break;
+
+ case 'sqlite3':
+ $return_array['primary_key_set'] = false;
+ if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
+ {
+ $sql .= ' INTEGER PRIMARY KEY AUTOINCREMENT';
+ $return_array['primary_key_set'] = true;
+ }
+ else
+ {
+ $sql .= ' ' . $column_type;
+ }
+
+ if (!is_null($column_data[1]))
+ {
+ $sql .= ' NOT NULL ';
+ $sql .= "DEFAULT '{$column_data[1]}'";
+ }
+
+ break;
+ }
+
+ $return_array['column_type_sql'] = $sql;
+
+ return $return_array;
+ }
+
+ /**
+ * Get the column's database type from the type map
+ *
+ * @param string $column_map_type
+ * @return array column type for this database
+ * and map type without length
+ */
+ function get_column_type($column_map_type)
+ {
+ $column_type = '';
+ if (strpos($column_map_type, ':') !== false)
+ {
+ list($orig_column_type, $column_length) = explode(':', $column_map_type);
+ if (!is_array($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']))
+ {
+ $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'], $column_length);
+ }
+ else
+ {
+ if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule']))
+ {
+ switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][0])
+ {
+ case 'div':
+ $column_length /= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][1];
+ $column_length = ceil($column_length);
+ $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
+ break;
+ }
+ }
+
+ if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit']))
+ {
+ switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][0])
+ {
+ case 'mult':
+ $column_length *= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][1];
+ if ($column_length > $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][2])
+ {
+ $column_type = $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][3];
+ }
+ else
+ {
+ $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
+ }
+ break;
+ }
+ }
+ }
+ $orig_column_type .= ':';
+ }
+ else
+ {
+ $orig_column_type = $column_map_type;
+ $column_type = $this->dbms_type_map[$this->sql_layer][$column_map_type];
+ }
+
+ return array($column_type, $orig_column_type);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_add($table_name, $column_name, $column_data, $inline = false)
+ {
+ $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+ $statements = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : '';
+ $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after;
+ break;
+
+ case 'oracle':
+ // Does not support AFTER, only through temporary table
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
+ break;
+
+ case 'sqlite3':
+ if ($inline && $this->return_statements)
+ {
+ return $column_name . ' ' . $column_data['column_type_sql'];
+ }
+
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql'];
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_remove($table_name, $column_name, $inline = false)
+ {
+ $statements = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`';
+ break;
+
+ case 'oracle':
+ $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name;
+ break;
+
+ case 'sqlite3':
+
+ if ($inline && $this->return_statements)
+ {
+ return $column_name;
+ }
+
+ $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name, $column_name);
+ if (empty($recreate_queries))
+ {
+ break;
+ }
+
+ $statements[] = 'begin';
+
+ $sql_create_table = array_shift($recreate_queries);
+
+ // Create a backup table and populate it, destroy the existing one
+ $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table);
+ $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ preg_match('#\((.*)\)#s', $sql_create_table, $matches);
+
+ $new_table_cols = trim($matches[1]);
+ $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
+ $column_list = array();
+
+ foreach ($old_table_cols as $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name)
+ {
+ continue;
+ }
+ $column_list[] = $entities[0];
+ }
+
+ $columns = implode(',', $column_list);
+
+ $new_table_cols = trim(preg_replace('/' . $column_name . '\b[^,]+(?:,|$)/m', '', $new_table_cols));
+ if (substr($new_table_cols, -1) === ',')
+ {
+ // Remove the comma from the last entry again
+ $new_table_cols = substr($new_table_cols, 0, -1);
+ }
+
+ // create a new table and fill it up. destroy the temp one
+ $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');';
+ $statements = array_merge($statements, $recreate_queries);
+
+ $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
+ $statements[] = 'DROP TABLE ' . $table_name . '_temp';
+
+ $statements[] = 'commit';
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_index_drop($table_name, $index_name)
+ {
+ $statements = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $index_name = $this->check_index_name_length($table_name, $index_name, false);
+ $statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name;
+ break;
+
+ case 'oracle':
+ case 'sqlite3':
+ $index_name = $this->check_index_name_length($table_name, $table_name . '_' . $index_name, false);
+ $statements[] = 'DROP INDEX ' . $index_name;
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_table_drop($table_name)
+ {
+ $statements = array();
+
+ if (!$this->sql_table_exists($table_name))
+ {
+ return $this->_sql_run_sql($statements);
+ }
+
+ // the most basic operation, get rid of the table
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ $sql = 'SELECT A.REFERENCED_NAME
+ FROM USER_DEPENDENCIES A, USER_TRIGGERS B
+ WHERE A.REFERENCED_TYPE = \'SEQUENCE\'
+ AND A.NAME = B.TRIGGER_NAME
+ AND B.TABLE_NAME = \'' . strtoupper($table_name) . "'";
+ $result = $this->db->sql_query($sql);
+
+ // any sequences ref'd to this table's triggers?
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $statements[] = "DROP SEQUENCE {$row['referenced_name']}";
+ }
+ $this->db->sql_freeresult($result);
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_primary_key($table_name, $column, $inline = false)
+ {
+ $statements = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
+ break;
+
+ case 'oracle':
+ $statements[] = 'ALTER TABLE ' . $table_name . ' add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')';
+ break;
+
+ case 'sqlite3':
+
+ if ($inline && $this->return_statements)
+ {
+ return $column;
+ }
+
+ $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name);
+ if (empty($recreate_queries))
+ {
+ break;
+ }
+
+ $statements[] = 'begin';
+
+ $sql_create_table = array_shift($recreate_queries);
+
+ // Create a backup table and populate it, destroy the existing one
+ $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table);
+ $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ preg_match('#\((.*)\)#s', $sql_create_table, $matches);
+
+ $new_table_cols = trim($matches[1]);
+ $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
+ $column_list = array();
+
+ foreach ($old_table_cols as $declaration)
+ {
+ $entities = preg_split('#\s+#', trim($declaration));
+ if ($entities[0] == 'PRIMARY')
+ {
+ continue;
+ }
+ $column_list[] = $entities[0];
+ }
+
+ $columns = implode(',', $column_list);
+
+ // create a new table and fill it up. destroy the temp one
+ $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));';
+ $statements = array_merge($statements, $recreate_queries);
+
+ $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
+ $statements[] = 'DROP TABLE ' . $table_name . '_temp';
+
+ $statements[] = 'commit';
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_unique_index($table_name, $index_name, $column)
+ {
+ $statements = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ case 'sqlite3':
+ $index_name = $this->check_index_name_length($table_name, $table_name . '_' . $index_name);
+ $statements[] = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
+ break;
+
+ case 'mysql_40':
+ case 'mysql_41':
+ $index_name = $this->check_index_name_length($table_name, $index_name);
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')';
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_create_index($table_name, $index_name, $column)
+ {
+ $statements = array();
+
+ // remove index length unless MySQL4
+ if ('mysql_40' != $this->sql_layer)
+ {
+ $column = preg_replace('#:.*$#', '', $column);
+ }
+
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ case 'sqlite3':
+ $index_name = $this->check_index_name_length($table_name, $table_name . '_' . $index_name);
+ $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
+ break;
+
+ case 'mysql_40':
+ // add index size to definition as required by MySQL4
+ foreach ($column as $i => $col)
+ {
+ if (false !== strpos($col, ':'))
+ {
+ list($col, $index_size) = explode(':', $col);
+ $column[$i] = "$col($index_size)";
+ }
+ }
+ // no break
+ case 'mysql_41':
+ $index_name = $this->check_index_name_length($table_name, $index_name);
+ $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . ' (' . implode(', ', $column) . ')';
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * Check whether the index name is too long
+ *
+ * @param string $table_name
+ * @param string $index_name
+ * @param bool $throw_error
+ * @return string The index name, shortened if too long
+ */
+ protected function check_index_name_length($table_name, $index_name, $throw_error = true)
+ {
+ $max_index_name_length = $this->get_max_index_name_length();
+ if (strlen($index_name) > $max_index_name_length)
+ {
+ // Try removing the table prefix if it's at the beginning
+ $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
+ if (strpos($index_name, $table_prefix) === 0)
+ {
+ $index_name = substr($index_name, strlen($table_prefix));
+ return $this->check_index_name_length($table_name, $index_name, $throw_error);
+ }
+
+ // Try removing the remaining suffix part of table name then
+ $table_suffix = substr($table_name, strlen($table_prefix));
+ if (strpos($index_name, $table_suffix) === 0)
+ {
+ // Remove the suffix and underscore separator between table_name and index_name
+ $index_name = substr($index_name, strlen($table_suffix) + 1);
+ return $this->check_index_name_length($table_name, $index_name, $throw_error);
+ }
+
+ if ($throw_error)
+ {
+ trigger_error("Index name '$index_name' on table '$table_name' is too long. The maximum is $max_index_name_length characters.", E_USER_ERROR);
+ }
+ }
+
+ return $index_name;
+ }
+
+ /**
+ * Get maximum index name length. Might vary depending on db type
+ *
+ * @return int Maximum index name length
+ */
+ protected function get_max_index_name_length()
+ {
+ return 30;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_list_index($table_name)
+ {
+ $index_array = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $sql = 'SHOW KEYS
+ FROM ' . $table_name;
+ $col = 'Key_name';
+ break;
+
+ case 'oracle':
+ $sql = "SELECT index_name
+ FROM user_indexes
+ WHERE table_name = '" . strtoupper($table_name) . "'
+ AND generated = 'N'
+ AND uniqueness = 'NONUNIQUE'";
+ $col = 'index_name';
+ break;
+
+ case 'sqlite3':
+ $sql = "PRAGMA index_info('" . $table_name . "');";
+ $col = 'name';
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
+ {
+ continue;
+ }
+
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ case 'sqlite3':
+ $row[$col] = substr($row[$col], strlen($table_name) + 1);
+ break;
+ }
+
+ $index_array[] = $row[$col];
+ }
+ $this->db->sql_freeresult($result);
+
+ return array_map('strtolower', $index_array);
+ }
+
+ /**
+ * Removes table_name from the index_name if it is at the beginning
+ *
+ * @param $table_name
+ * @param $index_name
+ * @return string
+ */
+ protected function strip_table_name_from_index_name($table_name, $index_name)
+ {
+ return (strpos(strtoupper($index_name), strtoupper($table_name)) === 0) ? substr($index_name, strlen($table_name) + 1) : $index_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_column_change($table_name, $column_name, $column_data, $inline = false)
+ {
+ $original_column_data = $column_data;
+ $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
+ $statements = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ $statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql'];
+ break;
+
+ case 'oracle':
+ // We need the data here
+ $old_return_statements = $this->return_statements;
+ $this->return_statements = true;
+
+ // Get list of existing indexes
+ $indexes = $this->get_existing_indexes($table_name, $column_name);
+ $unique_indexes = $this->get_existing_indexes($table_name, $column_name, true);
+
+ // Drop any indexes
+ if (!empty($indexes) || !empty($unique_indexes))
+ {
+ $drop_indexes = array_merge(array_keys($indexes), array_keys($unique_indexes));
+ foreach ($drop_indexes as $index_name)
+ {
+ $result = $this->sql_index_drop($table_name, $this->strip_table_name_from_index_name($table_name, $index_name));
+ $statements = array_merge($statements, $result);
+ }
+ }
+
+ $temp_column_name = 'temp_' . substr(md5($column_name), 0, 25);
+ // Add a temporary table with the new type
+ $result = $this->sql_column_add($table_name, $temp_column_name, $original_column_data);
+ $statements = array_merge($statements, $result);
+
+ // Copy the data to the new column
+ $statements[] = 'UPDATE ' . $table_name . ' SET ' . $temp_column_name . ' = ' . $column_name;
+
+ // Drop the original column
+ $result = $this->sql_column_remove($table_name, $column_name);
+ $statements = array_merge($statements, $result);
+
+ // Recreate the original column with the new type
+ $result = $this->sql_column_add($table_name, $column_name, $original_column_data);
+ $statements = array_merge($statements, $result);
+
+ if (!empty($indexes))
+ {
+ // Recreate indexes after we changed the column
+ foreach ($indexes as $index_name => $index_data)
+ {
+ $result = $this->sql_create_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data);
+ $statements = array_merge($statements, $result);
+ }
+ }
+
+ if (!empty($unique_indexes))
+ {
+ // Recreate unique indexes after we changed the column
+ foreach ($unique_indexes as $index_name => $index_data)
+ {
+ $result = $this->sql_create_unique_index($table_name, $this->strip_table_name_from_index_name($table_name, $index_name), $index_data);
+ $statements = array_merge($statements, $result);
+ }
+ }
+
+ // Copy the data to the original column
+ $statements[] = 'UPDATE ' . $table_name . ' SET ' . $column_name . ' = ' . $temp_column_name;
+
+ // Drop the temporary column again
+ $result = $this->sql_column_remove($table_name, $temp_column_name);
+ $statements = array_merge($statements, $result);
+
+ $this->return_statements = $old_return_statements;
+ break;
+
+ case 'sqlite3':
+
+ if ($inline && $this->return_statements)
+ {
+ return $column_name . ' ' . $column_data['column_type_sql'];
+ }
+
+ $recreate_queries = $this->sqlite_get_recreate_table_queries($table_name);
+ if (empty($recreate_queries))
+ {
+ break;
+ }
+
+ $statements[] = 'begin';
+
+ $sql_create_table = array_shift($recreate_queries);
+
+ // Create a temp table and populate it, destroy the existing one
+ $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $sql_create_table);
+ $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name;
+ $statements[] = 'DROP TABLE ' . $table_name;
+
+ preg_match('#\((.*)\)#s', $sql_create_table, $matches);
+
+ $new_table_cols = trim($matches[1]);
+ $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
+ $column_list = array();
+
+ foreach ($old_table_cols as $key => $declaration)
+ {
+ $declaration = trim($declaration);
+
+ // Check for the beginning of the constraint section and stop
+ if (preg_match('/[^\(]*\s*PRIMARY KEY\s+\(/', $declaration) ||
+ preg_match('/[^\(]*\s*UNIQUE\s+\(/', $declaration) ||
+ preg_match('/[^\(]*\s*FOREIGN KEY\s+\(/', $declaration) ||
+ preg_match('/[^\(]*\s*CHECK\s+\(/', $declaration))
+ {
+ break;
+ }
+
+ $entities = preg_split('#\s+#', $declaration);
+ $column_list[] = $entities[0];
+ if ($entities[0] == $column_name)
+ {
+ $old_table_cols[$key] = $column_name . ' ' . $column_data['column_type_sql'];
+ }
+ }
+
+ $columns = implode(',', $column_list);
+
+ // Create a new table and fill it up. destroy the temp one
+ $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');';
+ $statements = array_merge($statements, $recreate_queries);
+
+ $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
+ $statements[] = 'DROP TABLE ' . $table_name . '_temp';
+
+ $statements[] = 'commit';
+
+ break;
+ }
+
+ return $this->_sql_run_sql($statements);
+ }
+
+ /**
+ * Get a list with existing indexes for the column
+ *
+ * @param string $table_name
+ * @param string $column_name
+ * @param bool $unique Should we get unique indexes or normal ones
+ * @return array Array with Index name => columns
+ */
+ public function get_existing_indexes($table_name, $column_name, $unique = false)
+ {
+ switch ($this->sql_layer)
+ {
+ case 'mysql_40':
+ case 'mysql_41':
+ case 'sqlite3':
+ // Not supported
+ throw new \Exception('DBMS is not supported');
+ break;
+ }
+
+ $sql = '';
+ $existing_indexes = array();
+
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ $sql = "SELECT ix.index_name AS phpbb_index_name, ix.uniqueness AS is_unique
+ FROM all_ind_columns ixc, all_indexes ix
+ WHERE ix.index_name = ixc.index_name
+ AND ixc.table_name = '" . strtoupper($table_name) . "'
+ AND ixc.column_name = '" . strtoupper($column_name) . "'";
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (!isset($row['is_unique']) || ($unique && $row['is_unique'] == 'UNIQUE') || (!$unique && $row['is_unique'] == 'NONUNIQUE'))
+ {
+ $existing_indexes[$row['phpbb_index_name']] = array();
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if (empty($existing_indexes))
+ {
+ return array();
+ }
+
+ switch ($this->sql_layer)
+ {
+ case 'oracle':
+ $sql = "SELECT index_name AS phpbb_index_name, column_name AS phpbb_column_name
+ FROM all_ind_columns
+ WHERE table_name = '" . strtoupper($table_name) . "'
+ AND " . $this->db->sql_in_set('index_name', array_keys($existing_indexes));
+ break;
+ }
+
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $existing_indexes[$row['phpbb_index_name']][] = $row['phpbb_column_name'];
+ }
+ $this->db->sql_freeresult($result);
+
+ return $existing_indexes;
+ }
+
+ /**
+ * Returns the Queries which are required to recreate a table including indexes
+ *
+ * @param string $table_name
+ * @param string $remove_column When we drop a column, we remove the column
+ * from all indexes. If the index has no other
+ * column, we drop it completly.
+ * @return array
+ */
+ protected function sqlite_get_recreate_table_queries($table_name, $remove_column = '')
+ {
+ $queries = array();
+
+ $sql = "SELECT sql
+ FROM sqlite_master
+ WHERE type = 'table'
+ AND name = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+ $sql_create_table = $this->db->sql_fetchfield('sql');
+ $this->db->sql_freeresult($result);
+
+ if (!$sql_create_table)
+ {
+ return array();
+ }
+ $queries[] = $sql_create_table;
+
+ $sql = "SELECT sql
+ FROM sqlite_master
+ WHERE type = 'index'
+ AND tbl_name = '{$table_name}'";
+ $result = $this->db->sql_query($sql);
+ while ($sql_create_index = $this->db->sql_fetchfield('sql'))
+ {
+ if ($remove_column)
+ {
+ $match = array();
+ preg_match('#(?:[\w ]+)\((.*)\)#', $sql_create_index, $match);
+ if (!isset($match[1]))
+ {
+ continue;
+ }
+
+ // Find and remove $remove_column from the index
+ $columns = explode(', ', $match[1]);
+ $found_column = array_search($remove_column, $columns);
+ if ($found_column !== false)
+ {
+ unset($columns[$found_column]);
+
+ // If the column list is not empty add the index to the list
+ if (!empty($columns))
+ {
+ $queries[] = str_replace($match[1], implode(', ', $columns), $sql_create_index);
+ }
+ }
+ else
+ {
+ $queries[] = $sql_create_index;
+ }
+ }
+ else
+ {
+ $queries[] = $sql_create_index;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return $queries;
+ }
+}
diff --git a/phpBB/phpbb/db/tools/tools_interface.php b/phpBB/phpbb/db/tools/tools_interface.php
new file mode 100644
index 0000000000..f153f73a54
--- /dev/null
+++ b/phpBB/phpbb/db/tools/tools_interface.php
@@ -0,0 +1,202 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\db\tools;
+
+/**
+ * Interface for a Database Tools for handling cross-db actions such as altering columns, etc.
+ */
+interface tools_interface
+{
+ /**
+ * Handle passed database update array.
+ * Expected structure...
+ * Key being one of the following
+ * drop_tables: Drop tables
+ * add_tables: Add tables
+ * change_columns: Column changes (only type, not name)
+ * add_columns: Add columns to a table
+ * drop_keys: Dropping keys
+ * drop_columns: Removing/Dropping columns
+ * add_primary_keys: adding primary keys
+ * add_unique_index: adding an unique index
+ * add_index: adding an index (can be column:index_size if you need to provide size)
+ *
+ * The values are in this format:
+ * {TABLE NAME} => array(
+ * {COLUMN NAME} => array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}),
+ * {KEY/INDEX NAME} => array({COLUMN NAMES}),
+ * )
+ *
+ *
+ * @param array $schema_changes
+ * @return null
+ */
+ public function perform_schema_changes($schema_changes);
+
+ /**
+ * Gets a list of tables in the database.
+ *
+ * @return array Array of table names (all lower case)
+ */
+ public function sql_list_tables();
+
+ /**
+ * Check if table exists
+ *
+ * @param string $table_name The table name to check for
+ * @return bool true if table exists, else false
+ */
+ public function sql_table_exists($table_name);
+
+ /**
+ * Create SQL Table
+ *
+ * @param string $table_name The table name to create
+ * @param array $table_data Array containing table data.
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_create_table($table_name, $table_data);
+
+ /**
+ * Drop Table
+ *
+ * @param string $table_name The table name to drop
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_table_drop($table_name);
+
+ /**
+ * Gets a list of columns of a table.
+ *
+ * @param string $table_name Table name
+ * @return array Array of column names (all lower case)
+ */
+ public function sql_list_columns($table_name);
+
+ /**
+ * Check whether a specified column exist in a table
+ *
+ * @param string $table_name Table to check
+ * @param string $column_name Column to check
+ * @return bool True if column exists, false otherwise
+ */
+ public function sql_column_exists($table_name, $column_name);
+
+ /**
+ * Add new column
+ *
+ * @param string $table_name Table to modify
+ * @param string $column_name Name of the column to add
+ * @param array $column_data Column data
+ * @param bool $inline Whether the query should actually be run,
+ * or return a string for adding the column
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_column_add($table_name, $column_name, $column_data, $inline = false);
+
+ /**
+ * Change column type (not name!)
+ *
+ * @param string $table_name Table to modify
+ * @param string $column_name Name of the column to modify
+ * @param array $column_data Column data
+ * @param bool $inline Whether the query should actually be run,
+ * or return a string for modifying the column
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_column_change($table_name, $column_name, $column_data, $inline = false);
+
+ /**
+ * Drop column
+ *
+ * @param string $table_name Table to modify
+ * @param string $column_name Name of the column to drop
+ * @param bool $inline Whether the query should actually be run,
+ * or return a string for deleting the column
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_column_remove($table_name, $column_name, $inline = false);
+
+ /**
+ * List all of the indices that belong to a table
+ *
+ * NOTE: does not list
+ * - UNIQUE indices
+ * - PRIMARY keys
+ *
+ * @param string $table_name Table to check
+ * @return array Array with index names
+ */
+ public function sql_list_index($table_name);
+
+ /**
+ * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes.
+ *
+ * @param string $table_name Table to check the index at
+ * @param string $index_name The index name to check
+ * @return bool True if index exists, else false
+ */
+ public function sql_index_exists($table_name, $index_name);
+
+ /**
+ * Add index
+ *
+ * @param string $table_name Table to modify
+ * @param string $index_name Name of the index to create
+ * @param string|array $column Either a string with a column name, or an array with columns
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_create_index($table_name, $index_name, $column);
+
+ /**
+ * Drop Index
+ *
+ * @param string $table_name Table to modify
+ * @param string $index_name Name of the index to delete
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_index_drop($table_name, $index_name);
+
+ /**
+ * Check if a specified index exists in table.
+ *
+ * NOTE: Does not return normal and PRIMARY KEY indexes
+ *
+ * @param string $table_name Table to check the index at
+ * @param string $index_name The index name to check
+ * @return bool True if index exists, else false
+ */
+ public function sql_unique_index_exists($table_name, $index_name);
+
+ /**
+ * Add unique index
+ *
+ * @param string $table_name Table to modify
+ * @param string $index_name Name of the unique index to create
+ * @param string|array $column Either a string with a column name, or an array with columns
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_create_unique_index($table_name, $index_name, $column);
+
+ /**
+ * Add primary key
+ *
+ * @param string $table_name Table to modify
+ * @param string|array $column Either a string with a column name, or an array with columns
+ * @param bool $inline Whether the query should actually be run,
+ * or return a string for creating the key
+ * @return array|true Statements to run, or true if the statements have been executed
+ */
+ public function sql_create_primary_key($table_name, $column, $inline = false);
+}
diff --git a/phpBB/phpbb/debug/debug.php b/phpBB/phpbb/debug/debug.php
new file mode 100644
index 0000000000..c5ffada2e5
--- /dev/null
+++ b/phpBB/phpbb/debug/debug.php
@@ -0,0 +1,80 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\debug;
+
+use Symfony\Component\Debug\BufferingLogger;
+use Symfony\Component\Debug\DebugClassLoader;
+use Symfony\Component\Debug\ExceptionHandler;
+
+/**
+ * Registers all the debug tools.
+
+ * @see Symfony\Component\Debug\Debug
+ */
+class debug
+{
+ private static $enabled = false;
+
+ /**
+ * Enables the debug tools.
+ *
+ * This method registers an error handler and an exception handler.
+ *
+ * If the Symfony ClassLoader component is available, a special
+ * class loader is also registered.
+ *
+ * @param int $errorReportingLevel The level of error reporting you want
+ * @param bool $displayErrors Whether to display errors (for development) or just log them (for production)
+ */
+ public static function enable($errorReportingLevel = null, $displayErrors = true)
+ {
+ if (static::$enabled)
+ {
+ return;
+ }
+
+ static::$enabled = true;
+
+ if ($errorReportingLevel !== null)
+ {
+ error_reporting($errorReportingLevel);
+ }
+ else
+ {
+ error_reporting(-1);
+ }
+
+ if ('cli' !== php_sapi_name())
+ {
+ ini_set('display_errors', 0);
+ ExceptionHandler::register();
+ }
+ else if ($displayErrors && (!ini_get('log_errors') || ini_get('error_log')))
+ {
+ // CLI - display errors only if they're not already logged to STDERR
+ ini_set('display_errors', 1);
+ }
+
+ if ($displayErrors)
+ {
+ error_handler::register(new error_handler(new BufferingLogger()));
+ }
+ else
+ {
+ error_handler::register()->throwAt(0, true);
+ }
+
+ DebugClassLoader::enable();
+ }
+}
diff --git a/phpBB/phpbb/debug/error_handler.php b/phpBB/phpbb/debug/error_handler.php
new file mode 100644
index 0000000000..ebd828b97f
--- /dev/null
+++ b/phpBB/phpbb/debug/error_handler.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\debug;
+
+use Symfony\Component\Debug\ErrorHandler;
+
+class error_handler extends ErrorHandler
+{
+ public function handleError($type, $message, $file, $line)
+ {
+ if ($type === E_USER_WARNING || $type === E_USER_NOTICE)
+ {
+ $handler = defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler';
+
+ $handler($type, $message, $file, $line);
+ }
+
+ return parent::handleError($type, $message, $file, $line);
+ }
+}
diff --git a/phpBB/phpbb/di/container_builder.php b/phpBB/phpbb/di/container_builder.php
index 5f3aa685bf..8c1ce8bde2 100644
--- a/phpBB/phpbb/di/container_builder.php
+++ b/phpBB/phpbb/di/container_builder.php
@@ -13,406 +13,661 @@
namespace phpbb\di;
+use phpbb\filesystem\filesystem;
+use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
+use Symfony\Component\Config\ConfigCache;
+use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
-use Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
+use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
+use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
+use Symfony\Component\Filesystem\Exception\IOException;
+use Symfony\Component\Finder\Finder;
+use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
class container_builder
{
- /** @var string phpBB Root Path */
+ /**
+ * @var string The environment to use.
+ */
+ protected $environment;
+
+ /**
+ * @var string phpBB Root Path
+ */
protected $phpbb_root_path;
- /** @var string php file extension */
+ /**
+ * @var string php file extension
+ */
protected $php_ext;
/**
- * The container under construction
- *
- * @var ContainerBuilder
- */
+ * The container under construction
+ *
+ * @var ContainerBuilder
+ */
protected $container;
/**
- * @var \phpbb\db\driver\driver_interface
- */
+ * @var \phpbb\db\driver\driver_interface
+ */
protected $dbal_connection = null;
/**
- * @var array the installed extensions
- */
- protected $installed_exts = null;
-
- /**
- * Indicates whether the php config file should be injected into the container (default to true).
- *
- * @var bool
- */
- protected $inject_config = true;
-
- /**
- * Indicates whether extensions should be used (default to true).
- *
- * @var bool
- */
+ * Indicates whether extensions should be used (default to true).
+ *
+ * @var bool
+ */
protected $use_extensions = true;
/**
- * Defines a custom path to find the configuration of the container (default to $this->phpbb_root_path . 'config')
- *
- * @var string
- */
+ * Defines a custom path to find the configuration of the container (default to $this->phpbb_root_path . 'config')
+ *
+ * @var string
+ */
protected $config_path = null;
/**
- * Indicates whether the phpBB compile pass should be used (default to true).
- *
- * @var bool
- */
- protected $use_custom_pass = true;
+ * Indicates whether the container should be dumped to the filesystem (default to true).
+ *
+ * If DEBUG_CONTAINER is set this option is ignored and a new container is build.
+ *
+ * @var bool
+ */
+ protected $use_cache = true;
/**
- * Indicates whether the kernel compile pass should be used (default to true).
- *
- * @var bool
- */
- protected $use_kernel_pass = true;
+ * Indicates if the container should be compiled automatically (default to true).
+ *
+ * @var bool
+ */
+ protected $compile_container = true;
/**
- * Indicates whether the container should be dumped to the filesystem (default to true).
- *
- * If DEBUG_CONTAINER is set this option is ignored and a new container is build.
- *
- * @var bool
- */
- protected $dump_container = true;
+ * Custom parameters to inject into the container.
+ *
+ * Default to:
+ * array(
+ * 'core.root_path', $this->phpbb_root_path,
+ * 'core.php_ext', $this->php_ext,
+ * );
+ *
+ * @var array
+ */
+ protected $custom_parameters = [];
/**
- * Indicates if the container should be compiled automatically (default to true).
- *
- * @var bool
- */
- protected $compile_container = true;
+ * @var \phpbb\config_php_file
+ */
+ protected $config_php_file;
/**
- * Custom parameters to inject into the container.
- *
- * Default to true:
- * array(
- * 'core.root_path', $this->phpbb_root_path,
- * 'core.php_ext', $this->php_ext,
- * );
- *
- * @var array
- */
- protected $custom_parameters = null;
+ * @var string
+ */
+ protected $cache_dir;
/**
- * @var \phpbb\config_php_file
- */
- protected $config_php_file;
+ * @var array
+ */
+ private $container_extensions;
+
+ /** @var \Exception */
+ private $build_exception;
/**
- * Constructor
- *
- * @param \phpbb\config_php_file $config_php_file
- * @param string $phpbb_root_path Path to the phpbb includes directory.
- * @param string $php_ext php file extension
- */
- function __construct(\phpbb\config_php_file $config_php_file, $phpbb_root_path, $php_ext)
+ * Constructor
+ *
+ * @param string $phpbb_root_path Path to the phpbb includes directory.
+ * @param string $php_ext php file extension
+ */
+ public function __construct($phpbb_root_path, $php_ext)
{
- $this->config_php_file = $config_php_file;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
}
/**
- * Build and return a new Container respecting the current configuration
- *
- * @return \phpbb_cache_container|ContainerBuilder
- */
+ * Build and return a new Container respecting the current configuration
+ *
+ * @return \phpbb_cache_container|ContainerBuilder
+ */
public function get_container()
{
- $container_filename = $this->get_container_filename();
- if (!defined('DEBUG_CONTAINER') && $this->dump_container && file_exists($container_filename))
+ try
{
- require($container_filename);
- $this->container = new \phpbb_cache_container();
- }
- else
- {
- if ($this->config_path === null)
+ $container_filename = $this->get_container_filename();
+ $config_cache = new ConfigCache($container_filename, defined('DEBUG'));
+ if ($this->use_cache && $config_cache->isFresh())
{
- $this->config_path = $this->phpbb_root_path . 'config';
- }
- $container_extensions = array(new \phpbb\di\extension\core($this->config_path));
+ if ($this->use_extensions)
+ {
+ $autoload_cache = new ConfigCache($this->get_autoload_filename(), defined('DEBUG'));
+ if (!$autoload_cache->isFresh())
+ {
+ // autoload cache should be refreshed
+ $this->load_extensions();
+ }
+
+ require($this->get_autoload_filename());
+ }
- if ($this->use_extensions)
- {
- $installed_exts = $this->get_installed_extensions();
- $container_extensions[] = new \phpbb\di\extension\ext($installed_exts);
+ require($config_cache->getPath());
+ $this->container = new \phpbb_cache_container();
}
-
- if ($this->inject_config)
+ else
{
- $container_extensions[] = new \phpbb\di\extension\config($this->config_php_file);
- }
+ $this->container_extensions = array(new extension\core($this->get_config_path()));
- $this->container = $this->create_container($container_extensions);
+ if ($this->use_extensions)
+ {
+ $this->load_extensions();
+ }
- if ($this->use_custom_pass)
- {
- // Symfony Kernel Listeners
- $this->container->addCompilerPass(new \phpbb\di\pass\collection_pass());
+ // Inject the config
+ if ($this->config_php_file)
+ {
+ $this->container_extensions[] = new extension\config($this->config_php_file);
+ }
+
+ $this->container = $this->create_container($this->container_extensions);
+
+ // Easy collections through tags
+ $this->container->addCompilerPass(new pass\collection_pass());
+
+ // Event listeners "phpBB style"
$this->container->addCompilerPass(new RegisterListenersPass('dispatcher', 'event.listener_listener', 'event.listener'));
- if ($this->use_kernel_pass)
+ // Event listeners "Symfony style"
+ $this->container->addCompilerPass(new RegisterListenersPass('dispatcher'));
+
+ if ($this->use_extensions)
{
- $this->container->addCompilerPass(new RegisterListenersPass('dispatcher'));
+ $this->register_ext_compiler_pass();
}
+
+ $filesystem = new filesystem();
+ $loader = new YamlFileLoader($this->container, new FileLocator($filesystem->realpath($this->get_config_path())));
+ $loader->load($this->container->getParameter('core.environment') . '/config.yml');
+
+ $this->inject_custom_parameters();
+
+ if ($this->compile_container)
+ {
+ $this->container->compile();
+
+ if ($this->use_cache)
+ {
+ $this->dump_container($config_cache);
+ }
+ }
+ }
+
+ if ($this->compile_container && $this->config_php_file)
+ {
+ $this->container->set('config.php', $this->config_php_file);
}
- $this->inject_custom_parameters();
+ $this->inject_dbal_driver();
- if ($this->compile_container)
+ return $this->container;
+ }
+ catch (\Exception $e)
+ {
+ // Don't try to recover if we are in the development environment
+ if ($this->get_environment() === 'development')
{
- $this->container->compile();
+ throw $e;
}
- if ($this->dump_container && !defined('DEBUG_CONTAINER'))
+ if ($this->build_exception === null)
+ {
+ $this->build_exception = $e;
+
+ return $this
+ ->without_extensions()
+ ->without_cache()
+ ->with_custom_parameters(array_merge($this->custom_parameters, [
+ 'container_exception' => $e,
+ ]))
+ ->get_container();
+ }
+ else
{
- $this->dump_container($container_filename);
+ // Rethrow the original exception if it's still failing
+ throw $this->build_exception;
}
}
+ }
- $this->container->set('config.php', $this->config_php_file);
- $this->inject_dbal_driver();
+ /**
+ * Enable the extensions.
+ *
+ * @param string $environment The environment to use
+ * @return $this
+ */
+ public function with_environment($environment)
+ {
+ $this->environment = $environment;
- if ($this->compile_container)
- {
- $this->inject_dbal();
- }
+ return $this;
+ }
- return $this->container;
+ /**
+ * Enable the extensions.
+ *
+ * @return $this
+ */
+ public function with_extensions()
+ {
+ $this->use_extensions = true;
+
+ return $this;
}
/**
- * Set if the extensions should be used.
- *
- * @param bool $use_extensions
- */
- public function set_use_extensions($use_extensions)
+ * Disable the extensions.
+ *
+ * @return $this
+ */
+ public function without_extensions()
{
- $this->use_extensions = $use_extensions;
+ $this->use_extensions = false;
+
+ return $this;
}
/**
- * Set if the phpBB compile pass have to be used.
- *
- * @param bool $use_custom_pass
- */
- public function set_use_custom_pass($use_custom_pass)
+ * Enable the caching of the container.
+ *
+ * If DEBUG_CONTAINER is set this option is ignored and a new container is build.
+ *
+ * @return $this
+ */
+ public function with_cache()
{
- $this->use_custom_pass = $use_custom_pass;
+ $this->use_cache = true;
+
+ return $this;
}
/**
- * Set if the kernel compile pass have to be used.
- *
- * @param bool $use_kernel_pass
- */
- public function set_use_kernel_pass($use_kernel_pass)
+ * Disable the caching of the container.
+ *
+ * @return $this
+ */
+ public function without_cache()
{
- $this->use_kernel_pass = $use_kernel_pass;
+ $this->use_cache = false;
+
+ return $this;
}
/**
- * Set if the php config file should be injecting into the container.
- *
- * @param bool $inject_config
- */
- public function set_inject_config($inject_config)
+ * Set the cache directory.
+ *
+ * @param string $cache_dir The cache directory.
+ * @return $this
+ */
+ public function with_cache_dir($cache_dir)
{
- $this->inject_config = $inject_config;
+ $this->cache_dir = $cache_dir;
+
+ return $this;
}
/**
- * Set if a dump container should be used.
- *
- * If DEBUG_CONTAINER is set this option is ignored and a new container is build.
- *
- * @var bool $dump_container
- */
- public function set_dump_container($dump_container)
+ * Enable the compilation of the container.
+ *
+ * @return $this
+ */
+ public function with_compiled_container()
{
- $this->dump_container = $dump_container;
+ $this->compile_container = true;
+
+ return $this;
}
/**
- * Set if the container should be compiled automatically (default to true).
- *
- * @var bool $dump_container
- */
- public function set_compile_container($compile_container)
+ * Disable the compilation of the container.
+ *
+ * @return $this
+ */
+ public function without_compiled_container()
{
- $this->compile_container = $compile_container;
+ $this->compile_container = false;
+
+ return $this;
}
/**
- * Set a custom path to find the configuration of the container
- *
- * @param string $config_path
- */
- public function set_config_path($config_path)
+ * Set a custom path to find the configuration of the container.
+ *
+ * @param string $config_path
+ * @return $this
+ */
+ public function with_config_path($config_path)
{
$this->config_path = $config_path;
+
+ return $this;
}
/**
- * Set custom parameters to inject into the container.
- *
- * @param array $custom_parameters
- */
- public function set_custom_parameters($custom_parameters)
+ * Set custom parameters to inject into the container.
+ *
+ * @param array $custom_parameters
+ * @return $this
+ */
+ public function with_custom_parameters($custom_parameters)
{
$this->custom_parameters = $custom_parameters;
+
+ return $this;
}
/**
- * Dump the container to the disk.
- *
- * @param string $container_filename The name of the file.
- */
- protected function dump_container($container_filename)
+ * Set custom parameters to inject into the container.
+ *
+ * @param \phpbb\config_php_file $config_php_file
+ * @return $this
+ */
+ public function with_config(\phpbb\config_php_file $config_php_file)
{
- $dumper = new PhpDumper($this->container);
- $cached_container_dump = $dumper->dump(array(
- 'class' => 'phpbb_cache_container',
- 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder',
- ));
+ $this->config_php_file = $config_php_file;
- file_put_contents($container_filename, $cached_container_dump);
+ return $this;
}
/**
- * Inject the connection into the container if one was opened.
- */
- protected function inject_dbal()
+ * Returns the path to the container configuration (default: root_path/config)
+ *
+ * @return string
+ */
+ protected function get_config_path()
{
- if ($this->dbal_connection !== null)
- {
- $this->container->get('dbal.conn')->set_driver($this->dbal_connection);
- }
+ return $this->config_path ?: $this->phpbb_root_path . 'config';
}
/**
- * Inject the dbal connection driver into container
+ * Returns the path to the cache directory (default: root_path/cache/environment).
+ *
+ * @return string Path to the cache directory.
*/
- protected function inject_dbal_driver()
+ protected function get_cache_dir()
{
- $config_data = $this->config_php_file->get_all();
- if (!empty($config_data))
- {
- $this->container->set('dbal.conn.driver', $this->get_dbal_connection());
- }
+ return $this->cache_dir ?: $this->phpbb_root_path . 'cache/' . $this->get_environment() . '/';
}
/**
- * Get DB connection.
- *
- * @return \phpbb\db\driver\driver_interface
- */
- protected function get_dbal_connection()
+ * Load the enabled extensions.
+ */
+ protected function load_extensions()
{
- if ($this->dbal_connection === null)
+ if ($this->config_php_file !== null)
{
- $dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms'));
- $this->dbal_connection = new $dbal_driver_class();
- $this->dbal_connection->sql_connect(
- $this->config_php_file->get('dbhost'),
- $this->config_php_file->get('dbuser'),
- $this->config_php_file->get('dbpasswd'),
- $this->config_php_file->get('dbname'),
- $this->config_php_file->get('dbport'),
- false,
- defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK
- );
- }
+ // Build an intermediate container to load the ext list from the database
+ $container_builder = new container_builder($this->phpbb_root_path, $this->php_ext);
+ $ext_container = $container_builder
+ ->without_cache()
+ ->without_extensions()
+ ->with_config($this->config_php_file)
+ ->with_config_path($this->get_config_path())
+ ->with_environment('production')
+ ->without_compiled_container()
+ ->get_container()
+ ;
+
+ $ext_container->register('cache.driver', '\\phpbb\\cache\\driver\\dummy');
+ $ext_container->compile();
+
+ $extensions = $ext_container->get('ext.manager')->all_enabled();
+
+ // Load each extension found
+ $autoloaders = '<?php
+/**
+ * Loads all extensions custom auto-loaders.
+ *
+ * This file has been auto-generated
+ * by phpBB while loading the extensions.
+ */
+
+';
+ foreach ($extensions as $ext_name => $path)
+ {
+ $extension_class = '\\' . str_replace('/', '\\', $ext_name) . '\\di\\extension';
+
+ if (!class_exists($extension_class))
+ {
+ $extension_class = '\\phpbb\\extension\\di\\extension_base';
+ }
+
+ $this->container_extensions[] = new $extension_class($ext_name, $path);
+
+ // Load extension autoloader
+ $filename = $path . 'vendor/autoload.php';
+ if (file_exists($filename))
+ {
+ $autoloaders .= "require('{$filename}');\n";
+ }
+ }
+
+ $configCache = new ConfigCache($this->get_autoload_filename(), false);
+ $configCache->write($autoloaders);
- return $this->dbal_connection;
+ require($this->get_autoload_filename());
+ }
+ else
+ {
+ // To load the extensions we need the database credentials.
+ // Automatically disable the extensions if we don't have them.
+ $this->use_extensions = false;
+ }
}
/**
- * Get enabled extensions.
- *
- * @return array enabled extensions
- */
- protected function get_installed_extensions()
+ * Dump the container to the disk.
+ *
+ * @param ConfigCache $cache The config cache
+ */
+ protected function dump_container($cache)
{
- $db = $this->get_dbal_connection();
- $extension_table = $this->config_php_file->get('table_prefix') . 'ext';
-
- $sql = 'SELECT *
- FROM ' . $extension_table . '
- WHERE ext_active = 1';
+ try
+ {
+ $dumper = new PhpDumper($this->container);
+ $proxy_dumper = new ProxyDumper();
+ $dumper->setProxyDumper($proxy_dumper);
- $result = $db->sql_query($sql);
- $rows = $db->sql_fetchrowset($result);
- $db->sql_freeresult($result);
+ $cached_container_dump = $dumper->dump(array(
+ 'class' => 'phpbb_cache_container',
+ 'base_class' => 'Symfony\\Component\\DependencyInjection\\ContainerBuilder',
+ ));
- $exts = array();
- foreach ($rows as $row)
+ $cache->write($cached_container_dump, $this->container->getResources());
+ }
+ catch (IOException $e)
{
- $exts[$row['ext_name']] = $this->phpbb_root_path . 'ext/' . $row['ext_name'] . '/';
+ // Don't fail if the cache isn't writeable
}
-
- return $exts;
}
/**
- * Create the ContainerBuilder object
- *
- * @param array $extensions Array of Container extension objects
- * @return ContainerBuilder object
- */
+ * Create the ContainerBuilder object
+ *
+ * @param array $extensions Array of Container extension objects
+ * @return ContainerBuilder object
+ */
protected function create_container(array $extensions)
{
- $container = new ContainerBuilder();
+ $container = new ContainerBuilder(new ParameterBag($this->get_core_parameters()));
+ $container->setProxyInstantiator(new proxy_instantiator($this->get_cache_dir()));
+
+ $extensions_alias = array();
foreach ($extensions as $extension)
{
$container->registerExtension($extension);
- $container->loadFromExtension($extension->getAlias());
+ $extensions_alias[] = $extension->getAlias();
}
+ $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions_alias));
+
return $container;
}
/**
- * Inject the customs parameters into the container
- */
+ * Inject the customs parameters into the container
+ */
protected function inject_custom_parameters()
{
- if ($this->custom_parameters === null)
+ foreach ($this->custom_parameters as $key => $value)
{
- $this->custom_parameters = array(
- 'core.root_path' => $this->phpbb_root_path,
- 'core.php_ext' => $this->php_ext,
- );
+ $this->container->setParameter($key, $value);
}
+ }
- foreach ($this->custom_parameters as $key => $value)
+ /**
+ * Inject the dbal connection driver into container
+ */
+ protected function inject_dbal_driver()
+ {
+ if (empty($this->config_php_file))
{
- $this->container->setParameter($key, $value);
+ return;
+ }
+
+ $config_data = $this->config_php_file->get_all();
+ if (!empty($config_data))
+ {
+ if ($this->dbal_connection === null)
+ {
+ $dbal_driver_class = $this->config_php_file->convert_30_dbms_to_31($this->config_php_file->get('dbms'));
+ /** @var \phpbb\db\driver\driver_interface $dbal_connection */
+ $this->dbal_connection = new $dbal_driver_class();
+ $this->dbal_connection->sql_connect(
+ $this->config_php_file->get('dbhost'),
+ $this->config_php_file->get('dbuser'),
+ $this->config_php_file->get('dbpasswd'),
+ $this->config_php_file->get('dbname'),
+ $this->config_php_file->get('dbport'),
+ false,
+ defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK
+ );
+ }
+ $this->container->set('dbal.conn.driver', $this->dbal_connection);
+ }
+ }
+
+ /**
+ * Returns the core parameters.
+ *
+ * @return array An array of core parameters
+ */
+ protected function get_core_parameters()
+ {
+ return array_merge(
+ array(
+ 'core.root_path' => $this->phpbb_root_path,
+ 'core.php_ext' => $this->php_ext,
+ 'core.environment' => $this->get_environment(),
+ 'core.debug' => defined('DEBUG') ? DEBUG : false,
+ 'core.cache_dir' => $this->get_cache_dir(),
+ ),
+ $this->get_env_parameters()
+ );
+ }
+
+ /**
+ * Gets the environment parameters.
+ *
+ * Only the parameters starting with "PHPBB__" are considered.
+ *
+ * @return array An array of parameters
+ */
+ protected function get_env_parameters()
+ {
+ $parameters = array();
+ foreach ($_SERVER as $key => $value)
+ {
+ if (0 === strpos($key, 'PHPBB__'))
+ {
+ $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value;
+ }
}
+
+ return $parameters;
}
/**
- * Get the filename under which the dumped container will be stored.
- *
- * @return string Path for dumped container
- */
+ * Get the filename under which the dumped container will be stored.
+ *
+ * @return string Path for dumped container
+ */
protected function get_container_filename()
{
- return $this->phpbb_root_path . 'cache/container_' . md5($this->phpbb_root_path) . '.' . $this->php_ext;
+ $container_params = [
+ 'phpbb_root_path' => $this->phpbb_root_path,
+ 'use_extensions' => $this->use_extensions,
+ 'config_path' => $this->config_path,
+ ];
+
+ return $this->get_cache_dir() . 'container_' . md5(implode(',', $container_params)) . '.' . $this->php_ext;
+ }
+
+ /**
+ * Get the filename under which the dumped extensions autoloader will be stored.
+ *
+ * @return string Path for dumped extensions autoloader
+ */
+ protected function get_autoload_filename()
+ {
+ $container_params = [
+ 'phpbb_root_path' => $this->phpbb_root_path,
+ 'use_extensions' => $this->use_extensions,
+ 'config_path' => $this->config_path,
+ ];
+
+ return $this->get_cache_dir() . 'autoload_' . md5(implode(',', $container_params)) . '.' . $this->php_ext;
+ }
+
+ /**
+ * Return the name of the current environment.
+ *
+ * @return string
+ */
+ protected function get_environment()
+ {
+ return $this->environment ?: PHPBB_ENVIRONMENT;
+ }
+
+ private function register_ext_compiler_pass()
+ {
+ $finder = new Finder();
+ $finder
+ ->name('*_pass.php')
+ ->path('di/pass')
+ ->files()
+ ->ignoreDotFiles(true)
+ ->ignoreUnreadableDirs(true)
+ ->ignoreVCS(true)
+ ->followLinks()
+ ->in($this->phpbb_root_path . 'ext')
+ ;
+
+ /** @var \SplFileInfo $pass */
+ foreach ($finder as $pass)
+ {
+ $filename = $pass->getPathname();
+ $filename = substr($filename, 0, -strlen('.' . $pass->getExtension()));
+ $filename = str_replace(DIRECTORY_SEPARATOR, '/', $filename);
+ $className = preg_replace('#^.*ext/#', '', $filename);
+ $className = '\\' . str_replace('/', '\\', $className);
+
+ if (class_exists($className) && in_array('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface', class_implements($className), true))
+ {
+ $this->container->addCompilerPass(new $className());
+ }
+ }
}
}
diff --git a/phpBB/phpbb/di/extension/container_configuration.php b/phpBB/phpbb/di/extension/container_configuration.php
new file mode 100644
index 0000000000..4585d6509e
--- /dev/null
+++ b/phpBB/phpbb/di/extension/container_configuration.php
@@ -0,0 +1,52 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\di\extension;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+class container_configuration implements ConfigurationInterface
+{
+
+ /**
+ * Generates the configuration tree builder.
+ *
+ * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
+ */
+ public function getConfigTreeBuilder()
+ {
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('core');
+ $rootNode
+ ->children()
+ ->booleanNode('require_dev_dependencies')->defaultValue(false)->end()
+ ->arrayNode('debug')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->booleanNode('exceptions')->defaultValue(false)->end()
+ ->end()
+ ->end()
+ ->arrayNode('twig')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->booleanNode('debug')->defaultValue(null)->end()
+ ->booleanNode('auto_reload')->defaultValue(null)->end()
+ ->booleanNode('enable_debug_extension')->defaultValue(false)->end()
+ ->end()
+ ->end()
+ ->end()
+ ;
+ return $treeBuilder;
+ }
+}
diff --git a/phpBB/phpbb/di/extension/core.php b/phpBB/phpbb/di/extension/core.php
index ca4fa5c082..67150f0103 100644
--- a/phpBB/phpbb/di/extension/core.php
+++ b/phpBB/phpbb/di/extension/core.php
@@ -13,53 +13,110 @@
namespace phpbb\di\extension;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
-use Symfony\Component\Config\FileLocator;
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
* Container core extension
*/
class core extends Extension
{
+ const TWIG_OPTIONS_POSITION = 7;
+
/**
- * Config path
- * @var string
- */
+ * Config path
+ * @var string
+ */
protected $config_path;
/**
- * Constructor
- *
- * @param string $config_path Config path
- */
+ * Constructor
+ *
+ * @param string $config_path Config path
+ */
public function __construct($config_path)
{
$this->config_path = $config_path;
}
/**
- * Loads a specific configuration.
- *
- * @param array $config An array of configuration values
- * @param ContainerBuilder $container A ContainerBuilder instance
- *
- * @throws \InvalidArgumentException When provided tag is not defined in this extension
- */
- public function load(array $config, ContainerBuilder $container)
+ * Loads a specific configuration.
+ *
+ * @param array $configs An array of configuration values
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ *
+ * @throws \InvalidArgumentException When provided tag is not defined in this extension
+ */
+ public function load(array $configs, ContainerBuilder $container)
+ {
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $loader = new YamlFileLoader($container, new FileLocator($filesystem->realpath($this->config_path)));
+ $loader->load($container->getParameter('core.environment') . '/container/environment.yml');
+
+ $config = $this->getConfiguration($configs, $container);
+ $config = $this->processConfiguration($config, $configs);
+
+ if ($config['require_dev_dependencies'])
+ {
+ if (!class_exists('Goutte\Client', true))
+ {
+ trigger_error(
+ 'Composer development dependencies have not been set up for the ' . $container->getParameter('core.environment') . ' environment yet, run ' .
+ "'php ../composer.phar install --dev' from the phpBB directory to do so.",
+ E_USER_ERROR
+ );
+ }
+ }
+
+ // Set the Twig options if defined in the environment
+ $definition = $container->getDefinition('template.twig.environment');
+ $twig_environment_options = $definition->getArgument(static::TWIG_OPTIONS_POSITION);
+ if ($config['twig']['debug'])
+ {
+ $twig_environment_options['debug'] = true;
+ }
+ if ($config['twig']['auto_reload'])
+ {
+ $twig_environment_options['auto_reload'] = true;
+ }
+
+ // Replace the 7th argument, the options passed to the environment
+ $definition->replaceArgument(static::TWIG_OPTIONS_POSITION, $twig_environment_options);
+
+ if ($config['twig']['enable_debug_extension'])
+ {
+ $definition = $container->getDefinition('template.twig.extensions.debug');
+ $definition->addTag('twig.extension');
+ }
+
+ // Set the debug options
+ foreach ($config['debug'] as $name => $value)
+ {
+ $container->setParameter('debug.' . $name, $value);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConfiguration(array $config, ContainerBuilder $container)
{
- $loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($this->config_path)));
- $loader->load('services.yml');
+ $r = new \ReflectionClass('\phpbb\di\extension\container_configuration');
+ $container->addResource(new FileResource($r->getFileName()));
+
+ return new container_configuration();
}
/**
- * Returns the recommended alias to use in XML.
- *
- * This alias is also the mandatory prefix to use when using YAML.
- *
- * @return string The alias
- */
+ * Returns the recommended alias to use in XML.
+ *
+ * This alias is also the mandatory prefix to use when using YAML.
+ *
+ * @return string The alias
+ */
public function getAlias()
{
return 'core';
diff --git a/phpBB/phpbb/di/extension/ext.php b/phpBB/phpbb/di/extension/ext.php
deleted file mode 100644
index 718c992d2e..0000000000
--- a/phpBB/phpbb/di/extension/ext.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\di\extension;
-
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
-use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
-use Symfony\Component\Config\FileLocator;
-
-/**
-* Container ext extension
-*/
-class ext extends Extension
-{
- protected $paths = array();
-
- public function __construct($enabled_extensions)
- {
- foreach ($enabled_extensions as $ext => $path)
- {
- $this->paths[] = $path;
- }
- }
-
- /**
- * Loads a specific configuration.
- *
- * @param array $config An array of configuration values
- * @param ContainerBuilder $container A ContainerBuilder instance
- *
- * @throws \InvalidArgumentException When provided tag is not defined in this extension
- */
- public function load(array $config, ContainerBuilder $container)
- {
- foreach ($this->paths as $path)
- {
- if (file_exists($path . '/config/services.yml'))
- {
- $loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($path . '/config')));
- $loader->load('services.yml');
- }
- }
- }
-
- /**
- * Returns the recommended alias to use in XML.
- *
- * This alias is also the mandatory prefix to use when using YAML.
- *
- * @return string The alias
- */
- public function getAlias()
- {
- return 'ext';
- }
-}
diff --git a/phpBB/phpbb/di/ordered_service_collection.php b/phpBB/phpbb/di/ordered_service_collection.php
new file mode 100644
index 0000000000..046012ae5b
--- /dev/null
+++ b/phpBB/phpbb/di/ordered_service_collection.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\di;
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Collection of services in a specified order
+ */
+class ordered_service_collection extends service_collection
+{
+ /**
+ * @var bool
+ */
+ protected $is_ordered;
+
+ /**
+ * @var array
+ */
+ protected $service_ids;
+
+ /**
+ * Constructor
+ *
+ * @param ContainerInterface $container Container object
+ */
+ public function __construct(ContainerInterface $container)
+ {
+ $this->is_ordered = false;
+ $this->service_ids = array();
+
+ parent::__construct($container);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIterator()
+ {
+ if (!$this->is_ordered)
+ {
+ $this->sort_services();
+ }
+
+ return new service_collection_iterator($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetExists($index)
+ {
+ if (!$this->is_ordered)
+ {
+ $this->sort_services();
+ }
+
+ return parent::offsetExists($index);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function offsetGet($index)
+ {
+ if (!$this->is_ordered)
+ {
+ $this->sort_services();
+ }
+
+ return parent::offsetGet($index);
+ }
+
+ /**
+ * Adds a service ID to the collection
+ *
+ * @param string $service_id
+ * @param int $order
+ */
+ public function add($service_id, $order = 0)
+ {
+ $order = (int) $order;
+ $this->service_ids[$order][] = $service_id;
+ $this->is_ordered = false;
+ }
+
+ protected function sort_services()
+ {
+ if ($this->is_ordered)
+ {
+ return;
+ }
+
+ $this->exchangeArray(array());
+ ksort($this->service_ids);
+ foreach ($this->service_ids as $service_order_group)
+ {
+ foreach ($service_order_group as $service_id)
+ {
+ $this->offsetSet($service_id, null);
+ }
+ }
+
+ $this->is_ordered = true;
+ }
+}
diff --git a/phpBB/phpbb/di/pass/collection_pass.php b/phpBB/phpbb/di/pass/collection_pass.php
index a5c054674e..341f88518d 100644
--- a/phpBB/phpbb/di/pass/collection_pass.php
+++ b/phpBB/phpbb/di/pass/collection_pass.php
@@ -34,10 +34,30 @@ class collection_pass implements CompilerPassInterface
foreach ($container->findTaggedServiceIds('service_collection') as $id => $data)
{
$definition = $container->getDefinition($id);
+ $is_ordered_collection = (substr($definition->getClass(), -strlen('ordered_service_collection')) === 'ordered_service_collection');
+ $is_class_name_aware = (isset($data[0]['class_name_aware']) && $data[0]['class_name_aware']);
foreach ($container->findTaggedServiceIds($data[0]['tag']) as $service_id => $service_data)
{
- $definition->addMethodCall('add', array($service_id));
+ if ($is_ordered_collection)
+ {
+ $arguments = array($service_id, $service_data[0]['order']);
+ }
+ else
+ {
+ $arguments = array($service_id);
+ }
+
+ if ($is_class_name_aware)
+ {
+ $service_definition = $container->getDefinition($service_id);
+ $definition->addMethodCall('add_service_class', array(
+ $service_id,
+ $service_definition->getClass()
+ ));
+ }
+
+ $definition->addMethodCall('add', $arguments);
}
}
}
diff --git a/phpBB/phpbb/di/proxy_instantiator.php b/phpBB/phpbb/di/proxy_instantiator.php
new file mode 100644
index 0000000000..70295a3dec
--- /dev/null
+++ b/phpBB/phpbb/di/proxy_instantiator.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\di;
+
+use ProxyManager\Configuration;
+use ProxyManager\Factory\LazyLoadingValueHolderFactory;
+use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
+
+/**
+ * Runtime lazy loading proxy generator extended for allowing use while using
+ * open_basedir restrictions
+ *
+ * Original author: Marco Pivetta <ocramius@gmail.com>
+ */
+class proxy_instantiator implements InstantiatorInterface
+{
+ /**
+ * @var LazyLoadingValueHolderFactory
+ */
+ private $factory;
+
+ /**
+ * proxy_instantiator constructor
+ * @param string $cache_dir Cache dir for fall back when using open_basedir
+ */
+ public function __construct($cache_dir)
+ {
+ $config = new Configuration();
+
+ // Prevent trying to write to system temp dir in case of open_basedir
+ // restrictions being in effect
+ $tmp_dir = (function_exists('sys_get_temp_dir')) ? sys_get_temp_dir() : '';
+ if (empty($tmp_dir) || !@file_exists($tmp_dir) || !@is_writable($tmp_dir))
+ {
+ $config->setProxiesTargetDir($cache_dir);
+ }
+ $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy());
+
+ $this->factory = new LazyLoadingValueHolderFactory($config);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function instantiateProxy(ContainerInterface $container, Definition $definition, $id, $realInstantiator)
+ {
+ return $this->factory->createProxy(
+ $definition->getClass(),
+ function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) use ($realInstantiator) {
+ $wrappedInstance = call_user_func($realInstantiator);
+
+ $proxy->setProxyInitializer(null);
+
+ return true;
+ }
+ );
+ }
+}
diff --git a/phpBB/phpbb/di/service_collection.php b/phpBB/phpbb/di/service_collection.php
index 82ca9bf679..8e9175e204 100644
--- a/phpBB/phpbb/di/service_collection.php
+++ b/phpBB/phpbb/di/service_collection.php
@@ -26,6 +26,11 @@ class service_collection extends \ArrayObject
protected $container;
/**
+ * @var array
+ */
+ protected $service_classes;
+
+ /**
* Constructor
*
* @param ContainerInterface $container Container object
@@ -33,6 +38,7 @@ class service_collection extends \ArrayObject
public function __construct(ContainerInterface $container)
{
$this->container = $container;
+ $this->service_classes = array();
}
/**
@@ -76,4 +82,25 @@ class service_collection extends \ArrayObject
{
$this->offsetSet($name, null);
}
+
+ /**
+ * Add a service's class to the collection
+ *
+ * @param string $service_id
+ * @param string $class
+ */
+ public function add_service_class($service_id, $class)
+ {
+ $this->service_classes[$service_id] = $class;
+ }
+
+ /**
+ * Get services' classes
+ *
+ * @return array
+ */
+ public function get_service_classes()
+ {
+ return $this->service_classes;
+ }
}
diff --git a/phpBB/phpbb/di/service_collection_iterator.php b/phpBB/phpbb/di/service_collection_iterator.php
index 0d031ab52d..31bc156e99 100644
--- a/phpBB/phpbb/di/service_collection_iterator.php
+++ b/phpBB/phpbb/di/service_collection_iterator.php
@@ -32,7 +32,7 @@ class service_collection_iterator extends \ArrayIterator
*/
public function __construct(service_collection $collection, $flags = 0)
{
- parent::__construct($collection, $flags);
+ parent::__construct($collection->getArrayCopy(), $flags);
$this->collection = $collection;
}
diff --git a/phpBB/phpbb/event/data.php b/phpBB/phpbb/event/data.php
index c7365aee35..276ab027f2 100644
--- a/phpBB/phpbb/event/data.php
+++ b/phpBB/phpbb/event/data.php
@@ -63,4 +63,16 @@ class data extends Event implements \ArrayAccess
{
unset($this->data[$offset]);
}
+
+ /**
+ * Returns data with updated key in specified offset.
+ *
+ * @param string $subarray Data array subarray
+ * @param string $key Subarray key
+ * @param mixed $value Value to update
+ */
+ public function update_subarray($subarray, $key, $value)
+ {
+ $this->data[$subarray][$key] = $value;
+ }
}
diff --git a/phpBB/phpbb/event/dispatcher.php b/phpBB/phpbb/event/dispatcher.php
index 1c4abeb108..1ba2ab8987 100644
--- a/phpBB/phpbb/event/dispatcher.php
+++ b/phpBB/phpbb/event/dispatcher.php
@@ -57,7 +57,12 @@ class dispatcher extends ContainerAwareEventDispatcher implements dispatcher_int
return $event;
}
- return parent::dispatch($eventName, $event);
+ foreach ((array) $eventName as $name)
+ {
+ $event = parent::dispatch($name, $event);
+ }
+
+ return $event;
}
/**
diff --git a/phpBB/phpbb/event/kernel_exception_subscriber.php b/phpBB/phpbb/event/kernel_exception_subscriber.php
index 1ee771cfe7..373e59b0c8 100644
--- a/phpBB/phpbb/event/kernel_exception_subscriber.php
+++ b/phpBB/phpbb/event/kernel_exception_subscriber.php
@@ -16,6 +16,7 @@ namespace phpbb\event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
@@ -23,16 +24,25 @@ use Symfony\Component\HttpFoundation\Response;
class kernel_exception_subscriber implements EventSubscriberInterface
{
/**
+ * Set to true to show full exception messages
+ *
+ * @var bool
+ */
+ protected $debug;
+
+ /**
* Template object
+ *
* @var \phpbb\template\template
*/
protected $template;
/**
- * User object
- * @var \phpbb\user
+ * Language object
+ *
+ * @var \phpbb\language\language
*/
- protected $user;
+ protected $language;
/** @var \phpbb\request\type_cast_helper */
protected $type_caster;
@@ -40,13 +50,15 @@ class kernel_exception_subscriber implements EventSubscriberInterface
/**
* Construct method
*
- * @param \phpbb\template\template $template Template object
- * @param \phpbb\user $user User object
+ * @param \phpbb\template\template $template Template object
+ * @param \phpbb\language\language $language Language object
+ * @param bool $debug Set to true to show full exception messages
*/
- public function __construct(\phpbb\template\template $template, \phpbb\user $user)
+ public function __construct(\phpbb\template\template $template, \phpbb\language\language $language, $debug = false)
{
+ $this->debug = $debug || defined('DEBUG');
$this->template = $template;
- $this->user = $user;
+ $this->language = $language;
$this->type_caster = new \phpbb\request\type_cast_helper();
}
@@ -65,7 +77,11 @@ class kernel_exception_subscriber implements EventSubscriberInterface
if ($exception instanceof \phpbb\exception\exception_interface)
{
- $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($message), $exception->get_parameters()));
+ $message = $this->language->lang_array($message, $exception->get_parameters());
+ }
+ else if (!$this->debug && $exception instanceof NotFoundHttpException)
+ {
+ $message = $this->language->lang('PAGE_NOT_FOUND');
}
// Show <strong> text in bold
@@ -73,10 +89,10 @@ class kernel_exception_subscriber implements EventSubscriberInterface
if (!$event->getRequest()->isXmlHttpRequest())
{
- page_header($this->user->lang('INFORMATION'));
+ page_header($this->language->lang('INFORMATION'));
$this->template->assign_vars(array(
- 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'),
+ 'MESSAGE_TITLE' => $this->language->lang('INFORMATION'),
'MESSAGE_TEXT' => $message,
));
@@ -97,7 +113,7 @@ class kernel_exception_subscriber implements EventSubscriberInterface
$data['message'] = $message;
}
- if (defined('DEBUG'))
+ if ($this->debug)
{
$data['trace'] = $exception->getTrace();
}
@@ -114,7 +130,7 @@ class kernel_exception_subscriber implements EventSubscriberInterface
$event->setResponse($response);
}
- public static function getSubscribedEvents()
+ static public function getSubscribedEvents()
{
return array(
KernelEvents::EXCEPTION => 'on_kernel_exception',
diff --git a/phpBB/phpbb/event/kernel_request_subscriber.php b/phpBB/phpbb/event/kernel_request_subscriber.php
deleted file mode 100644
index ee9f29a59d..0000000000
--- a/phpBB/phpbb/event/kernel_request_subscriber.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\event;
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\HttpKernel\EventListener\RouterListener;
-use Symfony\Component\Routing\RequestContext;
-
-class kernel_request_subscriber implements EventSubscriberInterface
-{
- /**
- * Extension manager object
- * @var \phpbb\extension\manager
- */
- protected $manager;
-
- /**
- * PHP file extension
- * @var string
- */
- protected $php_ext;
-
- /**
- * Root path
- * @var string
- */
- protected $root_path;
-
- /**
- * Construct method
- *
- * @param \phpbb\extension\manager $manager Extension manager object
- * @param string $root_path Root path
- * @param string $php_ext PHP file extension
- */
- public function __construct(\phpbb\extension\manager $manager, $root_path, $php_ext)
- {
- $this->root_path = $root_path;
- $this->php_ext = $php_ext;
- $this->manager = $manager;
- }
-
- /**
- * This listener is run when the KernelEvents::REQUEST event is triggered
- *
- * This is responsible for setting up the routing information
- *
- * @param GetResponseEvent $event
- * @throws \BadMethodCallException
- * @return null
- */
- public function on_kernel_request(GetResponseEvent $event)
- {
- $request = $event->getRequest();
- $context = new RequestContext();
- $context->fromRequest($request);
-
- $matcher = phpbb_get_url_matcher($this->manager, $context, $this->root_path, $this->php_ext);
- $router_listener = new RouterListener($matcher, $context);
- $router_listener->onKernelRequest($event);
- }
-
- public static function getSubscribedEvents()
- {
- return array(
- KernelEvents::REQUEST => 'on_kernel_request',
- );
- }
-}
diff --git a/phpBB/phpbb/event/kernel_terminate_subscriber.php b/phpBB/phpbb/event/kernel_terminate_subscriber.php
index 3a709f73fd..f0d0a2f595 100644
--- a/phpBB/phpbb/event/kernel_terminate_subscriber.php
+++ b/phpBB/phpbb/event/kernel_terminate_subscriber.php
@@ -32,7 +32,7 @@ class kernel_terminate_subscriber implements EventSubscriberInterface
exit_handler();
}
- public static function getSubscribedEvents()
+ static public function getSubscribedEvents()
{
return array(
KernelEvents::TERMINATE => array('on_kernel_terminate', ~PHP_INT_MAX),
diff --git a/phpBB/phpbb/event/md_exporter.php b/phpBB/phpbb/event/md_exporter.php
index 02c2a1b9d6..1a2d7c989e 100644
--- a/phpBB/phpbb/event/md_exporter.php
+++ b/phpBB/phpbb/event/md_exporter.php
@@ -87,7 +87,7 @@ class md_exporter
$this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name));
}
- return sizeof($this->events);
+ return count($this->events);
}
/**
@@ -99,7 +99,7 @@ class md_exporter
{
$this->crawl_eventsmd($md_file, 'styles');
- $styles = array('prosilver', 'subsilver2');
+ $styles = array('prosilver');
foreach ($styles as $style)
{
$file_list = $this->get_recursive_file_list(
@@ -113,7 +113,7 @@ class md_exporter
}
}
- return sizeof($this->events);
+ return count($this->events);
}
/**
@@ -143,6 +143,8 @@ class md_exporter
list($event_name, $details) = explode("\n===\n", $event, 2);
$this->validate_event_name($event_name);
+ $sorted_events = [$this->current_event, $event_name];
+ natsort($sorted_events);
$this->current_event = $event_name;
if (isset($this->events[$this->current_event]))
@@ -150,6 +152,12 @@ class md_exporter
throw new \LogicException("The event '{$this->current_event}' is defined multiple times");
}
+ // Use array_values() to get actual first element and check against natural order
+ if (array_values($sorted_events)[0] === $event_name)
+ {
+ throw new \LogicException("The event '{$sorted_events[1]}' should be defined before '{$sorted_events[0]}'");
+ }
+
if (($this->filter == 'adm' && strpos($this->current_event, 'acp_') !== 0)
|| ($this->filter == 'styles' && strpos($this->current_event, 'acp_') === 0))
{
@@ -219,7 +227,7 @@ class md_exporter
);
}
- return sizeof($this->events);
+ return count($this->events);
}
/**
@@ -266,7 +274,7 @@ class md_exporter
$wiki_page = '= Template Events =' . "\n";
}
$wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n";
- $wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Subsilver Placement (If applicable) !! Added in Release !! Explanation' . "\n";
+ $wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Added in Release !! Explanation' . "\n";
}
foreach ($this->events as $event_name => $event)
@@ -280,7 +288,7 @@ class md_exporter
}
else
{
- $wiki_page .= implode(', ', $event['files']['prosilver']) . ' || ' . implode(', ', $event['files']['subsilver2']);
+ $wiki_page .= implode(', ', $event['files']['prosilver']);
}
$wiki_page .= " || {$event['since']} || " . str_replace("\n", ' ', $event['description']) . "\n";
@@ -371,7 +379,6 @@ class md_exporter
{
$files_list = array(
'prosilver' => array(),
- 'subsilver2' => array(),
'adm' => array(),
);
@@ -382,26 +389,29 @@ class md_exporter
$files = explode("\n + ", $file_details);
foreach ($files as $file)
{
+ if (!preg_match('#^([^ ]+)( \([0-9]+\))?$#', $file))
+ {
+ throw new \LogicException("Invalid event instances for file '{$file}' found for event '{$this->current_event}'", 1);
+ }
+
+ list($file) = explode(" ", $file);
+
if (!file_exists($this->path . $file) || substr($file, -5) !== '.html')
{
- throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 1);
+ throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 2);
}
if (($this->filter !== 'adm') && strpos($file, 'styles/prosilver/template/') === 0)
{
$files_list['prosilver'][] = substr($file, strlen('styles/prosilver/template/'));
}
- else if (($this->filter !== 'adm') && strpos($file, 'styles/subsilver2/template/') === 0)
- {
- $files_list['subsilver2'][] = substr($file, strlen('styles/subsilver2/template/'));
- }
else if (($this->filter === 'adm') && strpos($file, 'adm/style/') === 0)
{
$files_list['adm'][] = substr($file, strlen('adm/style/'));
}
else
{
- throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 2);
+ throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 3);
}
$this->events_by_file[$file][] = $this->current_event;
@@ -421,7 +431,7 @@ class md_exporter
}
else
{
- throw new \LogicException("Invalid file list found for event '{$this->current_event}'", 2);
+ throw new \LogicException("Invalid file list found for event '{$this->current_event}'", 1);
}
return $files_list;
@@ -444,16 +454,9 @@ class md_exporter
$event_list = array();
$file_content = file_get_contents($this->path . $file);
- $events = explode('<!-- EVENT ', $file_content);
- // Remove the code before the first event
- array_shift($events);
- foreach ($events as $event)
- {
- $event = explode(' -->', $event, 2);
- $event_list[] = array_shift($event);
- }
+ preg_match_all('/(?:{%|<!--) EVENT (.*) (?:%}|-->)/U', $file_content, $event_list);
- return $event_list;
+ return $event_list[1];
}
/**
diff --git a/phpBB/phpbb/event/php_exporter.php b/phpBB/phpbb/event/php_exporter.php
index ae3553c558..71c94a681d 100644
--- a/phpBB/phpbb/event/php_exporter.php
+++ b/phpBB/phpbb/event/php_exporter.php
@@ -117,7 +117,7 @@ class php_exporter
}
ksort($this->events);
- return sizeof($this->events);
+ return count($this->events);
}
/**
@@ -196,13 +196,13 @@ class php_exporter
$content = file_get_contents($this->path . $this->current_file);
$num_events_found = 0;
- if (strpos($content, "dispatcher->trigger_event('") || strpos($content, "dispatcher->dispatch('"))
+ if (strpos($content, 'dispatcher->trigger_event(') || strpos($content, 'dispatcher->dispatch('))
{
$this->set_content(explode("\n", $content));
- for ($i = 0, $num_lines = sizeof($this->file_lines); $i < $num_lines; $i++)
+ for ($i = 0, $num_lines = count($this->file_lines); $i < $num_lines; $i++)
{
$event_line = false;
- $found_trigger_event = strpos($this->file_lines[$i], "dispatcher->trigger_event('");
+ $found_trigger_event = strpos($this->file_lines[$i], 'dispatcher->trigger_event(');
$arguments = array();
if ($found_trigger_event !== false)
{
@@ -216,7 +216,7 @@ class php_exporter
}
else
{
- $found_dispatch = strpos($this->file_lines[$i], "dispatcher->dispatch('");
+ $found_dispatch = strpos($this->file_lines[$i], 'dispatcher->dispatch(');
if ($found_dispatch !== false)
{
$event_line = $i;
@@ -264,7 +264,30 @@ class php_exporter
// Find event description line
$description_line_num = $this->find_description();
- $description = substr(trim($this->file_lines[$description_line_num]), strlen('* '));
+ $description_lines = array();
+
+ while (true)
+ {
+ $description_line = substr(trim($this->file_lines[$description_line_num]), strlen('*'));
+ $description_line = trim(str_replace("\t", " ", $description_line));
+
+ // Reached end of description if line is a tag
+ if (strlen($description_line) && $description_line[0] == '@')
+ {
+ break;
+ }
+
+ $description_lines[] = $description_line;
+ $description_line_num++;
+ }
+
+ // If there is an empty line between description and first tag, remove it
+ if (!strlen(end($description_lines)))
+ {
+ array_pop($description_lines);
+ }
+
+ $description = trim(implode('<br/>', $description_lines));
if (isset($this->events[$this->current_event]))
{
@@ -316,17 +339,17 @@ class php_exporter
if ($is_dispatch)
{
- $regex = '#\$([a-z](?:[a-z0-9_]|->)*)';
- $regex .= '->dispatch\(';
- $regex .= '\'' . $this->preg_match_event_name() . '\'';
- $regex .= '\);#';
+ $regex = '#\$[a-z](?:[a-z0-9_]|->)*';
+ $regex .= '->dispatch\((\[)?';
+ $regex .= '\'' . $this->preg_match_event_name() . '(?(1)\', \'(?2))+\'';
+ $regex .= '(?(1)\])\);#';
}
else
{
- $regex = '#extract\(\$([a-z](?:[a-z0-9_]|->)*)';
- $regex .= '->trigger_event\(';
- $regex .= '\'' . $this->preg_match_event_name() . '\'';
- $regex .= ', compact\(\$vars\)\)\);#';
+ $regex = '#extract\(\$[a-z](?:[a-z0-9_]|->)*';
+ $regex .= '->trigger_event\((\[)?';
+ $regex .= '\'' . $this->preg_match_event_name() . '(?(1)\', \'(?2))+\'';
+ $regex .= '(?(1)\]), compact\(\$vars\)\)\);#';
}
$match = array();
@@ -359,7 +382,7 @@ class php_exporter
public function get_vars_from_array()
{
$line = ltrim($this->file_lines[$this->current_event_line - 1], "\t");
- if ($line === ');')
+ if ($line === ');' || $line === '];')
{
$vars_array = $this->get_vars_from_multi_line_array();
}
@@ -370,7 +393,7 @@ class php_exporter
foreach ($vars_array as $var)
{
- if (!preg_match('#^([a-zA-Z_][a-zA-Z0-9_]*)$#', $var))
+ if (!preg_match('#^[a-z_][a-z0-9_]*$#i', $var))
{
throw new \LogicException("Found invalid var '{$var}' in array for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 3);
}
@@ -392,12 +415,12 @@ class php_exporter
public function get_vars_from_single_line_array($line, $throw_multiline = true)
{
$match = array();
- preg_match('#^\$vars = array\(\'([a-zA-Z0-9_\' ,]+)\'\);$#', $line, $match);
+ preg_match('#^\$vars = (?:(\[)|array\()\'([a-z0-9_\' ,]+)\'(?(1)\]|\));$#i', $line, $match);
- if (isset($match[1]))
+ if (isset($match[2]))
{
- $vars_array = explode("', '", $match[1]);
- if ($throw_multiline && sizeof($vars_array) > 6)
+ $vars_array = explode("', '", $match[2]);
+ if ($throw_multiline && count($vars_array) > 6)
{
throw new \LogicException('Should use multiple lines for $vars definition '
. "for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 2);
@@ -420,7 +443,7 @@ class php_exporter
{
$current_vars_line = 2;
$var_lines = array();
- while (ltrim($this->file_lines[$this->current_event_line - $current_vars_line], "\t") !== '$vars = array(')
+ while (!in_array(ltrim($this->file_lines[$this->current_event_line - $current_vars_line], "\t"), ['$vars = array(', '$vars = [']))
{
$var_lines[] = substr(trim($this->file_lines[$this->current_event_line - $current_vars_line]), 0, -1);
@@ -460,7 +483,7 @@ class php_exporter
if (strpos($var_line, '* @var ') === 0)
{
$doc_line = explode(' ', $var_line, 5);
- if (sizeof($doc_line) !== 5)
+ if (count($doc_line) !== 5)
{
throw new \LogicException("Found invalid line '{$this->file_lines[$this->current_event_line - $current_doc_line]}' "
. "for event '{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 1);
@@ -485,7 +508,7 @@ class php_exporter
foreach ($doc_vars as $var)
{
- if (!preg_match('#^([a-zA-Z_][a-zA-Z0-9_]*)$#', $var))
+ if (!preg_match('#^[a-z_][a-z0-9_]*$#i', $var))
{
throw new \LogicException("Found invalid @var '{$var}' in docblock for event "
. "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'", 4);
@@ -707,9 +730,9 @@ class php_exporter
{
$vars_array = array_unique($vars_array);
$vars_docblock = array_unique($vars_docblock);
- $sizeof_vars_array = sizeof($vars_array);
+ $sizeof_vars_array = count($vars_array);
- if ($sizeof_vars_array !== sizeof($vars_docblock) || $sizeof_vars_array !== sizeof(array_intersect($vars_array, $vars_docblock)))
+ if ($sizeof_vars_array !== count($vars_docblock) || $sizeof_vars_array !== count(array_intersect($vars_array, $vars_docblock)))
{
throw new \LogicException("\$vars array does not match the list of '@var' tags for event "
. "'{$this->current_event}' in file '{$this->current_file}:{$this->current_event_line}'");
diff --git a/phpBB/phpbb/exception/version_check_exception.php b/phpBB/phpbb/exception/version_check_exception.php
new file mode 100644
index 0000000000..0810263ade
--- /dev/null
+++ b/phpBB/phpbb/exception/version_check_exception.php
@@ -0,0 +1,21 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\exception;
+
+/**
+ * Define an exception related to the version checker.
+ */
+class version_check_exception extends runtime_exception
+{
+}
diff --git a/phpBB/phpbb/extension/base.php b/phpBB/phpbb/extension/base.php
index 5bb530bad4..c7778cfed1 100644
--- a/phpBB/phpbb/extension/base.php
+++ b/phpBB/phpbb/extension/base.php
@@ -24,7 +24,7 @@ class base implements \phpbb\extension\extension_interface
protected $container;
/** @var \phpbb\finder */
- protected $finder;
+ protected $extension_finder;
/** @var \phpbb\db\migrator */
protected $migrator;
@@ -73,9 +73,7 @@ class base implements \phpbb\extension\extension_interface
*/
public function enable_step($old_state)
{
- $migrations = $this->get_migration_file_list();
-
- $this->migrator->set_migrations($migrations);
+ $this->get_migration_file_list();
$this->migrator->update();
@@ -103,8 +101,6 @@ class base implements \phpbb\extension\extension_interface
{
$migrations = $this->get_migration_file_list();
- $this->migrator->set_migrations($migrations);
-
foreach ($migrations as $migration)
{
while ($this->migrator->migration_state($migration) !== false)
@@ -137,6 +133,10 @@ class base implements \phpbb\extension\extension_interface
$migrations = $this->extension_finder->get_classes_from_files($migrations);
+ $this->migrator->set_migrations($migrations);
+
+ $migrations = $this->migrator->get_migrations();
+
return $migrations;
}
}
diff --git a/phpBB/phpbb/extension/di/extension_base.php b/phpBB/phpbb/extension/di/extension_base.php
new file mode 100644
index 0000000000..ba74615e70
--- /dev/null
+++ b/phpBB/phpbb/extension/di/extension_base.php
@@ -0,0 +1,138 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\extension\di;
+
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+
+/**
+ * Container core extension
+ */
+class extension_base extends Extension
+{
+ /**
+ * Name of the extension (vendor/name)
+ *
+ * @var string
+ */
+ protected $extension_name;
+
+ /**
+ * Path to the extension.
+ *
+ * @var string
+ */
+ protected $ext_path;
+
+ /**
+ * Constructor
+ *
+ * @param string $extension_name Name of the extension (vendor/name)
+ * @param string $ext_path Path to the extension
+ */
+ public function __construct($extension_name, $ext_path)
+ {
+ $this->extension_name = $extension_name;
+ $this->ext_path = $ext_path;
+ }
+
+ /**
+ * Loads a specific configuration.
+ *
+ * @param array $configs An array of configuration values
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ *
+ * @throws \InvalidArgumentException When provided tag is not defined in this extension
+ */
+ public function load(array $configs, ContainerBuilder $container)
+ {
+ $this->load_services($container);
+ }
+
+ /**
+ * Loads the services.yml file.
+ *
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ */
+ protected function load_services(ContainerBuilder $container)
+ {
+ $services_directory = false;
+ $services_file = false;
+
+ if (file_exists($this->ext_path . 'config/' . $container->getParameter('core.environment') . '/container/environment.yml'))
+ {
+ $services_directory = $this->ext_path . 'config/' . $container->getParameter('core.environment') . '/container/';
+ $services_file = 'environment.yml';
+ }
+ else if (!is_dir($this->ext_path . 'config/' . $container->getParameter('core.environment')))
+ {
+ if (file_exists($this->ext_path . 'config/default/container/environment.yml'))
+ {
+ $services_directory = $this->ext_path . 'config/default/container/';
+ $services_file = 'environment.yml';
+ }
+ else if (!is_dir($this->ext_path . 'config/default') && file_exists($this->ext_path . '/config/services.yml'))
+ {
+ $services_directory = $this->ext_path . 'config';
+ $services_file = 'services.yml';
+ }
+ }
+
+ if ($services_directory && $services_file)
+ {
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $loader = new YamlFileLoader($container, new FileLocator($filesystem->realpath($services_directory)));
+ $loader->load($services_file);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getConfiguration(array $config, ContainerBuilder $container)
+ {
+ $reflected = new \ReflectionClass($this);
+ $namespace = $reflected->getNamespaceName();
+
+ $class = $namespace . '\\di\configuration';
+ if (class_exists($class))
+ {
+ $r = new \ReflectionClass($class);
+ $container->addResource(new FileResource($r->getFileName()));
+
+ if (!method_exists($class, '__construct'))
+ {
+ $configuration = new $class();
+
+ return $configuration;
+ }
+ }
+
+ }
+
+ /**
+ * Returns the recommended alias to use in XML.
+ *
+ * This alias is also the mandatory prefix to use when using YAML.
+ *
+ * @return string The alias
+ */
+ public function getAlias()
+ {
+ return str_replace('/', '_', $this->extension_name);
+ }
+}
diff --git a/phpBB/phpbb/extension/exception.php b/phpBB/phpbb/extension/exception.php
index 3f7d251a4e..9050449bf1 100644
--- a/phpBB/phpbb/extension/exception.php
+++ b/phpBB/phpbb/extension/exception.php
@@ -16,10 +16,6 @@ namespace phpbb\extension;
/**
* Exception class for metadata
*/
-class exception extends \UnexpectedValueException
+class exception extends \phpbb\exception\runtime_exception
{
- public function __toString()
- {
- return $this->getMessage();
- }
}
diff --git a/phpBB/phpbb/extension/manager.php b/phpBB/phpbb/extension/manager.php
index e7e5f83c23..4b4109bd85 100644
--- a/phpBB/phpbb/extension/manager.php
+++ b/phpBB/phpbb/extension/manager.php
@@ -13,6 +13,8 @@
namespace phpbb\extension;
+use phpbb\exception\runtime_exception;
+use phpbb\file_downloader;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -26,7 +28,6 @@ class manager
protected $db;
protected $config;
protected $cache;
- protected $user;
protected $php_ext;
protected $extensions;
protected $extension_table;
@@ -39,15 +40,14 @@ class manager
* @param ContainerInterface $container A container
* @param \phpbb\db\driver\driver_interface $db A database connection
* @param \phpbb\config\config $config Config object
- * @param \phpbb\filesystem $filesystem
- * @param \phpbb\user $user User object
+ * @param \phpbb\filesystem\filesystem_interface $filesystem
* @param string $extension_table The name of the table holding extensions
* @param string $phpbb_root_path Path to the phpbb includes directory.
* @param string $php_ext php file extension, defaults to php
- * @param \phpbb\cache\driver\driver_interface $cache A cache instance or null
+ * @param \phpbb\cache\service $cache A cache instance or null
* @param string $cache_name The name of the cache variable, defaults to _ext
*/
- public function __construct(ContainerInterface $container, \phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\filesystem $filesystem, \phpbb\user $user, $extension_table, $phpbb_root_path, $php_ext = 'php', \phpbb\cache\driver\driver_interface $cache = null, $cache_name = '_ext')
+ public function __construct(ContainerInterface $container, \phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\filesystem\filesystem_interface $filesystem, $extension_table, $phpbb_root_path, $php_ext = 'php', \phpbb\cache\service $cache = null, $cache_name = '_ext')
{
$this->cache = $cache;
$this->cache_name = $cache_name;
@@ -58,7 +58,6 @@ class manager
$this->filesystem = $filesystem;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
- $this->user = $user;
$this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false;
@@ -149,12 +148,16 @@ class manager
* Instantiates the metadata manager for the extension with the given name
*
* @param string $name The extension name
- * @param \phpbb\template\template $template The template manager or null
* @return \phpbb\extension\metadata_manager Instance of the metadata manager
*/
- public function create_extension_metadata_manager($name, \phpbb\template\template $template = null)
+ public function create_extension_metadata_manager($name)
{
- return new \phpbb\extension\metadata_manager($name, $this->config, $this, $template, $this->user, $this->phpbb_root_path);
+ if (!isset($this->extensions[$name]['metadata']))
+ {
+ $metadata = new \phpbb\extension\metadata_manager($name, $this->get_extension_path($name, true));
+ $this->extensions[$name]['metadata'] = $metadata;
+ }
+ return $this->extensions[$name]['metadata'];
}
/**
@@ -170,7 +173,7 @@ class manager
public function enable_step($name)
{
// ignore extensions that are already enabled
- if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'])
+ if ($this->is_enabled($name))
{
return false;
}
@@ -259,8 +262,8 @@ class manager
*/
public function disable_step($name)
{
- // ignore extensions that are already disabled
- if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active'])
+ // ignore extensions that are not enabled
+ if (!$this->is_enabled($name))
{
return false;
}
@@ -338,8 +341,8 @@ class manager
*/
public function purge_step($name)
{
- // ignore extensions that do not exist
- if (!isset($this->extensions[$name]))
+ // ignore extensions that are not configured
+ if (!$this->is_configured($name))
{
return false;
}
@@ -436,7 +439,7 @@ class manager
$ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name);
if ($this->is_available($ext_name))
{
- $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/';
+ $available[$ext_name] = $this->get_extension_path($ext_name, true);
}
}
}
@@ -450,34 +453,41 @@ class manager
* All enabled and disabled extensions are considered configured. A purged
* extension that is no longer in the database is not configured.
*
+ * @param bool $phpbb_relative Whether the path should be relative to phpbb root
+ *
* @return array An array with extension names as keys and and the
* database stored extension information as values
*/
- public function all_configured()
+ public function all_configured($phpbb_relative = true)
{
$configured = array();
foreach ($this->extensions as $name => $data)
{
- $data['ext_path'] = $this->phpbb_root_path . $data['ext_path'];
- $configured[$name] = $data;
+ if ($this->is_configured($name))
+ {
+ unset($data['metadata']);
+ $data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
+ $configured[$name] = $data;
+ }
}
return $configured;
}
/**
* Retrieves all enabled extensions.
+ * @param bool $phpbb_relative Whether the path should be relative to phpbb root
*
* @return array An array with extension names as keys and and the
* database stored extension information as values
*/
- public function all_enabled()
+ public function all_enabled($phpbb_relative = true)
{
$enabled = array();
foreach ($this->extensions as $name => $data)
{
- if ($data['ext_active'])
+ if ($this->is_enabled($name))
{
- $enabled[$name] = $this->phpbb_root_path . $data['ext_path'];
+ $enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
}
}
return $enabled;
@@ -486,17 +496,19 @@ class manager
/**
* Retrieves all disabled extensions.
*
+ * @param bool $phpbb_relative Whether the path should be relative to phpbb root
+ *
* @return array An array with extension names as keys and and the
* database stored extension information as values
*/
- public function all_disabled()
+ public function all_disabled($phpbb_relative = true)
{
$disabled = array();
foreach ($this->extensions as $name => $data)
{
- if (!$data['ext_active'])
+ if ($this->is_disabled($name))
{
- $disabled[$name] = $this->phpbb_root_path . $data['ext_path'];
+ $disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
}
}
return $disabled;
@@ -529,7 +541,7 @@ class manager
*/
public function is_enabled($name)
{
- return isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'];
+ return isset($this->extensions[$name]['ext_active']) && $this->extensions[$name]['ext_active'];
}
/**
@@ -540,7 +552,7 @@ class manager
*/
public function is_disabled($name)
{
- return isset($this->extensions[$name]) && !$this->extensions[$name]['ext_active'];
+ return isset($this->extensions[$name]['ext_active']) && !$this->extensions[$name]['ext_active'];
}
/**
@@ -554,7 +566,36 @@ class manager
*/
public function is_configured($name)
{
- return isset($this->extensions[$name]);
+ return isset($this->extensions[$name]['ext_active']);
+ }
+
+ /**
+ * Check the version and return the available updates (for an extension).
+ *
+ * @param \phpbb\extension\metadata_manager $md_manager The metadata manager for the version to check.
+ * @param bool $force_update Ignores cached data. Defaults to false.
+ * @param bool $force_cache Force the use of the cache. Override $force_update.
+ * @param string $stability Force the stability (null by default).
+ * @return array
+ * @throws runtime_exception
+ */
+ public function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false, $stability = null)
+ {
+ $meta = $md_manager->get_metadata('all');
+
+ if (!isset($meta['extra']['version-check']))
+ {
+ throw new runtime_exception('NO_VERSIONCHECK');
+ }
+
+ $version_check = $meta['extra']['version-check'];
+
+ $version_helper = new \phpbb\version_helper($this->cache, $this->config, new file_downloader());
+ $version_helper->set_current_version($meta['version']);
+ $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename'], isset($version_check['ssl']) ? $version_check['ssl'] : false);
+ $version_helper->force_stability($stability);
+
+ return $version_helper->get_ext_update_on_branch($force_update, $force_cache);
}
/**
diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php
index a09f07bed2..60b8db8310 100644
--- a/phpBB/phpbb/extension/metadata_manager.php
+++ b/phpBB/phpbb/extension/metadata_manager.php
@@ -19,36 +19,6 @@ namespace phpbb\extension;
class metadata_manager
{
/**
- * phpBB Config instance
- * @var \phpbb\config\config
- */
- protected $config;
-
- /**
- * phpBB Extension Manager
- * @var \phpbb\extension\manager
- */
- protected $extension_manager;
-
- /**
- * phpBB Template instance
- * @var \phpbb\template\template
- */
- protected $template;
-
- /**
- * phpBB User instance
- * @var \phpbb\user
- */
- protected $user;
-
- /**
- * phpBB root path
- * @var string
- */
- protected $phpbb_root_path;
-
- /**
* Name (including vendor) of the extension
* @var string
*/
@@ -66,30 +36,18 @@ class metadata_manager
*/
protected $metadata_file;
- // @codingStandardsIgnoreStart
/**
* Creates the metadata manager
*
* @param string $ext_name Name (including vendor) of the extension
- * @param \phpbb\config\config $config phpBB Config instance
- * @param \phpbb\extension\manager $extension_manager An instance of the phpBB extension manager
- * @param \phpbb\template\template $template phpBB Template instance or null
- * @param \phpbb\user $user User instance
- * @param string $phpbb_root_path Path to the phpbb includes directory.
+ * @param string $ext_path Path to the extension directory including root path
*/
- public function __construct($ext_name, \phpbb\config\config $config, \phpbb\extension\manager $extension_manager, \phpbb\template\template $template = null, \phpbb\user $user, $phpbb_root_path)
+ public function __construct($ext_name, $ext_path)
{
- $this->config = $config;
- $this->extension_manager = $extension_manager;
- $this->template = $template;
- $this->user = $user;
- $this->phpbb_root_path = $phpbb_root_path;
-
$this->ext_name = $ext_name;
$this->metadata = array();
- $this->metadata_file = '';
+ $this->metadata_file = $ext_path . 'composer.json';
}
- // @codingStandardsIgnoreEnd
/**
* Processes and gets the metadata requested
@@ -100,7 +58,7 @@ class metadata_manager
public function get_metadata($element = 'all')
{
// Fetch and clean the metadata if not done yet
- if ($this->metadata_file === '')
+ if ($this->metadata === array())
{
$this->fetch_metadata_from_file();
}
@@ -126,30 +84,25 @@ class metadata_manager
}
/**
- * Sets the path of the metadata file, gets its contents and cleans loaded file
+ * Gets the metadata file contents and cleans loaded file
*
* @throws \phpbb\extension\exception
*/
private function fetch_metadata_from_file()
{
- $ext_filepath = $this->extension_manager->get_extension_path($this->ext_name);
- $metadata_filepath = $this->phpbb_root_path . $ext_filepath . 'composer.json';
-
- $this->metadata_file = $metadata_filepath;
-
if (!file_exists($this->metadata_file))
{
- throw new \phpbb\extension\exception($this->user->lang('FILE_NOT_FOUND', $this->metadata_file));
+ throw new \phpbb\extension\exception('FILE_NOT_FOUND', array($this->metadata_file));
}
if (!($file_contents = file_get_contents($this->metadata_file)))
{
- throw new \phpbb\extension\exception($this->user->lang('FILE_CONTENT_ERR', $this->metadata_file));
+ throw new \phpbb\extension\exception('FILE_CONTENT_ERR', array($this->metadata_file));
}
if (($metadata = json_decode($file_contents, true)) === null)
{
- throw new \phpbb\extension\exception($this->user->lang('FILE_JSON_DECODE_ERR', $this->metadata_file));
+ throw new \phpbb\extension\exception('FILE_JSON_DECODE_ERR', array($this->metadata_file));
}
array_walk_recursive($metadata, array($this, 'sanitize_json'));
@@ -190,7 +143,7 @@ class metadata_manager
{
case 'all':
$this->validate_enable();
- // no break
+ // no break
case 'display':
foreach ($fields as $field => $data)
@@ -206,12 +159,12 @@ class metadata_manager
{
if (!isset($this->metadata[$name]))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', $name));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array($name));
}
if (!preg_match($fields[$name], $this->metadata[$name]))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_INVALID', $name));
+ throw new \phpbb\extension\exception('META_FIELD_INVALID', array($name));
}
}
break;
@@ -230,14 +183,14 @@ class metadata_manager
{
if (empty($this->metadata['authors']))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'authors'));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('authors'));
}
foreach ($this->metadata['authors'] as $author)
{
if (!isset($author['name']))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'author name'));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('author name'));
}
}
@@ -266,7 +219,7 @@ class metadata_manager
{
if (substr_count($this->ext_name, '/') !== 1 || $this->ext_name != $this->get_metadata('name'))
{
- throw new \phpbb\extension\exception($this->user->lang('EXTENSION_DIR_INVALID'));
+ throw new \phpbb\extension\exception('EXTENSION_DIR_INVALID');
}
return true;
@@ -283,7 +236,7 @@ class metadata_manager
{
if (!isset($this->metadata['extra']['soft-require']['phpbb/phpbb']))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'soft-require'));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('soft-require'));
}
return true;
@@ -299,45 +252,9 @@ class metadata_manager
{
if (!isset($this->metadata['require']['php']))
{
- throw new \phpbb\extension\exception($this->user->lang('META_FIELD_NOT_SET', 'require php'));
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array('require php'));
}
return true;
}
-
- /**
- * Outputs the metadata into the template
- *
- * @return null
- */
- public function output_template_data()
- {
- $this->template->assign_vars(array(
- 'META_NAME' => $this->metadata['name'],
- 'META_TYPE' => $this->metadata['type'],
- 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? $this->metadata['description'] : '',
- 'META_HOMEPAGE' => (isset($this->metadata['homepage'])) ? $this->metadata['homepage'] : '',
- 'META_VERSION' => (isset($this->metadata['version'])) ? $this->metadata['version'] : '',
- 'META_TIME' => (isset($this->metadata['time'])) ? $this->metadata['time'] : '',
- 'META_LICENSE' => $this->metadata['license'],
-
- 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? $this->metadata['require']['php'] : '',
- 'META_REQUIRE_PHP_FAIL' => (isset($this->metadata['require']['php'])) ? false : true,
-
- 'META_REQUIRE_PHPBB' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? $this->metadata['extra']['soft-require']['phpbb/phpbb'] : '',
- 'META_REQUIRE_PHPBB_FAIL' => (isset($this->metadata['extra']['soft-require']['phpbb/phpbb'])) ? false : true,
-
- 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? $this->metadata['extra']['display-name'] : '',
- ));
-
- foreach ($this->metadata['authors'] as $author)
- {
- $this->template->assign_block_vars('meta_authors', array(
- 'AUTHOR_NAME' => $author['name'],
- 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '',
- 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '',
- 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '',
- ));
- }
- }
}
diff --git a/phpBB/phpbb/feed/attachments_base.php b/phpBB/phpbb/feed/attachments_base.php
index df8f29a626..5d3272e0d9 100644
--- a/phpBB/phpbb/feed/attachments_base.php
+++ b/phpBB/phpbb/feed/attachments_base.php
@@ -16,7 +16,7 @@ namespace phpbb\feed;
/**
* Abstract class for feeds displaying attachments
*/
-abstract class attachments_base extends \phpbb\feed\base
+abstract class attachments_base extends base
{
/**
* Attachments that may be displayed
diff --git a/phpBB/phpbb/feed/base.php b/phpBB/phpbb/feed/base.php
index eeea0a55df..d4be0dc592 100644
--- a/phpBB/phpbb/feed/base.php
+++ b/phpBB/phpbb/feed/base.php
@@ -1,27 +1,27 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* Base class with some generic functions and settings.
-*/
-abstract class base
+ * Base class with some generic functions and settings.
+ */
+abstract class base implements feed_interface
{
/**
- * Feed helper object
- * @var \phpbb\feed\helper
- */
+ * Feed helper object
+ * @var \phpbb\feed\helper
+ */
protected $helper;
/** @var \phpbb\config\config */
@@ -49,47 +49,47 @@ abstract class base
protected $phpEx;
/**
- * SQL Query to be executed to get feed items
- */
- var $sql = array();
+ * SQL Query to be executed to get feed items
+ */
+ protected $sql = array();
/**
- * Keys specified for retrieval of title, content, etc.
- */
- var $keys = array();
+ * Keys specified for retrieval of title, content, etc.
+ */
+ protected $keys = array();
/**
- * Number of items to fetch. Usually overwritten by $config['feed_something']
- */
- var $num_items = 15;
+ * Number of items to fetch. Usually overwritten by $config['feed_something']
+ */
+ protected $num_items = 15;
/**
- * Separator for title elements to separate items (for example forum / topic)
- */
- var $separator = "\xE2\x80\xA2"; // &bull;
+ * Separator for title elements to separate items (for example forum / topic)
+ */
+ protected $separator = "\xE2\x80\xA2"; // &bull;
/**
- * Separator for the statistics row (Posted by, post date, replies, etc.)
- */
- var $separator_stats = "\xE2\x80\x94"; // &mdash;
+ * Separator for the statistics row (Posted by, post date, replies, etc.)
+ */
+ protected $separator_stats = "\xE2\x80\x94"; // &mdash;
/** @var mixed Query result handle */
protected $result;
/**
- * Constructor
- *
- * @param \phpbb\feed\helper $helper Feed helper
- * @param \phpbb\config\config $config Config object
- * @param \phpbb\db\driver\driver_interface $db Database connection
- * @param \phpbb\cache\driver\driver_interface $cache Cache object
- * @param \phpbb\user $user User object
- * @param \phpbb\auth\auth $auth Auth object
- * @param \phpbb\content_visibility $content_visibility Content visibility object
- * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object
- * @param string $phpEx php file extension
- */
- function __construct(
+ * Constructor
+ *
+ * @param \phpbb\feed\helper $helper Feed helper
+ * @param \phpbb\config\config $config Config object
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param \phpbb\cache\driver\driver_interface $cache Cache object
+ * @param \phpbb\user $user User object
+ * @param \phpbb\auth\auth $auth Auth object
+ * @param \phpbb\content_visibility $content_visibility Auth object
+ * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object
+ * @param string $phpEx php file extension
+ */
+ public function __construct(
\phpbb\feed\helper $helper,
\phpbb\config\config $config,
\phpbb\db\driver\driver_interface $db,
@@ -127,23 +127,23 @@ abstract class base
}
/**
- * Set keys.
- */
- function set_keys()
+ * {@inheritdoc}
+ */
+ public function set_keys()
{
}
/**
- * Open feed
- */
- function open()
+ * {@inheritdoc}
+ */
+ public function open()
{
}
/**
- * Close feed
- */
- function close()
+ * {@inheritdoc}
+ */
+ public function close()
{
if (!empty($this->result))
{
@@ -152,28 +152,62 @@ abstract class base
}
/**
- * Set key
- *
- * @param string $key Key
- * @param mixed $value Value
- */
- function set($key, $value)
+ * {@inheritdoc}
+ */
+ public function set($key, $value)
{
$this->keys[$key] = $value;
}
/**
- * Get key
- *
- * @param string $key Key
- * @return mixed
- */
- function get($key)
+ * {@inheritdoc}
+ */
+ public function get($key)
{
return (isset($this->keys[$key])) ? $this->keys[$key] : null;
}
- function get_readable_forums()
+ /**
+ * {@inheritdoc}
+ */
+ public function get_item()
+ {
+ if (!isset($this->result))
+ {
+ if (!$this->get_sql())
+ {
+ return false;
+ }
+
+ $sql_ary = $this->sql;
+
+ /**
+ * Event to modify the feed item sql
+ *
+ * @event core.feed_base_modify_item_sql
+ * @var array sql_ary The SQL array to get the feed item data
+ *
+ * @since 3.1.10-RC1
+ */
+ $vars = array('sql_ary');
+ extract($this->phpbb_dispatcher->trigger_event('core.feed_base_modify_item_sql', compact($vars)));
+ $this->sql = $sql_ary;
+ unset($sql_ary);
+
+ // Query database
+ $sql = $this->db->sql_build_query('SELECT', $this->sql);
+ $this->result = $this->db->sql_query_limit($sql, $this->num_items);
+ }
+
+ return $this->db->sql_fetchrow($this->result);
+ }
+
+ /**
+ * Returns the ids of the forums readable by the current user.
+ *
+ * @return int[]
+ */
+ protected function get_readable_forums()
{
static $forum_ids;
@@ -185,7 +219,12 @@ abstract class base
return $forum_ids;
}
- function get_moderator_approve_forums()
+ /**
+ * Returns the ids of the forum for which the current user can approve the post in the moderation queue.
+ *
+ * @return int[]
+ */
+ protected function get_moderator_approve_forums()
{
static $forum_ids;
@@ -197,7 +236,13 @@ abstract class base
return $forum_ids;
}
- function is_moderator_approve_forum($forum_id)
+ /**
+ * Returns true if the current user can approve the post of the given forum
+ *
+ * @param int $forum_id Forum id to check
+ * @return bool
+ */
+ protected function is_moderator_approve_forum($forum_id)
{
static $forum_ids;
@@ -209,7 +254,12 @@ abstract class base
return (isset($forum_ids[$forum_id])) ? true : false;
}
- function get_excluded_forums()
+ /**
+ * Returns the ids of the forum excluded from the feeds
+ *
+ * @return int[]
+ */
+ protected function get_excluded_forums()
{
static $forum_ids;
@@ -236,51 +286,35 @@ abstract class base
return $forum_ids;
}
- function is_excluded_forum($forum_id)
+ /**
+ * Returns true if the given id is in the excluded forums list.
+ *
+ * @param int $forum_id Id to check
+ * @return bool
+ */
+ protected function is_excluded_forum($forum_id)
{
$forum_ids = $this->get_excluded_forums();
return isset($forum_ids[$forum_id]) ? true : false;
}
- function get_passworded_forums()
+ /**
+ * Returns all password protected forum ids the current user is currently NOT authenticated for.
+ *
+ * @return array Array of forum ids
+ */
+ protected function get_passworded_forums()
{
return $this->user->get_passworded_forums();
}
- function get_item()
- {
- if (!isset($this->result))
- {
- if (!$this->get_sql())
- {
- return false;
- }
-
- $sql_ary = $this->sql;
-
- /**
- * Event to modify the feed item sql
- *
- * @event core.feed_base_modify_item_sql
- * @var array sql_ary The SQL array to get the feed item data
- *
- * @since 3.1.10-RC1
- */
- $vars = array('sql_ary');
- extract($this->phpbb_dispatcher->trigger_event('core.feed_base_modify_item_sql', compact($vars)));
- $this->sql = $sql_ary;
- unset($sql_ary);
-
- // Query database
- $sql = $this->db->sql_build_query('SELECT', $this->sql);
- $this->result = $this->db->sql_query_limit($sql, $this->num_items);
- }
-
- return $this->db->sql_fetchrow($this->result);
- }
-
- function user_viewprofile($row)
+ /**
+ * Returns the link to the user profile.
+ *
+ * @return string
+ */
+ protected function user_viewprofile($row)
{
$author_id = (int) $row[$this->get('author_id')];
@@ -293,4 +327,11 @@ abstract class base
return '<a href="' . $this->helper->append_sid('memberlist.' . $this->phpEx, 'mode=viewprofile&amp;u=' . $author_id) . '">' . $row[$this->get('creator')] . '</a>';
}
+
+ /**
+ * Returns the SQL query used to retrieve the posts of the feed.
+ *
+ * @return string SQL SELECT query
+ */
+ protected abstract function get_sql();
}
diff --git a/phpBB/phpbb/feed/controller/feed.php b/phpBB/phpbb/feed/controller/feed.php
new file mode 100644
index 0000000000..c0d7bc72ec
--- /dev/null
+++ b/phpBB/phpbb/feed/controller/feed.php
@@ -0,0 +1,411 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\feed\controller;
+
+use phpbb\auth\auth;
+use phpbb\config\config;
+use phpbb\db\driver\driver_interface;
+use \phpbb\event\dispatcher_interface;
+use phpbb\exception\http_exception;
+use phpbb\feed\feed_interface;
+use phpbb\feed\exception\feed_unavailable_exception;
+use phpbb\feed\exception\unauthorized_exception;
+use phpbb\feed\helper as feed_helper;
+use phpbb\controller\helper as controller_helper;
+use phpbb\symfony_request;
+use phpbb\user;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+class feed
+{
+ /**
+ * @var \Twig_Environment
+ */
+ protected $template;
+
+ /**
+ * @var symfony_request
+ */
+ protected $request;
+
+ /**
+ * @var controller_helper
+ */
+ protected $controller_helper;
+
+ /**
+ * @var config
+ */
+ protected $config;
+
+ /**
+ * @var driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var ContainerInterface
+ */
+ protected $container;
+
+ /**
+ * @var feed_helper
+ */
+ protected $feed_helper;
+
+ /**
+ * @var user
+ */
+ protected $user;
+
+ /**
+ * @var auth
+ */
+ protected $auth;
+
+ /**
+ * @var dispatcher_interface
+ */
+ protected $phpbb_dispatcher;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \Twig_Environment $twig
+ * @param symfony_request $request
+ * @param controller_helper $controller_helper
+ * @param config $config
+ * @param driver_interface $db
+ * @param ContainerInterface $container
+ * @param feed_helper $feed_helper
+ * @param user $user
+ * @param auth $auth
+ * @param dispatcher_interface $phpbb_dispatcher
+ * @param string $php_ext
+ */
+ public function __construct(\Twig_Environment $twig, symfony_request $request, controller_helper $controller_helper, config $config, driver_interface $db, ContainerInterface $container, feed_helper $feed_helper, user $user, auth $auth, dispatcher_interface $phpbb_dispatcher, $php_ext)
+ {
+ $this->request = $request;
+ $this->controller_helper = $controller_helper;
+ $this->config = $config;
+ $this->db = $db;
+ $this->container = $container;
+ $this->feed_helper = $feed_helper;
+ $this->user = $user;
+ $this->auth = $auth;
+ $this->php_ext = $php_ext;
+ $this->template = $twig;
+ $this->phpbb_dispatcher = $phpbb_dispatcher;
+ }
+
+ /**
+ * Controller for /feed/forums route
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function forums()
+ {
+ if (!$this->config['feed_overall_forums'])
+ {
+ $this->send_unavailable();
+ }
+
+ return $this->send_feed($this->container->get('feed.forums'));
+ }
+
+ /**
+ * Controller for /feed/news route
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function news()
+ {
+ // Get at least one news forum
+ $sql = 'SELECT forum_id
+ FROM ' . FORUMS_TABLE . '
+ WHERE ' . $this->db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0');
+ $result = $this->db->sql_query_limit($sql, 1, 0, 600);
+ $s_feed_news = (int) $this->db->sql_fetchfield('forum_id');
+ $this->db->sql_freeresult($result);
+
+ if (!$s_feed_news)
+ {
+ $this->send_unavailable();
+ }
+
+ return $this->send_feed($this->container->get('feed.news'));
+ }
+
+ /**
+ * Controller for /feed/topics route
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function topics()
+ {
+ if (!$this->config['feed_topics_new'])
+ {
+ $this->send_unavailable();
+ }
+
+ return $this->send_feed($this->container->get('feed.topics'));
+ }
+
+ /**
+ * Controller for /feed/topics_new route
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function topics_new()
+ {
+ return $this->topics();
+ }
+
+ /**
+ * Controller for /feed/topics_active route
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function topics_active()
+ {
+ if (!$this->config['feed_topics_active'])
+ {
+ $this->send_unavailable();
+ }
+
+ return $this->send_feed($this->container->get('feed.topics_active'));
+ }
+
+ /**
+ * Controller for /feed/forum/{forum_id} route
+ *
+ * @param int $forum_id
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function forum($forum_id)
+ {
+ if (!$this->config['feed_forum'])
+ {
+ $this->send_unavailable();
+ }
+
+ return $this->send_feed($this->container->get('feed.forum')->set_forum_id($forum_id));
+ }
+
+ /**
+ * Controller for /feed/topic/{topic_id} route
+ *
+ * @param int $topic_id
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function topic($topic_id)
+ {
+ if (!$this->config['feed_topic'])
+ {
+ $this->send_unavailable();
+ }
+
+ return $this->send_feed($this->container->get('feed.topic')->set_topic_id($topic_id));
+ }
+
+ /**
+ * Controller for /feed/{mode] route
+ *
+ * @return Response
+ *
+ * @throws http_exception when the feed is disabled
+ */
+ public function overall()
+ {
+ if (!$this->config['feed_overall'])
+ {
+ $this->send_unavailable();
+ }
+
+ return $this->send_feed($this->container->get('feed.overall'));
+ }
+
+ /**
+ * Display a given feed
+ *
+ * @param feed_interface $feed
+ *
+ * @return Response
+ */
+ protected function send_feed(feed_interface $feed)
+ {
+ try
+ {
+ return $this->send_feed_do($feed);
+ }
+ catch (feed_unavailable_exception $e)
+ {
+ throw new http_exception(Response::HTTP_NOT_FOUND, $e->getMessage(), $e->get_parameters(), $e);
+ }
+ catch (unauthorized_exception $e)
+ {
+ throw new http_exception(Response::HTTP_FORBIDDEN, $e->getMessage(), $e->get_parameters(), $e);
+ }
+ }
+
+ /**
+ * Really send the feed
+ *
+ * @param feed_interface $feed
+ *
+ * @return Response
+ *
+ * @throw exception\feed_exception
+ */
+ protected function send_feed_do(feed_interface $feed)
+ {
+ $feed_updated_time = 0;
+ $item_vars = array();
+
+ $board_url = $this->feed_helper->get_board_url();
+
+ // Open Feed
+ $feed->open();
+
+ // Iterate through items
+ while ($row = $feed->get_item())
+ {
+ /**
+ * Event to modify the feed row
+ *
+ * @event core.feed_modify_feed_row
+ * @var int forum_id Forum ID
+ * @var string mode Feeds mode (forums|topics|topics_new|topics_active|news)
+ * @var array row Array with feed data
+ * @var int topic_id Topic ID
+ *
+ * @since 3.1.10-RC1
+ */
+ $vars = array('forum_id', 'mode', 'row', 'topic_id');
+ extract($this->phpbb_dispatcher->trigger_event('core.feed_modify_feed_row', compact($vars)));
+
+ // BBCode options to correctly disable urls, smilies, bbcode...
+ if ($feed->get('options') === null)
+ {
+ // Allow all combinations
+ $options = 7;
+
+ if ($feed->get('enable_bbcode') !== null && $feed->get('enable_smilies') !== null && $feed->get('enable_magic_url') !== null)
+ {
+ $options = (($row[$feed->get('enable_bbcode')]) ? OPTION_FLAG_BBCODE : 0) + (($row[$feed->get('enable_smilies')]) ? OPTION_FLAG_SMILIES : 0) + (($row[$feed->get('enable_magic_url')]) ? OPTION_FLAG_LINKS : 0);
+ }
+ }
+ else
+ {
+ $options = $row[$feed->get('options')];
+ }
+
+ $title = (isset($row[$feed->get('title')]) && $row[$feed->get('title')] !== '') ? $row[$feed->get('title')] : ((isset($row[$feed->get('title2')])) ? $row[$feed->get('title2')] : '');
+
+ $published = ($feed->get('published') !== null) ? (int) $row[$feed->get('published')] : 0;
+ $updated = ($feed->get('updated') !== null) ? (int) $row[$feed->get('updated')] : 0;
+
+ $display_attachments = ($this->auth->acl_get('u_download') && $this->auth->acl_get('f_download', $row['forum_id']) && isset($row['post_attachment']) && $row['post_attachment']) ? true : false;
+
+ $item_row = array(
+ 'author' => ($feed->get('creator') !== null) ? $row[$feed->get('creator')] : '',
+ 'published' => ($published > 0) ? $this->feed_helper->format_date($published) : '',
+ 'updated' => ($updated > 0) ? $this->feed_helper->format_date($updated) : '',
+ 'link' => '',
+ 'title' => censor_text($title),
+ 'category' => ($this->config['feed_item_statistics'] && !empty($row['forum_id'])) ? $board_url . '/viewforum.' . $this->php_ext . '?f=' . $row['forum_id'] : '',
+ 'category_name' => ($this->config['feed_item_statistics'] && isset($row['forum_name'])) ? $row['forum_name'] : '',
+ 'description' => censor_text($this->feed_helper->generate_content($row[$feed->get('text')], $row[$feed->get('bbcode_uid')], $row[$feed->get('bitfield')], $options, $row['forum_id'], ($display_attachments ? $feed->get_attachments($row['post_id']) : array()))),
+ 'statistics' => '',
+ );
+
+ // Adjust items, fill link, etc.
+ $feed->adjust_item($item_row, $row);
+
+ $item_vars[] = $item_row;
+
+ $feed_updated_time = max($feed_updated_time, $published, $updated);
+ }
+
+ // If we do not have any items at all, sending the current time is better than sending no time.
+ if (!$feed_updated_time)
+ {
+ $feed_updated_time = time();
+ }
+
+ $feed->close();
+
+ $content = $this->template->render('feed.xml.twig', array(
+ // Some default assignments
+ // FEED_IMAGE is not used (atom)
+ 'FEED_IMAGE' => '',
+ 'SELF_LINK' => $this->controller_helper->route($this->request->attributes->get('_route'), $this->request->attributes->get('_route_params'), true, '', UrlGeneratorInterface::ABSOLUTE_URL),
+ 'FEED_LINK' => $board_url . '/index.' . $this->php_ext,
+ 'FEED_TITLE' => $this->config['sitename'],
+ 'FEED_SUBTITLE' => $this->config['site_desc'],
+ 'FEED_UPDATED' => $this->feed_helper->format_date($feed_updated_time),
+ 'FEED_LANG' => $this->user->lang['USER_LANG'],
+ 'FEED_AUTHOR' => $this->config['sitename'],
+
+ // Feed entries
+ 'FEED_ROWS' => $item_vars,
+ ));
+
+ $response = new Response($content);
+ $response->headers->set('Content-Type', 'application/atom+xml');
+ $response->setCharset('UTF-8');
+ $response->setLastModified(new \DateTime('@' . $feed_updated_time));
+
+ if (!empty($this->user->data['is_bot']))
+ {
+ // Let reverse proxies know we detected a bot.
+ $response->headers->set('X-PHPBB-IS-BOT', 'yes');
+ }
+
+ return $response;
+ }
+
+ /**
+ * Throw and exception saying that the feed isn't available
+ *
+ * @throw http_exception
+ */
+ protected function send_unavailable()
+ {
+ throw new http_exception(404, 'FEATURE_NOT_AVAILABLE');
+ }
+}
diff --git a/phpBB/phpbb/feed/exception/feed_exception.php b/phpBB/phpbb/feed/exception/feed_exception.php
new file mode 100644
index 0000000000..c9c888211e
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/feed_exception.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+use phpbb\exception\runtime_exception;
+
+abstract class feed_exception extends runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/feed/exception/feed_unavailable_exception.php b/phpBB/phpbb/feed/exception/feed_unavailable_exception.php
new file mode 100644
index 0000000000..4b6605b47d
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/feed_unavailable_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+abstract class feed_unavailable_exception extends feed_exception
+{
+
+}
diff --git a/phpBB/phpbb/feed/exception/no_feed_exception.php b/phpBB/phpbb/feed/exception/no_feed_exception.php
new file mode 100644
index 0000000000..af6357b74c
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/no_feed_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+class no_feed_exception extends feed_unavailable_exception
+{
+ public function __construct(\Exception $previous = null, $code = 0)
+ {
+ parent::__construct('NO_FEED', array(), $previous, $code);
+ }
+}
diff --git a/phpBB/phpbb/feed/exception/no_forum_exception.php b/phpBB/phpbb/feed/exception/no_forum_exception.php
new file mode 100644
index 0000000000..a60832957a
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/no_forum_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+class no_forum_exception extends feed_unavailable_exception
+{
+ public function __construct($forum_id, \Exception $previous = null, $code = 0)
+ {
+ parent::__construct('NO_FORUM', array($forum_id), $previous, $code);
+ }
+}
diff --git a/phpBB/phpbb/feed/exception/no_topic_exception.php b/phpBB/phpbb/feed/exception/no_topic_exception.php
new file mode 100644
index 0000000000..b961a65d1c
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/no_topic_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+class no_topic_exception extends feed_unavailable_exception
+{
+ public function __construct($topic_id, \Exception $previous = null, $code = 0)
+ {
+ parent::__construct('NO_TOPIC', array($topic_id), $previous, $code);
+ }
+}
diff --git a/phpBB/phpbb/feed/exception/unauthorized_exception.php b/phpBB/phpbb/feed/exception/unauthorized_exception.php
new file mode 100644
index 0000000000..7868975779
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/unauthorized_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+abstract class unauthorized_exception extends feed_exception
+{
+
+}
diff --git a/phpBB/phpbb/feed/exception/unauthorized_forum_exception.php b/phpBB/phpbb/feed/exception/unauthorized_forum_exception.php
new file mode 100644
index 0000000000..4384c7b39b
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/unauthorized_forum_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+class unauthorized_forum_exception extends unauthorized_exception
+{
+ public function __construct($forum_id, \Exception $previous = null, $code = 0)
+ {
+ parent::__construct('SORRY_AUTH_READ', array($forum_id), $previous, $code);
+ }
+}
diff --git a/phpBB/phpbb/feed/exception/unauthorized_topic_exception.php b/phpBB/phpbb/feed/exception/unauthorized_topic_exception.php
new file mode 100644
index 0000000000..f49f0a0476
--- /dev/null
+++ b/phpBB/phpbb/feed/exception/unauthorized_topic_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed\exception;
+
+class unauthorized_topic_exception extends unauthorized_exception
+{
+ public function __construct($topic_id, \Exception $previous = null, $code = 0)
+ {
+ parent::__construct('SORRY_AUTH_READ_TOPIC', array($topic_id), $previous, $code);
+ }
+}
diff --git a/phpBB/phpbb/feed/factory.php b/phpBB/phpbb/feed/factory.php
deleted file mode 100644
index f364f06d03..0000000000
--- a/phpBB/phpbb/feed/factory.php
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\feed;
-
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
-* Factory class to return correct object
-*/
-class factory
-{
- /**
- * Service container object
- * @var ContainerInterface
- */
- protected $container;
-
- /** @var \phpbb\config\config */
- protected $config;
-
- /** @var \phpbb\db\driver\driver_interface */
- protected $db;
-
- /**
- * Constructor
- *
- * @param ContainerInterface $container Container object
- * @param \phpbb\config\config $config Config object
- * @param \phpbb\db\driver\driver_interface $db Database connection
- */
- public function __construct(ContainerInterface $container, \phpbb\config\config $config, \phpbb\db\driver\driver_interface $db)
- {
- $this->container = $container;
- $this->config = $config;
- $this->db = $db;
- }
-
- /**
- * Return correct object for specified mode
- *
- * @param string $mode The feeds mode.
- * @param int $forum_id Forum id specified by the script if forum feed provided.
- * @param int $topic_id Topic id specified by the script if topic feed provided.
- *
- * @return object Returns correct feeds object for specified mode.
- */
- function get_feed($mode, $forum_id, $topic_id)
- {
- switch ($mode)
- {
- case 'forums':
- if (!$this->config['feed_overall_forums'])
- {
- return false;
- }
-
- return $this->container->get('feed.forums');
- break;
-
- case 'topics':
- case 'topics_new':
- if (!$this->config['feed_topics_new'])
- {
- return false;
- }
-
- return $this->container->get('feed.topics');
- break;
-
- case 'topics_active':
- if (!$this->config['feed_topics_active'])
- {
- return false;
- }
-
- return $this->container->get('feed.topics_active');
- break;
-
- case 'news':
- // Get at least one news forum
- $sql = 'SELECT forum_id
- FROM ' . FORUMS_TABLE . '
- WHERE ' . $this->db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0');
- $result = $this->db->sql_query_limit($sql, 1, 0, 600);
- $s_feed_news = (int) $this->db->sql_fetchfield('forum_id');
- $this->db->sql_freeresult($result);
-
- if (!$s_feed_news)
- {
- return false;
- }
-
- return $this->container->get('feed.news');
- break;
-
- default:
- if ($topic_id && $this->config['feed_topic'])
- {
- return $this->container->get('feed.topic')
- ->set_topic_id($topic_id);
- }
- else if ($forum_id && $this->config['feed_forum'])
- {
- return $this->container->get('feed.forum')
- ->set_forum_id($forum_id);
- }
- else if ($this->config['feed_overall'])
- {
- return $this->container->get('feed.overall');
- }
-
- return false;
- break;
- }
- }
-}
diff --git a/phpBB/phpbb/feed/feed_interface.php b/phpBB/phpbb/feed/feed_interface.php
new file mode 100644
index 0000000000..c185cd249c
--- /dev/null
+++ b/phpBB/phpbb/feed/feed_interface.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed;
+
+/**
+ * Interface implemented by all feeds types
+ */
+interface feed_interface
+{
+ /**
+ * Set keys.
+ */
+ public function set_keys();
+
+ /**
+ * Open feed
+ */
+ public function open();
+
+ /**
+ * Close feed
+ */
+ public function close();
+
+ /**
+ * Set key
+ *
+ * @param string $key Key
+ * @param mixed $value Value
+ */
+ public function set($key, $value);
+
+ /**
+ * Get key
+ *
+ * @param string $key Key
+ * @return mixed
+ */
+ public function get($key);
+
+ /**
+ * Get the next post in the feed
+ *
+ * @return array
+ */
+ public function get_item();
+
+ /**
+ * Adjust a feed entry
+ *
+ * @param $item_row
+ * @param $row
+ * @return array
+ */
+ public function adjust_item(&$item_row, &$row);
+}
diff --git a/phpBB/phpbb/feed/forum.php b/phpBB/phpbb/feed/forum.php
index 6aba12a147..0c142e8cc8 100644
--- a/phpBB/phpbb/feed/forum.php
+++ b/phpBB/phpbb/feed/forum.php
@@ -1,35 +1,39 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
+use phpbb\feed\exception\no_feed_exception;
+use phpbb\feed\exception\no_forum_exception;
+use phpbb\feed\exception\unauthorized_forum_exception;
+
/**
-* Forum feed
-*
-* This will give you the last {$this->num_items} posts made
-* within a specific forum.
-*/
-class forum extends \phpbb\feed\post_base
+ * Forum feed
+ *
+ * This will give you the last {$this->num_items} posts made
+ * within a specific forum.
+ */
+class forum extends post_base
{
- var $forum_id = 0;
- var $forum_data = array();
+ protected $forum_id = 0;
+ protected $forum_data = array();
/**
- * Set the Forum ID
- *
- * @param int $forum_id Forum ID
- * @return \phpbb\feed\forum
- */
+ * Set the Forum ID
+ *
+ * @param int $forum_id Forum ID
+ * @return \phpbb\feed\forum
+ */
public function set_forum_id($forum_id)
{
$this->forum_id = (int) $forum_id;
@@ -37,7 +41,10 @@ class forum extends \phpbb\feed\post_base
return $this;
}
- function open()
+ /**
+ * {@inheritdoc}
+ */
+ public function open()
{
// Check if forum exists
$sql = 'SELECT forum_id, forum_name, forum_password, forum_type, forum_options
@@ -49,25 +56,33 @@ class forum extends \phpbb\feed\post_base
if (empty($this->forum_data))
{
- trigger_error('NO_FORUM');
+ throw new no_forum_exception($this->forum_id);
}
// Forum needs to be postable
if ($this->forum_data['forum_type'] != FORUM_POST)
{
- trigger_error('NO_FEED');
+ throw new no_feed_exception();
}
// Make sure forum is not excluded from feed
if (phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $this->forum_data['forum_options']))
{
- trigger_error('NO_FEED');
+ throw new no_feed_exception();
}
// Make sure we can read this forum
if (!$this->auth->acl_get('f_read', $this->forum_id))
{
- trigger_error('SORRY_AUTH_READ');
+ if ($this->user->data['user_id'] != ANONYMOUS)
+ {
+ send_status_line(403, 'Forbidden');
+ }
+ else
+ {
+ send_status_line(401, 'Unauthorized');
+ }
+ throw new unauthorized_forum_exception($this->forum_id);
}
// Make sure forum is not passworded or user is authed
@@ -77,7 +92,15 @@ class forum extends \phpbb\feed\post_base
if (isset($forum_ids_passworded[$this->forum_id]))
{
- trigger_error('SORRY_AUTH_READ');
+ if ($this->user->data['user_id'] != ANONYMOUS)
+ {
+ send_status_line(403, 'Forbidden');
+ }
+ else
+ {
+ send_status_line(401, 'Unauthorized');
+ }
+ throw new unauthorized_forum_exception($this->forum_id);
}
unset($forum_ids_passworded);
@@ -86,7 +109,10 @@ class forum extends \phpbb\feed\post_base
parent::open();
}
- function get_sql()
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_sql()
{
// Determine topics with recent activity
$sql = 'SELECT topic_id, topic_last_post_time
@@ -116,7 +142,7 @@ class forum extends \phpbb\feed\post_base
$this->sql = array(
'SELECT' => 'p.post_id, p.topic_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' .
- 'u.username, u.user_id',
+ 'u.username, u.user_id',
'FROM' => array(
POSTS_TABLE => 'p',
USERS_TABLE => 'u',
@@ -131,7 +157,10 @@ class forum extends \phpbb\feed\post_base
return true;
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
parent::adjust_item($item_row, $row);
@@ -139,7 +168,10 @@ class forum extends \phpbb\feed\post_base
$item_row['forum_id'] = $this->forum_id;
}
- function get_item()
+ /**
+ * {@inheritdoc}
+ */
+ public function get_item()
{
return ($row = parent::get_item()) ? array_merge($this->forum_data, $row) : $row;
}
diff --git a/phpBB/phpbb/feed/forums.php b/phpBB/phpbb/feed/forums.php
index ee14a5bc76..92f2b2dd4d 100644
--- a/phpBB/phpbb/feed/forums.php
+++ b/phpBB/phpbb/feed/forums.php
@@ -1,29 +1,32 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* 'All Forums' feed
-*
-* This will give you a list of all postable forums where feeds are enabled
-* including forum description, topic stats and post stats
-*/
-class forums extends \phpbb\feed\base
+ * 'All Forums' feed
+ *
+ * This will give you a list of all postable forums where feeds are enabled
+ * including forum description, topic stats and post stats
+ */
+class forums extends base
{
- var $num_items = 0;
+ protected $num_items = 0;
- function set_keys()
+ /**
+ * {@inheritdoc}
+ */
+ public function set_keys()
{
$this->set('title', 'forum_name');
$this->set('text', 'forum_desc');
@@ -33,7 +36,10 @@ class forums extends \phpbb\feed\base
$this->set('options', 'forum_desc_options');
}
- function get_sql()
+ /**
+ * {@inheritdoc}
+ */
+ public function get_sql()
{
$in_fid_ary = array_diff($this->get_readable_forums(), $this->get_excluded_forums());
if (empty($in_fid_ary))
@@ -55,7 +61,10 @@ class forums extends \phpbb\feed\base
return true;
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
$item_row['link'] = $this->helper->append_sid('viewforum.' . $this->phpEx, 'f=' . $row['forum_id']);
diff --git a/phpBB/phpbb/feed/helper.php b/phpBB/phpbb/feed/helper.php
index f2030f5ced..7d50b7ce7d 100644
--- a/phpBB/phpbb/feed/helper.php
+++ b/phpBB/phpbb/feed/helper.php
@@ -1,54 +1,65 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
+use phpbb\config\config;
+use phpbb\path_helper;
+use phpbb\textformatter\s9e\renderer;
+use phpbb\user;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
/**
-* Class with some helpful functions used in feeds
-*/
+ * Class with some helpful functions used in feeds
+ */
class helper
{
- /** @var \phpbb\config\config */
+ /** @var config */
protected $config;
- /** @var \phpbb\user */
- protected $user;
+ /** @var ContainerInterface */
+ protected $container;
- /** @var string */
- protected $phpbb_root_path;
+ /** @var path_helper */
+ protected $path_helper;
- /** @var string */
- protected $phpEx;
+ /** @var renderer */
+ protected $renderer;
+
+ /** @var user */
+ protected $user;
/**
- * Constructor
- *
- * @param \phpbb\config\config $config Config object
- * @param \phpbb\user $user User object
- * @param string $phpbb_root_path Root path
- * @param string $phpEx PHP file extension
- */
- public function __construct(\phpbb\config\config $config, \phpbb\user $user, $phpbb_root_path, $phpEx)
+ * Constructor
+ *
+ * @param config $config Config object
+ * @param ContainerInterface $container Service container object
+ * @param path_helper $path_helper Path helper object
+ * @param renderer $renderer TextFormatter renderer object
+ * @param user $user User object
+ */
+ public function __construct(config $config, ContainerInterface $container, path_helper $path_helper, renderer $renderer, user $user)
{
$this->config = $config;
+ $this->container = $container;
+ $this->path_helper = $path_helper;
+ $this->renderer = $renderer;
$this->user = $user;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->phpEx = $phpEx;
}
/**
- * Run links through append_sid(), prepend generate_board_url() and remove session id
- */
+ * Returns the board url (and caches it in the function)
+ */
public function get_board_url()
{
static $board_url;
@@ -62,16 +73,16 @@ class helper
}
/**
- * Run links through append_sid(), prepend generate_board_url() and remove session id
- */
+ * Run links through append_sid(), prepend generate_board_url() and remove session id
+ */
public function append_sid($url, $params)
{
return append_sid($this->get_board_url() . '/' . $url, $params, true, '');
}
/**
- * Generate ISO 8601 date string (RFC 3339)
- */
+ * Generate ISO 8601 date string (RFC 3339)
+ */
public function format_date($time)
{
static $zone_offset;
@@ -87,16 +98,16 @@ class helper
}
/**
- * Generate text content
- *
- * @param string $content is feed text content
- * @param string $uid is bbcode_uid
- * @param string $bitfield is bbcode bitfield
- * @param int $options bbcode flag options
- * @param int $forum_id is the forum id
- * @param array $post_attachments is an array containing the attachments and their respective info
- * @return string the html content to be printed for the feed
- */
+ * Generate text content
+ *
+ * @param string $content is feed text content
+ * @param string $uid is bbcode_uid
+ * @param string $bitfield is bbcode bitfield
+ * @param int $options bbcode flag options
+ * @param int $forum_id is the forum id
+ * @param array $post_attachments is an array containing the attachments and their respective info
+ * @return string the html content to be printed for the feed
+ */
public function generate_content($content, $uid, $bitfield, $options, $forum_id, $post_attachments)
{
if (empty($content))
@@ -104,16 +115,12 @@ class helper
return '';
}
- // Prepare some bbcodes for better parsing
- $content = preg_replace("#\[quote(=&quot;.*?&quot;)?:$uid\]\s*(.*?)\s*\[/quote:$uid\]#si", "[quote$1:$uid]<br />$2<br />[/quote:$uid]", $content);
+ // Setup our own quote_helper to remove all attributes from quotes
+ $this->renderer->configure_quote_helper($this->container->get('feed.quote_helper'));
- $content = generate_text_for_display($content, $uid, $bitfield, $options);
-
- // Add newlines
- $content = str_replace('<br />', '<br />' . "\n", $content);
+ $this->renderer->set_smilies_path($this->get_board_url() . '/' . $this->config['smilies_path']);
- // Convert smiley Relative paths to Absolute path, Windows style
- $content = str_replace($this->phpbb_root_path . $this->config['smilies_path'], $this->get_board_url() . '/' . $this->config['smilies_path'], $content);
+ $content = generate_text_for_display($content, $uid, $bitfield, $options);
// Remove "Select all" link and mouse events
$content = str_replace('<a href="#" onclick="selectCode(this); return false;">' . $this->user->lang['SELECT_ALL_CODE'] . '</a>', '', $content);
@@ -122,16 +129,16 @@ class helper
// Firefox does not support CSS for feeds, though
// Remove font sizes
- // $content = preg_replace('#<span style="font-size: [0-9]+%; line-height: [0-9]+%;">([^>]+)</span>#iU', '\1', $content);
+ // $content = preg_replace('#<span style="font-size: [0-9]+%; line-height: [0-9]+%;">([^>]+)</span>#iU', '\1', $content);
// Make text strong :P
- // $content = preg_replace('#<span style="font-weight: bold?">(.*?)</span>#iU', '<strong>\1</strong>', $content);
+ // $content = preg_replace('#<span style="font-weight: bold?">(.*?)</span>#iU', '<strong>\1</strong>', $content);
// Italic
- // $content = preg_replace('#<span style="font-style: italic?">([^<]+)</span>#iU', '<em>\1</em>', $content);
+ // $content = preg_replace('#<span style="font-style: italic?">([^<]+)</span>#iU', '<em>\1</em>', $content);
// Underline
- // $content = preg_replace('#<span style="text-decoration: underline?">([^<]+)</span>#iU', '<u>\1</u>', $content);
+ // $content = preg_replace('#<span style="text-decoration: underline?">([^<]+)</span>#iU', '<u>\1</u>', $content);
// Remove embed Windows Media Streams
$content = preg_replace( '#<\!--\[if \!IE\]>-->([^[]+)<\!--<!\[endif\]-->#si', '', $content);
@@ -152,7 +159,7 @@ class helper
$content .= implode('<br />', $post_attachments);
// Convert attachments' relative path to absolute path
- $content = str_replace($this->phpbb_root_path . 'download/file.' . $this->phpEx, $this->get_board_url() . '/download/file.' . $this->phpEx, $content);
+ $content = str_replace($this->path_helper->get_web_root_path() . 'download/file.' . $this->path_helper->get_php_ext(), $this->get_board_url() . '/download/file.' . $this->path_helper->get_php_ext(), $content);
}
// Remove Comments from inline attachments [ia]
diff --git a/phpBB/phpbb/feed/news.php b/phpBB/phpbb/feed/news.php
index 5d4786518b..13ca82c093 100644
--- a/phpBB/phpbb/feed/news.php
+++ b/phpBB/phpbb/feed/news.php
@@ -1,27 +1,31 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* News feed
-*
-* This will give you {$this->num_items} first posts
-* of all topics in the selected news forums.
-*/
-class news extends \phpbb\feed\topic_base
+ * News feed
+ *
+ * This will give you {$this->num_items} first posts
+ * of all topics in the selected news forums.
+ */
+class news extends topic_base
{
- function get_news_forums()
+ /**
+ * Returns the ids of the 'news forums'
+ * @return int[]
+ */
+ private function get_news_forums()
{
static $forum_ids;
@@ -48,7 +52,10 @@ class news extends \phpbb\feed\topic_base
return $forum_ids;
}
- function get_sql()
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_sql()
{
// Determine forum ids
$in_fid_ary = array_intersect($this->get_news_forums(), $this->get_readable_forums());
diff --git a/phpBB/phpbb/feed/overall.php b/phpBB/phpbb/feed/overall.php
index 1176a9c182..b083df922d 100644
--- a/phpBB/phpbb/feed/overall.php
+++ b/phpBB/phpbb/feed/overall.php
@@ -1,27 +1,30 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* Board wide feed (aka overall feed)
-*
-* This will give you the newest {$this->num_items} posts
-* from the whole board.
-*/
-class overall extends \phpbb\feed\post_base
+ * Board wide feed (aka overall feed)
+ *
+ * This will give you the newest {$this->num_items} posts
+ * from the whole board.
+ */
+class overall extends post_base
{
- function get_sql()
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_sql()
{
$forum_ids = array_diff($this->get_readable_forums(), $this->get_excluded_forums(), $this->get_passworded_forums());
if (empty($forum_ids))
@@ -57,8 +60,8 @@ class overall extends \phpbb\feed\post_base
// Get the actual data
$this->sql = array(
'SELECT' => 'f.forum_id, f.forum_name, ' .
- 'p.post_id, p.topic_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' .
- 'u.username, u.user_id',
+ 'p.post_id, p.topic_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' .
+ 'u.username, u.user_id',
'FROM' => array(
USERS_TABLE => 'u',
POSTS_TABLE => 'p',
@@ -79,7 +82,10 @@ class overall extends \phpbb\feed\post_base
return true;
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
parent::adjust_item($item_row, $row);
diff --git a/phpBB/phpbb/feed/post_base.php b/phpBB/phpbb/feed/post_base.php
index 011775b6af..f6dc39cbec 100644
--- a/phpBB/phpbb/feed/post_base.php
+++ b/phpBB/phpbb/feed/post_base.php
@@ -1,27 +1,29 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* Abstract class for post based feeds
-*/
-abstract class post_base extends \phpbb\feed\attachments_base
+ * Abstract class for post based feeds
+ */
+abstract class post_base extends attachments_base
{
- var $num_items = 'feed_limit_post';
- var $attachments = array();
+ protected $num_items = 'feed_limit_post';
- function set_keys()
+ /**
+ * {@inheritdoc}
+ */
+ public function set_keys()
{
$this->set('title', 'post_subject');
$this->set('title2', 'topic_title');
@@ -40,7 +42,10 @@ abstract class post_base extends \phpbb\feed\attachments_base
$this->set('enable_magic_url', 'enable_magic_url');
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
$item_row['link'] = $this->helper->append_sid('viewtopic.' . $this->phpEx, "t={$row['topic_id']}&amp;p={$row['post_id']}#p{$row['post_id']}");
diff --git a/phpBB/phpbb/feed/quote_helper.php b/phpBB/phpbb/feed/quote_helper.php
new file mode 100644
index 0000000000..843d075028
--- /dev/null
+++ b/phpBB/phpbb/feed/quote_helper.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\feed;
+
+/**
+ * Modified quote_helper for feeds (basically just removing all attributes)
+ */
+class quote_helper extends \phpbb\textformatter\s9e\quote_helper
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function inject_metadata($xml)
+ {
+ // In feeds we don't want any attributes, so delete all of them
+ return \s9e\TextFormatter\Utils::replaceAttributes(
+ $xml,
+ 'QUOTE',
+ function ()
+ {
+ return [];
+ }
+ );
+ }
+}
diff --git a/phpBB/phpbb/feed/topic.php b/phpBB/phpbb/feed/topic.php
index 295bf3f795..2504e411b1 100644
--- a/phpBB/phpbb/feed/topic.php
+++ b/phpBB/phpbb/feed/topic.php
@@ -1,35 +1,40 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
+use phpbb\feed\exception\no_feed_exception;
+use phpbb\feed\exception\no_topic_exception;
+use phpbb\feed\exception\unauthorized_forum_exception;
+use phpbb\feed\exception\unauthorized_topic_exception;
+
/**
-* Topic feed for a specific topic
-*
-* This will give you the last {$this->num_items} posts made within this topic.
-*/
-class topic extends \phpbb\feed\post_base
+ * Topic feed for a specific topic
+ *
+ * This will give you the last {$this->num_items} posts made within this topic.
+ */
+class topic extends post_base
{
- var $topic_id = 0;
- var $forum_id = 0;
- var $topic_data = array();
+ protected $topic_id = 0;
+ protected $forum_id = 0;
+ protected $topic_data = array();
/**
- * Set the Topic ID
- *
- * @param int $topic_id Topic ID
- * @return \phpbb\feed\topic
- */
+ * Set the Topic ID
+ *
+ * @param int $topic_id Topic ID
+ * @return \phpbb\feed\topic
+ */
public function set_topic_id($topic_id)
{
$this->topic_id = (int) $topic_id;
@@ -37,7 +42,10 @@ class topic extends \phpbb\feed\post_base
return $this;
}
- function open()
+ /**
+ * {@inheritdoc}
+ */
+ public function open()
{
$sql = 'SELECT f.forum_options, f.forum_password, t.topic_id, t.forum_id, t.topic_visibility, t.topic_title, t.topic_time, t.topic_views, t.topic_posts_approved, t.topic_type
FROM ' . TOPICS_TABLE . ' t
@@ -50,7 +58,7 @@ class topic extends \phpbb\feed\post_base
if (empty($this->topic_data))
{
- trigger_error('NO_TOPIC');
+ throw new no_topic_exception($this->topic_id);
}
$this->forum_id = (int) $this->topic_data['forum_id'];
@@ -58,19 +66,35 @@ class topic extends \phpbb\feed\post_base
// Make sure topic is either approved or user authed
if ($this->topic_data['topic_visibility'] != ITEM_APPROVED && !$this->auth->acl_get('m_approve', $this->forum_id))
{
- trigger_error('SORRY_AUTH_READ');
+ if ($this->user->data['user_id'] != ANONYMOUS)
+ {
+ send_status_line(403, 'Forbidden');
+ }
+ else
+ {
+ send_status_line(401, 'Unauthorized');
+ }
+ throw new unauthorized_topic_exception($this->topic_id);
}
// Make sure forum is not excluded from feed
if (phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $this->topic_data['forum_options']))
{
- trigger_error('NO_FEED');
+ throw new no_feed_exception();
}
// Make sure we can read this forum
if (!$this->auth->acl_get('f_read', $this->forum_id))
{
- trigger_error('SORRY_AUTH_READ');
+ if ($this->user->data['user_id'] != ANONYMOUS)
+ {
+ send_status_line(403, 'Forbidden');
+ }
+ else
+ {
+ send_status_line(401, 'Unauthorized');
+ }
+ throw new unauthorized_forum_exception($this->forum_id);
}
// Make sure forum is not passworded or user is authed
@@ -80,7 +104,15 @@ class topic extends \phpbb\feed\post_base
if (isset($forum_ids_passworded[$this->forum_id]))
{
- trigger_error('SORRY_AUTH_READ');
+ if ($this->user->data['user_id'] != ANONYMOUS)
+ {
+ send_status_line(403, 'Forbidden');
+ }
+ else
+ {
+ send_status_line(401, 'Unauthorized');
+ }
+ throw new unauthorized_forum_exception($this->forum_id);
}
unset($forum_ids_passworded);
@@ -89,13 +121,16 @@ class topic extends \phpbb\feed\post_base
parent::open();
}
- function get_sql()
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_sql()
{
parent::fetch_attachments();
$this->sql = array(
'SELECT' => 'p.post_id, p.post_time, p.post_edit_time, p.post_visibility, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.post_attachment, ' .
- 'u.username, u.user_id',
+ 'u.username, u.user_id',
'FROM' => array(
POSTS_TABLE => 'p',
USERS_TABLE => 'u',
@@ -109,14 +144,20 @@ class topic extends \phpbb\feed\post_base
return true;
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
parent::adjust_item($item_row, $row);
$item_row['forum_id'] = $this->forum_id;
}
- function get_item()
+ /**
+ * {@inheritdoc}
+ */
+ public function get_item()
{
return ($row = parent::get_item()) ? array_merge($this->topic_data, $row) : $row;
}
diff --git a/phpBB/phpbb/feed/topic_base.php b/phpBB/phpbb/feed/topic_base.php
index f9ff368cba..0f1a9ccb70 100644
--- a/phpBB/phpbb/feed/topic_base.php
+++ b/phpBB/phpbb/feed/topic_base.php
@@ -1,26 +1,29 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* Abstract class for topic based feeds
-*/
-abstract class topic_base extends \phpbb\feed\attachments_base
+ * Abstract class for topic based feeds
+ */
+abstract class topic_base extends attachments_base
{
- var $num_items = 'feed_limit_topic';
+ protected $num_items = 'feed_limit_topic';
- function set_keys()
+ /**
+ * {@inheritdoc}
+ */
+ public function set_keys()
{
$this->set('title', 'topic_title');
$this->set('title2', 'forum_name');
@@ -39,7 +42,10 @@ abstract class topic_base extends \phpbb\feed\attachments_base
$this->set('enable_magic_url', 'enable_magic_url');
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
$item_row['link'] = $this->helper->append_sid('viewtopic.' . $this->phpEx, 't=' . $row['topic_id'] . '&amp;p=' . $row['post_id'] . '#p' . $row['post_id']);
diff --git a/phpBB/phpbb/feed/topics.php b/phpBB/phpbb/feed/topics.php
index e6416bc064..183c29d11c 100644
--- a/phpBB/phpbb/feed/topics.php
+++ b/phpBB/phpbb/feed/topics.php
@@ -1,27 +1,30 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* New Topics feed
-*
-* This will give you the last {$this->num_items} created topics
-* including the first post.
-*/
-class topics extends \phpbb\feed\topic_base
+ * New Topics feed
+ *
+ * This will give you the last {$this->num_items} created topics
+ * including the first post.
+ */
+class topics extends topic_base
{
- function get_sql()
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_sql()
{
$forum_ids_read = $this->get_readable_forums();
if (empty($forum_ids_read))
@@ -79,7 +82,10 @@ class topics extends \phpbb\feed\topic_base
return true;
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
parent::adjust_item($item_row, $row);
diff --git a/phpBB/phpbb/feed/topics_active.php b/phpBB/phpbb/feed/topics_active.php
index 3b751f3233..ea9ee97b9d 100644
--- a/phpBB/phpbb/feed/topics_active.php
+++ b/phpBB/phpbb/feed/topics_active.php
@@ -1,30 +1,33 @@
<?php
/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
namespace phpbb\feed;
/**
-* Active Topics feed
-*
-* This will give you the last {$this->num_items} topics
-* with replies made withing the last {$this->sort_days} days
-* including the last post.
-*/
-class topics_active extends \phpbb\feed\topic_base
+ * Active Topics feed
+ *
+ * This will give you the last {$this->num_items} topics
+ * with replies made withing the last {$this->sort_days} days
+ * including the last post.
+ */
+class topics_active extends topic_base
{
- var $sort_days = 7;
+ protected $sort_days = 7;
- function set_keys()
+ /**
+ * {@inheritdoc}
+ */
+ public function set_keys()
{
parent::set_keys();
@@ -32,7 +35,10 @@ class topics_active extends \phpbb\feed\topic_base
$this->set('creator', 'topic_last_poster_name');
}
- function get_sql()
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_sql()
{
$forum_ids_read = $this->get_readable_forums();
if (empty($forum_ids_read))
@@ -96,7 +102,12 @@ class topics_active extends \phpbb\feed\topic_base
return true;
}
- function get_forum_ids()
+ /**
+ * Returns the ids of the forums not excluded from the active list
+ *
+ * @return int[]
+ */
+ private function get_forum_ids()
{
static $forum_ids;
@@ -108,7 +119,7 @@ class topics_active extends \phpbb\feed\topic_base
FROM ' . FORUMS_TABLE . '
WHERE forum_type = ' . FORUM_POST . '
AND ' . $this->db->sql_bit_and('forum_options', FORUM_OPTION_FEED_EXCLUDE, '= 0') . '
- AND ' . $this->db->sql_bit_and('forum_flags', log(FORUM_FLAG_ACTIVE_TOPICS, 2), '<> 0');
+ AND ' . $this->db->sql_bit_and('forum_flags', round(log(FORUM_FLAG_ACTIVE_TOPICS, 2)), '<> 0');
$result = $this->db->sql_query($sql);
$forum_ids = array();
@@ -124,7 +135,10 @@ class topics_active extends \phpbb\feed\topic_base
return $forum_ids;
}
- function adjust_item(&$item_row, &$row)
+ /**
+ * {@inheritdoc}
+ */
+ public function adjust_item(&$item_row, &$row)
{
parent::adjust_item($item_row, $row);
diff --git a/phpBB/phpbb/file_downloader.php b/phpBB/phpbb/file_downloader.php
index ab9505a14c..403ca5bc83 100644
--- a/phpBB/phpbb/file_downloader.php
+++ b/phpBB/phpbb/file_downloader.php
@@ -42,7 +42,7 @@ class file_downloader
$this->error_number = 0;
$this->error_string = '';
- if ($socket = @fsockopen(($port == 443 ? 'tls://' : '') . $host, $port, $this->error_number, $this->error_string, $timeout))
+ if ($socket = @fsockopen(($port == 443 ? 'ssl://' : '') . $host, $port, $this->error_number, $this->error_string, $timeout))
{
@fputs($socket, "GET $directory/$filename HTTP/1.0\r\n");
@fputs($socket, "HOST: $host\r\n");
diff --git a/phpBB/phpbb/files/factory.php b/phpBB/phpbb/files/factory.php
new file mode 100644
index 0000000000..84b7cc9449
--- /dev/null
+++ b/phpBB/phpbb/files/factory.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files;
+
+class factory
+{
+ /**
+ * @var \Symfony\Component\DependencyInjection\ContainerInterface
+ */
+ private $container;
+
+ /**
+ * Constructor
+ *
+ * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+ */
+ public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container)
+ {
+ $this->container = $container;
+ }
+
+ /**
+ * Get files service
+ *
+ * @param string $name Service name
+ *
+ * @return object|bool Requested service or false if service could not be
+ * found by the container
+ */
+ public function get($name)
+ {
+ $service = false;
+
+ $name = (strpos($name, '.') === false) ? 'files.' . $name : $name;
+
+ try
+ {
+ $service = $this->container->get($name);
+ }
+ catch (\Exception $e)
+ {
+ // do nothing
+ }
+
+ return $service;
+ }
+}
diff --git a/phpBB/phpbb/files/filespec.php b/phpBB/phpbb/files/filespec.php
new file mode 100644
index 0000000000..6847bca4cb
--- /dev/null
+++ b/phpBB/phpbb/files/filespec.php
@@ -0,0 +1,584 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files;
+
+use phpbb\language\language;
+
+/**
+ * Responsible for holding all file relevant information, as well as doing file-specific operations.
+ * The {@link fileupload fileupload class} can be used to upload several files, each of them being this object to operate further on.
+ */
+class filespec
+{
+ /** @var string File name */
+ protected $filename = '';
+
+ /** @var string Real name of file */
+ protected $realname = '';
+
+ /** @var string Upload name of file */
+ protected $uploadname = '';
+
+ /** @var string Mimetype of file */
+ protected $mimetype = '';
+
+ /** @var string File extension */
+ protected $extension = '';
+
+ /** @var int File size */
+ protected $filesize = 0;
+
+ /** @var int Width of file */
+ protected $width = 0;
+
+ /** @var int Height of file */
+ protected $height = 0;
+
+ /** @var array Image info including type and size */
+ protected $image_info = array();
+
+ /** @var string Destination file name */
+ protected $destination_file = '';
+
+ /** @var string Destination file path */
+ protected $destination_path = '';
+
+ /** @var bool Whether file was moved */
+ protected $file_moved = false;
+
+ /** @var bool Whether file is local */
+ protected $local = false;
+
+ /** @var bool Class initialization flag */
+ protected $class_initialized = false;
+
+ /** @var array Error array */
+ public $error = array();
+
+ /** @var upload Instance of upload class */
+ public $upload;
+
+ /** @var \phpbb\filesystem\filesystem_interface */
+ protected $filesystem;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper ini_get() wrapper class */
+ protected $php_ini;
+
+ /** @var \FastImageSize\FastImageSize */
+ protected $imagesize;
+
+ /** @var language Language class */
+ protected $language;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ /** @var \phpbb\plupload\plupload The plupload object */
+ protected $plupload;
+
+ /** @var \phpbb\mimetype\guesser phpBB Mimetype guesser */
+ protected $mimetype_guesser;
+
+ /**
+ * File upload class
+ *
+ * @param \phpbb\filesystem\filesystem_interface $phpbb_filesystem Filesystem
+ * @param language $language Language
+ * @param \bantu\IniGetWrapper\IniGetWrapper $php_ini ini_get() wrapper
+ * @param \FastImageSize\FastImageSize $imagesize Imagesize class
+ * @param string $phpbb_root_path phpBB root path
+ * @param \phpbb\mimetype\guesser $mimetype_guesser Mime type guesser
+ * @param \phpbb\plupload\plupload $plupload Plupload
+ */
+ public function __construct(\phpbb\filesystem\filesystem_interface $phpbb_filesystem, language $language, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \FastImageSize\FastImageSize $imagesize, $phpbb_root_path, \phpbb\mimetype\guesser $mimetype_guesser = null, \phpbb\plupload\plupload $plupload = null)
+ {
+ $this->filesystem = $phpbb_filesystem;
+ $this->language = $language;
+ $this->php_ini = $php_ini;
+ $this->imagesize = $imagesize;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->plupload = $plupload;
+ $this->mimetype_guesser = $mimetype_guesser;
+ }
+
+ /**
+ * Set upload ary
+ *
+ * @param array $upload_ary Upload ary
+ *
+ * @return filespec This instance of the filespec class
+ */
+ public function set_upload_ary($upload_ary)
+ {
+ if (!isset($upload_ary) || !count($upload_ary))
+ {
+ return $this;
+ }
+
+ $this->class_initialized = true;
+ $this->filename = $upload_ary['tmp_name'];
+ $this->filesize = $upload_ary['size'];
+ $name = $upload_ary['name'];
+ $name = trim(utf8_basename($name));
+ $this->realname = $this->uploadname = $name;
+ $this->mimetype = $upload_ary['type'];
+
+ // Opera adds the name to the mime type
+ $this->mimetype = (strpos($this->mimetype, '; name') !== false) ? str_replace(strstr($this->mimetype, '; name'), '', $this->mimetype) : $this->mimetype;
+
+ if (!$this->mimetype)
+ {
+ $this->mimetype = 'application/octet-stream';
+ }
+
+ $this->extension = strtolower(self::get_extension($this->realname));
+
+ // Try to get real filesize from temporary folder (not always working) ;)
+ $this->filesize = ($this->get_filesize($this->filename)) ?: $this->filesize;
+
+ $this->width = $this->height = 0;
+ $this->file_moved = false;
+
+ $this->local = (isset($upload_ary['local_mode'])) ? true : false;
+
+ return $this;
+ }
+
+ /**
+ * Set the upload namespace
+ *
+ * @param upload $namespace Instance of upload class
+ *
+ * @return filespec This instance of the filespec class
+ */
+ public function set_upload_namespace($namespace)
+ {
+ $this->upload = $namespace;
+
+ return $this;
+ }
+
+ /**
+ * Check if class members were not properly initialised yet
+ *
+ * @return bool True if there was an init error, false if not
+ */
+ public function init_error()
+ {
+ return !$this->class_initialized;
+ }
+
+ /**
+ * Set error in error array
+ *
+ * @param mixed $error Content for error array
+ *
+ * @return \phpbb\files\filespec This instance of the filespec class
+ */
+ public function set_error($error)
+ {
+ $this->error[] = $error;
+
+ return $this;
+ }
+
+ /**
+ * Cleans destination filename
+ *
+ * @param string $mode Either real, unique, or unique_ext. Real creates a
+ * realname, filtering some characters, lowering every
+ * character. Unique creates a unique filename.
+ * @param string $prefix Prefix applied to filename
+ * @param string $user_id The user_id is only needed for when cleaning a user's avatar
+ */
+ public function clean_filename($mode = 'unique', $prefix = '', $user_id = '')
+ {
+ if ($this->init_error())
+ {
+ return;
+ }
+
+ switch ($mode)
+ {
+ case 'real':
+ // Remove every extension from filename (to not let the mime bug being exposed)
+ if (strpos($this->realname, '.') !== false)
+ {
+ $this->realname = substr($this->realname, 0, strpos($this->realname, '.'));
+ }
+
+ // Replace any chars which may cause us problems with _
+ $bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|');
+
+ $this->realname = rawurlencode(str_replace($bad_chars, '_', strtolower($this->realname)));
+ $this->realname = preg_replace("/%(\w{2})/", '_', $this->realname);
+
+ $this->realname = $prefix . $this->realname . '.' . $this->extension;
+ break;
+
+ case 'unique':
+ $this->realname = $prefix . md5(unique_id());
+ break;
+
+ case 'avatar':
+ $this->extension = strtolower($this->extension);
+ $this->realname = $prefix . $user_id . '.' . $this->extension;
+
+ break;
+
+ case 'unique_ext':
+ default:
+ $this->realname = $prefix . md5(unique_id()) . '.' . $this->extension;
+ }
+ }
+
+ /**
+ * Get property from file object
+ *
+ * @param string $property Name of property
+ *
+ * @return mixed Content of property
+ */
+ public function get($property)
+ {
+ if ($this->init_error() || !isset($this->$property))
+ {
+ return false;
+ }
+
+ return $this->$property;
+ }
+
+ /**
+ * Check if file is an image (mime type)
+ *
+ * @return bool true if it is an image, false if not
+ */
+ public function is_image()
+ {
+ return (strpos($this->mimetype, 'image/') === 0);
+ }
+
+ /**
+ * Check if the file got correctly uploaded
+ *
+ * @return bool true if it is a valid upload, false if not
+ */
+ public function is_uploaded()
+ {
+ $is_plupload = $this->plupload && $this->plupload->is_active();
+
+ if (!$this->local && !$is_plupload && !is_uploaded_file($this->filename))
+ {
+ return false;
+ }
+
+ if (($this->local || $is_plupload) && !file_exists($this->filename))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Remove file
+ */
+ public function remove()
+ {
+ if ($this->file_moved)
+ {
+ @unlink($this->destination_file);
+ }
+ }
+
+ /**
+ * Get file extension
+ *
+ * @param string $filename Filename that needs to be checked
+ *
+ * @return string Extension of the supplied filename
+ */
+ static public function get_extension($filename)
+ {
+ $filename = utf8_basename($filename);
+
+ if (strpos($filename, '.') === false)
+ {
+ return '';
+ }
+
+ $filename = explode('.', $filename);
+ return array_pop($filename);
+ }
+
+ /**
+ * Get mime type
+ *
+ * @param string $filename Filename that needs to be checked
+ * @return string Mime type of supplied filename
+ */
+ public function get_mimetype($filename)
+ {
+ if ($this->mimetype_guesser !== null)
+ {
+ $mimetype = $this->mimetype_guesser->guess($filename, $this->uploadname);
+
+ if ($mimetype !== 'application/octet-stream')
+ {
+ $this->mimetype = $mimetype;
+ }
+ }
+
+ return $this->mimetype;
+ }
+
+ /**
+ * Get file size
+ *
+ * @param string $filename File name of file to check
+ *
+ * @return int File size
+ */
+ public function get_filesize($filename)
+ {
+ return @filesize($filename);
+ }
+
+
+ /**
+ * Check the first 256 bytes for forbidden content
+ *
+ * @param array $disallowed_content Array containg disallowed content
+ *
+ * @return bool False if disallowed content found, true if not
+ */
+ public function check_content($disallowed_content)
+ {
+ if (empty($disallowed_content))
+ {
+ return true;
+ }
+
+ $fp = @fopen($this->filename, 'rb');
+
+ if ($fp !== false)
+ {
+ $ie_mime_relevant = fread($fp, 256);
+ fclose($fp);
+ foreach ($disallowed_content as $forbidden)
+ {
+ if (stripos($ie_mime_relevant, '<' . $forbidden) !== false)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Move file to destination folder
+ * The phpbb_root_path variable will be applied to the destination path
+ *
+ * @param string $destination Destination path, for example $config['avatar_path']
+ * @param bool $overwrite If set to true, an already existing file will be overwritten
+ * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped
+ * @param string|bool $chmod Permission mask for chmodding the file after a successful move.
+ * The mode entered here reflects the mode defined by {@link phpbb_chmod()}
+ *
+ * @return bool True if file was moved, false if not
+ * @access public
+ */
+ public function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false)
+ {
+ if (count($this->error))
+ {
+ return false;
+ }
+
+ $chmod = ($chmod === false) ? CHMOD_READ | CHMOD_WRITE : $chmod;
+
+ // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it...
+ $this->destination_path = $this->phpbb_root_path . $destination;
+
+ // Check if the destination path exist...
+ if (!file_exists($this->destination_path))
+ {
+ @unlink($this->filename);
+ return false;
+ }
+
+ $upload_mode = ($this->php_ini->getBool('open_basedir') || $this->php_ini->getBool('safe_mode')) ? 'move' : 'copy';
+ $upload_mode = ($this->local) ? 'local' : $upload_mode;
+ $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname);
+
+ // Check if the file already exist, else there is something wrong...
+ if (file_exists($this->destination_file) && !$overwrite)
+ {
+ @unlink($this->filename);
+ $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
+ $this->file_moved = false;
+ return false;
+ }
+ else
+ {
+ if (file_exists($this->destination_file))
+ {
+ @unlink($this->destination_file);
+ }
+
+ switch ($upload_mode)
+ {
+ case 'copy':
+
+ if (!@copy($this->filename, $this->destination_file))
+ {
+ if (!@move_uploaded_file($this->filename, $this->destination_file))
+ {
+ $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
+ }
+ }
+
+ break;
+
+ case 'move':
+
+ if (!@move_uploaded_file($this->filename, $this->destination_file))
+ {
+ if (!@copy($this->filename, $this->destination_file))
+ {
+ $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
+ }
+ }
+
+ break;
+
+ case 'local':
+
+ if (!@copy($this->filename, $this->destination_file))
+ {
+ $this->error[] = $this->language->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file);
+ }
+
+ break;
+ }
+
+ // Remove temporary filename
+ @unlink($this->filename);
+
+ if (count($this->error))
+ {
+ return false;
+ }
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($this->destination_file, $chmod);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
+ }
+
+ // Try to get real filesize from destination folder
+ $this->filesize = ($this->get_filesize($this->destination_file)) ?: $this->filesize;
+
+ // Get mimetype of supplied file
+ $this->mimetype = $this->get_mimetype($this->destination_file);
+
+ if ($this->is_image() && !$skip_image_check)
+ {
+ $this->width = $this->height = 0;
+
+ $this->image_info = $this->imagesize->getImageSize($this->destination_file, $this->mimetype);
+
+ if ($this->image_info !== false)
+ {
+ $this->width = $this->image_info['width'];
+ $this->height = $this->image_info['height'];
+
+ // Check image type
+ $types = upload::image_types();
+
+ if (!isset($types[$this->image_info['type']]) || !in_array($this->extension, $types[$this->image_info['type']]))
+ {
+ if (!isset($types[$this->image_info['type']]))
+ {
+ $this->error[] = $this->language->lang('IMAGE_FILETYPE_INVALID', $this->image_info['type'], $this->mimetype);
+ }
+ else
+ {
+ $this->error[] = $this->language->lang('IMAGE_FILETYPE_MISMATCH', $types[$this->image_info['type']][0], $this->extension);
+ }
+ }
+
+ // Make sure the dimensions match a valid image
+ if (empty($this->width) || empty($this->height))
+ {
+ $this->error[] = $this->language->lang('ATTACHED_IMAGE_NOT_IMAGE');
+ }
+ }
+ else
+ {
+ $this->error[] = $this->language->lang('UNABLE_GET_IMAGE_SIZE');
+ }
+ }
+
+ $this->file_moved = true;
+ $this->additional_checks();
+ unset($this->upload);
+
+ return true;
+ }
+
+ /**
+ * Performing additional checks
+ *
+ * @return bool False if issue was found, true if not
+ */
+ public function additional_checks()
+ {
+ if (!$this->file_moved)
+ {
+ return false;
+ }
+
+ // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
+ if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0))
+ {
+ $max_filesize = get_formatted_filesize($this->upload->max_filesize, false);
+
+ $this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']);
+
+ return false;
+ }
+
+ if (!$this->upload->valid_dimensions($this))
+ {
+ $this->error[] = $this->language->lang($this->upload->error_prefix . 'WRONG_SIZE',
+ $this->language->lang('PIXELS', (int) $this->upload->min_width),
+ $this->language->lang('PIXELS', (int) $this->upload->min_height),
+ $this->language->lang('PIXELS', (int) $this->upload->max_width),
+ $this->language->lang('PIXELS', (int) $this->upload->max_height),
+ $this->language->lang('PIXELS', (int) $this->width),
+ $this->language->lang('PIXELS', (int) $this->height));
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/phpBB/phpbb/files/types/base.php b/phpBB/phpbb/files/types/base.php
new file mode 100644
index 0000000000..3313ad040b
--- /dev/null
+++ b/phpBB/phpbb/files/types/base.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files\types;
+
+abstract class base implements type_interface
+{
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\files\upload */
+ protected $upload;
+
+ /**
+ * Check if upload exceeds maximum file size
+ *
+ * @param \phpbb\files\filespec $file Filespec object
+ *
+ * @return \phpbb\files\filespec Returns same filespec instance
+ */
+ public function check_upload_size($file)
+ {
+ // PHP Upload filesize exceeded
+ if ($file->get('filename') == 'none')
+ {
+ $max_filesize = $this->php_ini->getString('upload_max_filesize');
+ $unit = 'MB';
+
+ if (!empty($max_filesize))
+ {
+ $unit = strtolower(substr($max_filesize, -1, 1));
+ $max_filesize = (int) $max_filesize;
+
+ $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
+ }
+
+ $file->error[] = (empty($max_filesize)) ? $this->language->lang($this->upload->error_prefix . 'PHP_SIZE_NA') : $this->language->lang($this->upload->error_prefix . 'PHP_SIZE_OVERRUN', $max_filesize, $this->language->lang($unit));
+ }
+
+ return $file;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_upload(\phpbb\files\upload $upload)
+ {
+ $this->upload = $upload;
+
+ return $this;
+ }
+}
diff --git a/phpBB/phpbb/files/types/form.php b/phpBB/phpbb/files/types/form.php
new file mode 100644
index 0000000000..2c3beb6e02
--- /dev/null
+++ b/phpBB/phpbb/files/types/form.php
@@ -0,0 +1,138 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files\types;
+
+use bantu\IniGetWrapper\IniGetWrapper;
+use phpbb\files\factory;
+use phpbb\files\filespec;
+use phpbb\language\language;
+use phpbb\plupload\plupload;
+use phpbb\request\request_interface;
+
+class form extends base
+{
+ /** @var factory Files factory */
+ protected $factory;
+
+ /** @var language */
+ protected $language;
+
+ /** @var IniGetWrapper */
+ protected $php_ini;
+
+ /** @var plupload */
+ protected $plupload;
+
+ /** @var request_interface */
+ protected $request;
+
+ /** @var \phpbb\files\upload */
+ protected $upload;
+
+ /**
+ * Construct a form upload type
+ *
+ * @param factory $factory Files factory
+ * @param language $language Language class
+ * @param IniGetWrapper $php_ini ini_get() wrapper
+ * @param plupload $plupload Plupload
+ * @param request_interface $request Request object
+ */
+ public function __construct(factory $factory, language $language, IniGetWrapper $php_ini, plupload $plupload, request_interface $request)
+ {
+ $this->factory = $factory;
+ $this->language = $language;
+ $this->php_ini = $php_ini;
+ $this->plupload = $plupload;
+ $this->request = $request;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function upload()
+ {
+ $args = func_get_args();
+ return $this->form_upload($args[0]);
+ }
+
+ /**
+ * Form upload method
+ * Upload file from users harddisk
+ *
+ * @param string $form_name Form name assigned to the file input field (if it is an array, the key has to be specified)
+ *
+ * @return filespec $file Object "filespec" is returned, all further operations can be done with this object
+ * @access public
+ */
+ protected function form_upload($form_name)
+ {
+ $upload = $this->request->file($form_name);
+ unset($upload['local_mode']);
+
+ $result = $this->plupload->handle_upload($form_name);
+ if (is_array($result))
+ {
+ $upload = array_merge($upload, $result);
+ }
+
+ /** @var filespec $file */
+ $file = $this->factory->get('filespec')
+ ->set_upload_ary($upload)
+ ->set_upload_namespace($this->upload);
+
+ if ($file->init_error())
+ {
+ $file->error[] = '';
+ return $file;
+ }
+
+ // Error array filled?
+ if (isset($upload['error']))
+ {
+ $error = $this->upload->assign_internal_error($upload['error']);
+
+ if ($error !== false)
+ {
+ $file->error[] = $error;
+ return $file;
+ }
+ }
+
+ // Check if empty file got uploaded (not catched by is_uploaded_file)
+ if (isset($upload['size']) && $upload['size'] == 0)
+ {
+ $file->error[] = $this->language->lang($this->upload->error_prefix . 'EMPTY_FILEUPLOAD');
+ return $file;
+ }
+
+ // PHP Upload file size check
+ $file = $this->check_upload_size($file);
+ if (count($file->error))
+ {
+ return $file;
+ }
+
+ // Not correctly uploaded
+ if (!$file->is_uploaded())
+ {
+ $file->error[] = $this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED');
+ return $file;
+ }
+
+ $this->upload->common_checks($file);
+
+ return $file;
+ }
+}
diff --git a/phpBB/phpbb/files/types/local.php b/phpBB/phpbb/files/types/local.php
new file mode 100644
index 0000000000..4dfe4f7506
--- /dev/null
+++ b/phpBB/phpbb/files/types/local.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files\types;
+
+use bantu\IniGetWrapper\IniGetWrapper;
+use phpbb\files\factory;
+use phpbb\files\filespec;
+use phpbb\language\language;
+use phpbb\request\request_interface;
+
+class local extends base
+{
+ /** @var factory Files factory */
+ protected $factory;
+
+ /** @var language */
+ protected $language;
+
+ /** @var IniGetWrapper */
+ protected $php_ini;
+
+ /** @var request_interface */
+ protected $request;
+
+ /** @var \phpbb\files\upload */
+ protected $upload;
+
+ /**
+ * Construct a form upload type
+ *
+ * @param factory $factory Files factory
+ * @param language $language Language class
+ * @param IniGetWrapper $php_ini ini_get() wrapper
+ * @param request_interface $request Request object
+ */
+ public function __construct(factory $factory, language $language, IniGetWrapper $php_ini, request_interface $request)
+ {
+ $this->factory = $factory;
+ $this->language = $language;
+ $this->php_ini = $php_ini;
+ $this->request = $request;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function upload()
+ {
+ $args = func_get_args();
+ return $this->local_upload($args[0], isset($args[1]) ? $args[1] : false);
+ }
+
+ /**
+ * Move file from another location to phpBB
+ *
+ * @param string $source_file Filename of source file
+ * @param array|bool $filedata Array with filedata or false
+ *
+ * @return filespec Object "filespec" is returned, all further operations can be done with this object
+ */
+ protected function local_upload($source_file, $filedata = false)
+ {
+ $upload = $this->get_upload_ary($source_file, $filedata);
+
+ /** @var filespec $file */
+ $file = $this->factory->get('filespec')
+ ->set_upload_ary($upload)
+ ->set_upload_namespace($this->upload);
+
+ if ($file->init_error())
+ {
+ $file->error[] = '';
+ return $file;
+ }
+
+ // PHP Upload file size check
+ $file = $this->check_upload_size($file);
+ if (count($file->error))
+ {
+ return $file;
+ }
+
+ // Not correctly uploaded
+ if (!$file->is_uploaded())
+ {
+ $file->error[] = $this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED');
+ return $file;
+ }
+
+ $this->upload->common_checks($file);
+ $this->request->overwrite('local', $upload, request_interface::FILES);
+
+ return $file;
+ }
+
+ /**
+ * Retrieve upload array
+ *
+ * @param string $source_file Source file name
+ * @param array $filedata File data array
+ *
+ * @return array Upload array
+ */
+ protected function get_upload_ary($source_file, $filedata)
+ {
+ $upload = array();
+
+ $upload['local_mode'] = true;
+ $upload['tmp_name'] = $source_file;
+
+ if ($filedata === false)
+ {
+ $upload['name'] = utf8_basename($source_file);
+ $upload['size'] = 0;
+ }
+ else
+ {
+ $upload['name'] = $filedata['realname'];
+ $upload['size'] = $filedata['size'];
+ $upload['type'] = $filedata['type'];
+ }
+
+ return $upload;
+ }
+}
diff --git a/phpBB/phpbb/files/types/remote.php b/phpBB/phpbb/files/types/remote.php
new file mode 100644
index 0000000000..1fdba0ca32
--- /dev/null
+++ b/phpBB/phpbb/files/types/remote.php
@@ -0,0 +1,207 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files\types;
+
+use bantu\IniGetWrapper\IniGetWrapper;
+use phpbb\config\config;
+use phpbb\files\factory;
+use phpbb\files\filespec;
+use phpbb\language\language;
+use phpbb\request\request_interface;
+
+class remote extends base
+{
+ /** @var config phpBB config */
+ protected $config;
+
+ /** @var factory Files factory */
+ protected $factory;
+
+ /** @var language */
+ protected $language;
+
+ /** @var IniGetWrapper */
+ protected $php_ini;
+
+ /** @var request_interface */
+ protected $request;
+
+ /** @var \phpbb\files\upload */
+ protected $upload;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ /**
+ * Construct a form upload type
+ *
+ * @param config $config phpBB config
+ * @param factory $factory Files factory
+ * @param language $language Language class
+ * @param IniGetWrapper $php_ini ini_get() wrapper
+ * @param request_interface $request Request object
+ * @param string $phpbb_root_path phpBB root path
+ */
+ public function __construct(config $config, factory $factory, language $language, IniGetWrapper $php_ini, request_interface $request, $phpbb_root_path)
+ {
+ $this->config = $config;
+ $this->factory = $factory;
+ $this->language = $language;
+ $this->php_ini = $php_ini;
+ $this->request = $request;
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function upload()
+ {
+ $args = func_get_args();
+ return $this->remote_upload($args[0]);
+ }
+
+ /**
+ * Remote upload method
+ * Uploads file from given url
+ *
+ * @param string $upload_url URL pointing to file to upload, for example http://www.foobar.com/example.gif
+ * @return filespec $file Object "filespec" is returned, all further operations can be done with this object
+ * @access public
+ */
+ protected function remote_upload($upload_url)
+ {
+ $upload_ary = array();
+ $upload_ary['local_mode'] = true;
+
+ if (!preg_match('#^(https?://).*?\.(' . implode('|', $this->upload->allowed_extensions) . ')$#i', $upload_url, $match))
+ {
+ return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'URL_INVALID'));
+ }
+
+ $url = parse_url($upload_url);
+
+ $upload_ary['type'] = 'application/octet-stream';
+
+ $url['path'] = explode('.', $url['path']);
+ $ext = array_pop($url['path']);
+
+ $url['path'] = implode('', $url['path']);
+ $upload_ary['name'] = utf8_basename($url['path']) . (($ext) ? '.' . $ext : '');
+
+ $remote_max_filesize = $this->get_max_file_size();
+
+ $guzzle_options = [
+ 'timeout' => $this->upload->upload_timeout,
+ 'connect_timeout' => $this->upload->upload_timeout,
+ 'verify' => !empty($this->config['remote_upload_verify']) ? (bool) $this->config['remote_upload_verify'] : false,
+ ];
+ $client = new \GuzzleHttp\Client($guzzle_options);
+
+ try
+ {
+ $response = $client->get($upload_url, $guzzle_options);
+ }
+ catch (\GuzzleHttp\Exception\ClientException $clientException)
+ {
+ return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'URL_NOT_FOUND');
+ }
+ catch (\GuzzleHttp\Exception\RequestException $requestException)
+ {
+ if (strpos($requestException->getMessage(), 'cURL error 28') !== false || preg_match('/408|504/', $requestException->getCode()))
+ {
+ return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'REMOTE_UPLOAD_TIMEOUT');
+ }
+ else
+ {
+ return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED'));
+ }
+ }
+ catch (\Exception $e)
+ {
+ return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'NOT_UPLOADED'));
+ }
+
+ $content_length = $response->getBody()->getSize();
+ if ($remote_max_filesize && $content_length > $remote_max_filesize)
+ {
+ $max_filesize = get_formatted_filesize($remote_max_filesize, false);
+
+ return $this->factory->get('filespec')->set_error($this->language->lang($this->upload->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']));
+ }
+
+ if ($content_length == 0)
+ {
+ return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'EMPTY_REMOTE_DATA');
+ }
+
+ $data = $response->getBody();
+
+ $filename = tempnam(sys_get_temp_dir(), unique_id() . '-');
+
+ if (!($fp = @fopen($filename, 'wb')))
+ {
+ return $this->factory->get('filespec')->set_error($this->upload->error_prefix . 'NOT_UPLOADED');
+ }
+
+ $upload_ary['size'] = fwrite($fp, $data);
+ fclose($fp);
+ unset($data);
+
+ $upload_ary['tmp_name'] = $filename;
+
+ /** @var filespec $file */
+ $file = $this->factory->get('filespec')
+ ->set_upload_ary($upload_ary)
+ ->set_upload_namespace($this->upload);
+ $this->upload->common_checks($file);
+
+ return $file;
+ }
+
+ /**
+ * Get maximum file size for remote uploads
+ *
+ * @return int Maximum file size
+ */
+ protected function get_max_file_size()
+ {
+ $max_file_size = $this->upload->max_filesize;
+ if (!$max_file_size)
+ {
+ $max_file_size = $this->php_ini->getString('upload_max_filesize');
+
+ if (!empty($max_file_size))
+ {
+ $unit = strtolower(substr($max_file_size, -1, 1));
+ $max_file_size = (int) $max_file_size;
+
+ switch ($unit)
+ {
+ case 'g':
+ $max_file_size *= 1024;
+ // no break
+ case 'm':
+ $max_file_size *= 1024;
+ // no break
+ case 'k':
+ $max_file_size *= 1024;
+ // no break
+ }
+ }
+ }
+
+ return $max_file_size;
+ }
+}
diff --git a/phpBB/phpbb/files/types/type_interface.php b/phpBB/phpbb/files/types/type_interface.php
new file mode 100644
index 0000000000..e07078349a
--- /dev/null
+++ b/phpBB/phpbb/files/types/type_interface.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files\types;
+
+use phpbb\files\upload;
+
+interface type_interface
+{
+ /**
+ * Handle upload for upload types. Arguments passed to this method will be
+ * handled by the upload type classes themselves.
+ *
+ * @return \phpbb\files\filespec|bool Filespec instance if upload is
+ * successful or false if not
+ */
+ public function upload();
+
+ /**
+ * Set upload instance
+ * Needs to be executed before every upload.
+ *
+ * @param upload $upload Upload instance
+ *
+ * @return type_interface Returns itself
+ */
+ public function set_upload(upload $upload);
+}
diff --git a/phpBB/phpbb/files/upload.php b/phpBB/phpbb/files/upload.php
new file mode 100644
index 0000000000..50e15c9844
--- /dev/null
+++ b/phpBB/phpbb/files/upload.php
@@ -0,0 +1,390 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files;
+
+use phpbb\filesystem\filesystem_interface;
+use phpbb\language\language;
+use phpbb\request\request_interface;
+
+/**
+ * File upload class
+ * Init class (all parameters optional and able to be set/overwritten separately) - scope is global and valid for all uploads
+ */
+class upload
+{
+ /** @var array Allowed file extensions */
+ public $allowed_extensions = array();
+
+ /** @var array Disallowed content */
+ protected $disallowed_content = array('body', 'head', 'html', 'img', 'plaintext', 'a href', 'pre', 'script', 'table', 'title');
+
+ /** @var int Maximum filesize */
+ public $max_filesize = 0;
+
+ /** @var int Minimum width of images */
+ public $min_width = 0;
+
+ /** @var int Minimum height of images */
+ public $min_height = 0;
+
+ /** @var int Maximum width of images */
+ public $max_width = 0;
+
+ /** @var int Maximum height of images */
+ public $max_height = 0;
+
+ /** @var string Prefix for language variables of errors */
+ public $error_prefix = '';
+
+ /** @var int Timeout for remote upload */
+ public $upload_timeout = 6;
+
+ /** @var filesystem_interface */
+ protected $filesystem;
+
+ /** @var \phpbb\files\factory Files factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper ini_get() wrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language Language class */
+ protected $language;
+
+ /** @var request_interface Request class */
+ protected $request;
+
+ /**
+ * Init file upload class.
+ *
+ * @param filesystem_interface $filesystem
+ * @param factory $factory Files factory
+ * @param language $language Language class
+ * @param \bantu\IniGetWrapper\IniGetWrapper $php_ini ini_get() wrapper
+ * @param request_interface $request Request class
+ */
+ public function __construct(filesystem_interface $filesystem, factory $factory, language $language, \bantu\IniGetWrapper\IniGetWrapper $php_ini, request_interface $request)
+ {
+ $this->filesystem = $filesystem;
+ $this->factory = $factory;
+ $this->language = $language;
+ $this->php_ini = $php_ini;
+ $this->request = $request;
+ }
+
+ /**
+ * Reset vars
+ */
+ public function reset_vars()
+ {
+ $this->max_filesize = 0;
+ $this->min_width = $this->min_height = $this->max_width = $this->max_height = 0;
+ $this->error_prefix = '';
+ $this->allowed_extensions = array();
+ $this->disallowed_content = array();
+ }
+
+ /**
+ * Set allowed extensions
+ *
+ * @param array $allowed_extensions Allowed file extensions
+ *
+ * @return \phpbb\files\upload This instance of upload
+ */
+ public function set_allowed_extensions($allowed_extensions)
+ {
+ if ($allowed_extensions !== false && is_array($allowed_extensions))
+ {
+ $this->allowed_extensions = $allowed_extensions;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set allowed dimensions
+ *
+ * @param int $min_width Minimum image width
+ * @param int $min_height Minimum image height
+ * @param int $max_width Maximum image width
+ * @param int $max_height Maximum image height
+ *
+ * @return \phpbb\files\upload This instance of upload
+ */
+ public function set_allowed_dimensions($min_width, $min_height, $max_width, $max_height)
+ {
+ $this->min_width = (int) $min_width;
+ $this->min_height = (int) $min_height;
+ $this->max_width = (int) $max_width;
+ $this->max_height = (int) $max_height;
+
+ return $this;
+ }
+
+ /**
+ * Set maximum allowed file size
+ *
+ * @param int $max_filesize Maximum file size
+ *
+ * @return \phpbb\files\upload This instance of upload
+ */
+ public function set_max_filesize($max_filesize)
+ {
+ if ($max_filesize !== false && (int) $max_filesize)
+ {
+ $this->max_filesize = (int) $max_filesize;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set disallowed strings
+ *
+ * @param array $disallowed_content Disallowed content
+ *
+ * @return \phpbb\files\upload This instance of upload
+ */
+ public function set_disallowed_content($disallowed_content)
+ {
+ if ($disallowed_content !== false && is_array($disallowed_content))
+ {
+ $this->disallowed_content = array_diff($disallowed_content, array(''));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set error prefix
+ *
+ * @param string $error_prefix Prefix for language variables of errors
+ *
+ * @return \phpbb\files\upload This instance of upload
+ */
+ public function set_error_prefix($error_prefix)
+ {
+ $this->error_prefix = $error_prefix;
+
+ return $this;
+ }
+
+ /**
+ * Handle upload based on type
+ *
+ * @param string $type Upload type
+ *
+ * @return \phpbb\files\filespec|bool A filespec instance if upload was
+ * successful, false if there were issues or the type is not supported
+ */
+ public function handle_upload($type)
+ {
+ $args = func_get_args();
+ array_shift($args);
+ $type_class = $this->factory->get($type)
+ ->set_upload($this);
+
+ return (is_object($type_class)) ? call_user_func_array(array($type_class, 'upload'), $args) : false;
+ }
+
+ /**
+ * Assign internal error
+ *
+ * @param string $errorcode Error code to assign
+ *
+ * @return string Error string
+ * @access public
+ */
+ public function assign_internal_error($errorcode)
+ {
+ switch ($errorcode)
+ {
+ case UPLOAD_ERR_INI_SIZE:
+ $max_filesize = $this->php_ini->getString('upload_max_filesize');
+ $unit = 'MB';
+
+ if (!empty($max_filesize))
+ {
+ $unit = strtolower(substr($max_filesize, -1, 1));
+ $max_filesize = (int) $max_filesize;
+
+ $unit = ($unit == 'k') ? 'KB' : (($unit == 'g') ? 'GB' : 'MB');
+ }
+
+ $error = (empty($max_filesize)) ? $this->language->lang($this->error_prefix . 'PHP_SIZE_NA') : $this->language->lang($this->error_prefix . 'PHP_SIZE_OVERRUN', $max_filesize, $this->language->lang($unit));
+ break;
+
+ case UPLOAD_ERR_FORM_SIZE:
+ $max_filesize = get_formatted_filesize($this->max_filesize, false);
+
+ $error = $this->language->lang($this->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']);
+ break;
+
+ case UPLOAD_ERR_PARTIAL:
+ $error = $this->language->lang($this->error_prefix . 'PARTIAL_UPLOAD');
+ break;
+
+ case UPLOAD_ERR_NO_FILE:
+ $error = $this->language->lang($this->error_prefix . 'NOT_UPLOADED');
+ break;
+
+ case UPLOAD_ERR_NO_TMP_DIR:
+ case UPLOAD_ERR_CANT_WRITE:
+ $error = $this->language->lang($this->error_prefix . 'NO_TEMP_DIR');
+ break;
+
+ case UPLOAD_ERR_EXTENSION:
+ $error = $this->language->lang($this->error_prefix . 'PHP_UPLOAD_STOPPED');
+ break;
+
+ default:
+ $error = false;
+ break;
+ }
+
+ return $error;
+ }
+
+ /**
+ * Perform common file checks
+ *
+ * @param filespec $file Instance of filespec class
+ */
+ public function common_checks($file)
+ {
+ // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form
+ if ($this->max_filesize && ($file->get('filesize') > $this->max_filesize || $file->get('filesize') == 0))
+ {
+ $max_filesize = get_formatted_filesize($this->max_filesize, false);
+
+ $file->error[] = $this->language->lang($this->error_prefix . 'WRONG_FILESIZE', $max_filesize['value'], $max_filesize['unit']);
+ }
+
+ // check Filename
+ if (preg_match("#[\\/:*?\"<>|]#i", $file->get('realname')))
+ {
+ $file->error[] = $this->language->lang($this->error_prefix . 'INVALID_FILENAME', $file->get('realname'));
+ }
+
+ // Invalid Extension
+ if (!$this->valid_extension($file))
+ {
+ $file->error[] = $this->language->lang($this->error_prefix . 'DISALLOWED_EXTENSION', $file->get('extension'));
+ }
+
+ // MIME Sniffing
+ if (!$this->valid_content($file))
+ {
+ $file->error[] = $this->language->lang($this->error_prefix . 'DISALLOWED_CONTENT');
+ }
+ }
+
+ /**
+ * Check for allowed extension
+ *
+ * @param filespec $file Instance of filespec class
+ *
+ * @return bool True if extension is allowed, false if not
+ */
+ public function valid_extension($file)
+ {
+ return (in_array($file->get('extension'), $this->allowed_extensions)) ? true : false;
+ }
+
+ /**
+ * Check for allowed dimension
+ *
+ * @param filespec $file Instance of filespec class
+ *
+ * @return bool True if dimensions are valid or no constraints set, false
+ * if not
+ */
+ public function valid_dimensions($file)
+ {
+ if (!$this->max_width && !$this->max_height && !$this->min_width && !$this->min_height)
+ {
+ return true;
+ }
+
+ if (($file->get('width') > $this->max_width && $this->max_width) ||
+ ($file->get('height') > $this->max_height && $this->max_height) ||
+ ($file->get('width') < $this->min_width && $this->min_width) ||
+ ($file->get('height') < $this->min_height && $this->min_height))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if form upload is valid
+ *
+ * @param string $form_name Name of form
+ *
+ * @return bool True if form upload is valid, false if not
+ */
+ public function is_valid($form_name)
+ {
+ $upload = $this->request->file($form_name);
+
+ return (!empty($upload) && $upload['name'] !== 'none');
+ }
+
+
+ /**
+ * Check for bad content (IE mime-sniffing)
+ *
+ * @param filespec $file Instance of filespec class
+ *
+ * @return bool True if content is valid, false if not
+ */
+ public function valid_content($file)
+ {
+ return ($file->check_content($this->disallowed_content));
+ }
+
+ /**
+ * Get image type/extension mapping
+ *
+ * @return array Array containing the image types and their extensions
+ */
+ static public function image_types()
+ {
+ $result = 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_IFF => array('iff'),
+ IMAGETYPE_WBMP => array('wbmp'),
+ IMAGETYPE_XBM => array('xbm'),
+ );
+
+ if (defined('IMAGETYPE_SWC'))
+ {
+ $result[IMAGETYPE_SWC] = array('swc');
+ }
+
+ return $result;
+ }
+}
diff --git a/phpBB/phpbb/filesystem.php b/phpBB/phpbb/filesystem.php
index 77517082e5..af56d78845 100644
--- a/phpBB/phpbb/filesystem.php
+++ b/phpBB/phpbb/filesystem.php
@@ -14,37 +14,8 @@
namespace phpbb;
/**
-* A class with various functions that are related to paths, files and the filesystem
-*/
-class filesystem
+ * @deprecated 3.2.0-dev (To be removed 3.3.0) use \phpbb\filesystem\filesystem instead
+ */
+class filesystem extends \phpbb\filesystem\filesystem
{
- /**
- * Eliminates useless . and .. components from specified path.
- *
- * @param string $path Path to clean
- * @return string Cleaned path
- */
- public function clean_path($path)
- {
- $exploded = explode('/', $path);
- $filtered = array();
- foreach ($exploded as $part)
- {
- if ($part === '.' && !empty($filtered))
- {
- continue;
- }
-
- if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '.' && $filtered[sizeof($filtered) - 1] !== '..')
- {
- array_pop($filtered);
- }
- else
- {
- $filtered[] = $part;
- }
- }
- $path = implode('/', $filtered);
- return $path;
- }
}
diff --git a/phpBB/phpbb/filesystem/exception/filesystem_exception.php b/phpBB/phpbb/filesystem/exception/filesystem_exception.php
new file mode 100644
index 0000000000..d68fa9adf3
--- /dev/null
+++ b/phpBB/phpbb/filesystem/exception/filesystem_exception.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\filesystem\exception;
+
+class filesystem_exception extends \phpbb\exception\runtime_exception
+{
+ /**
+ * Constructor
+ *
+ * @param string $message The Exception message to throw (must be a language variable).
+ * @param string $filename The file that caused the error.
+ * @param array $parameters The parameters to use with the language var.
+ * @param \Exception $previous The previous runtime_exception used for the runtime_exception chaining.
+ * @param integer $code The Exception code.
+ */
+ public function __construct($message = "", $filename = '', $parameters = array(), \Exception $previous = null, $code = 0)
+ {
+ parent::__construct($message, array_merge(array('filename' => $filename), $parameters), $previous, $code);
+ }
+
+ /**
+ * Returns the filename that triggered the error
+ *
+ * @return string
+ */
+ public function get_filename()
+ {
+ $parameters = parent::get_parameters();
+ return $parameters['filename'];
+ }
+}
diff --git a/phpBB/phpbb/filesystem/filesystem.php b/phpBB/phpbb/filesystem/filesystem.php
new file mode 100644
index 0000000000..c5be284d8c
--- /dev/null
+++ b/phpBB/phpbb/filesystem/filesystem.php
@@ -0,0 +1,916 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\filesystem;
+
+use phpbb\filesystem\exception\filesystem_exception;
+
+/**
+ * A class with various functions that are related to paths, files and the filesystem
+ */
+class filesystem implements filesystem_interface
+{
+ /**
+ * Store some information about file ownership for phpBB's chmod function
+ *
+ * @var array
+ */
+ protected $chmod_info;
+
+ /**
+ * Stores current working directory
+ *
+ * @var string|bool current working directory or false if it cannot be recovered
+ */
+ protected $working_directory;
+
+ /**
+ * Symfony's Filesystem component
+ *
+ * @var \Symfony\Component\Filesystem\Filesystem
+ */
+ protected $symfony_filesystem;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->chmod_info = array();
+ $this->symfony_filesystem = new \Symfony\Component\Filesystem\Filesystem();
+ $this->working_directory = null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function chgrp($files, $group, $recursive = false)
+ {
+ try
+ {
+ $this->symfony_filesystem->chgrp($files, $group, $recursive);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ // Try to recover filename
+ // By the time this is written that is at the end of the message
+ $error = trim($e->getMessage());
+ $file = substr($error, strrpos($error, ' '));
+
+ throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function chmod($files, $perms = null, $recursive = false, $force_chmod_link = false)
+ {
+ if (is_null($perms))
+ {
+ // Default to read permission for compatibility reasons
+ $perms = self::CHMOD_READ;
+ }
+
+ // Check if we got a permission flag
+ if ($perms > self::CHMOD_ALL)
+ {
+ $file_perm = $perms;
+
+ // Extract permissions
+ //$owner = ($file_perm >> 6) & 7; // This will be ignored
+ $group = ($file_perm >> 3) & 7;
+ $other = ($file_perm >> 0) & 7;
+
+ // Does any permissions provided? if so we add execute bit for directories
+ $group = ($group !== 0) ? ($group | self::CHMOD_EXECUTE) : $group;
+ $other = ($other !== 0) ? ($other | self::CHMOD_EXECUTE) : $other;
+
+ // Compute directory permissions
+ $dir_perm = (self::CHMOD_ALL << 6) + ($group << 3) + ($other << 3);
+ }
+ else
+ {
+ // Add execute bit to owner if execute bit is among perms
+ $owner_perm = (self::CHMOD_READ | self::CHMOD_WRITE) | ($perms & self::CHMOD_EXECUTE);
+ $file_perm = ($owner_perm << 6) + ($perms << 3) + ($perms << 0);
+
+ // Compute directory permissions
+ $perm = ($perms !== 0) ? ($perms | self::CHMOD_EXECUTE) : $perms;
+ $dir_perm = (($owner_perm | self::CHMOD_EXECUTE) << 6) + ($perm << 3) + ($perm << 0);
+ }
+
+ // Symfony's filesystem component does not support extra execution flags on directories
+ // so we need to implement it again
+ foreach ($this->to_iterator($files) as $file)
+ {
+ if ($recursive && is_dir($file) && !is_link($file))
+ {
+ $this->chmod(new \FilesystemIterator($file), $perms, true);
+ }
+
+ // Don't chmod links as mostly those require 0777 and that cannot be changed
+ if (is_dir($file) || (is_link($file) && $force_chmod_link))
+ {
+ if (true !== @chmod($file, $dir_perm))
+ {
+ throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array());
+ }
+ }
+ else if (is_file($file))
+ {
+ if (true !== @chmod($file, $file_perm))
+ {
+ throw new filesystem_exception('CANNOT_CHANGE_FILE_PERMISSIONS', $file, array());
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function chown($files, $user, $recursive = false)
+ {
+ try
+ {
+ $this->symfony_filesystem->chown($files, $user, $recursive);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ // Try to recover filename
+ // By the time this is written that is at the end of the message
+ $error = trim($e->getMessage());
+ $file = substr($error, strrpos($error, ' '));
+
+ throw new filesystem_exception('CANNOT_CHANGE_FILE_GROUP', $file, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clean_path($path)
+ {
+ $exploded = explode('/', $path);
+ $filtered = array();
+ foreach ($exploded as $part)
+ {
+ if ($part === '.' && !empty($filtered))
+ {
+ continue;
+ }
+
+ if ($part === '..' && !empty($filtered) && $filtered[count($filtered) - 1] !== '.' && $filtered[count($filtered) - 1] !== '..')
+ {
+ array_pop($filtered);
+ }
+ else
+ {
+ $filtered[] = $part;
+ }
+ }
+ $path = implode('/', $filtered);
+ return $path;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function copy($origin_file, $target_file, $override = false)
+ {
+ try
+ {
+ $this->symfony_filesystem->copy($origin_file, $target_file, $override);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ throw new filesystem_exception('CANNOT_COPY_FILES', '', array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dump_file($filename, $content)
+ {
+ try
+ {
+ $this->symfony_filesystem->dumpFile($filename, $content);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ throw new filesystem_exception('CANNOT_DUMP_FILE', $filename, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function exists($files)
+ {
+ return $this->symfony_filesystem->exists($files);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_absolute_path($path)
+ {
+ return (isset($path[0]) && $path[0] === '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_readable($files, $recursive = false)
+ {
+ foreach ($this->to_iterator($files) as $file)
+ {
+ if ($recursive && is_dir($file) && !is_link($file))
+ {
+ if (!$this->is_readable(new \FilesystemIterator($file), true))
+ {
+ return false;
+ }
+ }
+
+ if (!is_readable($file))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_writable($files, $recursive = false)
+ {
+ if (defined('PHP_WINDOWS_VERSION_MAJOR') || !function_exists('is_writable'))
+ {
+ foreach ($this->to_iterator($files) as $file)
+ {
+ if ($recursive && is_dir($file) && !is_link($file))
+ {
+ if (!$this->is_writable(new \FilesystemIterator($file), true))
+ {
+ return false;
+ }
+ }
+
+ if (!$this->phpbb_is_writable($file))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // use built in is_writable
+ foreach ($this->to_iterator($files) as $file)
+ {
+ if ($recursive && is_dir($file) && !is_link($file))
+ {
+ if (!$this->is_writable(new \FilesystemIterator($file), true))
+ {
+ return false;
+ }
+ }
+
+ if (!is_writable($file))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function make_path_relative($end_path, $start_path)
+ {
+ return $this->symfony_filesystem->makePathRelative($end_path, $start_path);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mirror($origin_dir, $target_dir, \Traversable $iterator = null, $options = array())
+ {
+ try
+ {
+ $this->symfony_filesystem->mirror($origin_dir, $target_dir, $iterator, $options);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ $msg = $e->getMessage();
+ $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"'));
+
+ throw new filesystem_exception('CANNOT_MIRROR_DIRECTORY', $filename, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mkdir($dirs, $mode = 0777)
+ {
+ try
+ {
+ $this->symfony_filesystem->mkdir($dirs, $mode);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ $msg = $e->getMessage();
+ $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"'));
+
+ throw new filesystem_exception('CANNOT_CREATE_DIRECTORY', $filename, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function phpbb_chmod($files, $perms = null, $recursive = false, $force_chmod_link = false)
+ {
+ if (is_null($perms))
+ {
+ // Default to read permission for compatibility reasons
+ $perms = self::CHMOD_READ;
+ }
+
+ if (empty($this->chmod_info))
+ {
+ if (!function_exists('fileowner') || !function_exists('filegroup'))
+ {
+ $this->chmod_info['process'] = false;
+ }
+ else
+ {
+ $common_php_owner = @fileowner(__FILE__);
+ $common_php_group = @filegroup(__FILE__);
+
+ // And the owner and the groups PHP is running under.
+ $php_uid = (function_exists('posix_getuid')) ? @posix_getuid() : false;
+ $php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false;
+
+ // If we are unable to get owner/group, then do not try to set them by guessing
+ if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group)
+ {
+ $this->chmod_info['process'] = false;
+ }
+ else
+ {
+ $this->chmod_info = array(
+ 'process' => true,
+ 'common_owner' => $common_php_owner,
+ 'common_group' => $common_php_group,
+ 'php_uid' => $php_uid,
+ 'php_gids' => $php_gids,
+ );
+ }
+ }
+ }
+
+ if ($this->chmod_info['process'])
+ {
+ try
+ {
+ foreach ($this->to_iterator($files) as $file)
+ {
+ $file_uid = @fileowner($file);
+ $file_gid = @filegroup($file);
+
+ // Change owner
+ if ($file_uid !== $this->chmod_info['common_owner'])
+ {
+ $this->chown($file, $this->chmod_info['common_owner'], $recursive);
+ }
+
+ // Change group
+ if ($file_gid !== $this->chmod_info['common_group'])
+ {
+ $this->chgrp($file, $this->chmod_info['common_group'], $recursive);
+ }
+
+ clearstatcache();
+ $file_uid = @fileowner($file);
+ $file_gid = @filegroup($file);
+ }
+ }
+ catch (filesystem_exception $e)
+ {
+ $this->chmod_info['process'] = false;
+ }
+ }
+
+ // Still able to process?
+ if ($this->chmod_info['process'])
+ {
+ if ($file_uid === $this->chmod_info['php_uid'])
+ {
+ $php = 'owner';
+ }
+ else if (in_array($file_gid, $this->chmod_info['php_gids']))
+ {
+ $php = 'group';
+ }
+ else
+ {
+ // Since we are setting the everyone bit anyway, no need to do expensive operations
+ $this->chmod_info['process'] = false;
+ }
+ }
+
+ // We are not able to determine or change something
+ if (!$this->chmod_info['process'])
+ {
+ $php = 'other';
+ }
+
+ switch ($php)
+ {
+ case 'owner':
+ try
+ {
+ $this->chmod($files, $perms, $recursive, $force_chmod_link);
+ clearstatcache();
+ if ($this->is_readable($files) && $this->is_writable($files))
+ {
+ break;
+ }
+ }
+ catch (filesystem_exception $e)
+ {
+ // Do nothing
+ }
+ case 'group':
+ try
+ {
+ $this->chmod($files, $perms, $recursive, $force_chmod_link);
+ clearstatcache();
+ if ((!($perms & self::CHMOD_READ) || $this->is_readable($files, $recursive)) && (!($perms & self::CHMOD_WRITE) || $this->is_writable($files, $recursive)))
+ {
+ break;
+ }
+ }
+ catch (filesystem_exception $e)
+ {
+ // Do nothing
+ }
+ case 'other':
+ default:
+ $this->chmod($files, $perms, $recursive, $force_chmod_link);
+ break;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function realpath($path)
+ {
+ if (!function_exists('realpath'))
+ {
+ return $this->phpbb_own_realpath($path);
+ }
+
+ $realpath = realpath($path);
+
+ // Strangely there are provider not disabling realpath but returning strange values. :o
+ // We at least try to cope with them.
+ if ((!$this->is_absolute_path($path) && $realpath === $path) || $realpath === false)
+ {
+ return $this->phpbb_own_realpath($path);
+ }
+
+ // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
+ if (substr($realpath, -1) === DIRECTORY_SEPARATOR)
+ {
+ $realpath = substr($realpath, 0, -1);
+ }
+
+ return $realpath;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove($files)
+ {
+ try
+ {
+ $this->symfony_filesystem->remove($files);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ // Try to recover filename
+ // By the time this is written that is at the end of the message
+ $error = trim($e->getMessage());
+ $file = substr($error, strrpos($error, ' '));
+
+ throw new filesystem_exception('CANNOT_DELETE_FILES', $file, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rename($origin, $target, $overwrite = false)
+ {
+ try
+ {
+ $this->symfony_filesystem->rename($origin, $target, $overwrite);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ $msg = $e->getMessage();
+ $filename = substr($msg, strpos($msg, '"'), strrpos($msg, '"'));
+
+ throw new filesystem_exception('CANNOT_RENAME_FILE', $filename, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function symlink($origin_dir, $target_dir, $copy_on_windows = false)
+ {
+ try
+ {
+ $this->symfony_filesystem->symlink($origin_dir, $target_dir, $copy_on_windows);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ throw new filesystem_exception('CANNOT_CREATE_SYMLINK', $origin_dir, array(), $e);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function touch($files, $time = null, $access_time = null)
+ {
+ try
+ {
+ $this->symfony_filesystem->touch($files, $time, $access_time);
+ }
+ catch (\Symfony\Component\Filesystem\Exception\IOException $e)
+ {
+ // Try to recover filename
+ // By the time this is written that is at the end of the message
+ $error = trim($e->getMessage());
+ $file = substr($error, strrpos($error, ' '));
+
+ throw new filesystem_exception('CANNOT_TOUCH_FILES', $file, array(), $e);
+ }
+ }
+
+ /**
+ * phpBB's implementation of is_writable
+ *
+ * @todo Investigate if is_writable is still buggy
+ *
+ * @param string $file file/directory to check if writable
+ *
+ * @return bool true if the given path is writable
+ */
+ protected function phpbb_is_writable($file)
+ {
+ if (file_exists($file))
+ {
+ // Canonicalise path to absolute path
+ $file = $this->realpath($file);
+
+ if (is_dir($file))
+ {
+ // Test directory by creating a file inside the directory
+ $result = @tempnam($file, 'i_w');
+
+ if (is_string($result) && file_exists($result))
+ {
+ unlink($result);
+
+ // Ensure the file is actually in the directory (returned realpathed)
+ return (strpos($result, $file) === 0) ? true : false;
+ }
+ }
+ else
+ {
+ $handle = @fopen($file, 'c');
+
+ if (is_resource($handle))
+ {
+ fclose($handle);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ // file does not exist test if we can write to the directory
+ $dir = dirname($file);
+
+ if (file_exists($dir) && is_dir($dir) && $this->phpbb_is_writable($dir))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Try to resolve real path when PHP's realpath failes to do so
+ *
+ * @param string $path
+ * @return bool|string
+ */
+ protected function phpbb_own_realpath($path)
+ {
+ // Replace all directory separators with '/'
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
+
+ $is_absolute_path = false;
+ $path_prefix = '';
+
+ if ($this->is_absolute_path($path))
+ {
+ $is_absolute_path = true;
+ }
+ else
+ {
+ // Resolve working directory and store it
+ if (is_null($this->working_directory))
+ {
+ if (function_exists('getcwd'))
+ {
+ $this->working_directory = str_replace(DIRECTORY_SEPARATOR, '/', getcwd());
+ }
+
+ //
+ // From this point on we really just guessing
+ // If chdir were called we screwed
+ //
+ else if (function_exists('debug_backtrace'))
+ {
+ $call_stack = debug_backtrace(0);
+ $this->working_directory = str_replace(DIRECTORY_SEPARATOR, '/', dirname($call_stack[count($call_stack) - 1]['file']));
+ }
+ else
+ {
+ //
+ // Assuming that the working directory is phpBB root
+ // we could use this as a fallback, when phpBB will use controllers
+ // everywhere this will be a safe assumption
+ //
+ //$dir_parts = explode(DIRECTORY_SEPARATOR, __DIR__);
+ //$namespace_parts = explode('\\', trim(__NAMESPACE__, '\\'));
+
+ //$namespace_part_count = count($namespace_parts);
+
+ // Check if we still loading from root
+ //if (array_slice($dir_parts, -$namespace_part_count) === $namespace_parts)
+ //{
+ // $this->working_directory = implode('/', array_slice($dir_parts, 0, -$namespace_part_count));
+ //}
+ //else
+ //{
+ // $this->working_directory = false;
+ //}
+
+ $this->working_directory = false;
+ }
+ }
+
+ if ($this->working_directory !== false)
+ {
+ $is_absolute_path = true;
+ $path = $this->working_directory . '/' . $path;
+ }
+ }
+
+ if ($is_absolute_path)
+ {
+ if (defined('PHP_WINDOWS_VERSION_MAJOR'))
+ {
+ $path_prefix = $path[0] . ':';
+ $path = substr($path, 2);
+ }
+ else
+ {
+ $path_prefix = '';
+ }
+ }
+
+ $resolved_path = $this->resolve_path($path, $path_prefix, $is_absolute_path);
+ if ($resolved_path === false)
+ {
+ return false;
+ }
+
+ if (!@file_exists($resolved_path) || (!@is_dir($resolved_path . '/') && !is_file($resolved_path)))
+ {
+ return false;
+ }
+
+ // Return OS specific directory separators
+ $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved_path);
+
+ // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
+ if (substr($resolved, -1) === DIRECTORY_SEPARATOR)
+ {
+ return substr($resolved, 0, -1);
+ }
+
+ return $resolved;
+ }
+
+ /**
+ * Convert file(s) to \Traversable object
+ *
+ * This is the same function as Symfony's toIterator, but that is private
+ * so we cannot use it.
+ *
+ * @param string|array|\Traversable $files filename/list of filenames
+ * @return \Traversable
+ */
+ protected function to_iterator($files)
+ {
+ if (!$files instanceof \Traversable)
+ {
+ $files = new \ArrayObject(is_array($files) ? $files : array($files));
+ }
+
+ return $files;
+ }
+
+ /**
+ * Try to resolve symlinks in path
+ *
+ * @param string $path The path to resolve
+ * @param string $prefix The path prefix (on windows the drive letter)
+ * @param bool $absolute Whether or not the path is absolute
+ * @param bool $return_array Whether or not to return path parts
+ *
+ * @return string|array|bool returns the resolved path or an array of parts of the path if $return_array is true
+ * or false if path cannot be resolved
+ */
+ protected function resolve_path($path, $prefix = '', $absolute = false, $return_array = false)
+ {
+ if ($return_array)
+ {
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
+ }
+
+ trim ($path, '/');
+ $path_parts = explode('/', $path);
+ $resolved = array();
+ $resolved_path = $prefix;
+ $file_found = false;
+
+ foreach ($path_parts as $path_part)
+ {
+ if ($file_found)
+ {
+ return false;
+ }
+
+ if (empty($path_part) || ($path_part === '.' && ($absolute || !empty($resolved))))
+ {
+ continue;
+ }
+ else if ($absolute && $path_part === '..')
+ {
+ if (empty($resolved))
+ {
+ // No directories above root
+ return false;
+ }
+
+ array_pop($resolved);
+ $resolved_path = false;
+ }
+ else if ($path_part === '..' && !empty($resolved) && !in_array($resolved[count($resolved) - 1], array('.', '..')))
+ {
+ array_pop($resolved);
+ $resolved_path = false;
+ }
+ else
+ {
+ if ($resolved_path === false)
+ {
+ if (empty($resolved))
+ {
+ $resolved_path = ($absolute) ? $prefix . '/' . $path_part : $path_part;
+ }
+ else
+ {
+ $tmp_array = $resolved;
+ if ($absolute)
+ {
+ array_unshift($tmp_array, $prefix);
+ }
+
+ $resolved_path = implode('/', $tmp_array);
+ }
+ }
+
+ $current_path = $resolved_path . '/' . $path_part;
+
+ // Resolve symlinks
+ if (@is_link($current_path))
+ {
+ if (!function_exists('readlink'))
+ {
+ return false;
+ }
+
+ $link = readlink($current_path);
+
+ // Is link has an absolute path in it?
+ if ($this->is_absolute_path($link))
+ {
+ if (defined('PHP_WINDOWS_VERSION_MAJOR'))
+ {
+ $prefix = $link[0] . ':';
+ $link = substr($link, 2);
+ }
+ else
+ {
+ $prefix = '';
+ }
+
+ $resolved = $this->resolve_path($link, $prefix, true, true);
+ $absolute = true;
+ }
+ else
+ {
+ $resolved = $this->resolve_path($resolved_path . '/' . $link, $prefix, $absolute, true);
+ }
+
+ if (!$resolved)
+ {
+ return false;
+ }
+
+ $resolved_path = false;
+ }
+ else if (@is_dir($current_path . '/'))
+ {
+ $resolved[] = $path_part;
+ $resolved_path = $current_path;
+ }
+ else if (@is_file($current_path))
+ {
+ $resolved[] = $path_part;
+ $resolved_path = $current_path;
+ $file_found = true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ // If at the end of the path there were a .. or .
+ // we need to build the path again.
+ // Only doing this when a string is expected in return
+ if ($resolved_path === false && $return_array === false)
+ {
+ if (empty($resolved))
+ {
+ $resolved_path = ($absolute) ? $prefix . '/' : './';
+ }
+ else
+ {
+ $tmp_array = $resolved;
+ if ($absolute)
+ {
+ array_unshift($tmp_array, $prefix);
+ }
+
+ $resolved_path = implode('/', $tmp_array);
+ }
+ }
+
+ return ($return_array) ? $resolved : $resolved_path;
+ }
+}
diff --git a/phpBB/phpbb/filesystem/filesystem_interface.php b/phpBB/phpbb/filesystem/filesystem_interface.php
new file mode 100644
index 0000000000..1093be2499
--- /dev/null
+++ b/phpBB/phpbb/filesystem/filesystem_interface.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\filesystem;
+
+/**
+ * Interface for phpBB's filesystem service
+ */
+interface filesystem_interface
+{
+ /**
+ * chmod all permissions flag
+ *
+ * @var int
+ */
+ const CHMOD_ALL = 7;
+
+ /**
+ * chmod read permissions flag
+ *
+ * @var int
+ */
+ const CHMOD_READ = 4;
+
+ /**
+ * chmod write permissions flag
+ *
+ * @var int
+ */
+ const CHMOD_WRITE = 2;
+
+ /**
+ * chmod execute permissions flag
+ *
+ * @var int
+ */
+ const CHMOD_EXECUTE = 1;
+
+ /**
+ * Change owner group of files/directories
+ *
+ * @param string|array|\Traversable $files The file(s)/directorie(s) to change group
+ * @param string $group The group that should own the files/directories
+ * @param bool $recursive If the group should be changed recursively
+ * @throws \phpbb\filesystem\exception\filesystem_exception the filename which triggered the error can be
+ * retrieved by filesystem_exception::get_filename()
+ */
+ public function chgrp($files, $group, $recursive = false);
+
+ /**
+ * Global function for chmodding directories and files for internal use
+ *
+ * The function accepts filesystem_interface::CHMOD_ flags in the permission argument
+ * or the user can specify octal values (or any integer if it makes sense). All directories will have
+ * an execution bit appended, if the user group (owner, group or other) has any bit specified.
+ *
+ * @param string|array|\Traversable $files The file/directory to be chmodded
+ * @param int $perms Permissions to set
+ * @param bool $recursive If the permissions should be changed recursively
+ * @param bool $force_chmod_link Try to apply permissions to symlinks as well
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception the filename which triggered the error can be
+ * retrieved by filesystem_exception::get_filename()
+ */
+ public function chmod($files, $perms = null, $recursive = false, $force_chmod_link = false);
+
+ /**
+ * Change owner group of files/directories
+ *
+ * @param string|array|\Traversable $files The file(s)/directorie(s) to change group
+ * @param string $user The owner user name
+ * @param bool $recursive Whether change the owner recursively or not
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception the filename which triggered the error can be
+ * retrieved by filesystem_exception::get_filename()
+ */
+ public function chown($files, $user, $recursive = false);
+
+ /**
+ * Eliminates useless . and .. components from specified path.
+ *
+ * @param string $path Path to clean
+ *
+ * @return string Cleaned path
+ */
+ public function clean_path($path);
+
+ /**
+ * Copies a file.
+ *
+ * This method only copies the file if the origin file is newer than the target file.
+ *
+ * By default, if the target already exists, it is not overridden.
+ *
+ * @param string $origin_file The original filename
+ * @param string $target_file The target filename
+ * @param bool $override Whether to override an existing file or not
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception When the file cannot be copied
+ */
+ public function copy($origin_file, $target_file, $override = false);
+
+ /**
+ * Atomically dumps content into a file.
+ *
+ * @param string $filename The file to be written to.
+ * @param string $content The data to write into the file.
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception When the file cannot be written
+ */
+ public function dump_file($filename, $content);
+
+ /**
+ * Checks the existence of files or directories.
+ *
+ * @param string|array|\Traversable $files files/directories to check
+ *
+ * @return bool Returns true if all files/directories exist, false otherwise
+ */
+ public function exists($files);
+
+ /**
+ * Checks if a path is absolute or not
+ *
+ * @param string $path Path to check
+ *
+ * @return bool true if the path is absolute, false otherwise
+ */
+ public function is_absolute_path($path);
+
+ /**
+ * Checks if files/directories are readable
+ *
+ * @param string|array|\Traversable $files files/directories to check
+ * @param bool $recursive Whether or not directories should be checked recursively
+ *
+ * @return bool True when the files/directories are readable, otherwise false.
+ */
+ public function is_readable($files, $recursive = false);
+
+ /**
+ * Test if a file/directory is writable
+ *
+ * @param string|array|\Traversable $files files/directories to perform write test on
+ * @param bool $recursive Whether or not directories should be checked recursively
+ *
+ * @return bool True when the files/directories are writable, otherwise false.
+ */
+ public function is_writable($files, $recursive = false);
+
+ /**
+ * Given an existing path, convert it to a path relative to a given starting path
+ *
+ * @param string $end_path Absolute path of target
+ * @param string $start_path Absolute path where traversal begins
+ *
+ * @return string Path of target relative to starting path
+ */
+ public function make_path_relative($end_path, $start_path);
+
+ /**
+ * Mirrors a directory to another.
+ *
+ * @param string $origin_dir The origin directory
+ * @param string $target_dir The target directory
+ * @param \Traversable $iterator A Traversable instance
+ * @param array $options An array of boolean options
+ * Valid options are:
+ * - $options['override'] Whether to override an existing file on copy or not (see copy())
+ * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink())
+ * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception When the file cannot be copied.
+ * The filename which triggered the error can be
+ * retrieved by filesystem_exception::get_filename()
+ */
+ public function mirror($origin_dir, $target_dir, \Traversable $iterator = null, $options = array());
+
+ /**
+ * Creates a directory recursively.
+ *
+ * @param string|array|\Traversable $dirs The directory path
+ * @param int $mode The directory mode
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception On any directory creation failure
+ * The filename which triggered the error can be
+ * retrieved by filesystem_exception::get_filename()
+ */
+ public function mkdir($dirs, $mode = 0777);
+
+ /**
+ * Global function for chmodding directories and files for internal use
+ *
+ * This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
+ * The function determines owner and group from common.php file and sets the same to the provided file.
+ * The function uses bit fields to build the permissions.
+ * The function sets the appropiate execute bit on directories.
+ *
+ * Supported constants representing bit fields are:
+ *
+ * filesystem_interface::CHMOD_ALL - all permissions (7)
+ * filesystem_interface::CHMOD_READ - read permission (4)
+ * filesystem_interface::CHMOD_WRITE - write permission (2)
+ * filesystem_interface::CHMOD_EXECUTE - execute permission (1)
+ *
+ * NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions.
+ *
+ * @param string|array|\Traversable $file The file/directory to be chmodded
+ * @param int $perms Permissions to set
+ * @param bool $recursive If the permissions should be changed recursively
+ * @param bool $force_chmod_link Try to apply permissions to symlinks as well
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception the filename which triggered the error can be
+ * retrieved by filesystem_exception::get_filename()
+ */
+ public function phpbb_chmod($file, $perms = null, $recursive = false, $force_chmod_link = false);
+
+ /**
+ * A wrapper for PHP's realpath
+ *
+ * Try to resolve realpath when PHP's realpath is not available, or
+ * known to be buggy.
+ *
+ * @param string $path Path to resolve
+ *
+ * @return string Resolved path
+ */
+ public function realpath($path);
+
+ /**
+ * Removes files or directories.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception When removal fails.
+ * The filename which triggered the error can be
+ * retrieved by filesystem_exception::get_filename()
+ */
+ public function remove($files);
+
+ /**
+ * Renames a file or a directory.
+ *
+ * @param string $origin The origin filename or directory
+ * @param string $target The new filename or directory
+ * @param bool $overwrite Whether to overwrite the target if it already exists
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception When target file or directory already exists,
+ * or origin cannot be renamed.
+ */
+ public function rename($origin, $target, $overwrite = false);
+
+ /**
+ * Creates a symbolic link or copy a directory.
+ *
+ * @param string $origin_dir The origin directory path
+ * @param string $target_dir The symbolic link name
+ * @param bool $copy_on_windows Whether to copy files if on Windows
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception When symlink fails
+ */
+ public function symlink($origin_dir, $target_dir, $copy_on_windows = false);
+
+ /**
+ * Sets access and modification time of file.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create
+ * @param int $time The touch time as a Unix timestamp
+ * @param int $access_time The access time as a Unix timestamp
+ *
+ * @throws \phpbb\filesystem\exception\filesystem_exception When touch fails
+ */
+ public function touch($files, $time = null, $access_time = null);
+}
diff --git a/phpBB/phpbb/finder.php b/phpBB/phpbb/finder.php
index 28f28825ba..1f1d931880 100644
--- a/phpBB/phpbb/finder.php
+++ b/phpBB/phpbb/finder.php
@@ -48,14 +48,14 @@ class finder
/**
* Creates a new finder instance with its dependencies
*
- * @param \phpbb\filesystem $filesystem Filesystem instance
+ * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem instance
* @param string $phpbb_root_path Path to the phpbb root directory
- * @param \phpbb\cache\driver\driver_interface $cache A cache instance or null
+ * @param \phpbb\cache\service $cache A cache instance or null
* @param string $php_ext php file extension
* @param string $cache_name The name of the cache variable, defaults to
* _ext_finder
*/
- public function __construct(\phpbb\filesystem $filesystem, $phpbb_root_path = '', \phpbb\cache\driver\driver_interface $cache = null, $php_ext = 'php', $cache_name = '_ext_finder')
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path = '', \phpbb\cache\service $cache = null, $php_ext = 'php', $cache_name = '_ext_finder')
{
$this->filesystem = $filesystem;
$this->phpbb_root_path = $phpbb_root_path;
diff --git a/phpBB/phpbb/group/helper.php b/phpBB/phpbb/group/helper.php
new file mode 100644
index 0000000000..aa3876b325
--- /dev/null
+++ b/phpBB/phpbb/group/helper.php
@@ -0,0 +1,294 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\group;
+
+use phpbb\auth\auth;
+use phpbb\cache\service as cache;
+use phpbb\config\config;
+use phpbb\language\language;
+use phpbb\event\dispatcher_interface;
+use phpbb\path_helper;
+use phpbb\user;
+
+class helper
+{
+ /** @var auth */
+ protected $auth;
+
+ /** @var cache */
+ protected $cache;
+
+ /** @var config */
+ protected $config;
+
+ /** @var language */
+ protected $language;
+
+ /** @var dispatcher_interface */
+ protected $dispatcher;
+
+ /** @var path_helper */
+ protected $path_helper;
+
+ /** @var user */
+ protected $user;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ /** @var array Return templates for a group name string */
+ protected $name_strings;
+
+ /**
+ * Constructor
+ *
+ * @param auth $auth Authentication object
+ * @param cache $cache Cache service object
+ * @param config $config Configuration object
+ * @param language $language Language object
+ * @param dispatcher_interface $dispatcher Event dispatcher object
+ * @param path_helper $path_helper Path helper object
+ * @param user $user User object
+ */
+ public function __construct(auth $auth, cache $cache, config $config, language $language, dispatcher_interface $dispatcher, path_helper $path_helper, user $user)
+ {
+ $this->auth = $auth;
+ $this->cache = $cache;
+ $this->config = $config;
+ $this->language = $language;
+ $this->dispatcher = $dispatcher;
+ $this->path_helper = $path_helper;
+ $this->user = $user;
+
+ $this->phpbb_root_path = $path_helper->get_phpbb_root_path();
+
+ /** @html Group name spans and links for usage in the template */
+ $this->name_strings = array(
+ 'base_url' => "{$path_helper->get_phpbb_root_path()}memberlist.{$path_helper->get_php_ext()}?mode=group&amp;g={GROUP_ID}",
+ 'tpl_noprofile' => '<span class="username">{GROUP_NAME}</span>',
+ 'tpl_noprofile_colour' => '<span class="username-coloured" style="color: {GROUP_COLOUR};">{GROUP_NAME}</span>',
+ 'tpl_profile' => '<a class="username" href="{PROFILE_URL}">{GROUP_NAME}</a>',
+ 'tpl_profile_colour' => '<a class="username-coloured" href="{PROFILE_URL}" style="color: {GROUP_COLOUR};">{GROUP_NAME}</a>',
+ );
+ }
+
+ /**
+ * @param $group_name string The stored group name
+ *
+ * @return string Group name or translated group name if it exists
+ */
+ public function get_name($group_name)
+ {
+ return $this->language->is_set('G_' . utf8_strtoupper($group_name)) ? $this->language->lang('G_' . utf8_strtoupper($group_name)) : $group_name;
+ }
+
+ /**
+ * Get group name details for placing into templates.
+ *
+ * @html Group name spans and links
+ *
+ * @param string $mode Profile (for getting an url to the profile),
+ * group_name (for obtaining the group name),
+ * colour (for obtaining the group colour),
+ * full (for obtaining a coloured group name link to the group's profile),
+ * no_profile (the same as full but forcing no profile link)
+ * @param int $group_id The group id
+ * @param string $group_name The group name
+ * @param string $group_colour The group colour
+ * @param mixed $custom_profile_url optional parameter to specify a profile url. The group id gets appended to this url as &amp;g={group_id}
+ *
+ * @return string A string consisting of what is wanted based on $mode.
+ */
+ public function get_name_string($mode, $group_id, $group_name, $group_colour = '', $custom_profile_url = false)
+ {
+ $s_is_bots = ($group_name === 'BOTS');
+
+ // This switch makes sure we only run code required for the mode
+ switch ($mode)
+ {
+ case 'full':
+ case 'no_profile':
+ case 'colour':
+
+ // Build correct group colour
+ $group_colour = $group_colour ? '#' . $group_colour : '';
+
+ // Return colour
+ if ($mode === 'colour')
+ {
+ $group_name_string = $group_colour;
+ break;
+ }
+
+ // no break;
+
+ case 'group_name':
+
+ // Build correct group name
+ $group_name = $this->get_name($group_name);
+
+ // Return group name
+ if ($mode === 'group_name')
+ {
+ $group_name_string = $group_name;
+ break;
+ }
+
+ // no break;
+
+ case 'profile':
+
+ // Build correct profile url - only show if not anonymous and permission to view profile if registered user
+ // For anonymous the link leads to a login page.
+ if ($group_id && !$s_is_bots && ($this->user->data['user_id'] == ANONYMOUS || $this->auth->acl_get('u_viewprofile')))
+ {
+ $profile_url = ($custom_profile_url !== false) ? $custom_profile_url . '&amp;g=' . (int) $group_id : str_replace(array('={GROUP_ID}', '=%7BGROUP_ID%7D'), '=' . (int) $group_id, append_sid($this->name_strings['base_url']));
+ }
+ else
+ {
+ $profile_url = '';
+ }
+
+ // Return profile
+ if ($mode === 'profile')
+ {
+ $group_name_string = $profile_url;
+ break;
+ }
+
+ // no break;
+ }
+
+ if (!isset($group_name_string))
+ {
+ if (($mode === 'full' && empty($profile_url)) || $mode === 'no_profile' || $s_is_bots)
+ {
+ $group_name_string = str_replace(array('{GROUP_COLOUR}', '{GROUP_NAME}'), array($group_colour, $group_name), (!$group_colour) ? $this->name_strings['tpl_noprofile'] : $this->name_strings['tpl_noprofile_colour']);
+ }
+ else
+ {
+ $group_name_string = str_replace(array('{PROFILE_URL}', '{GROUP_COLOUR}', '{GROUP_NAME}'), array($profile_url, $group_colour, $group_name), (!$group_colour) ? $this->name_strings['tpl_profile'] : $this->name_strings['tpl_profile_colour']);
+ }
+ }
+
+ $name_strings = $this->name_strings;
+
+ /**
+ * Use this event to change the output of the group name
+ *
+ * @event core.modify_group_name_string
+ * @var string mode profile|group_name|colour|full|no_profile
+ * @var int group_id The group identifier
+ * @var string group_name The group name
+ * @var string group_colour The group colour
+ * @var string custom_profile_url Optional parameter to specify a profile url.
+ * @var string group_name_string The string that has been generated
+ * @var array name_strings Array of original return templates
+ * @since 3.2.8-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'group_id',
+ 'group_name',
+ 'group_colour',
+ 'custom_profile_url',
+ 'group_name_string',
+ 'name_strings',
+ );
+ extract($this->dispatcher->trigger_event('core.modify_group_name_string', compact($vars)));
+
+ return $group_name_string;
+ }
+
+ /**
+ * Get group rank title and image
+ *
+ * @html Group rank image element
+ *
+ * @param array $group_data The current stored group data
+ *
+ * @return array An associative array containing the rank title (title),
+ * the rank image as full img tag (img) and the rank image source (img_src)
+ */
+ public function get_rank($group_data)
+ {
+ $group_rank_data = array(
+ 'title' => null,
+ 'img' => null,
+ 'img_src' => null,
+ );
+
+ /**
+ * Preparing a group's rank before displaying
+ *
+ * @event core.get_group_rank_before
+ * @var array group_data Array with group's data
+ * @since 3.2.8-RC1
+ */
+
+ $vars = array('group_data');
+ extract($this->dispatcher->trigger_event('core.get_group_rank_before', compact($vars)));
+
+ if (!empty($group_data['group_rank']))
+ {
+ // Only obtain ranks if group rank is set
+ $ranks = $this->cache->obtain_ranks();
+
+ if (isset($ranks['special'][$group_data['group_rank']]))
+ {
+ $rank = $ranks['special'][$group_data['group_rank']];
+
+ $group_rank_data['title'] = $rank['rank_title'];
+
+ $group_rank_data['img_src'] = (!empty($rank['rank_image'])) ? $this->path_helper->update_web_root_path($this->phpbb_root_path . $this->config['ranks_path'] . '/' . $rank['rank_image']) : '';
+
+ /** @html Group rank image element for usage in the template */
+ $group_rank_data['img'] = (!empty($rank['rank_image'])) ? '<img src="' . $group_rank_data['img_src'] . '" alt="' . $rank['rank_title'] . '" title="' . $rank['rank_title'] . '" />' : '';
+ }
+ }
+
+ /**
+ * Modify a group's rank before displaying
+ *
+ * @event core.get_group_rank_after
+ * @var array group_data Array with group's data
+ * @var array group_rank_data Group rank data
+ * @since 3.2.8-RC1
+ */
+
+ $vars = array(
+ 'group_data',
+ 'group_rank_data',
+ );
+ extract($this->dispatcher->trigger_event('core.get_group_rank_after', compact($vars)));
+
+ return $group_rank_data;
+ }
+
+ /**
+ * Get group avatar.
+ * Wrapper function for phpbb_get_group_avatar()
+ *
+ * @param array $group_row Row from the groups table
+ * @param string $alt Optional language string for alt tag within image, can be a language key or text
+ * @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
+ * @param bool $lazy If true, will be lazy loaded (requires JS)
+ *
+ * @return string Avatar html
+ */
+ function get_avatar($group_row, $alt = 'GROUP_AVATAR', $ignore_config = false, $lazy = false)
+ {
+ return phpbb_get_group_avatar($group_row, $alt, $ignore_config, $lazy);
+ }
+}
diff --git a/phpBB/phpbb/help/controller/bbcode.php b/phpBB/phpbb/help/controller/bbcode.php
new file mode 100644
index 0000000000..e16f99023d
--- /dev/null
+++ b/phpBB/phpbb/help/controller/bbcode.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\help\controller;
+
+/**
+ * BBCode help page
+ */
+class bbcode extends controller
+{
+ /**
+ * @return string The title of the page
+ */
+ public function display()
+ {
+ $this->language->add_lang('help/bbcode');
+
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_INTRO',
+ false,
+ array(
+ 'HELP_BBCODE_INTRO_BBCODE_QUESTION' => 'HELP_BBCODE_INTRO_BBCODE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_TEXT',
+ false,
+ array(
+ 'HELP_BBCODE_TEXT_BASIC_QUESTION' => 'HELP_BBCODE_TEXT_BASIC_ANSWER',
+ 'HELP_BBCODE_TEXT_COLOR_QUESTION' => 'HELP_BBCODE_TEXT_COLOR_ANSWER',
+ 'HELP_BBCODE_TEXT_COMBINE_QUESTION' => 'HELP_BBCODE_TEXT_COMBINE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_QUOTES',
+ false,
+ array(
+ 'HELP_BBCODE_QUOTES_TEXT_QUESTION' => 'HELP_BBCODE_QUOTES_TEXT_ANSWER',
+ 'HELP_BBCODE_QUOTES_CODE_QUESTION' => 'HELP_BBCODE_QUOTES_CODE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_LISTS',
+ false,
+ array(
+ 'HELP_BBCODE_LISTS_UNORDERER_QUESTION' => 'HELP_BBCODE_LISTS_UNORDERER_ANSWER',
+ 'HELP_BBCODE_LISTS_ORDERER_QUESTION' => 'HELP_BBCODE_LISTS_ORDERER_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_LINKS',
+ true,
+ array(
+ 'HELP_BBCODE_LINKS_BASIC_QUESTION' => 'HELP_BBCODE_LINKS_BASIC_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_IMAGES',
+ false,
+ array(
+ 'HELP_BBCODE_IMAGES_BASIC_QUESTION' => 'HELP_BBCODE_IMAGES_BASIC_ANSWER',
+ 'HELP_BBCODE_IMAGES_ATTACHMENT_QUESTION' => 'HELP_BBCODE_IMAGES_ATTACHMENT_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_BBCODE_BLOCK_OTHERS',
+ false,
+ array(
+ 'HELP_BBCODE_OTHERS_CUSTOM_QUESTION' => 'HELP_BBCODE_OTHERS_CUSTOM_ANSWER',
+ )
+ );
+
+ return $this->language->lang('BBCODE_GUIDE');
+ }
+}
diff --git a/phpBB/phpbb/help/controller/controller.php b/phpBB/phpbb/help/controller/controller.php
new file mode 100644
index 0000000000..29494205a9
--- /dev/null
+++ b/phpBB/phpbb/help/controller/controller.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\help\controller;
+
+/**
+ * BBCode help page
+ */
+abstract class controller
+{
+ /** @var \phpbb\controller\helper */
+ protected $helper;
+
+ /** @var \phpbb\help\manager */
+ protected $manager;
+
+ /** @var \phpbb\template\template */
+ protected $template;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var string */
+ protected $root_path;
+
+ /** @var string */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\controller\helper $helper
+ * @param \phpbb\help\manager $manager
+ * @param \phpbb\template\template $template
+ * @param \phpbb\language\language $language
+ * @param string $root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\controller\helper $helper, \phpbb\help\manager $manager, \phpbb\template\template $template, \phpbb\language\language $language, $root_path, $php_ext)
+ {
+ $this->helper = $helper;
+ $this->manager = $manager;
+ $this->template = $template;
+ $this->language = $language;
+ $this->root_path = $root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * @return string
+ */
+ abstract protected function display();
+
+ public function handle()
+ {
+ $title = $this->display();
+
+ $this->template->assign_vars(array(
+ 'L_FAQ_TITLE' => $title,
+ 'S_IN_FAQ' => true,
+ ));
+
+ make_jumpbox(append_sid("{$this->root_path}viewforum.{$this->php_ext}"));
+ return $this->helper->render('faq_body.html', $title);
+ }
+}
diff --git a/phpBB/phpbb/help/controller/faq.php b/phpBB/phpbb/help/controller/faq.php
new file mode 100644
index 0000000000..5e45cfe667
--- /dev/null
+++ b/phpBB/phpbb/help/controller/faq.php
@@ -0,0 +1,165 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\help\controller;
+
+/**
+ * FAQ help page
+ */
+class faq extends controller
+{
+ /**
+ * @return string The title of the page
+ */
+ public function display()
+ {
+ $this->language->add_lang('help/faq');
+
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_LOGIN',
+ false,
+ array(
+ 'HELP_FAQ_LOGIN_REGISTER_QUESTION' => 'HELP_FAQ_LOGIN_REGISTER_ANSWER',
+ 'HELP_FAQ_LOGIN_COPPA_QUESTION' => 'HELP_FAQ_LOGIN_COPPA_ANSWER',
+ 'HELP_FAQ_LOGIN_CANNOT_REGISTER_QUESTION' => 'HELP_FAQ_LOGIN_CANNOT_REGISTER_ANSWER',
+ 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_QUESTION' => 'HELP_FAQ_LOGIN_REGISTER_CONFIRM_ANSWER',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_QUESTION' => 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANSWER',
+ 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_QUESTION' => 'HELP_FAQ_LOGIN_CANNOT_LOGIN_ANYMORE_ANSWER',
+ 'HELP_FAQ_LOGIN_LOST_PASSWORD_QUESTION' => 'HELP_FAQ_LOGIN_LOST_PASSWORD_ANSWER',
+ 'HELP_FAQ_LOGIN_AUTO_LOGOUT_QUESTION' => 'HELP_FAQ_LOGIN_AUTO_LOGOUT_ANSWER',
+ 'HELP_FAQ_LOGIN_DELETE_COOKIES_QUESTION' => 'HELP_FAQ_LOGIN_DELETE_COOKIES_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_USERSETTINGS',
+ false,
+ array(
+ 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_QUESTION' => 'HELP_FAQ_USERSETTINGS_CHANGE_SETTINGS_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_QUESTION' => 'HELP_FAQ_USERSETTINGS_HIDE_ONLINE_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_TIMEZONE_QUESTION' => 'HELP_FAQ_USERSETTINGS_TIMEZONE_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_SERVERTIME_QUESTION' => 'HELP_FAQ_USERSETTINGS_SERVERTIME_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_LANGUAGE_QUESTION' => 'HELP_FAQ_USERSETTINGS_LANGUAGE_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_AVATAR_QUESTION' => 'HELP_FAQ_USERSETTINGS_AVATAR_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_QUESTION' => 'HELP_FAQ_USERSETTINGS_AVATAR_DISPLAY_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_RANK_QUESTION' => 'HELP_FAQ_USERSETTINGS_RANK_ANSWER',
+ 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_QUESTION' => 'HELP_FAQ_USERSETTINGS_EMAIL_LOGIN_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_POSTING',
+ false,
+ array(
+ 'HELP_FAQ_POSTING_CREATE_QUESTION' => 'HELP_FAQ_POSTING_CREATE_ANSWER',
+ 'HELP_FAQ_POSTING_EDIT_DELETE_QUESTION' => 'HELP_FAQ_POSTING_EDIT_DELETE_ANSWER',
+ 'HELP_FAQ_POSTING_SIGNATURE_QUESTION' => 'HELP_FAQ_POSTING_SIGNATURE_ANSWER',
+ 'HELP_FAQ_POSTING_POLL_CREATE_QUESTION' => 'HELP_FAQ_POSTING_POLL_CREATE_ANSWER',
+ 'HELP_FAQ_POSTING_POLL_ADD_QUESTION' => 'HELP_FAQ_POSTING_POLL_ADD_ANSWER',
+ 'HELP_FAQ_POSTING_POLL_EDIT_QUESTION' => 'HELP_FAQ_POSTING_POLL_EDIT_ANSWER',
+ 'HELP_FAQ_POSTING_FORUM_RESTRICTED_QUESTION' => 'HELP_FAQ_POSTING_FORUM_RESTRICTED_ANSWER',
+ 'HELP_FAQ_POSTING_NO_ATTACHMENTS_QUESTION' => 'HELP_FAQ_POSTING_NO_ATTACHMENTS_ANSWER',
+ 'HELP_FAQ_POSTING_WARNING_QUESTION' => 'HELP_FAQ_POSTING_WARNING_ANSWER',
+ 'HELP_FAQ_POSTING_REPORT_QUESTION' => 'HELP_FAQ_POSTING_REPORT_ANSWER',
+ 'HELP_FAQ_POSTING_DRAFT_QUESTION' => 'HELP_FAQ_POSTING_DRAFT_ANSWER',
+ 'HELP_FAQ_POSTING_QUEUE_QUESTION' => 'HELP_FAQ_POSTING_QUEUE_ANSWER',
+ 'HELP_FAQ_POSTING_BUMP_QUESTION' => 'HELP_FAQ_POSTING_BUMP_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_FORMATTING',
+ false,
+ array(
+ 'HELP_FAQ_FORMATTING_BBOCDE_QUESTION' => 'HELP_FAQ_FORMATTING_BBOCDE_ANSWER',
+ 'HELP_FAQ_FORMATTING_HTML_QUESTION' => 'HELP_FAQ_FORMATTING_HTML_ANSWER',
+ 'HELP_FAQ_FORMATTING_SMILIES_QUESTION' => 'HELP_FAQ_FORMATTING_SMILIES_ANSWER',
+ 'HELP_FAQ_FORMATTING_IMAGES_QUESTION' => 'HELP_FAQ_FORMATTING_IMAGES_ANSWER',
+ 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_QUESTION' => 'HELP_FAQ_FORMATTING_GLOBAL_ANNOUNCE_ANSWER',
+ 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_QUESTION' => 'HELP_FAQ_FORMATTING_ANNOUNCEMENT_ANSWER',
+ 'HELP_FAQ_FORMATTING_STICKIES_QUESTION' => 'HELP_FAQ_FORMATTING_STICKIES_ANSWER',
+ 'HELP_FAQ_FORMATTING_LOCKED_QUESTION' => 'HELP_FAQ_FORMATTING_LOCKED_ANSWER',
+ 'HELP_FAQ_FORMATTING_ICONS_QUESTION' => 'HELP_FAQ_FORMATTING_ICONS_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_GROUPS',
+ true,
+ array(
+ 'HELP_FAQ_GROUPS_ADMINISTRATORS_QUESTION' => 'HELP_FAQ_GROUPS_ADMINISTRATORS_ANSWER',
+ 'HELP_FAQ_GROUPS_MODERATORS_QUESTION' => 'HELP_FAQ_GROUPS_MODERATORS_ANSWER',
+ 'HELP_FAQ_GROUPS_USERGROUPS_QUESTION' => 'HELP_FAQ_GROUPS_USERGROUPS_ANSWER',
+ 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_QUESTION' => 'HELP_FAQ_GROUPS_USERGROUPS_JOIN_ANSWER',
+ 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_QUESTION' => 'HELP_FAQ_GROUPS_USERGROUPS_LEAD_ANSWER',
+ 'HELP_FAQ_GROUPS_COLORS_QUESTION' => 'HELP_FAQ_GROUPS_COLORS_ANSWER',
+ 'HELP_FAQ_GROUPS_DEFAULT_QUESTION' => 'HELP_FAQ_GROUPS_DEFAULT_ANSWER',
+ 'HELP_FAQ_GROUPS_TEAM_QUESTION' => 'HELP_FAQ_GROUPS_TEAM_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_PMS',
+ false,
+ array(
+ 'HELP_FAQ_PMS_CANNOT_SEND_QUESTION' => 'HELP_FAQ_PMS_CANNOT_SEND_ANSWER',
+ 'HELP_FAQ_PMS_UNWANTED_QUESTION' => 'HELP_FAQ_PMS_UNWANTED_ANSWER',
+ 'HELP_FAQ_PMS_SPAM_QUESTION' => 'HELP_FAQ_PMS_SPAM_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_FRIENDS',
+ false,
+ array(
+ 'HELP_FAQ_FRIENDS_BASIC_QUESTION' => 'HELP_FAQ_FRIENDS_BASIC_ANSWER',
+ 'HELP_FAQ_FRIENDS_MANAGE_QUESTION' => 'HELP_FAQ_FRIENDS_MANAGE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_SEARCH',
+ false,
+ array(
+ 'HELP_FAQ_SEARCH_FORUM_QUESTION' => 'HELP_FAQ_SEARCH_FORUM_ANSWER',
+ 'HELP_FAQ_SEARCH_NO_RESULT_QUESTION' => 'HELP_FAQ_SEARCH_NO_RESULT_ANSWER',
+ 'HELP_FAQ_SEARCH_BLANK_QUESTION' => 'HELP_FAQ_SEARCH_BLANK_ANSWER',
+ 'HELP_FAQ_SEARCH_MEMBERS_QUESTION' => 'HELP_FAQ_SEARCH_MEMBERS_ANSWER',
+ 'HELP_FAQ_SEARCH_OWN_QUESTION' => 'HELP_FAQ_SEARCH_OWN_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_BOOKMARKS',
+ false,
+ array(
+ 'HELP_FAQ_BOOKMARKS_DIFFERENCE_QUESTION' => 'HELP_FAQ_BOOKMARKS_DIFFERENCE_ANSWER',
+ 'HELP_FAQ_BOOKMARKS_TOPIC_QUESTION' => 'HELP_FAQ_BOOKMARKS_TOPIC_ANSWER',
+ 'HELP_FAQ_BOOKMARKS_FORUM_QUESTION' => 'HELP_FAQ_BOOKMARKS_FORUM_ANSWER',
+ 'HELP_FAQ_BOOKMARKS_REMOVE_QUESTION' => 'HELP_FAQ_BOOKMARKS_REMOVE_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_ATTACHMENTS',
+ false,
+ array(
+ 'HELP_FAQ_ATTACHMENTS_ALLOWED_QUESTION' => 'HELP_FAQ_ATTACHMENTS_ALLOWED_ANSWER',
+ 'HELP_FAQ_ATTACHMENTS_OWN_QUESTION' => 'HELP_FAQ_ATTACHMENTS_OWN_ANSWER',
+ )
+ );
+ $this->manager->add_block(
+ 'HELP_FAQ_BLOCK_ISSUES',
+ false,
+ array(
+ 'HELP_FAQ_ISSUES_WHOIS_PHPBB_QUESTION' => 'HELP_FAQ_ISSUES_WHOIS_PHPBB_ANSWER',
+ 'HELP_FAQ_ISSUES_FEATURE_QUESTION' => 'HELP_FAQ_ISSUES_FEATURE_ANSWER',
+ 'HELP_FAQ_ISSUES_LEGAL_QUESTION' => 'HELP_FAQ_ISSUES_LEGAL_ANSWER',
+ 'HELP_FAQ_ISSUES_ADMIN_QUESTION' => 'HELP_FAQ_ISSUES_ADMIN_ANSWER',
+ )
+ );
+
+ return $this->language->lang('FAQ_EXPLAIN');
+ }
+}
diff --git a/phpBB/phpbb/help/controller/help.php b/phpBB/phpbb/help/controller/help.php
new file mode 100644
index 0000000000..3bf6fe3098
--- /dev/null
+++ b/phpBB/phpbb/help/controller/help.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\help\controller;
+
+use phpbb\exception\http_exception;
+
+class help
+{
+ /** @var \phpbb\controller\helper */
+ protected $helper;
+
+ /** @var \phpbb\event\dispatcher_interface */
+ protected $dispatcher;
+
+ /** @var \phpbb\template\template */
+ protected $template;
+
+ /** @var \phpbb\user */
+ protected $user;
+
+ /** @var string */
+ protected $root_path;
+
+ /** @var string */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\controller\helper $helper
+ * @param \phpbb\event\dispatcher_interface $dispatcher
+ * @param \phpbb\template\template $template
+ * @param \phpbb\user $user
+ * @param string $root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\controller\helper $helper, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\template\template $template, \phpbb\user $user, $root_path, $php_ext)
+ {
+ $this->helper = $helper;
+ $this->dispatcher = $dispatcher;
+ $this->template = $template;
+ $this->user = $user;
+ $this->root_path = $root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Controller for /help/{mode} routes
+ *
+ * @param string $mode
+ * @return \Symfony\Component\HttpFoundation\Response A Symfony Response object
+ * @throws http_exception when the $mode is not known by any extension
+ */
+ public function handle($mode)
+ {
+ $template_file = 'faq_body.html';
+ switch ($mode)
+ {
+ case 'faq':
+ case 'bbcode':
+ $page_title = ($mode === 'faq') ? $this->user->lang['FAQ_EXPLAIN'] : $this->user->lang['BBCODE_GUIDE'];
+ $this->user->add_lang($mode, false, true);
+ break;
+
+ default:
+ $page_title = $this->user->lang['FAQ_EXPLAIN'];
+ $ext_name = $lang_file = '';
+
+ /**
+ * You can use this event display a custom help page
+ *
+ * @event core.faq_mode_validation
+ * @var string page_title Title of the page
+ * @var string mode FAQ that is going to be displayed
+ * @var string lang_file Language file containing the help data
+ * @var string ext_name Vendor and extension name where the help
+ * language file can be loaded from
+ * @var string template_file Template file name
+ * @since 3.1.4-RC1
+ * @changed 3.1.11-RC1 Added template_file var
+ */
+ $vars = array(
+ 'page_title',
+ 'mode',
+ 'lang_file',
+ 'ext_name',
+ 'template_file',
+ );
+ extract($this->dispatcher->trigger_event('core.faq_mode_validation', compact($vars)));
+
+ if ($ext_name === '' || $lang_file === '')
+ {
+ throw new http_exception(404, 'Not Found');
+ }
+
+ $this->user->add_lang($lang_file, false, true, $ext_name);
+ break;
+
+ }
+
+ $this->template->assign_vars(array(
+ 'L_FAQ_TITLE' => $page_title,
+ 'S_IN_FAQ' => true,
+ ));
+
+ $this->assign_to_template($this->user->help);
+
+ make_jumpbox(append_sid("{$this->root_path}viewforum.{$this->php_ext}"));
+ return $this->helper->render($template_file, $page_title);
+ }
+
+ /**
+ * Assigns the help data to the template blocks
+ *
+ * @param array $help_data
+ * @return null
+ */
+ protected function assign_to_template(array $help_data)
+ {
+ // Pull the array data from the lang pack
+ $switch_column = $found_switch = false;
+ foreach ($help_data as $help_ary)
+ {
+ if ($help_ary[0] == '--')
+ {
+ if ($help_ary[1] == '--')
+ {
+ $switch_column = true;
+ $found_switch = true;
+ continue;
+ }
+
+ $this->template->assign_block_vars('faq_block', array(
+ 'BLOCK_TITLE' => $help_ary[1],
+ 'SWITCH_COLUMN' => $switch_column,
+ ));
+
+ if ($switch_column)
+ {
+ $switch_column = false;
+ }
+ continue;
+ }
+
+ $this->template->assign_block_vars('faq_block.faq_row', array(
+ 'FAQ_QUESTION' => $help_ary[0],
+ 'FAQ_ANSWER' => $help_ary[1],
+ ));
+ }
+
+ $this->template->assign_var('SWITCH_COLUMN_MANUALLY', !$found_switch);
+ }
+}
diff --git a/phpBB/phpbb/help/manager.php b/phpBB/phpbb/help/manager.php
new file mode 100644
index 0000000000..1637c58a61
--- /dev/null
+++ b/phpBB/phpbb/help/manager.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\help;
+
+/**
+ * Class help page manager
+ */
+class manager
+{
+ /** @var \phpbb\event\dispatcher_interface */
+ protected $dispatcher;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\template\template */
+ protected $template;
+
+ /** @var bool */
+ protected $switched_column;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\event\dispatcher_interface $dispatcher
+ * @param \phpbb\language\language $language
+ * @param \phpbb\template\template $template
+ */
+ public function __construct(\phpbb\event\dispatcher_interface $dispatcher, \phpbb\language\language $language, \phpbb\template\template $template)
+ {
+ $this->dispatcher = $dispatcher;
+ $this->language = $language;
+ $this->template = $template;
+ }
+
+ /**
+ * Add a new faq block
+ *
+ * @param string $block_name Name or language key with the name of the block
+ * @param bool $switch_column Switch the column of the menu
+ * @param array $questions Array of frequently asked questions
+ */
+ public function add_block($block_name, $switch_column = false, $questions = array())
+ {
+ /**
+ * You can use this event to add a block before the current one.
+ *
+ * @event core.help_manager_add_block_before
+ * @var string block_name Language key of the block headline
+ * @var bool switch_column Should we switch the menu column before this headline
+ * @var array questions Array with questions
+ * @since 3.2.0-a1
+ */
+ $vars = array('block_name', 'switch_column', 'questions');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_block_before', compact($vars)));
+
+ $this->template->assign_block_vars('faq_block', array(
+ 'BLOCK_TITLE' => $this->language->lang($block_name),
+ 'SWITCH_COLUMN' => !$this->switched_column && $switch_column,
+ ));
+
+ foreach ($questions as $question => $answer)
+ {
+ $this->add_question($question, $answer);
+ }
+
+ $this->switched_column = $this->switched_column || $switch_column;
+
+ /**
+ * You can use this event to add a block after the current one.
+ *
+ * @event core.help_manager_add_block_after
+ * @var string block_name Language key of the block headline
+ * @var bool switch_column Should we switch the menu column before this headline
+ * @var array questions Array with questions
+ * @since 3.2.0-a1
+ */
+ $vars = array('block_name', 'switch_column', 'questions');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_block_after', compact($vars)));
+ }
+
+ /**
+ * Add a new faq question
+ *
+ * @param string $question Question or language key with the question of the block
+ * @param string $answer Answer or language key with the answer of the block
+ */
+ public function add_question($question, $answer)
+ {
+ /**
+ * You can use this event to add a question before the current one.
+ *
+ * @event core.help_manager_add_question_before
+ * @var string question Language key of the question
+ * @var string answer Language key of the answer
+ * @since 3.2.0-a1
+ */
+ $vars = array('question', 'answer');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_question_before', compact($vars)));
+
+ $this->template->assign_block_vars('faq_block.faq_row', array(
+ 'FAQ_QUESTION' => $this->language->lang($question),
+ 'FAQ_ANSWER' => $this->language->lang($answer),
+ ));
+
+ /**
+ * You can use this event to add a question after the current one.
+ *
+ * @event core.help_manager_add_question_after
+ * @var string question Language key of the question
+ * @var string answer Language key of the answer
+ * @since 3.2.0-a1
+ */
+ $vars = array('question', 'answer');
+ extract($this->dispatcher->trigger_event('core.help_manager_add_question_after', compact($vars)));
+ }
+
+ /**
+ * Returns whether the block titles switched side
+ * @return bool
+ */
+ public function switched_column()
+ {
+ return $this->switched_column;
+ }
+}
diff --git a/phpBB/phpbb/hook/finder.php b/phpBB/phpbb/hook/finder.php
index a3d02d3aa0..f5a68a1370 100644
--- a/phpBB/phpbb/hook/finder.php
+++ b/phpBB/phpbb/hook/finder.php
@@ -18,8 +18,19 @@ namespace phpbb\hook;
*/
class finder
{
- protected $phpbb_root_path;
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
protected $cache;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
protected $php_ext;
/**
diff --git a/phpBB/phpbb/install/console/command/install/config/show.php b/phpBB/phpbb/install/console/command/install/config/show.php
new file mode 100644
index 0000000000..b6c11956fe
--- /dev/null
+++ b/phpBB/phpbb/install/console/command/install/config/show.php
@@ -0,0 +1,123 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install\console\command\install\config;
+
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\installer_configuration;
+use phpbb\language\language;
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+
+class show extends \phpbb\console\command\command
+{
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * Constructor
+ *
+ * @param language $language
+ * @param factory $factory
+ */
+ public function __construct(language $language, factory $factory)
+ {
+ $this->iohandler_factory = $factory;
+ $this->language = $language;
+
+ parent::__construct(new \phpbb\user($language, 'datetime'));
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('install:config:show')
+ ->addArgument(
+ 'config-file',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_CONFIG_FILE'))
+ ->setDescription($this->language->lang('CLI_INSTALL_SHOW_CONFIG'))
+ ;
+ }
+
+ /**
+ * Show the validated configuration
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ *
+ * @return null
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->iohandler_factory->set_environment('cli');
+
+ /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $style = new SymfonyStyle($input, $output);
+ $iohandler->set_style($style, $output);
+
+ $config_file = $input->getArgument('config-file');
+
+ if (!is_file($config_file))
+ {
+ $iohandler->add_error_message(array('MISSING_FILE', $config_file));
+
+ return;
+ }
+
+ try
+ {
+ $config = Yaml::parse(file_get_contents($config_file), true, false);
+ }
+ catch (ParseException $e)
+ {
+ $iohandler->add_error_message('INVALID_YAML_FILE');
+
+ return;
+ }
+
+ $processor = new Processor();
+ $configuration = new installer_configuration();
+
+ try
+ {
+ $config = $processor->processConfiguration($configuration, $config);
+ }
+ catch (Exception $e)
+ {
+ $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage());
+
+ return;
+ }
+
+ $style->block(Yaml::dump(array('installer' => $config), 10, 4, true, false));
+ }
+}
diff --git a/phpBB/phpbb/install/console/command/install/config/validate.php b/phpBB/phpbb/install/console/command/install/config/validate.php
new file mode 100644
index 0000000000..b48a1acbd4
--- /dev/null
+++ b/phpBB/phpbb/install/console/command/install/config/validate.php
@@ -0,0 +1,124 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install\console\command\install\config;
+
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\installer_configuration;
+use phpbb\language\language;
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+
+class validate extends \phpbb\console\command\command
+{
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * Constructor
+ *
+ * @param language $language
+ * @param factory $factory
+ */
+ public function __construct(language $language, factory $factory)
+ {
+ $this->iohandler_factory = $factory;
+ $this->language = $language;
+
+ parent::__construct(new \phpbb\user($language, 'datetime'));
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('install:config:validate')
+ ->addArgument(
+ 'config-file',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_CONFIG_FILE'))
+ ->setDescription($this->language->lang('CLI_INSTALL_VALIDATE_CONFIG'))
+ ;
+ }
+
+ /**
+ * Validate the configuration file
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ *
+ * @return null
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->iohandler_factory->set_environment('cli');
+
+ /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $style = new SymfonyStyle($input, $output);
+ $iohandler->set_style($style, $output);
+
+ $config_file = $input->getArgument('config-file');
+
+ if (!is_file($config_file))
+ {
+ $iohandler->add_error_message(array('MISSING_FILE', array($config_file)));
+
+ return 1;
+ }
+
+ try
+ {
+ $config = Yaml::parse(file_get_contents($config_file), true, false);
+ }
+ catch (ParseException $e)
+ {
+ $iohandler->add_error_message('INVALID_YAML_FILE');
+
+ return 1;
+ }
+
+ $processor = new Processor();
+ $configuration = new installer_configuration();
+
+ try
+ {
+ $processor->processConfiguration($configuration, $config);
+ }
+ catch (Exception $e)
+ {
+ $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage());
+
+ return 1;
+ }
+
+ $iohandler->add_success_message('CONFIGURATION_VALID');
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/install/console/command/install/install.php b/phpBB/phpbb/install/console/command/install/install.php
new file mode 100644
index 0000000000..52a348fe44
--- /dev/null
+++ b/phpBB/phpbb/install/console/command/install/install.php
@@ -0,0 +1,210 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install\console\command\install;
+
+use phpbb\install\exception\installer_exception;
+use phpbb\install\helper\install_helper;
+use phpbb\install\helper\iohandler\cli_iohandler;
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\installer;
+use phpbb\install\installer_configuration;
+use phpbb\language\language;
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+
+class install extends \phpbb\console\command\command
+{
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var installer
+ */
+ protected $installer;
+
+ /**
+ * @var install_helper
+ */
+ protected $install_helper;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * Constructor
+ *
+ * @param language $language
+ * @param factory $factory
+ * @param installer $installer
+ * @param install_helper $install_helper
+ */
+ public function __construct(language $language, factory $factory, installer $installer, install_helper $install_helper)
+ {
+ $this->iohandler_factory = $factory;
+ $this->installer = $installer;
+ $this->language = $language;
+ $this->install_helper = $install_helper;
+
+ parent::__construct(new \phpbb\user($language, 'datetime'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('install')
+ ->addArgument(
+ 'config-file',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_CONFIG_FILE'))
+ ->setDescription($this->language->lang('CLI_INSTALL_BOARD'))
+ ;
+ }
+
+ /**
+ * Executes the command install.
+ *
+ * Install the board
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ *
+ * @return null
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->iohandler_factory->set_environment('cli');
+
+ /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $style = new SymfonyStyle($input, $output);
+ $iohandler->set_style($style, $output);
+
+ $this->installer->set_iohandler($iohandler);
+
+ $config_file = $input->getArgument('config-file');
+
+ if ($this->install_helper->is_phpbb_installed())
+ {
+ $iohandler->add_error_message('INSTALL_PHPBB_INSTALLED');
+
+ return 1;
+ }
+
+ if (!is_file($config_file))
+ {
+ $iohandler->add_error_message(array('MISSING_FILE', $config_file));
+
+ return 1;
+ }
+
+ try
+ {
+ $config = Yaml::parse(file_get_contents($config_file), true, false);
+ }
+ catch (ParseException $e)
+ {
+ $iohandler->add_error_message(array('INVALID_YAML_FILE', $config_file));
+
+ return 1;
+ }
+
+ $processor = new Processor();
+ $configuration = new installer_configuration();
+
+ try
+ {
+ $config = $processor->processConfiguration($configuration, $config);
+ }
+ catch (Exception $e)
+ {
+ $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage());
+
+ return 1;
+ }
+
+ $this->register_configuration($iohandler, $config);
+
+ try
+ {
+ $this->installer->run();
+ return 0;
+ }
+ catch (installer_exception $e)
+ {
+ $iohandler->add_error_message($e->getMessage());
+ return 1;
+ }
+ }
+
+ /**
+ * Register the configuration to simulate the forms.
+ *
+ * @param cli_iohandler $iohandler
+ * @param array $config
+ */
+ private function register_configuration(cli_iohandler $iohandler, $config)
+ {
+ $iohandler->set_input('admin_name', $config['admin']['name']);
+ $iohandler->set_input('admin_pass1', $config['admin']['password']);
+ $iohandler->set_input('admin_pass2', $config['admin']['password']);
+ $iohandler->set_input('board_email', $config['admin']['email']);
+ $iohandler->set_input('submit_admin', 'submit');
+
+ $iohandler->set_input('default_lang', $config['board']['lang']);
+ $iohandler->set_input('board_name', $config['board']['name']);
+ $iohandler->set_input('board_description', $config['board']['description']);
+ $iohandler->set_input('submit_board', 'submit');
+
+ $iohandler->set_input('dbms', $config['database']['dbms']);
+ $iohandler->set_input('dbhost', $config['database']['dbhost']);
+ $iohandler->set_input('dbport', $config['database']['dbport']);
+ $iohandler->set_input('dbuser', $config['database']['dbuser']);
+ $iohandler->set_input('dbpasswd', $config['database']['dbpasswd']);
+ $iohandler->set_input('dbname', $config['database']['dbname']);
+ $iohandler->set_input('table_prefix', $config['database']['table_prefix']);
+ $iohandler->set_input('submit_database', 'submit');
+
+ $iohandler->set_input('email_enable', $config['email']['enabled']);
+ $iohandler->set_input('smtp_delivery', $config['email']['smtp_delivery']);
+ $iohandler->set_input('smtp_host', $config['email']['smtp_host']);
+ $iohandler->set_input('smtp_port', $config['email']['smtp_port']);
+ $iohandler->set_input('smtp_auth', $config['email']['smtp_auth']);
+ $iohandler->set_input('smtp_user', $config['email']['smtp_user']);
+ $iohandler->set_input('smtp_pass', $config['email']['smtp_pass']);
+ $iohandler->set_input('submit_email', 'submit');
+
+ $iohandler->set_input('cookie_secure', $config['server']['cookie_secure']);
+ $iohandler->set_input('server_protocol', $config['server']['server_protocol']);
+ $iohandler->set_input('force_server_vars', $config['server']['force_server_vars']);
+ $iohandler->set_input('server_name', $config['server']['server_name']);
+ $iohandler->set_input('server_port', $config['server']['server_port']);
+ $iohandler->set_input('script_path', $config['server']['script_path']);
+ $iohandler->set_input('submit_server', 'submit');
+
+ $iohandler->set_input('install-extensions', $config['extensions']);
+ }
+}
diff --git a/phpBB/phpbb/install/console/command/update/config/show.php b/phpBB/phpbb/install/console/command/update/config/show.php
new file mode 100644
index 0000000000..e462763b5d
--- /dev/null
+++ b/phpBB/phpbb/install/console/command/update/config/show.php
@@ -0,0 +1,123 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install\console\command\update\config;
+
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\updater_configuration;
+use phpbb\language\language;
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+
+class show extends \phpbb\console\command\command
+{
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * Constructor
+ *
+ * @param language $language
+ * @param factory $factory
+ */
+ public function __construct(language $language, factory $factory)
+ {
+ $this->iohandler_factory = $factory;
+ $this->language = $language;
+
+ parent::__construct(new \phpbb\user($language, 'datetime'));
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('update:config:show')
+ ->addArgument(
+ 'config-file',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_CONFIG_FILE'))
+ ->setDescription($this->language->lang('CLI_INSTALL_SHOW_CONFIG'))
+ ;
+ }
+
+ /**
+ * Show the validated configuration
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ *
+ * @return null
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->iohandler_factory->set_environment('cli');
+
+ /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $style = new SymfonyStyle($input, $output);
+ $iohandler->set_style($style, $output);
+
+ $config_file = $input->getArgument('config-file');
+
+ if (!is_file($config_file))
+ {
+ $iohandler->add_error_message(array('MISSING_FILE', $config_file));
+
+ return;
+ }
+
+ try
+ {
+ $config = Yaml::parse(file_get_contents($config_file), true, false);
+ }
+ catch (ParseException $e)
+ {
+ $iohandler->add_error_message('INVALID_YAML_FILE');
+
+ return;
+ }
+
+ $processor = new Processor();
+ $configuration = new updater_configuration();
+
+ try
+ {
+ $config = $processor->processConfiguration($configuration, $config);
+ }
+ catch (Exception $e)
+ {
+ $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage());
+
+ return;
+ }
+
+ $style->block(Yaml::dump(array('updater' => $config), 10, 4, true, false));
+ }
+}
diff --git a/phpBB/phpbb/install/console/command/update/config/validate.php b/phpBB/phpbb/install/console/command/update/config/validate.php
new file mode 100644
index 0000000000..18de5eab46
--- /dev/null
+++ b/phpBB/phpbb/install/console/command/update/config/validate.php
@@ -0,0 +1,124 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install\console\command\update\config;
+
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\updater_configuration;
+use phpbb\language\language;
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+
+class validate extends \phpbb\console\command\command
+{
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * Constructor
+ *
+ * @param language $language
+ * @param factory $factory
+ */
+ public function __construct(language $language, factory $factory)
+ {
+ $this->iohandler_factory = $factory;
+ $this->language = $language;
+
+ parent::__construct(new \phpbb\user($language, 'datetime'));
+ }
+
+ /**
+ *
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('update:config:validate')
+ ->addArgument(
+ 'config-file',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_CONFIG_FILE'))
+ ->setDescription($this->language->lang('CLI_INSTALL_VALIDATE_CONFIG'))
+ ;
+ }
+
+ /**
+ * Validate the configuration file
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ *
+ * @return null
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->iohandler_factory->set_environment('cli');
+
+ /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $style = new SymfonyStyle($input, $output);
+ $iohandler->set_style($style, $output);
+
+ $config_file = $input->getArgument('config-file');
+
+ if (!is_file($config_file))
+ {
+ $iohandler->add_error_message(array('MISSING_FILE', array($config_file)));
+
+ return 1;
+ }
+
+ try
+ {
+ $config = Yaml::parse(file_get_contents($config_file), true, false);
+ }
+ catch (ParseException $e)
+ {
+ $iohandler->add_error_message('INVALID_YAML_FILE');
+
+ return 1;
+ }
+
+ $processor = new Processor();
+ $configuration = new updater_configuration();
+
+ try
+ {
+ $processor->processConfiguration($configuration, $config);
+ }
+ catch (Exception $e)
+ {
+ $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage());
+
+ return 1;
+ }
+
+ $iohandler->add_success_message('CONFIGURATION_VALID');
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/install/console/command/update/update.php b/phpBB/phpbb/install/console/command/update/update.php
new file mode 100644
index 0000000000..e827761d1c
--- /dev/null
+++ b/phpBB/phpbb/install/console/command/update/update.php
@@ -0,0 +1,182 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install\console\command\update;
+
+use phpbb\install\exception\installer_exception;
+use phpbb\install\helper\install_helper;
+use phpbb\install\helper\iohandler\cli_iohandler;
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\installer;
+use phpbb\install\updater_configuration;
+use phpbb\language\language;
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Yaml\Exception\ParseException;
+use Symfony\Component\Yaml\Yaml;
+
+class update extends \phpbb\console\command\command
+{
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var installer
+ */
+ protected $installer;
+
+ /**
+ * @var install_helper
+ */
+ protected $install_helper;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * Constructor
+ *
+ * @param language $language
+ * @param factory $factory
+ * @param installer $installer
+ * @param install_helper $install_helper
+ */
+ public function __construct(language $language, factory $factory, installer $installer, install_helper $install_helper)
+ {
+ $this->iohandler_factory = $factory;
+ $this->installer = $installer;
+ $this->language = $language;
+ $this->install_helper = $install_helper;
+
+ parent::__construct(new \phpbb\user($language, 'datetime'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this
+ ->setName('update')
+ ->addArgument(
+ 'config-file',
+ InputArgument::REQUIRED,
+ $this->language->lang('CLI_CONFIG_FILE'))
+ ->setDescription($this->language->lang('CLI_UPDATE_BOARD'))
+ ;
+ }
+
+ /**
+ * Executes the command update.
+ *
+ * Update the board
+ *
+ * @param InputInterface $input An InputInterface instance
+ * @param OutputInterface $output An OutputInterface instance
+ *
+ * @return int
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->iohandler_factory->set_environment('cli');
+
+ /** @var \phpbb\install\helper\iohandler\cli_iohandler $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $style = new SymfonyStyle($input, $output);
+ $iohandler->set_style($style, $output);
+
+ $this->installer->set_iohandler($iohandler);
+
+ $config_file = $input->getArgument('config-file');
+
+ if (!$this->install_helper->is_phpbb_installed())
+ {
+ $iohandler->add_error_message('INSTALL_PHPBB_NOT_INSTALLED');
+
+ return 1;
+ }
+
+ if (!is_file($config_file))
+ {
+ $iohandler->add_error_message(array('MISSING_FILE', $config_file));
+
+ return 1;
+ }
+
+ try
+ {
+ $config = Yaml::parse(file_get_contents($config_file), true, false);
+ }
+ catch (ParseException $e)
+ {
+ $iohandler->add_error_message(array('INVALID_YAML_FILE', $config_file));
+
+ return 1;
+ }
+
+ $processor = new Processor();
+ $configuration = new updater_configuration();
+
+ try
+ {
+ $config = $processor->processConfiguration($configuration, $config);
+ }
+ catch (Exception $e)
+ {
+ $iohandler->add_error_message('INVALID_CONFIGURATION', $e->getMessage());
+
+ return 1;
+ }
+
+ $this->register_configuration($iohandler, $config);
+
+ try
+ {
+ $this->installer->run();
+ return 0;
+ }
+ catch (installer_exception $e)
+ {
+ $iohandler->add_error_message($e->getMessage());
+ return 1;
+ }
+ }
+
+ /**
+ * Register the configuration to simulate the forms.
+ *
+ * @param cli_iohandler $iohandler
+ * @param array $config
+ */
+ private function register_configuration(cli_iohandler $iohandler, $config)
+ {
+ $iohandler->set_input('update_type', $config['type']);
+ $iohandler->set_input('submit_update', 'submit');
+
+ $iohandler->set_input('compression_method', '.tar');
+ $iohandler->set_input('method', 'direct_file');
+ $iohandler->set_input('submit_update_file', 'submit');
+
+ $iohandler->set_input('submit_continue_file_update', 'submit');
+
+ $iohandler->set_input('update-extensions', $config['extensions']);
+ }
+}
diff --git a/phpBB/phpbb/install/controller/archive_download.php b/phpBB/phpbb/install/controller/archive_download.php
new file mode 100644
index 0000000000..eabc0a9976
--- /dev/null
+++ b/phpBB/phpbb/install/controller/archive_download.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\controller;
+
+use phpbb\exception\http_exception;
+use phpbb\install\helper\config;
+use Symfony\Component\HttpFoundation\BinaryFileResponse;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+
+class archive_download
+{
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * Constructor
+ *
+ * @param config $config
+ */
+ public function __construct(config $config)
+ {
+ $this->installer_config = $config;
+ $this->installer_config->load_config();
+ }
+
+ /**
+ * Sends response with the merge conflict archive
+ *
+ * Merge conflicts always have to be resolved manually,
+ * so we use a different archive for that.
+ *
+ * @return BinaryFileResponse
+ */
+ public function conflict_archive()
+ {
+ $filename = $this->installer_config->get('update_file_conflict_archive', '');
+
+ if (empty($filename))
+ {
+ throw new http_exception(404, 'URL_NOT_FOUND');
+ }
+
+ return $this->send_response($filename);
+ }
+
+ /**
+ * Sends response with the updated files' archive
+ *
+ * @return BinaryFileResponse
+ */
+ public function update_archive()
+ {
+ $filename = $this->installer_config->get('update_file_archive', '');
+
+ if (empty($filename))
+ {
+ throw new http_exception(404, 'URL_NOT_FOUND');
+ }
+
+ return $this->send_response($filename);
+ }
+
+ /**
+ * Generates a download response
+ *
+ * @param string $filename Path to the file to download
+ *
+ * @return BinaryFileResponse Response object
+ */
+ private function send_response($filename)
+ {
+ $response = new BinaryFileResponse($filename);
+ $response->setContentDisposition(
+ ResponseHeaderBag::DISPOSITION_ATTACHMENT,
+ basename($filename)
+ );
+
+ return $response;
+ }
+}
diff --git a/phpBB/phpbb/install/controller/helper.php b/phpBB/phpbb/install/controller/helper.php
new file mode 100644
index 0000000000..ff7e691224
--- /dev/null
+++ b/phpBB/phpbb/install/controller/helper.php
@@ -0,0 +1,413 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\controller;
+
+use phpbb\install\helper\config;
+use phpbb\install\helper\navigation\navigation_provider;
+use phpbb\language\language;
+use phpbb\language\language_file_helper;
+use phpbb\path_helper;
+use phpbb\request\request;
+use phpbb\request\request_interface;
+use phpbb\routing\router;
+use phpbb\symfony_request;
+use phpbb\template\template;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Cookie;
+
+/**
+ * A duplicate of \phpbb\controller\helper
+ *
+ * This class is necessary because of controller\helper's legacy function calls
+ * to page_header() page_footer() functions which has unavailable dependencies.
+ */
+class helper
+{
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var bool|string
+ */
+ protected $language_cookie;
+
+ /**
+ * @var \phpbb\language\language_file_helper
+ */
+ protected $lang_helper;
+
+ /**
+ * @var \phpbb\install\helper\navigation\navigation_provider
+ */
+ protected $navigation_provider;
+
+ /**
+ * @var \phpbb\template\template
+ */
+ protected $template;
+
+ /**
+ * @var \phpbb\path_helper
+ */
+ protected $path_helper;
+
+ /**
+ * @var \phpbb\request\request
+ */
+ protected $phpbb_request;
+
+ /**
+ * @var \phpbb\symfony_request
+ */
+ protected $request;
+
+ /**
+ * @var \phpbb\routing\router
+ */
+ protected $router;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_admin_path;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param config $config
+ * @param language $language
+ * @param language_file_helper $lang_helper
+ * @param navigation_provider $nav
+ * @param template $template
+ * @param path_helper $path_helper
+ * @param request $phpbb_request
+ * @param symfony_request $request
+ * @param router $router
+ * @param string $phpbb_root_path
+ */
+ public function __construct(config $config, language $language, language_file_helper $lang_helper, navigation_provider $nav, template $template, path_helper $path_helper, request $phpbb_request, symfony_request $request, router $router, $phpbb_root_path)
+ {
+ $this->installer_config = $config;
+ $this->language = $language;
+ $this->language_cookie = false;
+ $this->lang_helper = $lang_helper;
+ $this->navigation_provider = $nav;
+ $this->template = $template;
+ $this->path_helper = $path_helper;
+ $this->phpbb_request = $phpbb_request;
+ $this->request = $request;
+ $this->router = $router;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->phpbb_admin_path = $phpbb_root_path . 'adm/';
+ }
+
+ /**
+ * Automate setting up the page and creating the response object.
+ *
+ * @param string $template_file The template handle to render
+ * @param string $page_title The title of the page to output
+ * @param bool $selected_language True to enable language selector it, false otherwise
+ * @param int $status_code The status code to be sent to the page header
+ *
+ * @return Response object containing rendered page
+ */
+ public function render($template_file, $page_title = '', $selected_language = false, $status_code = 200)
+ {
+ $this->page_header($page_title, $selected_language);
+
+ $this->template->set_filenames(array(
+ 'body' => $template_file,
+ ));
+
+ $response = new Response($this->template->assign_display('body'), $status_code);
+
+ // Set language cookie
+ if ($this->language_cookie !== false)
+ {
+ $cookie = new Cookie('lang', $this->language_cookie, time() + 3600);
+ $response->headers->setCookie($cookie);
+
+ $this->language_cookie = false;
+ }
+
+ return $response;
+ }
+
+ /**
+ * Returns path from route name
+ *
+ * @param string $route_name
+ * @param array $parameters
+ *
+ * @return string
+ */
+ public function route($route_name, $parameters = array())
+ {
+ $url = $this->router->generate($route_name, $parameters);
+
+ return $url;
+ }
+
+ /**
+ * Handles language selector form
+ */
+ public function handle_language_select()
+ {
+ $lang = null;
+
+ // Check if language form has been submited
+ $submit = $this->phpbb_request->variable('change_lang', '');
+ if (!empty($submit))
+ {
+ $lang = $this->phpbb_request->variable('language', '');
+ }
+
+ // Retrieve language from cookie
+ $lang_cookie = $this->phpbb_request->variable('lang', '', false, request_interface::COOKIE);
+ if (empty($lang) && !empty($lang_cookie))
+ {
+ $lang = $lang_cookie;
+ }
+
+ $lang = (!empty($lang) && strpos($lang, '/') === false) ? $lang : null;
+ $this->language_cookie = $lang;
+
+ $this->render_language_select($lang);
+
+ if ($lang !== null)
+ {
+ $this->language->set_user_language($lang, true);
+ $this->installer_config->set('user_language', $lang);
+ }
+ }
+
+ /**
+ * Process navigation data to reflect active/completed stages
+ *
+ * @param \phpbb\install\helper\iohandler\iohandler_interface|null $iohandler
+ */
+ public function handle_navigation($iohandler = null)
+ {
+ $nav_data = $this->installer_config->get_navigation_data();
+
+ // Set active navigation stage
+ if (isset($nav_data['active']) && is_array($nav_data['active']))
+ {
+ if ($iohandler !== null)
+ {
+ $iohandler->set_active_stage_menu($nav_data['active']);
+ }
+
+ $this->navigation_provider->set_nav_property($nav_data['active'], array(
+ 'selected' => true,
+ 'completed' => false,
+ ));
+ }
+
+ // Set finished navigation stages
+ if (isset($nav_data['finished']) && is_array($nav_data['finished']))
+ {
+ foreach ($nav_data['finished'] as $finished_stage)
+ {
+ if ($iohandler !== null)
+ {
+ $iohandler->set_finished_stage_menu($finished_stage);
+ }
+
+ $this->navigation_provider->set_nav_property($finished_stage, array(
+ 'selected' => false,
+ 'completed' => true,
+ ));
+ }
+ }
+ }
+
+ /**
+ * Set default template variables
+ *
+ * @param string $page_title Title of the page
+ * @param bool $selected_language True to enable language selector it, false otherwise
+ */
+ protected function page_header($page_title, $selected_language = false)
+ {
+ // Path to templates
+ $paths = array($this->phpbb_root_path . 'install/update/new/adm/', $this->phpbb_admin_path);
+ $paths = array_filter($paths, 'is_dir');
+ $path = array_shift($paths);
+ $path = substr($path, strlen($this->phpbb_root_path));
+
+ $this->template->assign_vars(array(
+ 'L_CHANGE' => $this->language->lang('CHANGE'),
+ 'L_COLON' => $this->language->lang('COLON'),
+ 'L_INSTALL_PANEL' => $this->language->lang('INSTALL_PANEL'),
+ 'L_SELECT_LANG' => $this->language->lang('SELECT_LANG'),
+ 'L_SKIP' => $this->language->lang('SKIP'),
+ 'PAGE_TITLE' => $this->language->lang($page_title),
+ 'T_IMAGE_PATH' => $this->path_helper->get_web_root_path() . $path . 'images',
+ 'T_JQUERY_LINK' => $this->path_helper->get_web_root_path() . $path . '../assets/javascript/jquery.min.js',
+ 'T_TEMPLATE_PATH' => $this->path_helper->get_web_root_path() . $path . 'style',
+ 'T_ASSETS_PATH' => $this->path_helper->get_web_root_path() . $path . '../assets',
+
+ 'S_CONTENT_DIRECTION' => $this->language->lang('DIRECTION'),
+ 'S_CONTENT_FLOW_BEGIN' => ($this->language->lang('DIRECTION') === 'ltr') ? 'left' : 'right',
+ 'S_CONTENT_FLOW_END' => ($this->language->lang('DIRECTION') === 'ltr') ? 'right' : 'left',
+ 'S_CONTENT_ENCODING' => 'UTF-8',
+ 'S_LANG_SELECT' => $selected_language,
+
+ 'S_USER_LANG' => $this->language->lang('USER_LANG'),
+ ));
+
+ $this->render_navigation();
+ }
+
+ /**
+ * Render navigation
+ */
+ protected function render_navigation()
+ {
+ // Get navigation items
+ $nav_array = $this->navigation_provider->get();
+ $nav_array = $this->sort_navigation_level($nav_array);
+
+ $active_main_menu = $this->get_active_main_menu($nav_array);
+
+ // Pass navigation to template
+ foreach ($nav_array as $key => $entry)
+ {
+ $this->template->assign_block_vars('t_block1', array(
+ 'L_TITLE' => $this->language->lang($entry['label']),
+ 'S_SELECTED' => ($active_main_menu === $key),
+ 'U_TITLE' => $this->route($entry['route']),
+ ));
+
+ if (is_array($entry[0]) && $active_main_menu === $key)
+ {
+ $entry[0] = $this->sort_navigation_level($entry[0]);
+
+ foreach ($entry[0] as $name => $sub_entry)
+ {
+ if (isset($sub_entry['stage']) && $sub_entry['stage'] === true)
+ {
+ $this->template->assign_block_vars('l_block2', array(
+ 'L_TITLE' => $this->language->lang($sub_entry['label']),
+ 'S_SELECTED' => (isset($sub_entry['selected']) && $sub_entry['selected'] === true),
+ 'S_COMPLETE' => (isset($sub_entry['completed']) && $sub_entry['completed'] === true),
+ 'STAGE_NAME' => $name,
+ ));
+ }
+ else
+ {
+ $this->template->assign_block_vars('l_block1', array(
+ 'L_TITLE' => $this->language->lang($sub_entry['label']),
+ 'S_SELECTED' => (isset($sub_entry['route']) && $sub_entry['route'] === $this->request->get('_route')),
+ 'U_TITLE' => $this->route($sub_entry['route']),
+ ));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Render language select form
+ *
+ * @param string $selected_language
+ */
+ protected function render_language_select($selected_language = null)
+ {
+ $langs = $this->lang_helper->get_available_languages();
+ foreach ($langs as $lang)
+ {
+ $this->template->assign_block_vars('language_select_item', array(
+ 'VALUE' => $lang['iso'],
+ 'NAME' => $lang['local_name'],
+ 'SELECTED' => ($lang['iso'] === $selected_language),
+ ));
+ }
+ }
+
+ /**
+ * Returns the name of the active main menu item
+ *
+ * @param array $nav_array
+ *
+ * @return string|bool Returns the name of the active main menu element, if the element not found, returns false
+ */
+ protected function get_active_main_menu($nav_array)
+ {
+ $active_route = $this->request->get('_route');
+
+ foreach ($nav_array as $nav_name => $nav_options)
+ {
+ $current_menu = $nav_name;
+
+ if (isset($nav_options['route']) && $nav_options['route'] === $active_route)
+ {
+ return $nav_name;
+ }
+
+ if (is_array($nav_options[0]))
+ {
+ foreach ($nav_options[0] as $sub_menus)
+ {
+ if (isset($sub_menus['route']) && $sub_menus['route'] === $active_route)
+ {
+ return $current_menu;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Sorts the top level of navigation array
+ *
+ * @param array $nav_array Navigation array
+ *
+ * @return array
+ */
+ protected function sort_navigation_level($nav_array)
+ {
+ $sorted = array();
+ foreach ($nav_array as $key => $nav)
+ {
+ $order = (isset($nav['order'])) ? $nav['order'] : 0;
+ $sorted[$order][$key] = $nav;
+ }
+
+ // Linearization of navigation array
+ $nav_array = array();
+ ksort($sorted);
+ foreach ($sorted as $nav)
+ {
+ $nav_array = array_merge($nav_array, $nav);
+ }
+
+ return $nav_array;
+ }
+}
diff --git a/phpBB/phpbb/install/controller/install.php b/phpBB/phpbb/install/controller/install.php
new file mode 100644
index 0000000000..92506872a3
--- /dev/null
+++ b/phpBB/phpbb/install/controller/install.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\controller;
+
+use phpbb\exception\http_exception;
+use phpbb\install\helper\install_helper;
+use phpbb\install\helper\navigation\navigation_provider;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+use Symfony\Component\HttpFoundation\Response;
+use phpbb\install\helper\iohandler\factory;
+use phpbb\template\template;
+use phpbb\request\request_interface;
+use phpbb\install\installer;
+use phpbb\language\language;
+
+/**
+ * Controller for installing phpBB
+ */
+class install
+{
+ /**
+ * @var helper
+ */
+ protected $controller_helper;
+
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var navigation_provider
+ */
+ protected $menu_provider;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * @var template
+ */
+ protected $template;
+
+ /**
+ * @var request_interface
+ */
+ protected $request;
+
+ /**
+ * @var installer
+ */
+ protected $installer;
+
+ /**
+ * @var install_helper
+ */
+ protected $install_helper;
+
+ /**
+ * Constructor
+ *
+ * @param helper $helper
+ * @param factory $factory
+ * @param navigation_provider $nav_provider
+ * @param language $language
+ * @param template $template
+ * @param request_interface $request
+ * @param installer $installer
+ * @param install_helper $install_helper
+ */
+ public function __construct(helper $helper, factory $factory, navigation_provider $nav_provider, language $language, template $template, request_interface $request, installer $installer, install_helper $install_helper)
+ {
+ $this->controller_helper = $helper;
+ $this->iohandler_factory = $factory;
+ $this->menu_provider = $nav_provider;
+ $this->language = $language;
+ $this->template = $template;
+ $this->request = $request;
+ $this->installer = $installer;
+ $this->install_helper = $install_helper;
+ }
+
+ /**
+ * Controller logic
+ *
+ * @return Response|StreamedResponse
+ *
+ * @throws http_exception When phpBB is already installed
+ */
+ public function handle()
+ {
+ if ($this->install_helper->is_phpbb_installed())
+ {
+ throw new http_exception(403, 'INSTALL_PHPBB_INSTALLED');
+ }
+
+ $this->template->assign_vars(array(
+ 'U_ACTION' => $this->controller_helper->route('phpbb_installer_install'),
+ ));
+
+ // Set up input-output handler
+ if ($this->request->is_ajax())
+ {
+ $this->iohandler_factory->set_environment('ajax');
+ }
+ else
+ {
+ $this->iohandler_factory->set_environment('nojs');
+ }
+
+ // Set the appropriate input-output handler
+ $this->installer->set_iohandler($this->iohandler_factory->get());
+ $this->controller_helper->handle_language_select();
+
+ if ($this->request->is_ajax())
+ {
+ $installer = $this->installer;
+ $response = new StreamedResponse();
+ $response->setCallback(function() use ($installer) {
+ $installer->run();
+ });
+
+ // Try to bypass any server output buffers
+ $response->headers->set('X-Accel-Buffering', 'no');
+
+ return $response;
+ }
+ else
+ {
+ // Determine whether the installation was started or not
+ if (true)
+ {
+ // Set active stage
+ $this->menu_provider->set_nav_property(
+ array('install', 0, 'introduction'),
+ array(
+ 'selected' => true,
+ 'completed' => false,
+ )
+ );
+
+ // If not, let's render the welcome page
+ $this->template->assign_vars(array(
+ 'SHOW_INSTALL_START_FORM' => true,
+ 'TITLE' => $this->language->lang('INSTALL_INTRO'),
+ 'CONTENT' => $this->language->lang('INSTALL_INTRO_BODY'),
+ ));
+
+ /** @var \phpbb\install\helper\iohandler\iohandler_interface $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $this->controller_helper->handle_navigation($iohandler);
+
+ return $this->controller_helper->render('installer_install.html', 'INSTALL', true);
+ }
+
+ // @todo: implement no js controller logic
+ }
+ }
+}
diff --git a/phpBB/phpbb/install/controller/installer_index.php b/phpBB/phpbb/install/controller/installer_index.php
new file mode 100644
index 0000000000..c2d9572284
--- /dev/null
+++ b/phpBB/phpbb/install/controller/installer_index.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\controller;
+
+class installer_index
+{
+ /**
+ * @var helper
+ */
+ protected $helper;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var \phpbb\template\template
+ */
+ protected $template;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param helper $helper
+ * @param \phpbb\language\language $language
+ * @param \phpbb\template\template $template
+ * @param string $phpbb_root_path
+ */
+ public function __construct(helper $helper, \phpbb\language\language $language, \phpbb\template\template $template, $phpbb_root_path)
+ {
+ $this->helper = $helper;
+ $this->language = $language;
+ $this->template = $template;
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ public function handle($mode)
+ {
+ $this->helper->handle_language_select();
+
+ switch ($mode)
+ {
+ case "intro":
+ $title = $this->language->lang('INTRODUCTION_TITLE');
+ $body = $this->language->lang('INTRODUCTION_BODY');
+ break;
+ case "support":
+ $title = $this->language->lang('SUPPORT_TITLE');
+ $body = $this->language->lang('SUPPORT_BODY');
+ break;
+ case "license":
+ $title = $this->language->lang('LICENSE_TITLE');
+ $body = implode("<br/>\n", file($this->phpbb_root_path . 'docs/LICENSE.txt'));
+ break;
+ }
+
+ $this->template->assign_vars(array(
+ 'TITLE' => $title,
+ 'BODY' => $body,
+ ));
+
+ return $this->helper->render('installer_main.html', $title, true);
+ }
+}
diff --git a/phpBB/phpbb/install/controller/timeout_check.php b/phpBB/phpbb/install/controller/timeout_check.php
new file mode 100644
index 0000000000..1c90e3caf3
--- /dev/null
+++ b/phpBB/phpbb/install/controller/timeout_check.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\controller;
+
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+class timeout_check
+{
+ /**
+ * @var helper
+ */
+ protected $helper;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param helper $helper
+ * @param string $phpbb_root_path
+ */
+ public function __construct(helper $helper, $phpbb_root_path)
+ {
+ $this->helper = $helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * Controller for querying installer status
+ */
+ public function status()
+ {
+ $lock_file = $this->phpbb_root_path . 'store/io_lock.lock';
+ $response = new JsonResponse();
+
+ if (!file_exists($lock_file))
+ {
+ $response->setData(array(
+ 'status' => 'fail',
+ ));
+ }
+ else
+ {
+ $fp = @fopen($lock_file, 'r');
+
+ if ($fp && flock($fp, LOCK_EX | LOCK_NB))
+ {
+ $status = (filesize($lock_file) >= 2 && fread($fp, 2) === 'ok') ? 'continue' : 'fail';
+
+ $response->setData(array(
+ 'status' => $status,
+ ));
+ flock($fp, LOCK_UN);
+ fclose($fp);
+ }
+ else
+ {
+ $response->setData(array(
+ 'status' => 'running',
+ ));
+ }
+ }
+
+ return $response;
+ }
+}
diff --git a/phpBB/phpbb/install/controller/update.php b/phpBB/phpbb/install/controller/update.php
new file mode 100644
index 0000000000..6b88827940
--- /dev/null
+++ b/phpBB/phpbb/install/controller/update.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\controller;
+
+use phpbb\exception\http_exception;
+use phpbb\install\helper\install_helper;
+use phpbb\install\helper\iohandler\factory;
+use phpbb\install\helper\navigation\navigation_provider;
+use phpbb\install\installer;
+use phpbb\language\language;
+use phpbb\request\request_interface;
+use phpbb\template\template;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+
+/**
+ * Updater controller
+ */
+class update
+{
+ /**
+ * @var helper
+ */
+ protected $controller_helper;
+
+ /**
+ * @var installer
+ */
+ protected $installer;
+
+ /**
+ * @var install_helper
+ */
+ protected $install_helper;
+
+ /**
+ * @var factory
+ */
+ protected $iohandler_factory;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * @var navigation_provider
+ */
+ protected $menu_provider;
+
+ /**
+ * @var request_interface
+ */
+ protected $request;
+
+ /**
+ * @var template
+ */
+ protected $template;
+
+ /**
+ * Constructor
+ *
+ * @param helper $controller_helper
+ * @param installer $installer
+ * @param install_helper $install_helper
+ * @param factory $iohandler
+ * @param language $language
+ * @param navigation_provider $menu_provider
+ * @param request_interface $request
+ * @param template $template
+ */
+ public function __construct(helper $controller_helper, installer $installer, install_helper $install_helper, factory $iohandler, language $language, navigation_provider $menu_provider, request_interface $request, template $template)
+ {
+ $this->controller_helper = $controller_helper;
+ $this->installer = $installer;
+ $this->install_helper = $install_helper;
+ $this->iohandler_factory = $iohandler;
+ $this->language = $language;
+ $this->menu_provider = $menu_provider;
+ $this->request = $request;
+ $this->template = $template;
+ }
+
+ /**
+ * Controller entry point
+ *
+ * @return Response|StreamedResponse
+ *
+ * @throws http_exception When phpBB is not installed
+ */
+ public function handle()
+ {
+ if (!$this->install_helper->is_phpbb_installed())
+ {
+ throw new http_exception(403, 'INSTALL_PHPBB_NOT_INSTALLED');
+ }
+
+ $this->template->assign_vars(array(
+ 'U_ACTION' => $this->controller_helper->route('phpbb_installer_update'),
+ ));
+
+ // Set up input-output handler
+ if ($this->request->is_ajax())
+ {
+ $this->iohandler_factory->set_environment('ajax');
+ }
+ else
+ {
+ $this->iohandler_factory->set_environment('nojs');
+ }
+
+ // Set the appropriate input-output handler
+ $this->installer->set_iohandler($this->iohandler_factory->get());
+ $this->controller_helper->handle_language_select();
+
+ // Render the intro page
+ if ($this->request->is_ajax())
+ {
+ $installer = $this->installer;
+ $response = new StreamedResponse();
+ $response->setCallback(function() use ($installer) {
+ $installer->run();
+ });
+
+ // Try to bypass any server output buffers
+ $response->headers->set('X-Accel-Buffering', 'no');
+ $response->headers->set('Content-type', 'application/json');
+
+ return $response;
+ }
+ else
+ {
+ // Set active stage
+ $this->menu_provider->set_nav_property(
+ array('update', 0, 'introduction'),
+ array(
+ 'selected' => true,
+ 'completed' => false,
+ )
+ );
+
+ $this->template->assign_vars(array(
+ 'SHOW_INSTALL_START_FORM' => true,
+ 'TITLE' => $this->language->lang('UPDATE_INSTALLATION'),
+ 'CONTENT' => $this->language->lang('UPDATE_INSTALLATION_EXPLAIN'),
+ ));
+
+ /** @var \phpbb\install\helper\iohandler\iohandler_interface $iohandler */
+ $iohandler = $this->iohandler_factory->get();
+ $this->controller_helper->handle_navigation($iohandler);
+
+ return $this->controller_helper->render('installer_update.html', 'UPDATE_INSTALLATION', true);
+ }
+ }
+}
diff --git a/phpBB/phpbb/install/event/kernel_exception_subscriber.php b/phpBB/phpbb/install/event/kernel_exception_subscriber.php
new file mode 100644
index 0000000000..60b7d9a400
--- /dev/null
+++ b/phpBB/phpbb/install/event/kernel_exception_subscriber.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\event;
+
+use phpbb\exception\exception_interface;
+use phpbb\install\controller\helper;
+use phpbb\language\language;
+use phpbb\template\template;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+/**
+ * Exception handler for the installer
+ */
+class kernel_exception_subscriber implements EventSubscriberInterface
+{
+ /**
+ * @var helper
+ */
+ protected $controller_helper;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * @var template
+ */
+ protected $template;
+
+ /**
+ * Constructor
+ *
+ * @param helper $controller_helper
+ * @param language $language
+ * @param template $template
+ */
+ public function __construct(helper $controller_helper, language $language, template $template)
+ {
+ $this->controller_helper = $controller_helper;
+ $this->language = $language;
+ $this->template = $template;
+ }
+
+ /**
+ * This listener is run when the KernelEvents::EXCEPTION event is triggered
+ *
+ * @param GetResponseForExceptionEvent $event
+ */
+ public function on_kernel_exception(GetResponseForExceptionEvent $event)
+ {
+ $exception = $event->getException();
+ $message = $exception->getMessage();
+
+ if ($exception instanceof exception_interface)
+ {
+ $message = $this->language->lang_array($message, $exception->get_parameters());
+ }
+
+ if (!$event->getRequest()->isXmlHttpRequest())
+ {
+ $this->template->assign_vars(array(
+ 'TITLE' => $this->language->lang('INFORMATION'),
+ 'BODY' => $message,
+ ));
+
+ $response = $this->controller_helper->render(
+ 'installer_main.html',
+ $this->language->lang('INFORMATION'),
+ false,
+ 500
+ );
+ }
+ else
+ {
+ $data = array();
+
+ if (!empty($message))
+ {
+ $data['message'] = $message;
+ }
+
+ if (defined('DEBUG'))
+ {
+ $data['trace'] = $exception->getTrace();
+ }
+
+ $response = new JsonResponse($data, 500);
+ }
+
+ if ($exception instanceof HttpExceptionInterface)
+ {
+ $response->setStatusCode($exception->getStatusCode());
+ $response->headers->add($exception->getHeaders());
+ }
+
+ $event->setResponse($response);
+ }
+
+ /**
+ * Returns an array of events the object is subscribed to
+ *
+ * @return array Array of events the object is subscribed to
+ */
+ static public function getSubscribedEvents()
+ {
+ return array(
+ KernelEvents::EXCEPTION => 'on_kernel_exception',
+ );
+ }
+}
diff --git a/phpBB/phpbb/install/exception/cannot_build_container_exception.php b/phpBB/phpbb/install/exception/cannot_build_container_exception.php
new file mode 100644
index 0000000000..6cf12b008b
--- /dev/null
+++ b/phpBB/phpbb/install/exception/cannot_build_container_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+/**
+ * Thrown when the container cannot be built
+ */
+class cannot_build_container_exception extends installer_exception
+{
+
+}
diff --git a/phpBB/phpbb/install/exception/file_updater_failure_exception.php b/phpBB/phpbb/install/exception/file_updater_failure_exception.php
new file mode 100644
index 0000000000..46ba2ed32d
--- /dev/null
+++ b/phpBB/phpbb/install/exception/file_updater_failure_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+/**
+ * Thrown when the file updater fails
+ */
+class file_updater_failure_exception extends installer_exception
+{
+
+}
diff --git a/phpBB/phpbb/install/exception/installer_config_not_writable_exception.php b/phpBB/phpbb/install/exception/installer_config_not_writable_exception.php
new file mode 100644
index 0000000000..51864c5dca
--- /dev/null
+++ b/phpBB/phpbb/install/exception/installer_config_not_writable_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+/**
+ * Thrown when installer config is not writable to disk
+ */
+class installer_config_not_writable_exception extends installer_exception
+{
+
+}
diff --git a/phpBB/phpbb/install/exception/installer_exception.php b/phpBB/phpbb/install/exception/installer_exception.php
new file mode 100644
index 0000000000..f17dca8f17
--- /dev/null
+++ b/phpBB/phpbb/install/exception/installer_exception.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+use phpbb\exception\runtime_exception;
+
+/**
+ * Installer's base exception
+ */
+class installer_exception extends runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/install/exception/invalid_dbms_exception.php b/phpBB/phpbb/install/exception/invalid_dbms_exception.php
new file mode 100644
index 0000000000..38de5f613a
--- /dev/null
+++ b/phpBB/phpbb/install/exception/invalid_dbms_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+/**
+ * Thrown when an unavailable DBMS has been selected
+ */
+class invalid_dbms_exception extends installer_exception
+{
+
+}
diff --git a/phpBB/phpbb/install/exception/jump_to_restart_point_exception.php b/phpBB/phpbb/install/exception/jump_to_restart_point_exception.php
new file mode 100644
index 0000000000..b628c4fbe3
--- /dev/null
+++ b/phpBB/phpbb/install/exception/jump_to_restart_point_exception.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+class jump_to_restart_point_exception extends installer_exception
+{
+ /**
+ * @var string
+ */
+ protected $restart_point_name;
+
+ /**
+ * Constructor
+ *
+ * @param string $restart_point_name
+ */
+ public function __construct($restart_point_name)
+ {
+ $this->restart_point_name = $restart_point_name;
+
+ parent::__construct();
+ }
+
+ /**
+ * Returns the restart point's name
+ *
+ * @return string
+ */
+ public function get_restart_point_name()
+ {
+ return $this->restart_point_name;
+ }
+}
diff --git a/phpBB/phpbb/install/exception/resource_limit_reached_exception.php b/phpBB/phpbb/install/exception/resource_limit_reached_exception.php
new file mode 100644
index 0000000000..025e09fbd3
--- /dev/null
+++ b/phpBB/phpbb/install/exception/resource_limit_reached_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+/**
+ * Thrown when the installer is out of memory or time
+ */
+class resource_limit_reached_exception extends installer_exception
+{
+
+}
diff --git a/phpBB/phpbb/install/exception/user_interaction_required_exception.php b/phpBB/phpbb/install/exception/user_interaction_required_exception.php
new file mode 100644
index 0000000000..d65a448841
--- /dev/null
+++ b/phpBB/phpbb/install/exception/user_interaction_required_exception.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\exception;
+
+/**
+ * This exception should be thrown when user interaction is inevitable
+ *
+ * Note: Please note that the output should already be setup for the user
+ * when you use throw this exception
+ */
+class user_interaction_required_exception extends installer_exception
+{
+
+}
diff --git a/phpBB/phpbb/install/helper/config.php b/phpBB/phpbb/install/helper/config.php
new file mode 100644
index 0000000000..7eb0ae3b05
--- /dev/null
+++ b/phpBB/phpbb/install/helper/config.php
@@ -0,0 +1,452 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper;
+
+use phpbb\install\exception\installer_config_not_writable_exception;
+
+/**
+ * Stores common settings and installation status
+ */
+class config
+{
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * Array which contains config settings for the installer
+ *
+ * The array will also store all the user input, as well as any
+ * data that is passed to other tasks by a task.
+ *
+ * @var array
+ */
+ protected $installer_config;
+
+ /**
+ * @var string
+ */
+ protected $install_config_file;
+
+ /**
+ * @var \bantu\IniGetWrapper\IniGetWrapper
+ */
+ protected $php_ini;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Array containing progress information
+ *
+ * @var array
+ */
+ protected $progress_data;
+
+ /**
+ * Array containing system information
+ *
+ * The array contains run time and memory limitations.
+ *
+ * @var array
+ */
+ protected $system_data;
+
+ /**
+ * Array containing navigation bar information
+ *
+ * @var array
+ */
+ protected $navigation_data;
+
+ /**
+ * Flag indicating that config file should be cleaned up
+ *
+ * @var bool
+ */
+ protected $do_clean_up;
+
+ /**
+ * Constructor
+ */
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, \bantu\IniGetWrapper\IniGetWrapper $php_ini, $phpbb_root_path)
+ {
+ $this->filesystem = $filesystem;
+ $this->php_ini = $php_ini;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->do_clean_up = false;
+
+ // Set up data arrays
+ $this->navigation_data = array();
+ $this->installer_config = array();
+ $this->system_data = array();
+ $this->progress_data = array(
+ 'last_task_module_name' => '', // Stores the service name of the latest finished module
+ 'last_task_module_index' => 0, // Stores the index of the latest finished module
+ 'last_task_index' => 0, // Stores the index of the latest finished task
+ 'max_task_progress' => 0,
+ 'current_task_progress' => 0,
+ '_restart_points' => array(),
+ 'use_restart_point' => false,
+ );
+
+ $this->install_config_file = $this->phpbb_root_path . 'store/install_config.php';
+
+ $this->setup_system_data();
+ }
+
+ /**
+ * Returns data for a specified parameter
+ *
+ * @param string $param_name Name of the parameter to return
+ * @param mixed $default Default value to return when the specified data
+ * does not exist.
+ *
+ * @return mixed value of the specified parameter or the default value if the data
+ * cannot be recovered.
+ */
+ public function get($param_name, $default = false)
+ {
+ return (isset($this->installer_config[$param_name])) ? $this->installer_config[$param_name] : $default;
+ }
+
+ /**
+ * Sets a parameter in installer_config
+ *
+ * @param string $param_name Name of the parameter
+ * @param mixed $value Values to set the parameter
+ */
+ public function set($param_name, $value)
+ {
+ $this->installer_config = array_merge($this->installer_config, array(
+ $param_name => $value,
+ ));
+ }
+
+ /**
+ * Returns system parameter
+ *
+ * @param string $param_name Name of the parameter
+ *
+ * @return mixed Returns system parameter if it is defined, false otherwise
+ */
+ public function system_get($param_name)
+ {
+ return (isset($this->system_data[$param_name])) ? $this->system_data[$param_name] : false;
+ }
+
+ /**
+ * Returns remaining time until the run time limit
+ *
+ * @return int Remaining time until the run time limit in seconds
+ */
+ public function get_time_remaining()
+ {
+ if ($this->system_data['max_execution_time'] <= 0)
+ {
+ return PHP_INT_MAX;
+ }
+
+ return ($this->system_data['start_time'] + $this->system_data['max_execution_time']) - microtime(true);
+ }
+
+ /**
+ * Returns remaining memory available for PHP
+ *
+ * @return int Remaining memory until reaching the limit
+ */
+ public function get_memory_remaining()
+ {
+ if ($this->system_data['memory_limit'] <= 0)
+ {
+ return 1;
+ }
+
+ if (function_exists('memory_get_usage'))
+ {
+ return ($this->system_data['memory_limit'] - memory_get_usage());
+ }
+
+ // If we cannot get the information then just return a positive number (and cross fingers)
+ return 1;
+ }
+
+ /**
+ * Saves the latest executed task
+ *
+ * @param int $task_service_index Index of the installer task service in the module
+ */
+ public function set_finished_task($task_service_index)
+ {
+ $this->progress_data['last_task_index'] = $task_service_index;
+ }
+
+ /**
+ * Set active module
+ *
+ * @param string $module_service_name Name of the installer module service
+ * @param int $module_service_index Index of the installer module service
+ */
+ public function set_active_module($module_service_name, $module_service_index)
+ {
+ $this->progress_data['last_task_module_name'] = $module_service_name;
+ $this->progress_data['last_task_module_index'] = $module_service_index;
+ }
+
+ /**
+ * Getter for progress data
+ *
+ * @return array
+ */
+ public function get_progress_data()
+ {
+ return $this->progress_data;
+ }
+
+ /**
+ * Recovers install configuration from file
+ */
+ public function load_config()
+ {
+ if (!$this->filesystem->exists($this->install_config_file))
+ {
+ return;
+ }
+
+ $file_content = @file_get_contents($this->install_config_file);
+ $serialized_data = trim(substr($file_content, 8));
+
+ $installer_config = array();
+ $progress_data = array();
+ $navigation_data = array();
+
+ if (!empty($serialized_data))
+ {
+ $unserialized_data = json_decode($serialized_data, true);
+
+ $installer_config = (is_array($unserialized_data['installer_config'])) ? $unserialized_data['installer_config'] : array();
+ $progress_data = (is_array($unserialized_data['progress_data'])) ? $unserialized_data['progress_data'] : array();
+ $navigation_data = (is_array($unserialized_data['navigation_data'])) ? $unserialized_data['navigation_data'] : array();
+ }
+
+ $this->installer_config = array_merge($this->installer_config, $installer_config);
+ $this->progress_data = array_merge($this->progress_data, $progress_data);
+ $this->navigation_data = array_merge($this->navigation_data, $navigation_data);
+ }
+
+ /**
+ * Creates a progress restart point
+ *
+ * Restart points can be used to repeat certain tasks periodically.
+ * You need to call this method from the first task you want to repeat.
+ *
+ * @param string $name Name of the restart point
+ */
+ public function create_progress_restart_point($name)
+ {
+ $tmp_progress_data = $this->progress_data;
+ unset($tmp_progress_data['_restart_points']);
+
+ $this->progress_data['_restart_points'][$name] = $tmp_progress_data;
+ }
+
+ /**
+ * Set restart point to continue from
+ *
+ * @param string $name Name of the restart point
+ *
+ * @return bool Returns false if the restart point name does not exist, otherwise true
+ */
+ public function jump_to_restart_point($name)
+ {
+ if (!isset($this->progress_data['_restart_points'][$name]) || empty($this->progress_data['_restart_points'][$name]))
+ {
+ return false;
+ }
+
+ foreach ($this->progress_data['_restart_points'][$name] as $key => $value)
+ {
+ $this->progress_data[$key] = $value;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns whether a restart point with a given name exists or not
+ *
+ * @param string $name Name of the restart point
+ *
+ * @return bool
+ */
+ public function has_restart_point($name)
+ {
+ return isset($this->progress_data['_restart_points'][$name]);
+ }
+
+ /**
+ * Dumps install configuration to disk
+ */
+ public function save_config()
+ {
+ if ($this->do_clean_up)
+ {
+ @unlink($this->install_config_file);
+ return;
+ }
+
+ // Create array to save
+ $save_array = array(
+ 'installer_config' => $this->installer_config,
+ 'progress_data' => $this->progress_data,
+ 'navigation_data' => $this->navigation_data,
+ );
+
+ // Create file content
+ $file_content = '<?php // ';
+ $file_content .= json_encode($save_array);
+ $file_content .= "\n";
+
+ // Dump file_content to disk
+ $fp = @fopen($this->install_config_file, 'w');
+ if (!$fp)
+ {
+ throw new installer_config_not_writable_exception();
+ }
+
+ fwrite($fp, $file_content);
+ fclose($fp);
+ // Enforce 0600 permission for install config
+ $this->filesystem->chmod([$this->install_config_file], 0600);
+ }
+
+ /**
+ * Increments the task progress
+ *
+ * @param int $increment_by The amount to increment by
+ */
+ public function increment_current_task_progress($increment_by = 1)
+ {
+ $this->progress_data['current_task_progress'] += $increment_by;
+
+ if ($this->progress_data['current_task_progress'] > $this->progress_data['max_task_progress'])
+ {
+ $this->progress_data['current_task_progress'] = $this->progress_data['max_task_progress'];
+ }
+ }
+
+ /**
+ * Sets the task progress to a specific number
+ *
+ * @param int $task_progress The task progress number to be set
+ */
+ public function set_current_task_progress($task_progress)
+ {
+ $this->progress_data['current_task_progress'] = $task_progress;
+ }
+
+ /**
+ * Sets the number of tasks belonging to the installer in the current mode.
+ *
+ * @param int $task_progress_count Number of tasks
+ */
+ public function set_task_progress_count($task_progress_count)
+ {
+ $this->progress_data['max_task_progress'] = $task_progress_count;
+ }
+
+ /**
+ * Returns the number of the current task being executed
+ *
+ * @return int
+ */
+ public function get_current_task_progress()
+ {
+ return $this->progress_data['current_task_progress'];
+ }
+
+ /**
+ * Returns the number of tasks belonging to the installer in the current mode.
+ *
+ * @return int
+ */
+ public function get_task_progress_count()
+ {
+ return $this->progress_data['max_task_progress'];
+ }
+
+ /**
+ * Marks stage as completed in the navigation bar
+ *
+ * @param array $nav_path Array to the navigation elem
+ */
+ public function set_finished_navigation_stage($nav_path)
+ {
+ if (isset($this->navigation_data['finished']) && in_array($nav_path, $this->navigation_data['finished']))
+ {
+ return;
+ }
+
+ $this->navigation_data['finished'][] = $nav_path;
+ }
+
+ /**
+ * Marks stage as active in the navigation bar
+ *
+ * @param array $nav_path Array to the navigation elem
+ */
+ public function set_active_navigation_stage($nav_path)
+ {
+ $this->navigation_data['active'] = $nav_path;
+ }
+
+ /**
+ * Returns navigation data
+ *
+ * @return array
+ */
+ public function get_navigation_data()
+ {
+ return $this->navigation_data;
+ }
+
+ /**
+ * Removes install config file
+ */
+ public function clean_up_config_file()
+ {
+ $this->do_clean_up = true;
+ @unlink($this->install_config_file);
+ }
+
+ /**
+ * Filling up system_data array
+ */
+ protected function setup_system_data()
+ {
+ // Query maximum runtime from php.ini
+ $execution_time = $this->php_ini->getNumeric('max_execution_time');
+ $execution_time = min(15, $execution_time / 2);
+ $this->system_data['max_execution_time'] = $execution_time;
+
+ // Set start time
+ $this->system_data['start_time'] = microtime(true);
+
+ // Get memory limit
+ $this->system_data['memory_limit'] = $this->php_ini->getBytes('memory_limit');
+ }
+}
diff --git a/phpBB/phpbb/install/helper/container_factory.php b/phpBB/phpbb/install/helper/container_factory.php
new file mode 100644
index 0000000000..9e372fecde
--- /dev/null
+++ b/phpBB/phpbb/install/helper/container_factory.php
@@ -0,0 +1,191 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper;
+
+use phpbb\install\exception\cannot_build_container_exception;
+use phpbb\language\language;
+use phpbb\request\request;
+
+class container_factory
+{
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * @var \phpbb\request\request
+ */
+ protected $request;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * The full phpBB container
+ *
+ * @var \Symfony\Component\DependencyInjection\ContainerInterface
+ */
+ protected $container;
+
+ /**
+ * Constructor
+ *
+ * @param language $language Language service
+ * @param request $request Request interface
+ * @param update_helper $update_helper Update helper
+ * @param string $phpbb_root_path Path to phpBB's root
+ * @param string $php_ext Extension of PHP files
+ */
+ public function __construct(language $language, request $request, update_helper $update_helper, $phpbb_root_path, $php_ext)
+ {
+ $this->language = $language;
+ $this->request = $request;
+ $this->update_helper = $update_helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ $this->container = null;
+ }
+
+ /**
+ * Container getter
+ *
+ * @param null|string $service_name Name of the service to return
+ *
+ * @return \Symfony\Component\DependencyInjection\ContainerInterface|Object phpBB's dependency injection container
+ * or the service specified in $service_name
+ *
+ * @throws \phpbb\install\exception\cannot_build_container_exception When container cannot be built
+ * @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException If the service is not defined
+ * @throws \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException When a circular reference is detected
+ * @throws \Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException When the service is not defined
+ */
+ public function get($service_name = null)
+ {
+ // Check if container was built, if not try to build it
+ if ($this->container === null)
+ {
+ $this->build_container();
+ }
+
+ return ($service_name === null) ? $this->container : $this->container->get($service_name);
+ }
+
+ /**
+ * Returns the specified parameter from the container
+ *
+ * @param string $param_name
+ *
+ * @return mixed
+ *
+ * @throws \phpbb\install\exception\cannot_build_container_exception When container cannot be built
+ */
+ public function get_parameter($param_name)
+ {
+ // Check if container was built, if not try to build it
+ if ($this->container === null)
+ {
+ $this->build_container();
+ }
+
+ return $this->container->getParameter($param_name);
+ }
+
+ /**
+ * Build dependency injection container
+ *
+ * @throws \phpbb\install\exception\cannot_build_container_exception When container cannot be built
+ */
+ protected function build_container()
+ {
+ // If the container has been already built just return.
+ // Although this should never happen
+ if ($this->container instanceof \Symfony\Component\DependencyInjection\ContainerInterface)
+ {
+ return;
+ }
+
+ // Check whether container can be built
+ // We need config.php for that so let's check if it has been set up yet
+ if (!filesize($this->phpbb_root_path . 'config.' . $this->php_ext))
+ {
+ throw new cannot_build_container_exception();
+ }
+
+ $phpbb_config_php_file = new \phpbb\config_php_file($this->phpbb_root_path, $this->php_ext);
+ $phpbb_container_builder = new \phpbb\di\container_builder($this->phpbb_root_path, $this->php_ext);
+
+ // For BC with functions that we need during install
+ global $phpbb_container, $table_prefix;
+
+ $disable_super_globals = $this->request->super_globals_disabled();
+
+ // This is needed because container_builder::get_env_parameters() uses $_SERVER
+ if ($disable_super_globals)
+ {
+ $this->request->enable_super_globals();
+ }
+
+ $other_config_path = $this->phpbb_root_path . 'install/update/new/config';
+ $config_path = (is_dir($other_config_path)) ? $other_config_path : $this->phpbb_root_path . 'config';
+
+ $this->container = $phpbb_container_builder
+ ->with_environment('production')
+ ->with_config($phpbb_config_php_file)
+ ->with_config_path($config_path)
+ ->without_compiled_container()
+ ->get_container();
+
+ // Setting request is required for the compatibility globals as those are generated from
+ // this container
+ if (!$this->container->isFrozen())
+ {
+ $this->container->register('request')->setSynthetic(true);
+ $this->container->register('language')->setSynthetic(true);
+ }
+
+ $this->container->set('request', $this->request);
+ $this->container->set('language', $this->language);
+
+ $this->container->compile();
+
+ $phpbb_container = $this->container;
+ $table_prefix = $phpbb_config_php_file->get('table_prefix');
+
+ // Restore super globals to previous state
+ if ($disable_super_globals)
+ {
+ $this->request->disable_super_globals();
+ }
+
+ // Get compatibilty globals and constants
+ $this->update_helper->include_file('includes/compatibility_globals.' . $this->php_ext);
+
+ register_compatibility_globals();
+
+ $this->update_helper->include_file('includes/constants.' . $this->php_ext);
+ }
+}
diff --git a/phpBB/phpbb/install/helper/database.php b/phpBB/phpbb/install/helper/database.php
new file mode 100644
index 0000000000..fa5a10c6fc
--- /dev/null
+++ b/phpBB/phpbb/install/helper/database.php
@@ -0,0 +1,439 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper;
+
+use phpbb\install\exception\invalid_dbms_exception;
+
+/**
+ * Database related general functionality for installer
+ */
+class database
+{
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var array
+ */
+ protected $supported_dbms = array(
+ // Note: php 5.5 alpha 2 deprecated mysql.
+ // Keep mysqli before mysql in this list.
+ 'mysqli' => array(
+ 'LABEL' => 'MySQL with MySQLi Extension',
+ 'SCHEMA' => 'mysql_41',
+ 'MODULE' => 'mysqli',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\mysqli',
+ 'AVAILABLE' => true,
+ '2.0.x' => true,
+ ),
+ 'mysql' => array(
+ 'LABEL' => 'MySQL',
+ 'SCHEMA' => 'mysql',
+ 'MODULE' => 'mysql',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\mysql',
+ 'AVAILABLE' => true,
+ '2.0.x' => true,
+ ),
+ 'mssql_odbc'=> array(
+ 'LABEL' => 'MS SQL Server [ ODBC ]',
+ 'SCHEMA' => 'mssql',
+ 'MODULE' => 'odbc',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\mssql_odbc',
+ 'AVAILABLE' => true,
+ '2.0.x' => true,
+ ),
+ 'mssqlnative' => array(
+ 'LABEL' => 'MS SQL Server 2005+ [ Native ]',
+ 'SCHEMA' => 'mssql',
+ 'MODULE' => 'sqlsrv',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\mssqlnative',
+ 'AVAILABLE' => true,
+ '2.0.x' => false,
+ ),
+ 'oracle' => array(
+ 'LABEL' => 'Oracle',
+ 'SCHEMA' => 'oracle',
+ 'MODULE' => 'oci8',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\oracle',
+ 'AVAILABLE' => true,
+ '2.0.x' => false,
+ ),
+ 'postgres' => array(
+ 'LABEL' => 'PostgreSQL 8.3+',
+ 'SCHEMA' => 'postgres',
+ 'MODULE' => 'pgsql',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\postgres',
+ 'AVAILABLE' => true,
+ '2.0.x' => true,
+ ),
+ 'sqlite3' => array(
+ 'LABEL' => 'SQLite3',
+ 'SCHEMA' => 'sqlite',
+ 'MODULE' => 'sqlite3',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\sqlite3',
+ 'AVAILABLE' => true,
+ '2.0.x' => false,
+ ),
+ );
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem interface
+ * @param string $phpbb_root_path Path to phpBB's root
+ */
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, $phpbb_root_path)
+ {
+ $this->filesystem = $filesystem;
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * Returns an array of available DBMS supported by phpBB
+ *
+ * If a DBMS is specified it will only return data for that DBMS
+ * and will load its extension if necessary.
+ *
+ * @param mixed $dbms name of the DBMS that's info is required or false for all DBMS info
+ * @param bool $return_unavailable set it to true if you expect unavailable but supported DBMS
+ * returned as well
+ * @param bool $only_20x_options set it to true if you only want to recover 2.0.x options
+ *
+ * @return array Array of available and supported DBMS
+ */
+ public function get_available_dbms($dbms = false, $return_unavailable = false, $only_20x_options = false)
+ {
+ $available_dbms = $this->supported_dbms;
+
+ if ($dbms)
+ {
+ if (isset($this->supported_dbms[$dbms]))
+ {
+ $available_dbms = array($dbms => $this->supported_dbms[$dbms]);
+ }
+ else
+ {
+ return array();
+ }
+ }
+
+ $any_dbms_available = false;
+ foreach ($available_dbms as $db_name => $db_array)
+ {
+ if ($only_20x_options && !$db_array['2.0.x'])
+ {
+ if ($return_unavailable)
+ {
+ $available_dbms[$db_name]['AVAILABLE'] = false;
+ }
+ else
+ {
+ unset($available_dbms[$db_name]);
+ }
+
+ continue;
+ }
+
+ $dll = $db_array['MODULE'];
+ if (!@extension_loaded($dll))
+ {
+ if ($return_unavailable)
+ {
+ $available_dbms[$db_name]['AVAILABLE'] = false;
+ }
+ else
+ {
+ unset($available_dbms[$db_name]);
+ }
+
+ continue;
+ }
+
+ $any_dbms_available = true;
+ }
+
+ if ($return_unavailable)
+ {
+ $available_dbms['ANY_DB_SUPPORT'] = $any_dbms_available;
+ }
+
+ return $available_dbms;
+ }
+
+ /**
+ * Removes "/* style" as well as "# style" comments from $input.
+ *
+ * @param string $sql_query Input string
+ *
+ * @return string Input string with comments removed
+ */
+ public function remove_comments($sql_query)
+ {
+ // Remove /* */ comments (http://ostermiller.org/findcomment.html)
+ $sql_query = preg_replace('#/\*(.|[\r\n])*?\*/#', "\n", $sql_query);
+
+ // Remove # style comments
+ $sql_query = preg_replace('/\n{2,}/', "\n", preg_replace('/^#.*$/m', "\n", $sql_query));
+
+ return $sql_query;
+ }
+
+ /**
+ * split_sql_file() will split an uploaded sql file into single sql statements.
+ *
+ * Note: expects trim() to have already been run on $sql.
+ *
+ * @param string $sql SQL statements
+ * @param string $delimiter Delimiter between sql statements
+ *
+ * @return array Array of sql statements
+ */
+ public function split_sql_file($sql, $delimiter)
+ {
+ $sql = str_replace("\r" , '', $sql);
+ $data = preg_split('/' . preg_quote($delimiter, '/') . '$/m', $sql);
+
+ $data = array_map('trim', $data);
+
+ // The empty case
+ $end_data = end($data);
+
+ if (empty($end_data))
+ {
+ unset($data[key($data)]);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Validates table prefix
+ *
+ * @param string $dbms The selected dbms
+ * @param string $table_prefix The table prefix to validate
+ *
+ * @return bool|array true if table prefix is valid, array of errors otherwise
+ *
+ * @throws \phpbb\install\exception\invalid_dbms_exception When $dbms is not a valid
+ */
+ public function validate_table_prefix($dbms, $table_prefix)
+ {
+ $errors = array();
+
+ if (!preg_match('#^[a-zA-Z][a-zA-Z0-9_]*$#', $table_prefix))
+ {
+ $errors[] = array(
+ 'title' => 'INST_ERR_DB_INVALID_PREFIX',
+ );
+ }
+
+ // Do dbms specific checks
+ $dbms_info = $this->get_available_dbms($dbms);
+ switch ($dbms_info[$dbms]['SCHEMA'])
+ {
+ case 'mysql':
+ case 'mysql_41':
+ $prefix_length = 36;
+ break;
+ case 'mssql':
+ $prefix_length = 90;
+ break;
+ case 'oracle':
+ $prefix_length = 6;
+ break;
+ case 'postgres':
+ $prefix_length = 36;
+ break;
+ case 'sqlite':
+ $prefix_length = 200;
+ break;
+ default:
+ throw new invalid_dbms_exception();
+ break;
+ }
+
+ // Check the prefix length to ensure that index names are not too long
+ if (strlen($table_prefix) > $prefix_length)
+ {
+ $errors[] = array(
+ 'title' => array('INST_ERR_PREFIX_TOO_LONG', $prefix_length),
+ );
+ }
+
+ return (empty($errors)) ? true : $errors;
+ }
+
+ /**
+ * Check if the user provided database parameters are correct
+ *
+ * This function checks the database connection data and also checks for
+ * any other problems that could cause an error during the installation
+ * such as if there is any database table names conflicting.
+ *
+ * Note: The function assumes that $table_prefix has been already validated
+ * with validate_table_prefix().
+ *
+ * @param string $dbms Selected database type
+ * @param string $dbhost Database host address
+ * @param int $dbport Database port number
+ * @param string $dbuser Database username
+ * @param string $dbpass Database password
+ * @param string $dbname Database name
+ * @param string $table_prefix Database table prefix
+ *
+ * @return array|bool Returns true if test is successful, array of errors otherwise
+ */
+ public function check_database_connection($dbms, $dbhost, $dbport, $dbuser, $dbpass, $dbname, $table_prefix)
+ {
+ $dbms_info = $this->get_available_dbms($dbms);
+ $dbms_info = $dbms_info[$dbms];
+ $errors = array();
+
+ // Instantiate it and set return on error true
+ /** @var \phpbb\db\driver\driver_interface $db */
+ $db = new $dbms_info['DRIVER'];
+ $db->sql_return_on_error(true);
+
+ // Check that we actually have a database name before going any further
+ if (!in_array($dbms_info['SCHEMA'], array('sqlite', 'oracle'), true) && $dbname === '')
+ {
+ $errors[] = array(
+ 'title' => 'INST_ERR_DB_NO_NAME',
+ );
+ }
+
+ // 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_info['SCHEMA'] === 'sqlite'
+ && stripos($this->filesystem->realpath($dbhost), $this->filesystem->realpath($this->phpbb_root_path) === 0))
+ {
+ $errors[] = array(
+ 'title' =>'INST_ERR_DB_FORUM_PATH',
+ );
+ }
+
+ // Check if SQLite database is writable
+ if ($dbms_info['SCHEMA'] === 'sqlite'
+ && (($this->filesystem->exists($dbhost) && !$this->filesystem->is_writable($dbhost)) || !$this->filesystem->is_writable(pathinfo($dbhost, PATHINFO_DIRNAME))))
+ {
+ $errors[] = array(
+ 'title' =>'INST_ERR_DB_NO_WRITABLE',
+ );
+ }
+
+ // Try to connect to db
+ if (is_array($db->sql_connect($dbhost, $dbuser, $dbpass, $dbname, $dbport, false, true)))
+ {
+ $db_error = $db->sql_error();
+ $errors[] = array(
+ 'title' => 'INST_ERR_DB_CONNECT',
+ 'description' => ($db_error['message']) ? utf8_convert_message($db_error['message']) : 'INST_ERR_DB_NO_ERROR',
+ );
+ }
+ else
+ {
+ // Check if there is any table name collisions
+ $temp_prefix = strtolower($table_prefix);
+ $table_ary = array(
+ $temp_prefix . 'attachments',
+ $temp_prefix . 'config',
+ $temp_prefix . 'sessions',
+ $temp_prefix . 'topics',
+ $temp_prefix . 'users',
+ );
+
+ $db_tools_factory = new \phpbb\db\tools\factory();
+ $db_tools = $db_tools_factory->get($db);
+ $tables = $db_tools->sql_list_tables();
+ $tables = array_map('strtolower', $tables);
+ $table_intersect = array_intersect($tables, $table_ary);
+
+ if (count($table_intersect))
+ {
+ $errors[] = array(
+ 'title' => 'INST_ERR_PREFIX',
+ );
+ }
+
+ // Check if database version is supported
+ switch ($dbms)
+ {
+ case 'mysqli':
+ if (version_compare($db->sql_server_info(true), '4.1.3', '<'))
+ {
+ $errors[] = array(
+ 'title' => 'INST_ERR_DB_NO_MYSQLI',
+ );
+ }
+ break;
+ case 'sqlite3':
+ if (version_compare($db->sql_server_info(true), '3.6.15', '<'))
+ {
+ $errors[] = array(
+ 'title' => 'INST_ERR_DB_NO_SQLITE3',
+ );
+ }
+ break;
+ case 'oracle':
+ $sql = "SELECT *
+ FROM NLS_DATABASE_PARAMETERS
+ WHERE PARAMETER = 'NLS_RDBMS_VERSION'
+ OR PARAMETER = 'NLS_CHARACTERSET'";
+ $result = $db->sql_query($sql);
+
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $stats[$row['parameter']] = $row['value'];
+ }
+ $db->sql_freeresult($result);
+
+ if (version_compare($stats['NLS_RDBMS_VERSION'], '9.2', '<') && $stats['NLS_CHARACTERSET'] !== 'UTF8')
+ {
+ $errors[] = array(
+ 'title' => 'INST_ERR_DB_NO_ORACLE',
+ );
+ }
+ break;
+ case 'postgres':
+ $sql = "SHOW server_encoding;";
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ if ($row['server_encoding'] !== 'UNICODE' && $row['server_encoding'] !== 'UTF8')
+ {
+ $errors[] = array(
+ 'title' => 'INST_ERR_DB_NO_POSTGRES',
+ );
+ }
+ break;
+ }
+ }
+
+ return (empty($errors)) ? true : $errors;
+ }
+}
diff --git a/phpBB/phpbb/install/helper/file_updater/compression_file_updater.php b/phpBB/phpbb/install/helper/file_updater/compression_file_updater.php
new file mode 100644
index 0000000000..ede992fb6e
--- /dev/null
+++ b/phpBB/phpbb/install/helper/file_updater/compression_file_updater.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\file_updater;
+
+use phpbb\install\helper\update_helper;
+
+/**
+ * File updater for generating archive with updated files
+ */
+class compression_file_updater implements file_updater_interface
+{
+ /**
+ * @var \compress
+ */
+ protected $compress;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param update_helper $update_helper
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(update_helper $update_helper, $phpbb_root_path, $php_ext)
+ {
+ $this->compress = null;
+ $this->update_helper = $update_helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Set the compression method
+ *
+ * @param string $method Compression method's file extension
+ *
+ * @return string Archive's filename
+ */
+ public function init($method)
+ {
+ $this->update_helper->include_file('includes/functions_compress.' . $this->php_ext);
+
+ $archive_filename = 'update_archive_' . time() . '_' . uniqid();
+ $path = $this->phpbb_root_path . 'store/' . $archive_filename . '' . $method;
+
+ if ($method === '.zip')
+ {
+ $this->compress = new \compress_zip('w', $path);
+ }
+ else
+ {
+ $this->compress = new \compress_tar('w', $path, $method);
+ }
+
+ return $path;
+ }
+
+ /**
+ * Close archive writing process
+ */
+ public function close()
+ {
+ $this->compress->close();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete_file($path_to_file)
+ {
+ // We do absolutely nothing here, as this function is called when a file should be
+ // removed from the filesystem, but since this is an archive generator, it clearly
+ // cannot do that.
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function create_new_file($path_to_file_to_create, $source, $create_from_content = false)
+ {
+ if ($create_from_content)
+ {
+ $this->compress->add_data($source, $path_to_file_to_create);
+ }
+ else
+ {
+ $this->compress->add_custom_file($source, $path_to_file_to_create);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function update_file($path_to_file_to_update, $source, $create_from_content = false)
+ {
+ // Both functions are identical here
+ $this->create_new_file($path_to_file_to_update, $source, $create_from_content);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_method_name()
+ {
+ return 'compression';
+ }
+}
diff --git a/phpBB/phpbb/install/helper/file_updater/factory.php b/phpBB/phpbb/install/helper/file_updater/factory.php
new file mode 100644
index 0000000000..d3a2f22782
--- /dev/null
+++ b/phpBB/phpbb/install/helper/file_updater/factory.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\file_updater;
+
+use phpbb\di\service_collection;
+use phpbb\install\exception\file_updater_failure_exception;
+
+/**
+ * File updater factory
+ */
+class factory
+{
+ /**
+ * @var array
+ */
+ protected $file_updaters;
+
+ /**
+ * Constructor
+ *
+ * @param service_collection $collection File updater service collection
+ */
+ public function __construct(service_collection $collection)
+ {
+ foreach ($collection as $service)
+ {
+ $this->register($service);
+ }
+ }
+
+ /**
+ * Register updater object
+ *
+ * @param file_updater_interface $updater Updater object
+ */
+ public function register(file_updater_interface $updater)
+ {
+ $name = $updater->get_method_name();
+ $this->file_updaters[$name] = $updater;
+ }
+
+ /**
+ * Returns file updater object
+ *
+ * @param string $name Name of the updater method
+ *
+ * @throws file_updater_failure_exception When the specified file updater does not exist
+ */
+ public function get($name)
+ {
+ if (!isset($this->file_updaters[$name]))
+ {
+ throw new file_updater_failure_exception();
+ }
+
+ return $this->file_updaters[$name];
+ }
+}
diff --git a/phpBB/phpbb/install/helper/file_updater/file_updater.php b/phpBB/phpbb/install/helper/file_updater/file_updater.php
new file mode 100644
index 0000000000..cc0f5c6b5f
--- /dev/null
+++ b/phpBB/phpbb/install/helper/file_updater/file_updater.php
@@ -0,0 +1,202 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\file_updater;
+
+use phpbb\filesystem\exception\filesystem_exception;
+use phpbb\filesystem\filesystem;
+use phpbb\install\exception\file_updater_failure_exception;
+
+/**
+ * File updater for direct filesystem access
+ */
+class file_updater implements file_updater_interface
+{
+ /**
+ * @var filesystem
+ */
+ protected $filesystem;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param filesystem $filesystem
+ * @param string $phpbb_root_path
+ */
+ public function __construct(filesystem $filesystem, $phpbb_root_path)
+ {
+ $this->filesystem = $filesystem;
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws file_updater_failure_exception When the file is not writable
+ * @throws filesystem_exception When the filesystem class fails
+ */
+ public function delete_file($path_to_file)
+ {
+ $this->filesystem->remove($this->phpbb_root_path . $path_to_file);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws file_updater_failure_exception When the file is not writable
+ * @throws filesystem_exception When the filesystem class fails
+ */
+ public function create_new_file($path_to_file_to_create, $source, $create_from_content = false)
+ {
+ $path_to_file_to_create = $this->phpbb_root_path . $path_to_file_to_create;
+
+ $dir = dirname($path_to_file_to_create);
+ if (!$this->filesystem->exists($dir))
+ {
+ $this->make_dir($dir);
+ }
+
+ $original_dir_perms = false;
+
+ if (!$this->filesystem->is_writable($dir))
+ {
+ // Extract last 9 bits we actually need
+ $original_dir_perms = @fileperms($dir) & 511;
+ $this->filesystem->phpbb_chmod($dir, filesystem::CHMOD_ALL);
+ }
+
+ if (!$create_from_content)
+ {
+ try
+ {
+ $this->filesystem->copy($source, $path_to_file_to_create);
+ }
+ catch (filesystem_exception $e)
+ {
+ $this->write_file($path_to_file_to_create, $source, $create_from_content);
+ }
+ }
+ else
+ {
+ $this->write_file($path_to_file_to_create, $source, $create_from_content);
+ }
+
+ if ($original_dir_perms !== false)
+ {
+ $this->filesystem->phpbb_chmod($dir, $original_dir_perms);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws file_updater_failure_exception When the file is not writable
+ * @throws filesystem_exception When the filesystem class fails
+ */
+ public function update_file($path_to_file_to_update, $source, $create_from_content = false)
+ {
+ $path_to_file_to_update = $this->phpbb_root_path . $path_to_file_to_update;
+ $original_file_perms = false;
+
+ // Maybe necessary for binary files
+ $dir = dirname($path_to_file_to_update);
+ if (!$this->filesystem->exists($dir))
+ {
+ $this->make_dir($dir);
+ }
+
+ if (!$this->filesystem->is_writable($path_to_file_to_update))
+ {
+ // Extract last 9 bits we actually need
+ $original_file_perms = @fileperms($path_to_file_to_update) & 511;
+ $this->filesystem->phpbb_chmod($path_to_file_to_update, filesystem::CHMOD_WRITE);
+ }
+
+ if (!$create_from_content)
+ {
+ try
+ {
+ $this->filesystem->copy($source, $path_to_file_to_update, true);
+ }
+ catch (filesystem_exception $e)
+ {
+ $this->write_file($path_to_file_to_update, $source, $create_from_content);
+ }
+ }
+ else
+ {
+ $this->write_file($path_to_file_to_update, $source, $create_from_content);
+ }
+
+ if ($original_file_perms !== false)
+ {
+ $this->filesystem->phpbb_chmod($path_to_file_to_update, $original_file_perms);
+ }
+ }
+
+ /**
+ * Creates directory structure
+ *
+ * @param string $path Path to the directory where the file should be placed (and non-existent)
+ */
+ private function make_dir($path)
+ {
+ if (is_dir($path))
+ {
+ return;
+ }
+
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
+ $this->filesystem->mkdir($path, 493); // 493 === 0755
+ }
+
+ /**
+ * Fallback function for file writing
+ *
+ * @param string $path_to_file Path to the file's location
+ * @param string $source Path to file to copy or string with the new file's content
+ * @param bool|false $create_from_content Whether or not to use $source as the content, false by default
+ *
+ * @throws file_updater_failure_exception When the file is not writable
+ */
+ private function write_file($path_to_file, $source, $create_from_content = false)
+ {
+ if (!$create_from_content)
+ {
+ $source = @file_get_contents($source);
+ }
+
+ $file_pointer = @fopen($path_to_file, 'w');
+
+ if (!is_resource($file_pointer))
+ {
+ throw new file_updater_failure_exception();
+ }
+
+ @fwrite($file_pointer, $source);
+ @fclose($file_pointer);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_method_name()
+ {
+ return 'direct_file';
+ }
+}
diff --git a/phpBB/phpbb/install/helper/file_updater/file_updater_interface.php b/phpBB/phpbb/install/helper/file_updater/file_updater_interface.php
new file mode 100644
index 0000000000..b13d7c9fe1
--- /dev/null
+++ b/phpBB/phpbb/install/helper/file_updater/file_updater_interface.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\file_updater;
+
+interface file_updater_interface
+{
+ /**
+ * Deletes a file
+ *
+ * @param string $path_to_file Path to the file to delete
+ */
+ public function delete_file($path_to_file);
+
+ /**
+ * Creates a new file
+ *
+ * @param string $path_to_file_to_create Path to the new file's location
+ * @param string $source Path to file to copy or string with the new file's content
+ * @param bool $create_from_content Whether or not to use $source as the content, false by default
+ */
+ public function create_new_file($path_to_file_to_create, $source, $create_from_content = false);
+
+ /**
+ * Update file
+ *
+ * @param string $path_to_file_to_update Path to the file's location
+ * @param string $source Path to file to copy or string with the new file's content
+ * @param bool $create_from_content Whether or not to use $source as the content, false by default
+ */
+ public function update_file($path_to_file_to_update, $source, $create_from_content = false);
+
+ /**
+ * Returns the name of the file updater method
+ *
+ * @return string
+ */
+ public function get_method_name();
+}
diff --git a/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php
new file mode 100644
index 0000000000..5cdc331cbc
--- /dev/null
+++ b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\file_updater;
+
+use phpbb\install\helper\update_helper;
+
+/**
+ * File updater for FTP updates
+ */
+class ftp_file_updater implements file_updater_interface
+{
+ /**
+ * @var \transfer
+ */
+ protected $transfer;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param update_helper $update_helper
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(update_helper $update_helper, $phpbb_root_path, $php_ext)
+ {
+ $this->transfer = null;
+ $this->update_helper = $update_helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Initialize FTP connection
+ *
+ * @param string $method
+ * @param string $host
+ * @param string $user
+ * @param string $pass
+ * @param string $path
+ * @param int $port
+ * @param int $timeout
+ */
+ public function init($method, $host, $user, $pass, $path, $port, $timeout)
+ {
+ $this->update_helper->include_file('includes/functions_transfer.' . $this->php_ext);
+ $this->transfer = new $method($host, $user, $pass, $path, $port, $timeout);
+ $this->transfer->open_session();
+ }
+
+ /**
+ * Close FTP session
+ */
+ public function close()
+ {
+ $this->transfer->close_session();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete_file($path_to_file)
+ {
+ $this->transfer->delete_file($path_to_file);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function create_new_file($path_to_file_to_create, $source, $create_from_content = false)
+ {
+ $dirname = dirname($path_to_file_to_create);
+
+ if ($dirname && !file_exists($this->phpbb_root_path . $dirname))
+ {
+ $this->transfer->make_dir($dirname);
+ }
+
+ if ($create_from_content)
+ {
+ $this->transfer->write_file($path_to_file_to_create, $source);
+ }
+ else
+ {
+ $this->transfer->copy_file($path_to_file_to_create, $source);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function update_file($path_to_file_to_update, $source, $create_from_content = false)
+ {
+ if ($create_from_content)
+ {
+ $this->transfer->write_file($path_to_file_to_update, $source);
+ }
+ else
+ {
+ $this->transfer->copy_file($path_to_file_to_update, $source);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_method_name()
+ {
+ return 'ftp';
+ }
+}
diff --git a/phpBB/phpbb/install/helper/install_helper.php b/phpBB/phpbb/install/helper/install_helper.php
new file mode 100644
index 0000000000..ffe36cd645
--- /dev/null
+++ b/phpBB/phpbb/install/helper/install_helper.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper;
+
+/**
+ * General helper functionality for the installer
+ */
+class install_helper
+{
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param string $phpbb_root_path path to phpBB's root
+ * @param string $php_ext Extension of PHP files
+ */
+ public function __construct($phpbb_root_path, $php_ext)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Check whether phpBB is installed.
+ *
+ * @return bool
+ */
+ public function is_phpbb_installed()
+ {
+ $config_path = $this->phpbb_root_path . 'config.' . $this->php_ext;
+ $install_lock_path = $this->phpbb_root_path . 'cache/install_lock';
+
+ if (file_exists($config_path) && !file_exists($install_lock_path) && filesize($config_path))
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php
new file mode 100644
index 0000000000..2a608f504e
--- /dev/null
+++ b/phpBB/phpbb/install/helper/iohandler/ajax_iohandler.php
@@ -0,0 +1,509 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\iohandler;
+
+use phpbb\path_helper;
+use phpbb\routing\router;
+
+/**
+ * Input-Output handler for the AJAX frontend
+ */
+class ajax_iohandler extends iohandler_base
+{
+ /**
+ * @var path_helper
+ */
+ protected $path_helper;
+
+ /**
+ * @var \phpbb\request\request_interface
+ */
+ protected $request;
+
+ /**
+ * @var \phpbb\template\template
+ */
+ protected $template;
+
+ /**
+ * @var router
+ */
+ protected $router;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $file_status;
+
+ /**
+ * @var string
+ */
+ protected $form;
+
+ /**
+ * @var bool
+ */
+ protected $request_client_refresh;
+
+ /**
+ * @var array
+ */
+ protected $nav_data;
+
+ /**
+ * @var array
+ */
+ protected $cookies;
+
+ /**
+ * @var array
+ */
+ protected $download;
+
+ /**
+ * @var array
+ */
+ protected $redirect_url;
+
+ /**
+ * @var resource
+ */
+ protected $file_lock_pointer;
+
+ /**
+ * Constructor
+ *
+ * @param path_helper $path_helper
+ * @param \phpbb\request\request_interface $request HTTP request interface
+ * @param \phpbb\template\template $template Template engine
+ * @param router $router Router
+ * @param string $root_path Path to phpBB's root
+ */
+ public function __construct(path_helper $path_helper, \phpbb\request\request_interface $request, \phpbb\template\template $template, router $router, $root_path)
+ {
+ $this->path_helper = $path_helper;
+ $this->request = $request;
+ $this->router = $router;
+ $this->template = $template;
+ $this->form = '';
+ $this->nav_data = array();
+ $this->cookies = array();
+ $this->download = array();
+ $this->redirect_url = array();
+ $this->file_status = '';
+ $this->phpbb_root_path = $root_path;
+
+ parent::__construct();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_input($name, $default, $multibyte = false)
+ {
+ return $this->request->variable($name, $default, $multibyte);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_raw_input($name, $default)
+ {
+ return $this->request->raw_variable($name, $default);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_server_variable($name, $default = '')
+ {
+ return $this->request->server($name, $default);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_header_variable($name, $default = '')
+ {
+ return $this->request->header($name, $default);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_secure()
+ {
+ return $this->request->is_secure();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_user_form_group($title, $form)
+ {
+ $this->form = $this->generate_form_render_data($title, $form);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function generate_form_render_data($title, $form)
+ {
+ $this->template->assign_block_vars('options', array(
+ 'LEGEND' => $this->language->lang($title),
+ 'S_LEGEND' => true,
+ ));
+
+ $not_button_form = false;
+
+ foreach ($form as $input_name => $input_options)
+ {
+ if (!isset($input_options['type']))
+ {
+ continue;
+ }
+
+ $tpl_ary = array();
+ $not_button_form = ($input_options['type'] !== 'submit' || $not_button_form);
+
+ $tpl_ary['TYPE'] = $input_options['type'];
+ $tpl_ary['TITLE'] = $this->language->lang($input_options['label']);
+ $tpl_ary['KEY'] = $input_name;
+ $tpl_ary['S_EXPLAIN'] = false;
+ $tpl_ary['DISABLED'] = isset($input_options['disabled']) ? $input_options['disabled'] : false;
+ $tpl_ary['IS_SECONDARY'] = isset($input_options['is_secondary']) ? $input_options['is_secondary'] : false;
+
+ if (isset($input_options['default']))
+ {
+ $default = $input_options['default'];
+ $default = preg_replace_callback('#\{L_([A-Z0-9\-_]*)\}#s', array($this, 'lang_replace_callback'), $default);
+ $tpl_ary['DEFAULT'] = $default;
+ }
+
+ if (isset($input_options['description']))
+ {
+ $tpl_ary['TITLE_EXPLAIN'] = $this->language->lang($input_options['description']);
+ $tpl_ary['S_EXPLAIN'] = true;
+ }
+
+ if (in_array($input_options['type'], array('select', 'radio'), true))
+ {
+ for ($i = 0, $total = count($input_options['options']); $i < $total; $i++)
+ {
+ if (isset($input_options['options'][$i]['label']))
+ {
+ $input_options['options'][$i]['label'] = $this->language->lang($input_options['options'][$i]['label']);
+ }
+ }
+
+ $tpl_ary['OPTIONS'] = $input_options['options'];
+ }
+
+ $block_name = ($input_options['type'] === 'submit') ? 'submit_buttons' : 'options';
+ $this->template->assign_block_vars($block_name, $tpl_ary);
+ }
+
+ if (isset($form['database_update_submit']) && !$form['database_update_submit']['disabled'])
+ {
+ $this->template->assign_var('FORM_TITLE', $this->language->lang('UPDATE_CONTINUE_UPDATE_PROCESS'));
+ }
+
+ $this->template->assign_var('S_NOT_ONLY_BUTTON_FORM', $not_button_form);
+
+ if (!$not_button_form)
+ {
+ $this->template->destroy_block_vars('options');
+ }
+
+ $this->template->set_filenames(array(
+ 'form_install' => 'installer_form.html',
+ ));
+
+ return $this->template->assign_display('form_install');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function send_response($no_more_output = false)
+ {
+ $json_data_array = $this->prepare_json_array($no_more_output);
+
+ if (empty($json_data_array))
+ {
+ return;
+ }
+
+ $json_data = json_encode($json_data_array);
+
+ // Try to push content to the browser
+ print(str_pad(' ', 4096) . "\n");
+ print($json_data . "\n\n");
+ flush();
+ }
+
+ /**
+ * Prepares iohandler's data to be sent out to the client.
+ *
+ * @param bool $no_more_output Whether or not there will be more output in this response
+ *
+ * @return array
+ */
+ protected function prepare_json_array($no_more_output = false)
+ {
+ $json_array = array();
+
+ if (!empty($this->errors))
+ {
+ $json_array['errors'] = $this->errors;
+ $this->errors = array();
+ }
+
+ if (!empty($this->warnings))
+ {
+ $json_array['warnings'] = $this->warnings;
+ $this->warnings = array();
+ }
+
+ if (!empty($this->logs))
+ {
+ $json_array['logs'] = $this->logs;
+ $this->logs = array();
+ }
+
+ if (!empty($this->success))
+ {
+ $json_array['success'] = $this->success;
+ $this->success = array();
+ }
+
+ if (!empty($this->download))
+ {
+ $json_array['download'] = $this->download;
+ $this->download = array();
+ }
+
+ if (!empty($this->form))
+ {
+ $json_array['form'] = $this->form;
+ $this->form = '';
+ }
+
+ if (!empty($this->file_status))
+ {
+ $json_array['file_status'] = $this->file_status;
+ $this->file_status = '';
+ }
+
+ // If current task name is set, we push progress message to the client side
+ if (!empty($this->current_task_name))
+ {
+ $json_array['progress'] = array(
+ 'task_name' => $this->current_task_name,
+ 'task_num' => $this->current_task_progress,
+ 'task_count' => $this->task_progress_count,
+ );
+
+ if ($this->restart_progress_bar)
+ {
+ $json_array['progress']['restart'] = 1;
+ $this->restart_progress_bar = false;
+ }
+ }
+
+ if (!empty($this->nav_data))
+ {
+ $json_array['nav'] = $this->nav_data;
+ $this->nav_data = array();
+ }
+
+ if ($this->request_client_refresh)
+ {
+ $json_array['refresh'] = true;
+ $this->request_client_refresh = false;
+ }
+
+ if (!empty($this->cookies))
+ {
+ $json_array['cookies'] = $this->cookies;
+ $this->cookies = array();
+ }
+
+ if (!empty($this->redirect_url))
+ {
+ $json_array['redirect'] = $this->redirect_url;
+ $this->redirect_url = array();
+ }
+
+ if ($no_more_output)
+ {
+ $json_array['over'] = true;
+ }
+
+ return $json_array;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_progress($task_lang_key, $task_number)
+ {
+ parent::set_progress($task_lang_key, $task_number);
+ $this->send_response();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function request_refresh()
+ {
+ $this->request_client_refresh = true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_active_stage_menu($menu_path)
+ {
+ $this->nav_data['active'] = $menu_path[count($menu_path) - 1];
+ $this->send_response();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_finished_stage_menu($menu_path)
+ {
+ $this->nav_data['finished'][] = $menu_path[count($menu_path) - 1];
+ $this->send_response();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_cookie($cookie_name, $cookie_value)
+ {
+ $this->cookies[] = array(
+ 'name' => $cookie_name,
+ 'value' => $cookie_value
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_download_link($route, $title, $msg = null)
+ {
+ $link_properties = array(
+ 'href' => $this->router->generate($route),
+ 'title' => $this->language->lang($title),
+ 'download' => $this->language->lang('DOWNLOAD'),
+ );
+
+ if ($msg !== null)
+ {
+ $link_properties['msg'] = htmlspecialchars_decode($this->language->lang($msg));
+ }
+
+ $this->download[] = $link_properties;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render_update_file_status($status_array)
+ {
+ $this->template->assign_vars(array(
+ 'T_IMAGE_PATH' => $this->path_helper->get_web_root_path() . 'adm/images/',
+ ));
+
+ foreach ($status_array as $block => $list)
+ {
+ foreach ($list as $filename)
+ {
+ $dirname = dirname($filename);
+
+ $this->template->assign_block_vars($block, array(
+ 'STATUS' => $block,
+ 'FILENAME' => $filename,
+ 'DIR_PART' => (!empty($dirname) && $dirname !== '.') ? dirname($filename) . '/' : false,
+ 'FILE_PART' => basename($filename),
+ ));
+ }
+ }
+
+ $this->template->set_filenames(array(
+ 'file_status' => 'installer_update_file_status.html',
+ ));
+
+ $this->file_status = $this->template->assign_display('file_status');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function redirect($url, $use_ajax = false)
+ {
+ $this->redirect_url = array('url' => $url, 'use_ajax' => $use_ajax);
+ $this->send_response(true);
+ }
+
+ /**
+ * Acquires a file lock
+ */
+ public function acquire_lock()
+ {
+ $lock_file = $this->phpbb_root_path . 'store/io_lock.lock';
+ $this->file_lock_pointer = @fopen($lock_file, 'w+');
+
+ if ($this->file_lock_pointer)
+ {
+ flock($this->file_lock_pointer, LOCK_EX);
+ }
+ }
+
+ /**
+ * Release file lock
+ */
+ public function release_lock()
+ {
+ if ($this->file_lock_pointer)
+ {
+ fwrite($this->file_lock_pointer, 'ok');
+ flock($this->file_lock_pointer, LOCK_UN);
+ fclose($this->file_lock_pointer);
+ }
+ }
+
+ /**
+ * Callback function for language replacing
+ *
+ * @param array $matches
+ * @return string
+ */
+ public function lang_replace_callback($matches)
+ {
+ if (!empty($matches[1]))
+ {
+ return $this->language->lang($matches[1]);
+ }
+
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/helper/iohandler/cli_iohandler.php b/phpBB/phpbb/install/helper/iohandler/cli_iohandler.php
new file mode 100644
index 0000000000..4117a3dfd3
--- /dev/null
+++ b/phpBB/phpbb/install/helper/iohandler/cli_iohandler.php
@@ -0,0 +1,323 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\iohandler;
+
+use phpbb\install\exception\installer_exception;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\OutputStyle;
+
+/**
+ * Input-Output handler for the CLI frontend
+ */
+class cli_iohandler extends iohandler_base
+{
+ /**
+ * @var OutputInterface
+ */
+ protected $output;
+
+ /**
+ * @var OutputStyle
+ */
+ protected $io;
+
+ /**
+ * @var array
+ */
+ protected $input_values = array();
+
+ /**
+ * @var \Symfony\Component\Console\Helper\ProgressBar
+ */
+ protected $progress_bar;
+
+ /**
+ * Set the style and output used to display feedback;
+ *
+ * @param OutputStyle $style
+ * @param OutputInterface $output
+ */
+ public function set_style(OutputStyle $style, OutputInterface $output)
+ {
+ $this->io = $style;
+ $this->output = $output;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_input($name, $default, $multibyte = false)
+ {
+ $result = $default;
+
+ if (isset($this->input_values[$name]))
+ {
+ $result = $this->input_values[$name];
+ }
+
+ if ($multibyte)
+ {
+ return utf8_normalize_nfc($result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_raw_input($name, $default)
+ {
+ return $this->get_input($name, $default, true);
+ }
+
+ /**
+ * Set input variable
+ *
+ * @param string $name Name of input variable
+ * @param mixed $value Value of input variable
+ */
+ public function set_input($name, $value)
+ {
+ $this->input_values[$name] = $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_server_variable($name, $default = '')
+ {
+ return $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_header_variable($name, $default = '')
+ {
+ return $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_secure()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_user_form_group($title, $form)
+ {
+ throw new installer_exception('MISSING_DATA');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function send_response($no_more_output = false)
+ {
+ }
+
+ /**
+ * {@inheritdoc
+ */
+ public function add_error_message($error_title, $error_description = false)
+ {
+ $this->io->newLine();
+ $message = $this->translate_message($error_title, $error_description);
+ $message_string = $message['title'] . (!empty($message['description']) ? "\n" . $message['description'] : '');
+
+ if (strpos($message_string, '<br />') !== false)
+ {
+ $message_string = strip_tags(str_replace('<br />', "\n", $message_string));
+ }
+
+ $this->io->error($message_string);
+
+ if ($this->progress_bar !== null)
+ {
+ $this->io->newLine(2);
+ $this->progress_bar->display();
+ }
+ }
+
+ /**
+ * {@inheritdoc
+ */
+ public function add_warning_message($warning_title, $warning_description = false)
+ {
+ $this->io->newLine();
+
+ $message = $this->translate_message($warning_title, $warning_description);
+ $message_string = $message['title'] . (!empty($message['description']) ? "\n" . $message['description'] : '');
+ $this->io->warning($message_string);
+
+ if ($this->progress_bar !== null)
+ {
+ $this->io->newLine(2);
+ $this->progress_bar->display();
+ }
+ }
+
+ /**
+ * {@inheritdoc
+ */
+ public function add_log_message($log_title, $log_description = false)
+ {
+ if ($this->output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL)
+ {
+ $message = $this->translate_message($log_title, $log_description);
+ $this->output->writeln(sprintf('[%3d/%-3d] ---- %s', $this->current_task_progress, $this->task_progress_count, $message['title']));
+ }
+ }
+
+ /**
+ * {@inheritdoc
+ */
+ public function add_success_message($error_title, $error_description = false)
+ {
+ $this->io->newLine();
+
+ $message = $this->translate_message($error_title, $error_description);
+ $message_string = $message['title'] . (!empty($message['description']) ? "\n" . $message['description'] : '');
+ $this->io->success($message_string);
+
+ if ($this->progress_bar !== null)
+ {
+ $this->io->newLine(2);
+ $this->progress_bar->display();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_task_count($task_count, $restart = false)
+ {
+ parent::set_task_count($task_count, $restart);
+
+ if ($this->output->getVerbosity() === OutputInterface::VERBOSITY_NORMAL)
+ {
+ if ($this->progress_bar !== null)
+ {
+ // Symfony's ProgressBar is immutable regarding task_count, so delete the old and create a new one.
+ $this->progress_bar->clear();
+ }
+ else
+ {
+ $this->io->newLine(2);
+ }
+
+ $this->progress_bar = $this->io->createProgressBar($task_count);
+ $this->progress_bar->setFormat(
+ " %current:3s%/%max:-3s% %bar% %percent:3s%%\n" .
+ " %message%\n");
+ $this->progress_bar->setBarWidth(60);
+
+ if (!defined('PHP_WINDOWS_VERSION_BUILD'))
+ {
+ $this->progress_bar->setEmptyBarCharacter('â–‘'); // light shade character \u2591
+ $this->progress_bar->setProgressCharacter('');
+ $this->progress_bar->setBarCharacter('â–“'); // dark shade character \u2593
+ }
+
+ $this->progress_bar->setMessage('');
+ $this->progress_bar->start();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_progress($task_lang_key, $task_number)
+ {
+ parent::set_progress($task_lang_key, $task_number);
+
+ if ($this->progress_bar !== null)
+ {
+ $this->progress_bar->setProgress($this->current_task_progress);
+ $this->progress_bar->setMessage($this->current_task_name);
+ }
+ else
+ {
+ $this->output->writeln(sprintf('[%3d/%-3d] %s', $this->current_task_progress, $this->task_progress_count, $this->current_task_name));
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function finish_progress($message_lang_key)
+ {
+ parent::finish_progress($message_lang_key);
+
+ if ($this->progress_bar !== null)
+ {
+ $this->progress_bar->finish();
+ $this->progress_bar = null;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function request_refresh()
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_active_stage_menu($menu_path)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_finished_stage_menu($menu_path)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_cookie($cookie_name, $cookie_value)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_download_link($route, $title, $msg = null)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render_update_file_status($status_array)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function redirect($url, $use_ajax = false)
+ {
+ }
+}
diff --git a/phpBB/phpbb/install/helper/iohandler/exception/iohandler_not_implemented_exception.php b/phpBB/phpbb/install/helper/iohandler/exception/iohandler_not_implemented_exception.php
new file mode 100644
index 0000000000..f2ddeda6f7
--- /dev/null
+++ b/phpBB/phpbb/install/helper/iohandler/exception/iohandler_not_implemented_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\iohandler\exception;
+
+class iohandler_not_implemented_exception extends \Exception
+{
+
+}
diff --git a/phpBB/phpbb/install/helper/iohandler/factory.php b/phpBB/phpbb/install/helper/iohandler/factory.php
new file mode 100644
index 0000000000..1e8395760a
--- /dev/null
+++ b/phpBB/phpbb/install/helper/iohandler/factory.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\iohandler;
+
+use phpbb\install\helper\iohandler\exception\iohandler_not_implemented_exception;
+
+/**
+ * Input-output handler factory
+ */
+class factory
+{
+ /**
+ * @var \Symfony\Component\DependencyInjection\ContainerInterface
+ */
+ protected $container;
+
+ /**
+ * @var string
+ */
+ protected $environment;
+
+ /**
+ * Constructor
+ *
+ * @param \Symfony\Component\DependencyInjection\ContainerInterface $container Dependency injection container
+ */
+ public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container)
+ {
+ $this->container = $container;
+ $this->environment = null;
+ }
+
+ /**
+ * @param string $environment The name of the input-output handler to use
+ */
+ public function set_environment($environment)
+ {
+ $this->environment = $environment;
+ }
+
+ /**
+ * Factory getter for iohandler
+ *
+ * @return \phpbb\install\helper\iohandler\iohandler_interface
+ *
+ * @throws \phpbb\install\helper\iohandler\exception\iohandler_not_implemented_exception
+ * When the specified iohandler_interface does not exists
+ */
+ public function get()
+ {
+ switch ($this->environment)
+ {
+ case 'ajax':
+ return $this->container->get('installer.helper.iohandler_ajax');
+ break;
+ case 'nojs':
+ // @todo replace this
+ return $this->container->get('installer.helper.iohandler_ajax');
+ break;
+ case 'cli':
+ return $this->container->get('installer.helper.iohandler_cli');
+ break;
+ default:
+ throw new iohandler_not_implemented_exception();
+ break;
+ }
+ }
+}
diff --git a/phpBB/phpbb/install/helper/iohandler/iohandler_base.php b/phpBB/phpbb/install/helper/iohandler/iohandler_base.php
new file mode 100644
index 0000000000..1797a6c9ad
--- /dev/null
+++ b/phpBB/phpbb/install/helper/iohandler/iohandler_base.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\iohandler;
+
+/**
+ * Base class for installer input-output handlers
+ */
+abstract class iohandler_base implements iohandler_interface
+{
+ /**
+ * Array of errors
+ *
+ * Errors should be added, when the installation cannot continue without
+ * user interaction. If the aim is to notify the user about something, please
+ * use a warning instead.
+ *
+ * @var array
+ */
+ protected $errors;
+
+ /**
+ * Array of warnings
+ *
+ * @var array
+ */
+ protected $warnings;
+
+ /**
+ * Array of logs
+ *
+ * @var array
+ */
+ protected $logs;
+
+ /**
+ * Array of success messages
+ *
+ * @var array
+ */
+ protected $success;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var int
+ */
+ protected $task_progress_count;
+
+ /**
+ * @var int
+ */
+ protected $current_task_progress;
+
+ /**
+ * @var string
+ */
+ protected $current_task_name;
+
+ /**
+ * @var bool
+ */
+ protected $restart_progress_bar;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ $this->errors = array();
+ $this->warnings = array();
+ $this->logs = array();
+ $this->success = array();
+
+ $this->restart_progress_bar = false;
+ $this->task_progress_count = 0;
+ $this->current_task_progress = 0;
+ $this->current_task_name = '';
+ }
+
+ /**
+ * Set language service
+ *
+ * @param \phpbb\language\language $language
+ */
+ public function set_language(\phpbb\language\language $language)
+ {
+ $this->language = $language;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_error_message($error_title, $error_description = false)
+ {
+ if (!is_array($error_title) && strpos($error_title, '<br />') !== false)
+ {
+ $error_title = strip_tags(htmlspecialchars_decode($error_title));
+ }
+ $this->errors[] = $this->translate_message($error_title, $error_description);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_warning_message($warning_title, $warning_description = false)
+ {
+ $this->warnings[] = $this->translate_message($warning_title, $warning_description);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_log_message($log_title, $log_description = false)
+ {
+ $this->logs[] = $this->translate_message($log_title, $log_description);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_success_message($success_title, $success_description = false)
+ {
+ $this->success[] = $this->translate_message($success_title, $success_description);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_task_count($task_count, $restart = false)
+ {
+ $this->task_progress_count = $task_count;
+ $this->restart_progress_bar = $restart;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_progress($task_lang_key, $task_number)
+ {
+ $this->current_task_name = '';
+
+ if (!empty($task_lang_key))
+ {
+ $this->current_task_name = $this->language->lang($task_lang_key);
+ }
+
+ $this->current_task_progress = $task_number;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function finish_progress($message_lang_key)
+ {
+ if (!empty($message_lang_key))
+ {
+ $this->current_task_name = $this->language->lang($message_lang_key);
+ }
+
+ $this->current_task_progress = $this->task_progress_count;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function generate_form_render_data($title, $form)
+ {
+ return '';
+ }
+
+ /**
+ * Localize message.
+ *
+ * Note: When an array is passed into the parameters below, it will be
+ * resolved as printf($param[0], $param[1], ...).
+ *
+ * @param array|string $title Title of the message
+ * @param array|string|bool $description Description of the message
+ *
+ * @return array Localized message in an array
+ */
+ protected function translate_message($title, $description)
+ {
+ $message_array = array();
+
+ $message_array['title'] = call_user_func_array(array($this->language, 'lang'), (array) $title);
+
+ if ($description !== false)
+ {
+ $message_array['description'] = call_user_func_array(array($this->language, 'lang'), (array) $description);
+ }
+
+ return $message_array;
+ }
+}
diff --git a/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php b/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php
new file mode 100644
index 0000000000..440748901c
--- /dev/null
+++ b/phpBB/phpbb/install/helper/iohandler/iohandler_interface.php
@@ -0,0 +1,222 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\iohandler;
+
+/**
+ * Input-Output handler interface for the installer
+ */
+interface iohandler_interface
+{
+ /**
+ * Renders or returns response message
+ *
+ * @param bool $no_more_output Whether or not there will be more output in this output unit
+ */
+ public function send_response($no_more_output = false);
+
+ /**
+ * Returns input variable
+ *
+ * @param string $name Name of the input variable to obtain
+ * @param mixed $default A default value that is returned if the variable was not set.
+ * This function will always return a value of the same type as the default.
+ * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
+ * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
+ *
+ * @return mixed Value of the input variable
+ */
+ public function get_input($name, $default, $multibyte = false);
+
+ /**
+ * Returns raw input variable
+ *
+ * @param string $name Name of the input variable to obtain
+ * @param mixed $default A default value that is returned if the variable was not set.
+ * This function will always return a value of the same type as the default.
+ *
+ * @return mixed Value of the raw input variable
+ */
+ public function get_raw_input($name, $default);
+
+ /**
+ * Returns server variable
+ *
+ * This function should work the same as request_interface::server().
+ *
+ * @param string $name Name of the server variable
+ * @param mixed $default Default value to return when the requested variable does not exist
+ *
+ * @return mixed Value of the server variable
+ */
+ public function get_server_variable($name, $default = '');
+
+ /**
+ * Wrapper function for request_interface::header()
+ *
+ * @param string $name Name of the request header variable
+ * @param mixed $default Default value to return when the requested variable does not exist
+ *
+ * @return mixed
+ */
+ public function get_header_variable($name, $default = '');
+
+ /**
+ * Returns true if the connection is encrypted
+ *
+ * @return bool
+ */
+ public function is_secure();
+
+ /**
+ * Adds an error message to the rendering queue
+ *
+ * Note: When an array is passed into the parameters below, it will be
+ * resolved as printf($param[0], $param[1], ...).
+ *
+ * @param string|array $error_title Title of the error message.
+ * @param string|bool|array $error_description Description of the error (and possibly guidelines to resolve it),
+ * or false if the error description is not available.
+ */
+ public function add_error_message($error_title, $error_description = false);
+
+ /**
+ * Adds a warning message to the rendering queue
+ *
+ * Note: When an array is passed into the parameters below, it will be
+ * resolved as printf($param[0], $param[1], ...).
+ *
+ * @param string|array $warning_title Title of the warning message
+ * @param string|bool|array $warning_description Description of the warning (and possibly guidelines to resolve it),
+ * or false if the warning description is not available
+ */
+ public function add_warning_message($warning_title, $warning_description = false);
+
+ /**
+ * Adds a log message to the rendering queue
+ *
+ * Note: When an array is passed into the parameters below, it will be
+ * resolved as printf($param[0], $param[1], ...).
+ *
+ * @param string|array $log_title Title of the log message
+ * @param string|bool|array $log_description Description of the log,
+ * or false if the log description is not available
+ */
+ public function add_log_message($log_title, $log_description = false);
+
+ /**
+ * Adds a success message to the rendering queue
+ *
+ * Note: When an array is passed into the parameters below, it will be
+ * resolved as printf($param[0], $param[1], ...).
+ *
+ * @param string|array $success_title Title of the success message
+ * @param string|bool|array $success_description Description of the success,
+ * or false if the success description is not available
+ *
+ * @return null
+ */
+ public function add_success_message($success_title, $success_description = false);
+
+ /**
+ * Adds a requested data group to the rendering queue
+ *
+ * @param string $title Language variable with the title of the form
+ * @param array $form An array describing the required data (options etc)
+ */
+ public function add_user_form_group($title, $form);
+
+ /**
+ * Returns the rendering information for the form
+ *
+ * @param string $title Language variable with the title of the form
+ * @param array $form An array describing the required data (options etc)
+ *
+ * @return string Information to render the form
+ */
+ public function generate_form_render_data($title, $form);
+
+ /**
+ * Sets the number of tasks belonging to the installer in the current mode.
+ *
+ * @param int $task_count Number of tasks
+ * @param bool $restart Whether or not to restart the progress bar, false by default
+ */
+ public function set_task_count($task_count, $restart = false);
+
+ /**
+ * Sets the progress information
+ *
+ * @param string $task_lang_key Language key for the name of the task
+ * @param int $task_number Position of the current task in the task queue
+ */
+ public function set_progress($task_lang_key, $task_number);
+
+ /**
+ * Sends refresh request to the client
+ */
+ public function request_refresh();
+
+ /**
+ * Marks stage as active in the navigation bar
+ *
+ * @param array $menu_path Array to the navigation elem
+ */
+ public function set_active_stage_menu($menu_path);
+
+ /**
+ * Marks stage as completed in the navigation bar
+ *
+ * @param array $menu_path Array to the navigation elem
+ */
+ public function set_finished_stage_menu($menu_path);
+
+ /**
+ * Finish the progress bar
+ *
+ * @param string $message_lang_key Language key for the message
+ */
+ public function finish_progress($message_lang_key);
+
+ /**
+ * Adds a download link
+ *
+ * @param string $route Route for the link
+ * @param string $title Language key for the title
+ * @param string|null|array $msg Language key for the message
+ */
+ public function add_download_link($route, $title, $msg = null);
+
+ /**
+ * Redirects the user to a new page
+ *
+ * @param string $url URL to redirect to
+ * @param bool $use_ajax Whether or not to use AJAX redirect
+ */
+ public function redirect($url, $use_ajax = false);
+
+ /**
+ * Renders the status of update files
+ *
+ * @param array $status_array Array containing files in groups to render
+ */
+ public function render_update_file_status($status_array);
+
+ /**
+ * Sends and sets cookies
+ *
+ * @param string $cookie_name Name of the cookie to set
+ * @param string $cookie_value Value of the cookie to set
+ */
+ public function set_cookie($cookie_name, $cookie_value);
+}
diff --git a/phpBB/phpbb/install/helper/navigation/convertor_navigation.php b/phpBB/phpbb/install/helper/navigation/convertor_navigation.php
new file mode 100644
index 0000000000..54cab83b1d
--- /dev/null
+++ b/phpBB/phpbb/install/helper/navigation/convertor_navigation.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\navigation;
+
+use phpbb\install\helper\install_helper;
+
+class convertor_navigation implements navigation_interface
+{
+ /**
+ * @var install_helper
+ */
+ private $install_helper;
+
+ /**
+ * Constructor
+ *
+ * @param install_helper $install_helper
+ */
+ public function __construct(install_helper $install_helper)
+ {
+ $this->install_helper = $install_helper;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get()
+ {
+ if (!$this->install_helper->is_phpbb_installed())
+ {
+ return array();
+ }
+
+ return array(
+ 'convert' => array(
+ 'label' => 'CONVERT',
+ 'route' => 'phpbb_convert_intro',
+ 'order' => 3,
+ array(
+ 'intro' => array(
+ 'label' => 'SUB_INTRO',
+ 'stage' => true,
+ 'order' => 0,
+ ),
+ 'settings' => array(
+ 'label' => 'STAGE_SETTINGS',
+ 'stage' => true,
+ 'route' => 'phpbb_convert_settings',
+ 'order' => 1,
+ ),
+ 'convert' => array(
+ 'label' => 'STAGE_IN_PROGRESS',
+ 'stage' => true,
+ 'route' => 'phpbb_convert_convert',
+ 'order' => 2,
+ ),
+ 'finish' => array(
+ 'label' => 'CONVERT_COMPLETE',
+ 'stage' => true,
+ 'route' => 'phpbb_convert_finish',
+ 'order' => 3,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/install/helper/navigation/install_navigation.php b/phpBB/phpbb/install/helper/navigation/install_navigation.php
new file mode 100644
index 0000000000..f690f8de76
--- /dev/null
+++ b/phpBB/phpbb/install/helper/navigation/install_navigation.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\navigation;
+
+use phpbb\install\helper\install_helper;
+
+class install_navigation implements navigation_interface
+{
+ /**
+ * @var install_helper
+ */
+ private $install_helper;
+
+ /**
+ * Constructor
+ *
+ * @param install_helper $install_helper
+ */
+ public function __construct(install_helper $install_helper)
+ {
+ $this->install_helper = $install_helper;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get()
+ {
+ if ($this->install_helper->is_phpbb_installed())
+ {
+ return array();
+ }
+
+ return array(
+ 'install' => array(
+ 'label' => 'INSTALL',
+ 'route' => 'phpbb_installer_install',
+ 'order' => 1,
+ array(
+ 'introduction' => array(
+ 'label' => 'INTRODUCTION_TITLE',
+ 'stage' => true,
+ 'order' => 0,
+ ),
+ 'requirements' => array(
+ 'label' => 'STAGE_REQUIREMENTS',
+ 'stage' => true,
+ 'order' => 1,
+ ),
+ 'obtain_data' => array(
+ 'label' => 'STAGE_OBTAIN_DATA',
+ 'stage' => true,
+ 'order' => 2,
+ ),
+ 'install' => array(
+ 'label' => 'STAGE_INSTALL',
+ 'stage' => true,
+ 'order' => 3,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/install/helper/navigation/main_navigation.php b/phpBB/phpbb/install/helper/navigation/main_navigation.php
new file mode 100644
index 0000000000..214bb04963
--- /dev/null
+++ b/phpBB/phpbb/install/helper/navigation/main_navigation.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\navigation;
+
+class main_navigation implements navigation_interface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get()
+ {
+ return array(
+ 'overview' => array(
+ 'label' => 'MENU_OVERVIEW',
+ 'route' => 'phpbb_installer_index',
+ 'order' => 0,
+ array(
+ 'introduction' => array(
+ 'label' => 'MENU_INTRO',
+ 'route' => 'phpbb_installer_index',
+ 'order' => 0,
+ ),
+ 'support' => array(
+ 'label' => 'MENU_SUPPORT',
+ 'route' => 'phpbb_installer_support',
+ 'order' => 1,
+ ),
+ 'license' => array(
+ 'label' => 'MENU_LICENSE',
+ 'route' => 'phpbb_installer_license',
+ 'order' => 2,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/install/helper/navigation/navigation_interface.php b/phpBB/phpbb/install/helper/navigation/navigation_interface.php
new file mode 100644
index 0000000000..eebdbe923f
--- /dev/null
+++ b/phpBB/phpbb/install/helper/navigation/navigation_interface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\navigation;
+
+/**
+ * Interface for installer's navigation defining services
+ */
+interface navigation_interface
+{
+ /**
+ * Returns an array with the navigation items
+ *
+ * The returned array should have the following format:
+ * <code>
+ * array(
+ * 'parent_nav_name' => array(
+ * 'nav_name' => array(
+ * 'label' => 'MY_MENU',
+ * 'route' => 'phpbb_route_name',
+ * )
+ * )
+ * )
+ * </code>
+ *
+ * Navigation item setting options:
+ * - label: The language variable name
+ * - route: Name of the route which it is belongs to
+ *
+ * @return array
+ */
+ public function get();
+}
diff --git a/phpBB/phpbb/install/helper/navigation/navigation_provider.php b/phpBB/phpbb/install/helper/navigation/navigation_provider.php
new file mode 100644
index 0000000000..d52aec8999
--- /dev/null
+++ b/phpBB/phpbb/install/helper/navigation/navigation_provider.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\navigation;
+
+use phpbb\di\service_collection;
+
+/**
+ * Installers navigation provider
+ */
+class navigation_provider
+{
+ /**
+ * @var array
+ */
+ private $menu_collection;
+
+ /**
+ * Constructor
+ *
+ * @param service_collection $plugins
+ */
+ public function __construct(service_collection $plugins)
+ {
+ $this->menu_collection = array();
+
+ foreach ($plugins as $plugin => $plugin_instance)
+ {
+ $this->register($plugin_instance);
+ }
+ }
+
+ /**
+ * Returns navigation array
+ *
+ * @return array
+ */
+ public function get()
+ {
+ return $this->menu_collection;
+ }
+
+ /**
+ * Registers a navigation provider's navigation items
+ *
+ * @param navigation_interface $navigation
+ */
+ public function register(navigation_interface $navigation)
+ {
+ $nav_arry = $navigation->get();
+ $this->menu_collection = $this->merge($nav_arry, $this->menu_collection);
+ }
+
+ /**
+ * Set a property in the navigation array
+ *
+ * @param array $nav_element Array to the navigation elem
+ * @param array $property_array Array with the properties to set
+ */
+ public function set_nav_property($nav_element, $property_array)
+ {
+ $array_pointer = array();
+ $array_root_pointer = &$array_pointer;
+ foreach ($nav_element as $array_path)
+ {
+ $array_pointer[$array_path] = array();
+ $array_pointer = &$array_pointer[$array_path];
+ }
+
+ $array_pointer = $property_array;
+
+ $this->menu_collection = $this->merge($array_root_pointer, $this->menu_collection);
+ }
+
+ /**
+ * Recursive array merge
+ *
+ * This function is necessary to be able to replace the options of
+ * already set navigation items.
+ *
+ * @param array $array_to_merge
+ * @param array $array_to_merge_into
+ *
+ * @return array Merged array
+ */
+ private function merge($array_to_merge, $array_to_merge_into)
+ {
+ $merged_array = $array_to_merge_into;
+
+ foreach ($array_to_merge as $key => $value)
+ {
+ if (isset($array_to_merge_into[$key]))
+ {
+ if (is_array($array_to_merge_into[$key]) && is_array($value))
+ {
+ $merged_array[$key] = $this->merge($value, $array_to_merge_into[$key]);
+ }
+ else
+ {
+ $merged_array[$key] = $value;
+ }
+ }
+ else
+ {
+ $merged_array[$key] = $value;
+ }
+ }
+
+ return $merged_array;
+ }
+}
diff --git a/phpBB/phpbb/install/helper/navigation/update_navigation.php b/phpBB/phpbb/install/helper/navigation/update_navigation.php
new file mode 100644
index 0000000000..3d239c3451
--- /dev/null
+++ b/phpBB/phpbb/install/helper/navigation/update_navigation.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper\navigation;
+
+use phpbb\install\helper\install_helper;
+
+class update_navigation implements navigation_interface
+{
+ /**
+ * @var install_helper
+ */
+ private $install_helper;
+
+ /**
+ * Constructor
+ *
+ * @param install_helper $install_helper
+ */
+ public function __construct(install_helper $install_helper)
+ {
+ $this->install_helper = $install_helper;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get()
+ {
+ if (!$this->install_helper->is_phpbb_installed())
+ {
+ return array();
+ }
+
+ return array(
+ 'update' => array(
+ 'label' => 'UPDATE',
+ 'route' => 'phpbb_installer_update',
+ 'order' => 1,
+ array(
+ 'introduction' => array(
+ 'label' => 'INTRODUCTION_TITLE',
+ 'stage' => true,
+ 'order' => 0,
+ ),
+ 'requirements' => array(
+ 'label' => 'STAGE_REQUIREMENTS',
+ 'stage' => true,
+ 'order' => 1,
+ ),
+ 'obtain_data' => array(
+ 'label' => 'STAGE_OBTAIN_DATA',
+ 'stage' => true,
+ 'order' => 2,
+ ),
+ 'update_files' => array(
+ 'label' => 'STAGE_UPDATE_FILES',
+ 'stage' => true,
+ 'order' => 3,
+ ),
+ 'update_database' => array(
+ 'label' => 'STAGE_UPDATE_DATABASE',
+ 'stage' => true,
+ 'order' => 4,
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/phpbb/install/helper/update_helper.php b/phpBB/phpbb/install/helper/update_helper.php
new file mode 100644
index 0000000000..a00731d317
--- /dev/null
+++ b/phpBB/phpbb/install/helper/update_helper.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\helper;
+
+/**
+ * General helper functionality for the updater
+ */
+class update_helper
+{
+ /**
+ * @var string
+ */
+ protected $path_to_new_files;
+
+ /**
+ * @var string
+ */
+ protected $path_to_old_files;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param string $phpbb_root_path
+ */
+ public function __construct($phpbb_root_path)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->path_to_new_files = $phpbb_root_path . 'install/update/new/';
+ $this->path_to_old_files = $phpbb_root_path . 'install/update/old/';
+ }
+
+ /**
+ * Returns path to new update files
+ *
+ * @return string
+ */
+ public function get_path_to_new_update_files()
+ {
+ return $this->path_to_new_files;
+ }
+
+ /**
+ * Returns path to new update files
+ *
+ * @return string
+ */
+ public function get_path_to_old_update_files()
+ {
+ return $this->path_to_old_files;
+ }
+
+ /**
+ * Includes the updated file if available
+ *
+ * @param string $filename Path to the file relative to phpBB root path
+ */
+ public function include_file($filename)
+ {
+ if (is_file($this->path_to_new_files . $filename))
+ {
+ include_once($this->path_to_new_files . $filename);
+ }
+ else if (is_file($this->phpbb_root_path . $filename))
+ {
+ include_once($this->phpbb_root_path . $filename);
+ }
+ }
+
+ /**
+ * Customized version_compare()
+ *
+ * @param string $version_number1
+ * @param string $version_number2
+ * @param string|null $operator
+ * @return int|bool The returned value is identical to the PHP build-in function version_compare()
+ */
+ public function phpbb_version_compare($version_number1, $version_number2, $operator = null)
+ {
+ if ($operator === null)
+ {
+ $result = version_compare(
+ str_replace('rc', 'RC', strtolower($version_number1)),
+ str_replace('rc', 'RC', strtolower($version_number2))
+ );
+ }
+ else
+ {
+ $result = version_compare(
+ str_replace('rc', 'RC', strtolower($version_number1)),
+ str_replace('rc', 'RC', strtolower($version_number2)),
+ $operator
+ );
+ }
+
+ return $result;
+ }
+}
diff --git a/phpBB/phpbb/install/installer.php b/phpBB/phpbb/install/installer.php
new file mode 100644
index 0000000000..e04e233a76
--- /dev/null
+++ b/phpBB/phpbb/install/installer.php
@@ -0,0 +1,350 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install;
+
+use phpbb\cache\driver\driver_interface;
+use phpbb\di\ordered_service_collection;
+use phpbb\install\exception\cannot_build_container_exception;
+use phpbb\install\exception\installer_config_not_writable_exception;
+use phpbb\install\exception\jump_to_restart_point_exception;
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\iohandler\ajax_iohandler;
+use phpbb\install\helper\iohandler\cli_iohandler;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\path_helper;
+
+class installer
+{
+ /**
+ * @var driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var container_factory
+ */
+ protected $container_factory;
+
+ /**
+ * @var config
+ */
+ protected $install_config;
+
+ /**
+ * @var ordered_service_collection
+ */
+ protected $installer_modules;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var string
+ */
+ protected $web_root;
+
+ /**
+ * Stores the number of steps that a given module has
+ *
+ * @var array
+ */
+ protected $module_step_count;
+
+ /**
+ * @var bool
+ */
+ protected $purge_cache_before;
+
+ /**
+ * Constructor
+ *
+ * @param driver_interface $cache Cache service
+ * @param config $config Installer config handler
+ * @param path_helper $path_helper Path helper
+ * @param container_factory $container Container
+ */
+ public function __construct(driver_interface $cache, config $config, path_helper $path_helper, container_factory $container)
+ {
+ $this->cache = $cache;
+ $this->install_config = $config;
+ $this->container_factory = $container;
+ $this->installer_modules = null;
+ $this->web_root = $path_helper->get_web_root_path();
+ $this->purge_cache_before = false;
+ }
+
+ /**
+ * Sets modules to execute
+ *
+ * Note: The installer will run modules in the order they are set in
+ * the array.
+ *
+ * @param ordered_service_collection $modules Service collection of module service names
+ */
+ public function set_modules(ordered_service_collection $modules)
+ {
+ $this->installer_modules = $modules;
+ }
+
+ /**
+ * Sets input-output handler objects
+ *
+ * @param iohandler_interface $iohandler
+ */
+ public function set_iohandler(iohandler_interface $iohandler)
+ {
+ $this->iohandler = $iohandler;
+ }
+
+ /**
+ * Sets whether to purge cache before the installation process
+ *
+ * @param bool $purge_cache_before
+ */
+ public function set_purge_cache_before($purge_cache_before)
+ {
+ $this->purge_cache_before = $purge_cache_before;
+ }
+
+ /**
+ * Run phpBB installer
+ */
+ public function run()
+ {
+ if ($this->iohandler instanceof ajax_iohandler)
+ {
+ $this->iohandler->acquire_lock();
+ }
+
+ // Load install progress
+ $this->install_config->load_config();
+
+ if (!$this->install_config->get('cache_purged_before', false) && $this->purge_cache_before)
+ {
+ /** @var \phpbb\cache\driver\driver_interface $cache */
+ $cache = $this->container_factory->get('cache.driver');
+ $cache->purge();
+ $this->install_config->set('cache_purged_before', true);
+ }
+
+ // Recover install progress
+ $module_index = $this->recover_progress();
+
+ // Variable used to check if the install process have been finished
+ $install_finished = false;
+ $fail_cleanup = false;
+ $send_refresh = false;
+
+ // We are installing something, so the introduction stage can go now...
+ $this->install_config->set_finished_navigation_stage(array('install', 0, 'introduction'));
+ $this->iohandler->set_finished_stage_menu(array('install', 0, 'introduction'));
+
+ if ($this->install_config->get_task_progress_count() === 0)
+ {
+ // Count all tasks in the current installer modules
+ $step_count = 0;
+
+ /** @var \phpbb\install\module_interface $module */
+ foreach ($this->installer_modules as $name => $module)
+ {
+ $module_step_count = $module->get_step_count();
+ $step_count += $module_step_count;
+ $this->module_step_count[$name] = $module_step_count;
+ }
+
+ // Set task count
+ $this->install_config->set_task_progress_count($step_count);
+ }
+
+ // Set up progress information
+ $this->iohandler->set_task_count(
+ $this->install_config->get_task_progress_count()
+ );
+
+ try
+ {
+ $iterator = $this->installer_modules->getIterator();
+
+ if ($module_index < $iterator->count())
+ {
+ $iterator->seek($module_index);
+ }
+ else
+ {
+ $iterator->seek($module_index - 1);
+ $iterator->next();
+ }
+
+ while ($iterator->valid())
+ {
+ $module = $iterator->current();
+ $name = $iterator->key();
+
+ // Check if module should be executed
+ if (!$module->is_essential() && !$module->check_requirements())
+ {
+ $this->install_config->set_finished_navigation_stage($module->get_navigation_stage_path());
+ $this->iohandler->set_finished_stage_menu($module->get_navigation_stage_path());
+
+ $this->iohandler->add_log_message(array(
+ 'SKIP_MODULE',
+ $name,
+ ));
+ $this->install_config->increment_current_task_progress($this->module_step_count[$name]);
+ }
+ else
+ {
+ // Set the correct stage in the navigation bar
+ $this->install_config->set_active_navigation_stage($module->get_navigation_stage_path());
+ $this->iohandler->set_active_stage_menu($module->get_navigation_stage_path());
+
+ $this->iohandler->send_response();
+
+ $module->run();
+
+ $this->install_config->set_finished_navigation_stage($module->get_navigation_stage_path());
+ $this->iohandler->set_finished_stage_menu($module->get_navigation_stage_path());
+ }
+
+ $module_index++;
+ $iterator->next();
+
+ // Save progress
+ $this->install_config->set_active_module($name, $module_index);
+
+ if ($iterator->valid() && ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0))
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ // Installation finished
+ $install_finished = true;
+
+ if ($this->iohandler instanceof cli_iohandler)
+ {
+ $this->iohandler->add_success_message('INSTALLER_FINISHED');
+ }
+ else
+ {
+ // Start session if not installing and get user object
+ // to allow redirecting to ACP
+ $user = $this->container_factory->get('user');
+ if (!isset($module) || !($module instanceof \phpbb\install\module\install_finish\module))
+ {
+ $auth = $this->container_factory->get('auth');
+
+ $user->session_begin();
+ $auth->acl($user->data);
+ $user->setup();
+ }
+
+ $phpbb_root_path = $this->container_factory->get_parameter('core.root_path');
+
+ $acp_url = append_sid($phpbb_root_path . 'adm/index.php', 'i=acp_help_phpbb&mode=help_phpbb', true, $user->session_id);
+ $this->iohandler->add_success_message('INSTALLER_FINISHED', array(
+ 'ACP_LINK',
+ $acp_url,
+ ));
+ }
+ }
+ catch (user_interaction_required_exception $e)
+ {
+ $this->iohandler->send_response(true);
+ }
+ catch (resource_limit_reached_exception $e)
+ {
+ $send_refresh = true;
+ }
+ catch (jump_to_restart_point_exception $e)
+ {
+ $this->install_config->jump_to_restart_point($e->get_restart_point_name());
+ $send_refresh = true;
+ }
+ catch (\Exception $e)
+ {
+ $this->iohandler->add_error_message($e->getMessage());
+ $this->iohandler->send_response(true);
+ $fail_cleanup = true;
+ }
+
+ if ($this->iohandler instanceof ajax_iohandler)
+ {
+ $this->iohandler->release_lock();
+ }
+
+ if ($install_finished)
+ {
+ // Send install finished message
+ $this->iohandler->set_progress('INSTALLER_FINISHED', $this->install_config->get_task_progress_count());
+ $this->iohandler->send_response(true);
+ }
+ else if ($send_refresh)
+ {
+ $this->iohandler->request_refresh();
+ $this->iohandler->send_response(true);
+ }
+
+ // Save install progress
+ try
+ {
+ if ($install_finished || $fail_cleanup)
+ {
+ $this->install_config->clean_up_config_file();
+ $this->cache->purge();
+
+ try
+ {
+ /** @var \phpbb\cache\driver\driver_interface $cache */
+ $cache = $this->container_factory->get('cache.driver');
+ $cache->purge();
+ }
+ catch (cannot_build_container_exception $e)
+ {
+ // Do not do anything, this just means there is no config.php yet
+ }
+ }
+ else
+ {
+ $this->install_config->save_config();
+ }
+ }
+ catch (installer_config_not_writable_exception $e)
+ {
+ // It is allowed to fail this test during requirements testing
+ $progress_data = $this->install_config->get_progress_data();
+
+ if ($progress_data['last_task_module_name'] !== 'installer.module.requirements_install')
+ {
+ $this->iohandler->add_error_message('INSTALLER_CONFIG_NOT_WRITABLE');
+ }
+ }
+ }
+
+ /**
+ * Recover install progress
+ *
+ * @return string Index of the next installer module to execute
+ */
+ protected function recover_progress()
+ {
+ $progress_array = $this->install_config->get_progress_data();
+ return $progress_array['last_task_module_index'];
+ }
+}
diff --git a/phpBB/phpbb/install/installer_configuration.php b/phpBB/phpbb/install/installer_configuration.php
new file mode 100644
index 0000000000..805140338c
--- /dev/null
+++ b/phpBB/phpbb/install/installer_configuration.php
@@ -0,0 +1,147 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+class installer_configuration implements ConfigurationInterface
+{
+
+ /**
+ * Generates the configuration tree builder.
+ *
+ * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
+ */
+ public function getConfigTreeBuilder()
+ {
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('installer');
+ $rootNode
+ ->children()
+ ->arrayNode('admin')
+ ->children()
+ ->scalarNode('name')->defaultValue('admin')->cannotBeEmpty()->end()
+ ->scalarNode('password')->defaultValue('adminadmin')->cannotBeEmpty()->end()
+ ->scalarNode('email')->defaultValue('admin@example.org')->cannotBeEmpty()->end()
+ ->end()
+ ->end()
+ ->arrayNode('board')
+ ->children()
+ ->scalarNode('lang')
+ ->defaultValue('en')
+ ->cannotBeEmpty()
+ ->end()
+ ->scalarNode('name')
+ ->defaultValue('My Board')
+ ->cannotBeEmpty()
+ ->end()
+ ->scalarNode('description')
+ ->defaultValue('My amazing new phpBB board')
+ ->cannotBeEmpty()
+ ->end()
+ ->end()
+ ->end()
+ ->arrayNode('database')
+ ->children()
+ ->scalarNode('dbms')
+ ->defaultValue('sqlite3')
+ ->cannotBeEmpty()
+ ->isRequired()
+ ->end()
+ ->scalarNode('dbhost')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('dbport')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('dbuser')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('dbpasswd')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('dbname')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('table_prefix')
+ ->defaultValue('phpbb_')
+ ->cannotBeEmpty()
+ ->isRequired()
+ ->end()
+ ->end()
+ ->end()
+ ->arrayNode('email')
+ ->canBeEnabled()
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->booleanNode('smtp_delivery')
+ ->defaultValue(false)
+ ->treatNullLike(false)
+ ->end()
+ ->scalarNode('smtp_host')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('smtp_port')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('smtp_auth')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('smtp_user')
+ ->defaultValue(null)
+ ->end()
+ ->scalarNode('smtp_pass')
+ ->defaultValue(null)
+ ->end()
+ ->end()
+ ->end()
+ ->arrayNode('server')
+ ->children()
+ ->booleanNode('cookie_secure')
+ ->defaultValue(false)
+ ->treatNullLike(false)
+ ->end()
+ ->scalarNode('server_protocol')
+ ->defaultValue('http://')
+ ->cannotBeEmpty()
+ ->end()
+ ->booleanNode('force_server_vars')
+ ->defaultValue(false)
+ ->treatNullLike(false)
+ ->end()
+ ->scalarNode('server_name')
+ ->defaultValue('localhost')
+ ->cannotBeEmpty()
+ ->end()
+ ->integerNode('server_port')
+ ->defaultValue(80)
+ ->min(1)
+ ->cannotBeEmpty()
+ ->end()
+ ->scalarNode('script_path')
+ ->defaultValue('/')
+ ->cannotBeEmpty()
+ ->end()
+ ->end()
+ ->end()
+ ->arrayNode('extensions')
+ ->prototype('scalar')->end()
+ ->defaultValue([])
+ ->end()
+ ->end()
+ ;
+ return $treeBuilder;
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_data/module.php b/phpBB/phpbb/install/module/install_data/module.php
new file mode 100644
index 0000000000..77f1f73f1f
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_data/module.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_data;
+
+/**
+ * Installer module for recovering and installing default data installation
+ */
+class module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('install', 0, 'install');
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_data/task/add_bots.php b/phpBB/phpbb/install/module/install_data/task/add_bots.php
new file mode 100644
index 0000000000..07f8e025cf
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_data/task/add_bots.php
@@ -0,0 +1,263 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_data\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+
+class add_bots extends \phpbb\install\task_base
+{
+ /**
+ * A list of the web-crawlers/bots we recognise by default
+ *
+ * Candidates but not included:
+ * 'Accoona [Bot]' 'Accoona-AI-Agent/'
+ * 'ASPseek [Crawler]' 'ASPseek/'
+ * 'Boitho [Crawler]' 'boitho.com-dc/'
+ * 'Bunnybot [Bot]' 'powered by www.buncat.de'
+ * 'Cosmix [Bot]' 'cfetch/'
+ * 'Crawler Search [Crawler]' '.Crawler-Search.de'
+ * 'Findexa [Crawler]' 'Findexa Crawler ('
+ * 'GBSpider [Spider]' 'GBSpider v'
+ * 'genie [Bot]' 'genieBot ('
+ * 'Hogsearch [Bot]' 'oegp v. 1.3.0'
+ * 'Insuranco [Bot]' 'InsurancoBot'
+ * 'IRLbot [Bot]' 'http://irl.cs.tamu.edu/crawler'
+ * 'ISC Systems [Bot]' 'ISC Systems iRc Search'
+ * 'Jyxobot [Bot]' 'Jyxobot/'
+ * 'Kraehe [Metasuche]' '-DIE-KRAEHE- META-SEARCH-ENGINE/'
+ * 'LinkWalker' 'LinkWalker'
+ * 'MMSBot [Bot]' 'http://www.mmsweb.at/bot.html'
+ * 'Naver [Bot]' 'nhnbot@naver.com)'
+ * 'NetResearchServer' 'NetResearchServer/'
+ * 'Nimble [Crawler]' 'NimbleCrawler'
+ * 'Ocelli [Bot]' 'Ocelli/'
+ * 'Onsearch [Bot]' 'onCHECK-Robot'
+ * 'Orange [Spider]' 'OrangeSpider'
+ * 'Sproose [Bot]' 'http://www.sproose.com/bot'
+ * 'Susie [Sync]' '!Susie (http://www.sync2it.com/susie)'
+ * 'Tbot [Bot]' 'Tbot/'
+ * 'Thumbshots [Capture]' 'thumbshots-de-Bot'
+ * 'Vagabondo [Crawler]' 'http://webagent.wise-guys.nl/'
+ * 'Walhello [Bot]' 'appie 1.1 (www.walhello.com)'
+ * 'WissenOnline [Bot]' 'WissenOnline-Bot'
+ * 'WWWeasel [Bot]' 'WWWeasel Robot v'
+ * 'Xaldon [Spider]' 'Xaldon WebSpider'
+ *
+ * @var array
+ */
+ protected $bot_list = array(
+ 'AdsBot [Google]' => array('AdsBot-Google', ''),
+ 'Alexa [Bot]' => array('ia_archiver', ''),
+ 'Alta Vista [Bot]' => array('Scooter/', ''),
+ 'Ask Jeeves [Bot]' => array('Ask Jeeves', ''),
+ 'Baidu [Spider]' => array('Baiduspider', ''),
+ 'Bing [Bot]' => array('bingbot/', ''),
+ 'Exabot [Bot]' => array('Exabot', ''),
+ 'FAST Enterprise [Crawler]' => array('FAST Enterprise Crawler', ''),
+ 'FAST WebCrawler [Crawler]' => array('FAST-WebCrawler/', ''),
+ 'Francis [Bot]' => array('http://www.neomo.de/', ''),
+ 'Gigabot [Bot]' => array('Gigabot/', ''),
+ 'Google Adsense [Bot]' => array('Mediapartners-Google', ''),
+ 'Google Desktop' => array('Google Desktop', ''),
+ 'Google Feedfetcher' => array('Feedfetcher-Google', ''),
+ 'Google [Bot]' => array('Googlebot', ''),
+ 'Heise IT-Markt [Crawler]' => array('heise-IT-Markt-Crawler', ''),
+ 'Heritrix [Crawler]' => array('heritrix/1.', ''),
+ 'IBM Research [Bot]' => array('ibm.com/cs/crawler', ''),
+ 'ICCrawler - ICjobs' => array('ICCrawler - ICjobs', ''),
+ 'ichiro [Crawler]' => array('ichiro/', ''),
+ 'Majestic-12 [Bot]' => array('MJ12bot/', ''),
+ 'Metager [Bot]' => array('MetagerBot/', ''),
+ 'MSN NewsBlogs' => array('msnbot-NewsBlogs/', ''),
+ 'MSN [Bot]' => array('msnbot/', ''),
+ 'MSNbot Media' => array('msnbot-media/', ''),
+ 'Nutch [Bot]' => array('http://lucene.apache.org/nutch/', ''),
+ 'Online link [Validator]' => array('online link validator', ''),
+ 'psbot [Picsearch]' => array('psbot/0', ''),
+ 'Sensis [Crawler]' => array('Sensis Web Crawler', ''),
+ 'SEO Crawler' => array('SEO search Crawler/', ''),
+ 'Seoma [Crawler]' => array('Seoma [SEO Crawler]', ''),
+ 'SEOSearch [Crawler]' => array('SEOsearch/', ''),
+ 'Snappy [Bot]' => array('Snappy/1.1 ( http://www.urltrends.com/ )', ''),
+ 'Steeler [Crawler]' => array('http://www.tkl.iis.u-tokyo.ac.jp/~crawler/', ''),
+ 'Telekom [Bot]' => array('crawleradmin.t-info@telekom.de', ''),
+ 'TurnitinBot [Bot]' => array('TurnitinBot/', ''),
+ 'Voyager [Bot]' => array('voyager/', ''),
+ 'W3 [Sitesearch]' => array('W3 SiteSearch Crawler', ''),
+ 'W3C [Linkcheck]' => array('W3C-checklink/', ''),
+ 'W3C [Validator]' => array('W3C_Validator', ''),
+ 'YaCy [Bot]' => array('yacybot', ''),
+ 'Yahoo MMCrawler [Bot]' => array('Yahoo-MMCrawler/', ''),
+ 'Yahoo Slurp [Bot]' => array('Yahoo! DE Slurp', ''),
+ 'Yahoo [Bot]' => array('Yahoo! Slurp', ''),
+ 'YahooSeeker [Bot]' => array('YahooSeeker/', ''),
+ );
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $io_handler;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $install_config Installer's config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Input-output handler for the installer
+ * @param \phpbb\install\helper\container_factory $container Installer's DI container
+ * @param \phpbb\language\language $language Language provider
+ * @param string $phpbb_root_path Relative path to phpBB root
+ * @param string $php_ext PHP extension
+ */
+ public function __construct(\phpbb\install\helper\config $install_config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ \phpbb\install\helper\container_factory $container,
+ \phpbb\language\language $language,
+ $phpbb_root_path,
+ $php_ext)
+ {
+ parent::__construct(true);
+
+ $this->db = $container->get('dbal.conn');
+ $this->install_config = $install_config;
+ $this->io_handler = $iohandler;
+ $this->language = $language;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->db->sql_return_on_error(true);
+
+ $sql = 'SELECT group_id
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name = 'BOTS'";
+ $result = $this->db->sql_query($sql);
+ $group_id = (int) $this->db->sql_fetchfield('group_id');
+ $this->db->sql_freeresult($result);
+
+ if (!$group_id)
+ {
+ // If we reach this point then something has gone very wrong
+ $this->io_handler->add_error_message('NO_GROUP');
+ }
+
+ $i = $this->install_config->get('add_bot_index', 0);
+ $bot_list = array_slice($this->bot_list, $i);
+
+ foreach ($bot_list as $bot_name => $bot_ary)
+ {
+ $user_row = array(
+ 'user_type' => USER_IGNORE,
+ 'group_id' => $group_id,
+ 'username' => $bot_name,
+ 'user_regdate' => time(),
+ 'user_password' => '',
+ 'user_colour' => '9E8DA7',
+ 'user_email' => '',
+ 'user_lang' => $this->install_config->get('default_lang'),
+ 'user_style' => 1,
+ 'user_timezone' => 'UTC',
+ 'user_dateformat' => $this->language->lang('default_dateformat'),
+ 'user_allow_massemail' => 0,
+ 'user_allow_pm' => 0,
+ );
+
+ if (!function_exists('user_add'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+
+ $user_id = user_add($user_row);
+
+ if (!$user_id)
+ {
+ // If we can't insert this user then continue to the next one to avoid inconsistent data
+ $this->io_handler->add_error_message('CONV_ERROR_INSERT_BOT');
+
+ $i++;
+ continue;
+ }
+
+ $sql = 'INSERT INTO ' . BOTS_TABLE . ' ' . $this->db->sql_build_array('INSERT', array(
+ 'bot_active' => 1,
+ 'bot_name' => (string) $bot_name,
+ 'user_id' => (int) $user_id,
+ 'bot_agent' => (string) $bot_ary[0],
+ 'bot_ip' => (string) $bot_ary[1],
+ ));
+
+ $this->db->sql_query($sql);
+
+ $i++;
+
+ // Stop execution if resource limit is reached
+ if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0)
+ {
+ break;
+ }
+ }
+
+ $this->install_config->set('add_bot_index', $i);
+
+ if ($i < count($this->bot_list))
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_ADD_BOTS';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_data/task/add_languages.php b/phpBB/phpbb/install/module/install_data/task/add_languages.php
new file mode 100644
index 0000000000..7ffdf4f276
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_data/task/add_languages.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_data\task;
+
+class add_languages extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\language\language_file_helper
+ */
+ protected $language_helper;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ * @param \phpbb\install\helper\container_factory $container Installer's DI container
+ * @param \phpbb\language\language_file_helper $language_helper Language file helper service
+ */
+ public function __construct(\phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ \phpbb\install\helper\container_factory $container,
+ \phpbb\language\language_file_helper $language_helper)
+ {
+ $this->db = $container->get('dbal.conn');
+ $this->iohandler = $iohandler;
+ $this->language_helper = $language_helper;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->db->sql_return_on_error(true);
+
+ $languages = $this->language_helper->get_available_languages();
+ $installed_languages = array();
+
+ foreach ($languages as $lang_info)
+ {
+ $lang_pack = array(
+ 'lang_iso' => $lang_info['iso'],
+ 'lang_dir' => $lang_info['iso'],
+ 'lang_english_name' => htmlspecialchars($lang_info['name']),
+ 'lang_local_name' => htmlspecialchars($lang_info['local_name'], ENT_COMPAT, 'UTF-8'),
+ 'lang_author' => htmlspecialchars($lang_info['author'], ENT_COMPAT, 'UTF-8'),
+ );
+
+ $this->db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $this->db->sql_build_array('INSERT', $lang_pack));
+
+ $installed_languages[] = (int) $this->db->sql_nextid();
+ if ($this->db->get_sql_error_triggered())
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message($error['message']);
+ }
+ }
+
+ $sql = 'SELECT * FROM ' . PROFILE_FIELDS_TABLE;
+ $result = $this->db->sql_query($sql);
+
+ $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, PROFILE_LANG_TABLE);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ foreach ($installed_languages as $lang_id)
+ {
+ $insert_buffer->insert(array(
+ 'field_id' => $row['field_id'],
+ 'lang_id' => $lang_id,
+
+ // Remove phpbb_ from field name
+ 'lang_name' => strtoupper(substr($row['field_name'], 6)),
+ 'lang_explain' => '',
+ 'lang_default_value' => '',
+ ));
+ }
+ }
+
+ $this->db->sql_freeresult($result);
+
+ $insert_buffer->flush();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_ADD_LANGUAGES';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_data/task/add_modules.php b/phpBB/phpbb/install/module/install_data/task/add_modules.php
new file mode 100644
index 0000000000..b64f4c31db
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_data/task/add_modules.php
@@ -0,0 +1,568 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_data\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\iohandler\iohandler_interface;
+
+class add_modules extends \phpbb\install\task_base
+{
+ /**
+ * @var config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\extension\manager
+ */
+ protected $extension_manager;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\module\module_manager
+ */
+ protected $module_manager;
+
+ /**
+ * Define the module structure so that we can populate the database without
+ * needing to hard-code module_id values
+ *
+ * @var array
+ */
+ protected $module_categories = array(
+ 'acp' => array(
+ 'ACP_CAT_GENERAL' => array(
+ 'ACP_QUICK_ACCESS',
+ 'ACP_BOARD_CONFIGURATION',
+ 'ACP_CLIENT_COMMUNICATION',
+ 'ACP_SERVER_CONFIGURATION',
+ ),
+ 'ACP_CAT_FORUMS' => array(
+ 'ACP_MANAGE_FORUMS',
+ 'ACP_FORUM_BASED_PERMISSIONS',
+ ),
+ 'ACP_CAT_POSTING' => array(
+ 'ACP_MESSAGES',
+ 'ACP_ATTACHMENTS',
+ ),
+ 'ACP_CAT_USERGROUP' => array(
+ 'ACP_CAT_USERS',
+ 'ACP_GROUPS',
+ 'ACP_USER_SECURITY',
+ ),
+ 'ACP_CAT_PERMISSIONS' => array(
+ 'ACP_GLOBAL_PERMISSIONS',
+ 'ACP_FORUM_BASED_PERMISSIONS',
+ 'ACP_PERMISSION_ROLES',
+ 'ACP_PERMISSION_MASKS',
+ ),
+ 'ACP_CAT_CUSTOMISE' => array(
+ 'ACP_STYLE_MANAGEMENT',
+ 'ACP_EXTENSION_MANAGEMENT',
+ 'ACP_LANGUAGE',
+ ),
+ 'ACP_CAT_MAINTENANCE' => array(
+ 'ACP_FORUM_LOGS',
+ 'ACP_CAT_DATABASE',
+ ),
+ 'ACP_CAT_SYSTEM' => array(
+ 'ACP_AUTOMATION',
+ 'ACP_GENERAL_TASKS',
+ 'ACP_MODULE_MANAGEMENT',
+ ),
+ 'ACP_CAT_DOT_MODS' => null,
+ ),
+ 'mcp' => array(
+ 'MCP_MAIN' => null,
+ 'MCP_QUEUE' => null,
+ 'MCP_REPORTS' => null,
+ 'MCP_NOTES' => null,
+ 'MCP_WARN' => null,
+ 'MCP_LOGS' => null,
+ 'MCP_BAN' => null,
+ ),
+ 'ucp' => array(
+ 'UCP_MAIN' => null,
+ 'UCP_PROFILE' => null,
+ 'UCP_PREFS' => null,
+ 'UCP_PM' => null,
+ 'UCP_USERGROUPS' => null,
+ 'UCP_ZEBRA' => null,
+ ),
+ );
+
+ /**
+ * @var array
+ */
+ protected $module_categories_basenames = array(
+ 'UCP_PM' => 'ucp_pm',
+ );
+
+ /**
+ * @var array
+ */
+ protected $module_extras = array(
+ 'acp' => array(
+ 'ACP_QUICK_ACCESS' => array(
+ 'ACP_MANAGE_USERS',
+ 'ACP_GROUPS_MANAGE',
+ 'ACP_MANAGE_FORUMS',
+ 'ACP_MOD_LOGS',
+ 'ACP_BOTS',
+ 'ACP_PHP_INFO',
+ ),
+ 'ACP_FORUM_BASED_PERMISSIONS' => array(
+ 'ACP_FORUM_PERMISSIONS',
+ 'ACP_FORUM_PERMISSIONS_COPY',
+ 'ACP_FORUM_MODERATORS',
+ 'ACP_USERS_FORUM_PERMISSIONS',
+ 'ACP_GROUPS_FORUM_PERMISSIONS',
+ ),
+ ),
+ );
+
+ /**
+ * Constructor
+ *
+ * @parma config $config Installer's config
+ * @param iohandler_interface $iohandler Installer's input-output handler
+ * @param container_factory $container Installer's DI container
+ */
+ public function __construct(config $config, iohandler_interface $iohandler, container_factory $container)
+ {
+ $this->config = $config;
+ $this->db = $container->get('dbal.conn');
+ $this->extension_manager = $container->get('ext.manager');
+ $this->iohandler = $iohandler;
+ $this->module_manager = $container->get('module.manager');
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->db->sql_return_on_error(true);
+
+ $module_classes = array('acp', 'mcp', 'ucp');
+ $total = count($module_classes);
+ $i = $this->config->get('module_class_index', 0);
+ $module_classes = array_slice($module_classes, $i);
+
+ foreach ($module_classes as $module_class)
+ {
+ $categories = $this->config->get('module_categories_array', array());
+
+ $k = $this->config->get('module_categories_index', 0);
+ $module_categories = array_slice($this->module_categories[$module_class], $k);
+ $timed_out = false;
+
+ foreach ($module_categories as $cat_name => $subs)
+ {
+ // Check if this sub-category has a basename. If it has, use it.
+ $basename = (isset($this->module_categories_basenames[$cat_name])) ? $this->module_categories_basenames[$cat_name] : '';
+
+ $module_data = array(
+ 'module_basename' => $basename,
+ 'module_enabled' => 1,
+ 'module_display' => 1,
+ 'parent_id' => 0,
+ 'module_class' => $module_class,
+ 'module_langname' => $cat_name,
+ 'module_mode' => '',
+ 'module_auth' => '',
+ );
+
+ $this->module_manager->update_module_data($module_data);
+
+ // Check for last sql error happened
+ if ($this->db->get_sql_error_triggered())
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+
+ $categories[$cat_name]['id'] = (int) $module_data['module_id'];
+ $categories[$cat_name]['parent_id'] = 0;
+
+ if (is_array($subs))
+ {
+ foreach ($subs as $level2_name)
+ {
+ // Check if this sub-category has a basename. If it has, use it.
+ $basename = (isset($this->module_categories_basenames[$level2_name])) ? $this->module_categories_basenames[$level2_name] : '';
+
+ $module_data = array(
+ 'module_basename' => $basename,
+ 'module_enabled' => 1,
+ 'module_display' => 1,
+ 'parent_id' => (int) $categories[$cat_name]['id'],
+ 'module_class' => $module_class,
+ 'module_langname' => $level2_name,
+ 'module_mode' => '',
+ 'module_auth' => '',
+ );
+
+ $this->module_manager->update_module_data($module_data);
+
+ // Check for last sql error happened
+ if ($this->db->get_sql_error_triggered())
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+
+ $categories[$level2_name]['id'] = (int) $module_data['module_id'];
+ $categories[$level2_name]['parent_id'] = (int) $categories[$cat_name]['id'];
+ }
+ }
+
+ $k++;
+
+ // Stop execution if resource limit is reached
+ if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
+ {
+ $timed_out = true;
+ break;
+ }
+ }
+
+ $this->config->set('module_categories_array', $categories);
+ $this->config->set('module_categories_index', $k);
+
+ if ($timed_out)
+ {
+ throw new resource_limit_reached_exception();
+ }
+
+ // Get the modules we want to add... returned sorted by name
+ $module_info = $this->module_manager->get_module_infos($module_class);
+
+ $k = $this->config->get('module_info_index', 0);
+ $module_info = array_slice($module_info, $k);
+
+ foreach ($module_info as $module_basename => $fileinfo)
+ {
+ foreach ($fileinfo['modes'] as $module_mode => $row)
+ {
+ foreach ($row['cat'] as $cat_name)
+ {
+ if (!isset($categories[$cat_name]))
+ {
+ continue;
+ }
+
+ $module_data = array(
+ 'module_basename' => $module_basename,
+ 'module_enabled' => 1,
+ 'module_display' => (isset($row['display'])) ? (int) $row['display'] : 1,
+ 'parent_id' => (int) $categories[$cat_name]['id'],
+ 'module_class' => $module_class,
+ 'module_langname' => $row['title'],
+ 'module_mode' => $module_mode,
+ 'module_auth' => $row['auth'],
+ );
+
+ $this->module_manager->update_module_data($module_data);
+
+ // Check for last sql error happened
+ if ($this->db->get_sql_error_triggered())
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+ }
+ }
+
+ $k++;
+
+ // Stop execution if resource limit is reached
+ if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
+ {
+ $timed_out = true;
+ break;
+ }
+ }
+
+ $this->config->set('module_info_index', $k);
+
+ // Stop execution if resource limit is reached
+ if ($timed_out)
+ {
+ throw new resource_limit_reached_exception();
+ }
+
+ // Move some of the modules around since the code above will put them in the wrong place
+ if (!$this->config->get('modules_ordered', false))
+ {
+ $this->order_modules($module_class);
+ $this->config->set('modules_ordered', true);
+
+ // Stop execution if resource limit is reached
+ if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ // And now for the special ones
+ // (these are modules which appear in multiple categories and thus get added manually
+ // to some for more control)
+ if (isset($this->module_extras[$module_class]))
+ {
+ $this->add_module_extras($module_class);
+ }
+
+ $this->module_manager->remove_cache_file($module_class);
+
+ $i++;
+
+ $this->config->set('module_class_index', $i);
+ $this->config->set('module_categories_index', 0);
+ $this->config->set('module_info_index', 0);
+ $this->config->set('added_extra_modules', false);
+ $this->config->set('modules_ordered', false);
+ $this->config->set('module_categories_array', array());
+
+ // Stop execution if resource limit is reached
+ if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
+ {
+ break;
+ }
+ }
+
+ if ($i < $total)
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ /**
+ * Move modules to their correct place
+ *
+ * @param string $module_class
+ */
+ protected function order_modules($module_class)
+ {
+ if ($module_class == 'acp')
+ {
+ // Move main module 4 up...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'acp_main'
+ AND module_class = 'acp'
+ AND module_mode = 'main'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'acp', 'move_up', 4);
+
+ // Move permissions intro screen module 4 up...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'acp_permissions'
+ AND module_class = 'acp'
+ AND module_mode = 'intro'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'acp', 'move_up', 4);
+
+ // Move manage users screen module 5 up...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'acp_users'
+ AND module_class = 'acp'
+ AND module_mode = 'overview'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'acp', 'move_up', 5);
+
+ // Move extension management module 1 up...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_langname = 'ACP_EXTENSION_MANAGEMENT'
+ AND module_class = 'acp'
+ AND module_mode = ''
+ AND module_basename = ''";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'acp', 'move_up', 1);
+ }
+
+ if ($module_class == 'mcp')
+ {
+ // Move pm report details module 3 down...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'mcp_pm_reports'
+ AND module_class = 'mcp'
+ AND module_mode = 'pm_report_details'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3);
+
+ // Move closed pm reports module 3 down...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'mcp_pm_reports'
+ AND module_class = 'mcp'
+ AND module_mode = 'pm_reports_closed'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3);
+
+ // Move open pm reports module 3 down...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'mcp_pm_reports'
+ AND module_class = 'mcp'
+ AND module_mode = 'pm_reports'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'mcp', 'move_down', 3);
+ }
+
+ if ($module_class == 'ucp')
+ {
+ // Move attachment module 4 down...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'ucp_attachments'
+ AND module_class = 'ucp'
+ AND module_mode = 'attachments'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'ucp', 'move_down', 4);
+
+ // Move notification options module 4 down...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'ucp_notifications'
+ AND module_class = 'ucp'
+ AND module_mode = 'notification_options'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'ucp', 'move_down', 4);
+
+ // Move OAuth module 5 down...
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_basename = 'ucp_auth_link'
+ AND module_class = 'ucp'
+ AND module_mode = 'auth_link'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->module_manager->move_module_by($row, 'ucp', 'move_down', 5);
+ }
+ }
+
+ /**
+ * Add extra modules
+ *
+ * @param string $module_class
+ */
+ protected function add_module_extras($module_class)
+ {
+ foreach ($this->module_extras[$module_class] as $cat_name => $mods)
+ {
+ $sql = 'SELECT module_id, left_id, right_id
+ FROM ' . MODULES_TABLE . "
+ WHERE module_langname = '" . $this->db->sql_escape($cat_name) . "'
+ AND module_class = '" . $this->db->sql_escape($module_class) . "'";
+ $result = $this->db->sql_query_limit($sql, 1);
+ $row2 = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ foreach ($mods as $mod_name)
+ {
+ $sql = 'SELECT *
+ FROM ' . MODULES_TABLE . "
+ WHERE module_langname = '" . $this->db->sql_escape($mod_name) . "'
+ AND module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND module_basename <> ''";
+ $result = $this->db->sql_query_limit($sql, 1);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $module_data = array(
+ 'module_basename' => $row['module_basename'],
+ 'module_enabled' => (int) $row['module_enabled'],
+ 'module_display' => (int) $row['module_display'],
+ 'parent_id' => (int) $row2['module_id'],
+ 'module_class' => $row['module_class'],
+ 'module_langname' => $row['module_langname'],
+ 'module_mode' => $row['module_mode'],
+ 'module_auth' => $row['module_auth'],
+ );
+
+ $this->module_manager->update_module_data($module_data);
+
+ // Check for last sql error happened
+ if ($this->db->get_sql_error_triggered())
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_ADD_MODULES';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_data/task/create_search_index.php b/phpBB/phpbb/install/module/install_data/task/create_search_index.php
new file mode 100644
index 0000000000..8a2f6aa1de
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_data/task/create_search_index.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_data\task;
+
+use phpbb\auth\auth;
+use phpbb\db\driver\driver_interface;
+use phpbb\event\dispatcher;
+use phpbb\config\config;
+use phpbb\install\helper\container_factory;
+use phpbb\language\language;
+use phpbb\search\fulltext_native;
+use phpbb\user;
+
+class create_search_index extends \phpbb\install\task_base
+{
+ /**
+ * @var auth
+ */
+ protected $auth;
+
+ /**
+ * @var config
+ */
+ protected $config;
+
+ /**
+ * @var driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var dispatcher
+ */
+ protected $phpbb_dispatcher;
+
+ /**
+ * @var language
+ */
+ protected $language;
+
+ /**
+ * @var user
+ */
+ protected $user;
+
+ /**
+ * @var string phpBB root path
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string PHP file extension
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param config $config phpBB config
+ * @param container_factory $container Installer's DI container
+ * @param string $phpbb_root_path phpBB root path
+ * @param string $php_ext PHP file extension
+ */
+ public function __construct(config $config, container_factory $container,
+ $phpbb_root_path, $php_ext)
+ {
+ $this->auth = $container->get('auth');
+ $this->config = $config;
+ $this->db = $container->get('dbal.conn');
+ $this->language = $container->get('language');
+ $this->phpbb_dispatcher = $container->get('dispatcher');
+ $this->user = $container->get('user');
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Make sure fulltext native load update is set
+ $this->config->set('fulltext_native_load_upd', 1);
+
+ $error = false;
+ $search = new fulltext_native(
+ $error,
+ $this->phpbb_root_path,
+ $this->php_ext,
+ $this->auth,
+ $this->config,
+ $this->db,
+ $this->user,
+ $this->phpbb_dispatcher
+ );
+
+ $sql = 'SELECT post_id, post_subject, post_text, poster_id, forum_id
+ FROM ' . POSTS_TABLE;
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']);
+ }
+ $this->db->sql_freeresult($result);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_CREATE_SEARCH_INDEX';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_database/module.php b/phpBB/phpbb/install/module/install_database/module.php
new file mode 100644
index 0000000000..0d8b33087f
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_database/module.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_database;
+
+/**
+ * Installer module for database installation
+ */
+class module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('install', 0, 'install');
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_database/task/add_config_settings.php b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php
new file mode 100644
index 0000000000..ba439609ff
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_database/task/add_config_settings.php
@@ -0,0 +1,368 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_database\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+
+/**
+ * Create database schema
+ */
+class add_config_settings extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var \phpbb\passwords\manager
+ */
+ protected $password_manager;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $config_table;
+
+ /**
+ * @var string
+ */
+ protected $user_table;
+
+ /**
+ * @var string
+ */
+ protected $topics_table;
+
+ /**
+ * @var string
+ */
+ protected $forums_table;
+
+ /**
+ * @var string
+ */
+ protected $posts_table;
+
+ /**
+ * @var string
+ */
+ protected $moderator_cache_table;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem service
+ * @param \phpbb\install\helper\config $install_config Installer's config helper
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ * @param \phpbb\install\helper\container_factory $container Installer's DI container
+ * @param \phpbb\language\language $language Language service
+ * @param string $phpbb_root_path Path to phpBB's root
+ */
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem,
+ \phpbb\install\helper\config $install_config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ \phpbb\install\helper\container_factory $container,
+ \phpbb\language\language $language,
+ $phpbb_root_path)
+ {
+ $this->db = $container->get('dbal.conn');
+ $this->filesystem = $filesystem;
+ $this->install_config = $install_config;
+ $this->iohandler = $iohandler;
+ $this->language = $language;
+ $this->password_manager = $container->get('passwords.manager');
+ $this->phpbb_root_path = $phpbb_root_path;
+
+ // Table names
+ $this->config_table = $container->get_parameter('tables.config');
+ $this->forums_table = $container->get_parameter('tables.forums');
+ $this->topics_table = $container->get_parameter('tables.topics');
+ $this->user_table = $container->get_parameter('tables.users');
+ $this->moderator_cache_table = $container->get_parameter('tables.moderator_cache');
+ $this->posts_table = $container->get_parameter('tables.posts');
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->db->sql_return_on_error(true);
+
+ $server_name = $this->install_config->get('server_name');
+ $current_time = time();
+ $user_ip = phpbb_ip_normalise($this->iohandler->get_server_variable('REMOTE_ADDR'));
+ $user_ip = ($user_ip === false) ? '' : $user_ip;
+ $referer = $this->iohandler->get_server_variable('REFERER');
+
+ // Calculate cookie domain
+ $cookie_domain = $server_name;
+
+ if (strpos($cookie_domain, 'www.') === 0)
+ {
+ $cookie_domain = substr($cookie_domain, 3);
+ }
+
+ // Set default config and post data, this applies to all DB's
+ $sql_ary = array(
+ 'INSERT INTO ' . $this->config_table . " (config_name, config_value)
+ VALUES ('board_startdate', '$current_time')",
+
+ 'INSERT INTO ' . $this->config_table . " (config_name, config_value)
+ VALUES ('default_lang', '" . $this->db->sql_escape($this->install_config->get('default_lang')) . "')",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('server_name')) . "'
+ WHERE config_name = 'server_name'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('server_port')) . "'
+ WHERE config_name = 'server_port'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_email')) . "'
+ WHERE config_name = 'board_email'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_email')) . "'
+ WHERE config_name = 'board_contact'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($cookie_domain) . "'
+ WHERE config_name = 'cookie_domain'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->language->lang('default_dateformat')) . "'
+ WHERE config_name = 'default_dateformat'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('email_enable')) . "'
+ WHERE config_name = 'email_enable'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_delivery')) . "'
+ WHERE config_name = 'smtp_delivery'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_host')) . "'
+ WHERE config_name = 'smtp_host'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_port')) . "'
+ WHERE config_name = 'smtp_port'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_auth')) . "'
+ WHERE config_name = 'smtp_auth_method'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_user')) . "'
+ WHERE config_name = 'smtp_username'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('smtp_pass')) . "'
+ WHERE config_name = 'smtp_password'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('cookie_secure')) . "'
+ WHERE config_name = 'cookie_secure'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('force_server_vars')) . "'
+ WHERE config_name = 'force_server_vars'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('script_path')) . "'
+ WHERE config_name = 'script_path'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('server_protocol')) . "'
+ WHERE config_name = 'server_protocol'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "'
+ WHERE config_name = 'newest_username'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . md5(mt_rand()) . "'
+ WHERE config_name = 'avatar_salt'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . md5(mt_rand()) . "'
+ WHERE config_name = 'plupload_salt'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_name')) . "'
+ WHERE config_name = 'sitename'",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->install_config->get('board_description')) . "'
+ WHERE config_name = 'site_desc'",
+
+ 'UPDATE ' . $this->user_table . "
+ SET username = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "',
+ user_password='" . $this->password_manager->hash($this->install_config->get('admin_passwd')) . "',
+ user_ip = '" . $this->db->sql_escape($user_ip) . "',
+ user_lang = '" . $this->db->sql_escape($this->install_config->get('user_language', 'en')) . "',
+ user_email='" . $this->db->sql_escape($this->install_config->get('board_email')) . "',
+ user_dateformat='" . $this->db->sql_escape($this->language->lang('default_dateformat')) . "',
+ user_email_hash = " . $this->db->sql_escape(phpbb_email_hash($this->install_config->get('board_email'))) . ",
+ username_clean = '" . $this->db->sql_escape(utf8_clean_string($this->install_config->get('admin_name'))) . "'
+ WHERE username = 'Admin'",
+
+ 'UPDATE ' . $this->moderator_cache_table . "
+ SET username = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "'
+ WHERE username = 'Admin'",
+
+ 'UPDATE ' . $this->forums_table . "
+ SET forum_last_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "'
+ WHERE forum_last_poster_name = 'Admin'",
+
+ 'UPDATE ' . $this->topics_table . "
+ SET topic_first_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "',
+ topic_last_poster_name = '" . $this->db->sql_escape($this->install_config->get('admin_name')) . "'
+ WHERE topic_first_poster_name = 'Admin'
+ OR topic_last_poster_name = 'Admin'",
+
+ 'UPDATE ' . $this->user_table . "
+ SET user_regdate = $current_time",
+
+ 'UPDATE ' . $this->posts_table . "
+ SET post_time = $current_time, poster_ip = '" . $this->db->sql_escape($user_ip) . "'",
+
+ 'UPDATE ' . $this->topics_table . "
+ SET topic_time = $current_time, topic_last_post_time = $current_time",
+
+ 'UPDATE ' . $this->forums_table . "
+ SET forum_last_post_time = $current_time",
+
+ 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($this->db->sql_server_info(true)) . "'
+ WHERE config_name = 'dbms_version'",
+ );
+
+ if (@extension_loaded('gd'))
+ {
+ $sql_ary[] = 'UPDATE ' . $this->config_table . "
+ SET config_value = 'core.captcha.plugins.gd'
+ WHERE config_name = 'captcha_plugin'";
+
+ $sql_ary[] = 'UPDATE ' . $this->config_table . "
+ SET config_value = '1'
+ WHERE config_name = 'captcha_gd'";
+ }
+
+ $ref = substr($referer, strpos($referer, '://') + 3);
+ if (!(stripos($ref, $server_name) === 0))
+ {
+ $sql_ary[] = 'UPDATE ' . $this->config_table . "
+ SET config_value = '0'
+ WHERE config_name = 'referer_validation'";
+ }
+
+ // We set a (semi-)unique cookie name to bypass login issues related to the cookie name.
+ $cookie_name = 'phpbb3_';
+ $rand_str = md5(mt_rand());
+ $rand_str = str_replace('0', 'z', base_convert($rand_str, 16, 35));
+ $rand_str = substr($rand_str, 0, 5);
+ $cookie_name .= strtolower($rand_str);
+
+ $sql_ary[] = 'UPDATE ' . $this->config_table . "
+ SET config_value = '" . $this->db->sql_escape($cookie_name) . "'
+ WHERE config_name = 'cookie_name'";
+
+ // Disable avatars if upload directory is not writable
+ if (!$this->filesystem->is_writable($this->phpbb_root_path . 'images/avatars/upload/'))
+ {
+ $sql_ary[] = 'UPDATE ' . $this->config_table . "
+ SET config_value = '0'
+ WHERE config_name = 'allow_avatar'";
+
+ $sql_ary[] = 'UPDATE ' . $this->config_table . "
+ SET config_value = '0'
+ WHERE config_name = 'allow_avatar_upload'";
+ }
+
+ $i = $this->install_config->get('add_config_settings_index', 0);
+ $total = count($sql_ary);
+ $sql_ary = array_slice($sql_ary, $i);
+
+ foreach ($sql_ary as $sql)
+ {
+ if (!$this->db->sql_query($sql))
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+
+ $i++;
+
+ // Stop execution if resource limit is reached
+ if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0)
+ {
+ break;
+ }
+ }
+
+ if ($i < $total)
+ {
+ $this->install_config->set('add_config_settings_index', $i);
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_ADD_CONFIG_SETTINGS';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_database/task/add_default_data.php b/phpBB/phpbb/install/module/install_database/task/add_default_data.php
new file mode 100644
index 0000000000..c05e5321fb
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_database/task/add_default_data.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_database\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+
+/**
+ * Create database schema
+ */
+class add_default_data extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\install\helper\database
+ */
+ protected $database_helper;
+
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\database $db_helper Installer's database helper
+ * @param \phpbb\install\helper\config $config Installer config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ * @param \phpbb\install\helper\container_factory $container Installer's DI container
+ * @param \phpbb\language\language $language Language service
+ * @param string $root_path Root path of phpBB
+ */
+ public function __construct(\phpbb\install\helper\database $db_helper,
+ \phpbb\install\helper\config $config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ \phpbb\install\helper\container_factory $container,
+ \phpbb\language\language $language,
+ $root_path)
+ {
+ $this->db = $container->get('dbal.conn.driver');
+ $this->database_helper = $db_helper;
+ $this->config = $config;
+ $this->iohandler = $iohandler;
+ $this->language = $language;
+ $this->phpbb_root_path = $root_path;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->db->sql_return_on_error(true);
+
+ $table_prefix = $this->config->get('table_prefix');
+ $dbms = $this->config->get('dbms');
+ $dbms_info = $this->database_helper->get_available_dbms($dbms);
+
+ // Get schema data from file
+ $sql_query = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema_data.sql');
+
+ // Clean up SQL
+ $sql_query = $this->replace_dbms_specific_sql($sql_query);
+ $sql_query = preg_replace('# phpbb_([^\s]*) #i', ' ' . $table_prefix . '\1 ', $sql_query);
+ $sql_query = preg_replace_callback('#\{L_([A-Z0-9\-_]*)\}#s', array($this, 'lang_replace_callback'), $sql_query);
+ $sql_query = $this->database_helper->remove_comments($sql_query);
+ $sql_query = $this->database_helper->split_sql_file($sql_query, $dbms_info[$dbms]['DELIM']);
+
+ $i = $this->config->get('add_default_data_index', 0);
+ $total = count($sql_query);
+ $sql_query = array_slice($sql_query, $i);
+
+ foreach ($sql_query as $sql)
+ {
+ if (!$this->db->sql_query($sql))
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+
+ $i++;
+
+ // Stop execution if resource limit is reached
+ if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
+ {
+ break;
+ }
+ }
+
+ $this->config->set('add_default_data_index', $i);
+
+ if ($i < $total)
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ /**
+ * Process DB specific SQL
+ *
+ * @return string
+ */
+ protected function replace_dbms_specific_sql($query)
+ {
+ if ($this->db instanceof \phpbb\db\driver\mssql_base)
+ {
+ $query = preg_replace('#\# MSSQL IDENTITY (phpbb_[a-z_]+) (ON|OFF) \##s', 'SET IDENTITY_INSERT \1 \2;', $query);
+ }
+ else if ($this->db instanceof \phpbb\db\driver\postgres)
+ {
+ $query = preg_replace('#\# POSTGRES (BEGIN|COMMIT) \##s', '\1; ', $query);
+ }
+ else if ($this->db instanceof \phpbb\db\driver\mysql_base)
+ {
+ $query = str_replace('\\', '\\\\', $query);
+ }
+
+ return $query;
+ }
+
+ /**
+ * Callback function for language replacing
+ *
+ * @param array $matches
+ * @return string
+ */
+ public function lang_replace_callback($matches)
+ {
+ if (!empty($matches[1]))
+ {
+ return $this->db->sql_escape($this->language->lang($matches[1]));
+ }
+
+ return '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_ADD_DEFAULT_DATA';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_database/task/add_tables.php b/phpBB/phpbb/install/module/install_database/task/add_tables.php
new file mode 100644
index 0000000000..dc814f36ef
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_database/task/add_tables.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_database\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+
+/**
+ * Create tables
+ */
+class add_tables extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\db\tools\tools_interface
+ */
+ protected $db_tools;
+
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var string
+ */
+ protected $schema_file_path;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $config
+ * @param \phpbb\install\helper\database $db_helper
+ * @param \phpbb\filesystem\filesystem_interface $filesystem
+ * @param string $phpbb_root_path
+ */
+ public function __construct(\phpbb\install\helper\config $config,
+ \phpbb\install\helper\database $db_helper,
+ \phpbb\filesystem\filesystem_interface $filesystem,
+ $phpbb_root_path)
+ {
+ $dbms = $db_helper->get_available_dbms($config->get('dbms'));
+ $dbms = $dbms[$config->get('dbms')]['DRIVER'];
+ $factory = new \phpbb\db\tools\factory();
+
+ $this->db = new $dbms();
+ $this->db->sql_connect(
+ $config->get('dbhost'),
+ $config->get('dbuser'),
+ $config->get('dbpasswd'),
+ $config->get('dbname'),
+ $config->get('dbport'),
+ false,
+ false
+ );
+
+ $this->config = $config;
+ $this->db_tools = $factory->get($this->db);
+ $this->filesystem = $filesystem;
+ $this->schema_file_path = $phpbb_root_path . 'store/schema.json';
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->db->sql_return_on_error(true);
+
+ $table_prefix = $this->config->get('table_prefix');
+ $change_prefix = $this->config->get('change_table_prefix', true);
+
+ if (!defined('CONFIG_TABLE'))
+ {
+ // CONFIG_TABLE is required by sql_create_index() to check the
+ // length of index names. However table_prefix is not defined
+ // here yet, so we need to create the constant ourselves.
+ define('CONFIG_TABLE', $table_prefix . 'config');
+ }
+
+ $db_table_schema = @file_get_contents($this->schema_file_path);
+ $db_table_schema = json_decode($db_table_schema, true);
+ $total = count($db_table_schema);
+ $i = $this->config->get('add_table_index', 0);
+ $db_table_schema = array_slice($db_table_schema, $i);
+
+ foreach ($db_table_schema as $table_name => $table_data)
+ {
+ $i++;
+
+ $this->db_tools->sql_create_table(
+ ( ($change_prefix) ? ($table_prefix . substr($table_name, 6)) : $table_name ),
+ $table_data
+ );
+
+ // Stop execution if resource limit is reached
+ if ($this->config->get_time_remaining() <= 0 || $this->config->get_memory_remaining() <= 0)
+ {
+ break;
+ }
+ }
+
+ $this->config->set('add_table_index', $i);
+
+ if ($i < $total)
+ {
+ throw new resource_limit_reached_exception();
+ }
+ else
+ {
+ @unlink($this->schema_file_path);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_CREATE_TABLES';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_database/task/create_schema.php b/phpBB/phpbb/install/module/install_database/task/create_schema.php
new file mode 100644
index 0000000000..a5635d5dbe
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_database/task/create_schema.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_database\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+
+/**
+ * Create database schema
+ */
+class create_schema extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\db\tools\tools_interface
+ */
+ protected $db_tools;
+
+ /**
+ * @var \phpbb\install\helper\database
+ */
+ protected $database_helper;
+
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $config Installer's config provider
+ * @param \phpbb\install\helper\database $db_helper Installer's database helper
+ * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem service
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ * @param string $phpbb_root_path Path phpBB's root
+ * @param string $php_ext Extension of PHP files
+ */
+ public function __construct(\phpbb\install\helper\config $config,
+ \phpbb\install\helper\database $db_helper,
+ \phpbb\filesystem\filesystem_interface $filesystem,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ $phpbb_root_path,
+ $php_ext)
+ {
+ $dbms = $db_helper->get_available_dbms($config->get('dbms'));
+ $dbms = $dbms[$config->get('dbms')]['DRIVER'];
+ $factory = new \phpbb\db\tools\factory();
+
+ $this->db = new $dbms();
+ $this->db->sql_connect(
+ $config->get('dbhost'),
+ $config->get('dbuser'),
+ $config->get('dbpasswd'),
+ $config->get('dbname'),
+ $config->get('dbport'),
+ false,
+ false
+ );
+
+ $this->config = $config;
+ $this->db_tools = $factory->get($this->db);
+ $this->database_helper = $db_helper;
+ $this->filesystem = $filesystem;
+ $this->iohandler = $iohandler;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // As this task may take a large amount of time to complete refreshing the page might be necessary for some
+ // server configurations with limited resources
+ if (!$this->config->get('pre_schema_forced_refresh'))
+ {
+ if ($this->config->get_time_remaining() < 5)
+ {
+ $this->config->set('pre_schema_forced_refresh', true);
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ $this->db->sql_return_on_error(true);
+
+ $dbms = $this->config->get('dbms');
+ $dbms_info = $this->database_helper->get_available_dbms($dbms);
+ $schema_name = $dbms_info[$dbms]['SCHEMA'];
+ $delimiter = $dbms_info[$dbms]['DELIM'];
+ $table_prefix = $this->config->get('table_prefix');
+
+ if ($dbms === 'mysql')
+ {
+ if (version_compare($this->db->sql_server_info(true), '4.1.3', '>='))
+ {
+ $schema_name .= '_41';
+ }
+ else
+ {
+ $schema_name .= '_40';
+ }
+ }
+
+ $db_schema_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql';
+
+ // Load database vendor specific code if there is any
+ if ($this->filesystem->exists($db_schema_path))
+ {
+ $sql_query = @file_get_contents($db_schema_path);
+ $sql_query = preg_replace('#phpbb_#i', $table_prefix, $sql_query);
+ $sql_query = $this->database_helper->remove_comments($sql_query);
+ $sql_query = $this->database_helper->split_sql_file($sql_query, $delimiter);
+
+ foreach ($sql_query as $sql)
+ {
+ if (!$this->db->sql_query($sql))
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+ }
+
+ unset($sql_query);
+ }
+
+ $change_prefix = false;
+
+ // Generate database schema
+ if ($this->filesystem->exists($this->phpbb_root_path . 'install/schemas/schema.json'))
+ {
+ $db_table_schema = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema.json');
+ $db_table_schema = json_decode($db_table_schema, true);
+ $change_prefix = true;
+ }
+ else
+ {
+ global $table_prefix;
+
+ $table_prefix = $this->config->get('table_prefix');
+
+ if (!defined('CONFIG_TABLE'))
+ {
+ // We need to include the constants file for the table constants
+ // when we generate the schema from the migration files.
+ include ($this->phpbb_root_path . 'includes/constants.' . $this->php_ext);
+ }
+
+ $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, null, $this->php_ext);
+ $migrator_classes = $finder->core_path('phpbb/db/migration/data/')->get_classes();
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($this->db, true);
+ $schema_generator = new \phpbb\db\migration\schema_generator(
+ $migrator_classes,
+ new \phpbb\config\config(array()),
+ $this->db,
+ $db_tools,
+ $this->phpbb_root_path,
+ $this->php_ext,
+ $table_prefix
+ );
+ $db_table_schema = $schema_generator->get_schema();
+ }
+
+ if (!defined('CONFIG_TABLE'))
+ {
+ // CONFIG_TABLE is required by sql_create_index() to check the
+ // length of index names. However table_prefix is not defined
+ // here yet, so we need to create the constant ourselves.
+ define('CONFIG_TABLE', $table_prefix . 'config');
+ }
+
+ foreach ($db_table_schema as $table_name => $table_data)
+ {
+ $this->db_tools->sql_create_table(
+ ( ($change_prefix) ? ($table_prefix . substr($table_name, 6)) : $table_name ),
+ $table_data
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_CREATE_DATABASE_SCHEMA';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_database/task/create_schema_file.php b/phpBB/phpbb/install/module/install_database/task/create_schema_file.php
new file mode 100644
index 0000000000..b6d6ece17f
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_database/task/create_schema_file.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_database\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+
+/**
+ * Create database schema
+ */
+class create_schema_file extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $config Installer's config provider
+ * @param \phpbb\install\helper\database $db_helper Installer's database helper
+ * @param \phpbb\filesystem\filesystem_interface $filesystem Filesystem service
+ * @param string $phpbb_root_path Path phpBB's root
+ * @param string $php_ext Extension of PHP files
+ */
+ public function __construct(\phpbb\install\helper\config $config,
+ \phpbb\install\helper\database $db_helper,
+ \phpbb\filesystem\filesystem_interface $filesystem,
+ $phpbb_root_path,
+ $php_ext)
+ {
+ $dbms = $db_helper->get_available_dbms($config->get('dbms'));
+ $dbms = $dbms[$config->get('dbms')]['DRIVER'];
+
+ $this->db = new $dbms();
+ $this->db->sql_connect(
+ $config->get('dbhost'),
+ $config->get('dbuser'),
+ $config->get('dbpasswd'),
+ $config->get('dbname'),
+ $config->get('dbport'),
+ false,
+ false
+ );
+
+ $this->config = $config;
+ $this->filesystem = $filesystem;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Generate database schema
+ if ($this->filesystem->exists($this->phpbb_root_path . 'install/schemas/schema.json'))
+ {
+ $db_table_schema = @file_get_contents($this->phpbb_root_path . 'install/schemas/schema.json');
+ $this->config->set('change_table_prefix', true);
+ }
+ else
+ {
+ global $table_prefix;
+
+ // As this task may take a large amount of time to complete refreshing the page might be necessary for some
+ // server configurations with limited resources
+ if (!$this->config->get('pre_schema_forced_refresh', false))
+ {
+ if ($this->config->get_time_remaining() < 5)
+ {
+ $this->config->set('pre_schema_forced_refresh', true);
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ $table_prefix = $this->config->get('table_prefix');
+
+ if (!defined('CONFIG_TABLE'))
+ {
+ // We need to include the constants file for the table constants
+ // when we generate the schema from the migration files.
+ include ($this->phpbb_root_path . 'includes/constants.' . $this->php_ext);
+ }
+
+ $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, null, $this->php_ext);
+ $migrator_classes = $finder->core_path('phpbb/db/migration/data/')->get_classes();
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($this->db, true);
+ $schema_generator = new \phpbb\db\migration\schema_generator(
+ $migrator_classes,
+ new \phpbb\config\config(array()),
+ $this->db,
+ $db_tools,
+ $this->phpbb_root_path,
+ $this->php_ext,
+ $table_prefix
+ );
+ $db_table_schema = $schema_generator->get_schema();
+ $db_table_schema = json_encode($db_table_schema, JSON_PRETTY_PRINT);
+
+ $this->config->set('change_table_prefix', false);
+ }
+
+ $fp = @fopen($this->phpbb_root_path . 'store/schema.json', 'wb');
+ if (!$fp)
+ {
+ throw new \Exception('INST_SCHEMA_FILE_NOT_WRITABLE');
+ }
+
+ fwrite($fp, $db_table_schema);
+ fclose($fp);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_CREATE_DATABASE_SCHEMA_FILE';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_database/task/set_up_database.php b/phpBB/phpbb/install/module/install_database/task/set_up_database.php
new file mode 100644
index 0000000000..49c8ea23ad
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_database/task/set_up_database.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_database\task;
+
+/**
+ * Set up database for table generation
+ */
+class set_up_database extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\install\helper\database
+ */
+ protected $database_helper;
+
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var string
+ */
+ protected $schema_file_path;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $config
+ * @param \phpbb\install\helper\database $db_helper
+ * @param \phpbb\filesystem\filesystem_interface $filesystem
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler
+ * @param string $phpbb_root_path
+ */
+ public function __construct(\phpbb\install\helper\config $config,
+ \phpbb\install\helper\database $db_helper,
+ \phpbb\filesystem\filesystem_interface $filesystem,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ $phpbb_root_path)
+ {
+ $dbms = $db_helper->get_available_dbms($config->get('dbms'));
+ $dbms = $dbms[$config->get('dbms')]['DRIVER'];
+
+ $this->db = new $dbms();
+ $this->db->sql_connect(
+ $config->get('dbhost'),
+ $config->get('dbuser'),
+ $config->get('dbpasswd'),
+ $config->get('dbname'),
+ $config->get('dbport'),
+ false,
+ false
+ );
+
+ $this->config = $config;
+ $this->database_helper = $db_helper;
+ $this->filesystem = $filesystem;
+ $this->iohandler = $iohandler;
+ $this->phpbb_root_path = $phpbb_root_path;
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ $dbms = $this->config->get('dbms');
+ $dbms_info = $this->database_helper->get_available_dbms($dbms);
+ $schema_name = $dbms_info[$dbms]['SCHEMA'];
+
+ if ($dbms === 'mysql')
+ {
+ if (version_compare($this->db->sql_server_info(true), '4.1.3', '>='))
+ {
+ $schema_name .= '_41';
+ }
+ else
+ {
+ $schema_name .= '_40';
+ }
+ }
+
+ $this->schema_file_path = $this->phpbb_root_path . 'install/schemas/' . $schema_name . '_schema.sql';
+
+ return $this->filesystem->exists($this->schema_file_path);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->db->sql_return_on_error(true);
+
+ $dbms = $this->config->get('dbms');
+ $dbms_info = $this->database_helper->get_available_dbms($dbms);
+ $delimiter = $dbms_info[$dbms]['DELIM'];
+ $table_prefix = $this->config->get('table_prefix');
+
+ $sql_query = @file_get_contents($this->schema_file_path);
+ $sql_query = preg_replace('#phpbb_#i', $table_prefix, $sql_query);
+ $sql_query = $this->database_helper->remove_comments($sql_query);
+ $sql_query = $this->database_helper->split_sql_file($sql_query, $delimiter);
+
+ foreach ($sql_query as $sql)
+ {
+ if (!$this->db->sql_query($sql))
+ {
+ $error = $this->db->sql_error($this->db->get_sql_error_sql());
+ $this->iohandler->add_error_message('INST_ERR_DB', $error['message']);
+ }
+ }
+
+ unset($sql_query);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_SETUP_DATABASE';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_filesystem/module.php b/phpBB/phpbb/install/module/install_filesystem/module.php
new file mode 100644
index 0000000000..7215449664
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_filesystem/module.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_filesystem;
+
+/**
+ * Installer module for filesystem installation
+ */
+class module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('install', 0, 'install');
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php b/phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php
new file mode 100644
index 0000000000..5bc425b929
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_filesystem/task/create_config_file.php
@@ -0,0 +1,244 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_filesystem\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+
+/**
+ * Dumps config file
+ */
+class create_config_file extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var \phpbb\install\helper\database
+ */
+ protected $db_helper;
+
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * @var array
+ */
+ protected $options;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\filesystem\filesystem_interface $filesystem
+ * @param \phpbb\install\helper\config $install_config
+ * @param \phpbb\install\helper\database $db_helper
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ * @param array $options
+ */
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem,
+ \phpbb\install\helper\config $install_config,
+ \phpbb\install\helper\database $db_helper,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ $phpbb_root_path,
+ $php_ext,
+ $options = array())
+ {
+ $this->install_config = $install_config;
+ $this->db_helper = $db_helper;
+ $this->filesystem = $filesystem;
+ $this->iohandler = $iohandler;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ $this->options = array_merge(array(
+ 'debug' => false,
+ 'debug_container' => false,
+ 'environment' => null,
+ ), $options);
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $config_written = true;
+
+ // Create config.php
+ $path_to_config = $this->phpbb_root_path . 'config.' . $this->php_ext;
+
+ $fp = @fopen($path_to_config, 'w');
+ if (!$fp)
+ {
+ $config_written = false;
+ }
+
+ $config_content = $this->get_config_data($this->options['debug'], $this->options['debug_container'], $this->options['environment']);
+
+ if (!@fwrite($fp, $config_content))
+ {
+ $config_written = false;
+ }
+
+ @fclose($fp);
+
+ // chmod config.php to be only readable
+ if ($config_written)
+ {
+ try
+ {
+ $this->filesystem->phpbb_chmod($path_to_config, \phpbb\filesystem\filesystem_interface::CHMOD_READ);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing, the user will get a notice later
+ }
+ }
+ else
+ {
+ $this->iohandler->add_error_message('UNABLE_TO_WRITE_CONFIG_FILE');
+ throw new user_interaction_required_exception();
+ }
+
+ // Create a lock file to indicate that there is an install in progress
+ $fp = @fopen($this->phpbb_root_path . 'cache/install_lock', 'wb');
+ if ($fp === false)
+ {
+ // We were unable to create the lock file - abort
+ $this->iohandler->add_error_message('UNABLE_TO_WRITE_LOCK');
+ throw new user_interaction_required_exception();
+ }
+ @fclose($fp);
+
+ try
+ {
+ $this->filesystem->phpbb_chmod($this->phpbb_root_path . 'cache/install_lock', 0777);
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing, the user will get a notice later
+ }
+ }
+
+ /**
+ * Returns the content which should be dumped to config.php
+ *
+ * @param bool $debug If the debug constants should be enabled by default or not
+ * @param bool $debug_container If the container should be compiled on
+ * every page load or not
+ * @param string $environment The environment to use
+ *
+ * @return string content to be written to the config file
+ */
+ protected function get_config_data($debug = false, $debug_container = false, $environment = null)
+ {
+ $config_content = "<?php\n";
+ $config_content .= "// phpBB 3.2.x auto-generated configuration file\n// Do not change anything in this file!\n";
+
+ $dbms = $this->install_config->get('dbms');
+ $db_driver = $this->db_helper->get_available_dbms($dbms);
+ $db_driver = $db_driver[$dbms]['DRIVER'];
+
+ $config_data_array = array(
+ 'dbms' => $db_driver,
+ 'dbhost' => $this->install_config->get('dbhost'),
+ 'dbport' => $this->install_config->get('dbport'),
+ 'dbname' => $this->install_config->get('dbname'),
+ 'dbuser' => $this->install_config->get('dbuser'),
+ 'dbpasswd' => $this->install_config->get('dbpasswd'),
+ 'table_prefix' => $this->install_config->get('table_prefix'),
+
+ 'phpbb_adm_relative_path' => 'adm/',
+
+ 'acm_type' => 'phpbb\cache\driver\file',
+ );
+
+ foreach ($config_data_array as $key => $value)
+ {
+ $config_content .= "\${$key} = '" . str_replace("'", "\\'", str_replace('\\', '\\\\', $value)) . "';\n";
+ }
+
+ $config_content .= "\n@define('PHPBB_INSTALLED', true);\n";
+ $config_content .= "// @define('PHPBB_DISPLAY_LOAD_TIME', true);\n";
+
+ if ($environment)
+ {
+ $config_content .= "@define('PHPBB_ENVIRONMENT', 'test');\n";
+ }
+ else if ($debug)
+ {
+ $config_content .= "@define('PHPBB_ENVIRONMENT', 'development');\n";
+ }
+ else
+ {
+ $config_content .= "@define('PHPBB_ENVIRONMENT', 'production');\n";
+ }
+
+ if ($debug_container)
+ {
+ $config_content .= "@define('DEBUG_CONTAINER', true);\n";
+ }
+ else
+ {
+ $config_content .= "// @define('DEBUG_CONTAINER', true);\n";
+ }
+
+ if ($environment === 'test')
+ {
+ $config_content .= "@define('DEBUG_TEST', true);\n";
+
+ // Mandatory for the functional tests, will be removed by PHPBB3-12623
+ $config_content .= "@define('DEBUG', true);\n";
+ }
+
+ return $config_content;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_CREATE_CONFIG_FILE';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_finish/module.php b/phpBB/phpbb/install/module/install_finish/module.php
new file mode 100644
index 0000000000..3a7544b84f
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_finish/module.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_finish;
+
+/**
+ * Installer module for filesystem installation
+ */
+class module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('install', 0, 'install');
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_finish/task/install_extensions.php b/phpBB/phpbb/install/module/install_finish/task/install_extensions.php
new file mode 100644
index 0000000000..47ea156c66
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_finish/task/install_extensions.php
@@ -0,0 +1,207 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_finish\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+
+/**
+ * Installs extensions that exist in ext folder upon install
+ */
+class install_extensions extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\config\db
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\log\log_interface
+ */
+ protected $log;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /** @var \phpbb\extension\manager */
+ protected $extension_manager;
+
+ /** @var \Symfony\Component\Finder\Finder */
+ protected $finder;
+
+ /** @var string Extension table */
+ protected $extension_table;
+
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\container_factory $container
+ * @param \phpbb\install\helper\config $install_config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler
+ * @param string $phpbb_root_path phpBB root path
+ */
+ public function __construct(\phpbb\install\helper\container_factory $container, \phpbb\install\helper\config $install_config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler, $phpbb_root_path)
+ {
+ $this->install_config = $install_config;
+ $this->iohandler = $iohandler;
+ $this->extension_table = $container->get_parameter('tables.ext');
+
+ $this->log = $container->get('log');
+ $this->user = $container->get('user');
+ $this->extension_manager = $container->get('ext.manager');
+ $this->config = $container->get('config');
+ $this->db = $container->get('dbal.conn');
+ $this->finder = new \Symfony\Component\Finder\Finder();
+ $this->finder->in($phpbb_root_path . 'ext/')
+ ->ignoreUnreadableDirs()
+ ->depth('< 3')
+ ->files()
+ ->name('composer.json');
+
+ // Make sure asset version exists in config. Otherwise we might try to
+ // insert the assets_version setting into the database and cause a
+ // duplicate entry error.
+ if (!isset($this->config['assets_version']))
+ {
+ $this->config['assets_version'] = 0;
+ }
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->user->session_begin();
+ $this->user->setup(array('common', 'acp/common', 'cli'));
+
+ $install_extensions = $this->iohandler->get_input('install-extensions', array());
+
+ $all_available_extensions = $this->extension_manager->all_available();
+ $i = $this->install_config->get('install_extensions_index', 0);
+ $available_extensions = array_slice($all_available_extensions, $i);
+
+ // Install extensions
+ foreach ($available_extensions as $ext_name => $ext_path)
+ {
+ if (!empty($install_extensions) && $install_extensions !== ['all'] && !in_array($ext_name, $install_extensions))
+ {
+ continue;
+ }
+
+ try
+ {
+ $extension = $this->extension_manager->get_extension($ext_name);
+
+ if (!$extension->is_enableable())
+ {
+ $this->iohandler->add_log_message(array('CLI_EXTENSION_NOT_ENABLEABLE', $ext_name));
+ continue;
+ }
+
+ $this->extension_manager->enable($ext_name);
+ $extensions = $this->get_extensions();
+
+ if (isset($extensions[$ext_name]) && $extensions[$ext_name]['ext_active'])
+ {
+ // Create log
+ $this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_ENABLE', time(), array($ext_name));
+ $this->iohandler->add_success_message(array('CLI_EXTENSION_ENABLE_SUCCESS', $ext_name));
+ }
+ else
+ {
+ $this->iohandler->add_log_message(array('CLI_EXTENSION_ENABLE_FAILURE', $ext_name));
+ }
+ }
+ catch (\Exception $e)
+ {
+ // Add fail log and continue
+ $this->iohandler->add_log_message(array('CLI_EXTENSION_ENABLE_FAILURE', $ext_name));
+ }
+
+ $i++;
+
+ // Stop execution if resource limit is reached
+ if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0)
+ {
+ break;
+ }
+ }
+
+ $this->install_config->set('install_extensions_index', $i);
+
+ if ($i < count($all_available_extensions))
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_INSTALL_EXTENSIONS';
+ }
+
+ /**
+ * Get extensions from database
+ *
+ * @return array List of extensions
+ */
+ private function get_extensions()
+ {
+ $sql = 'SELECT *
+ FROM ' . $this->extension_table;
+
+ $result = $this->db->sql_query($sql);
+ $extensions_row = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ $extensions = array();
+
+ foreach ($extensions_row as $extension)
+ {
+ $extensions[$extension['ext_name']] = $extension;
+ }
+
+ ksort($extensions);
+
+ return $extensions;
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_finish/task/notify_user.php b/phpBB/phpbb/install/module/install_finish/task/notify_user.php
new file mode 100644
index 0000000000..292be57f5f
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_finish/task/notify_user.php
@@ -0,0 +1,174 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_finish\task;
+
+use phpbb\config\db;
+
+/**
+ * Logs installation and sends an email to the admin
+ */
+class notify_user extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\auth\auth
+ */
+ protected $auth;
+
+ /**
+ * @var \phpbb\config\db
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var \phpbb\log\log_interface
+ */
+ protected $log;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\container_factory $container
+ * @param \phpbb\install\helper\config $install_config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\install\helper\container_factory $container, \phpbb\install\helper\config $install_config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler, $phpbb_root_path, $php_ext)
+ {
+ $this->install_config = $install_config;
+ $this->iohandler = $iohandler;
+
+ $this->auth = $container->get('auth');
+ $this->language = $container->get('language');
+ $this->log = $container->get('log');
+ $this->user = $container->get('user');
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ // We need to reload config for cases when it doesn't have all values
+ /** @var \phpbb\cache\driver\driver_interface $cache */
+ $cache = $container->get('cache.driver');
+ $cache->destroy('config');
+
+ $this->config = new db(
+ $container->get('dbal.conn'),
+ $cache,
+ $container->get_parameter('tables.config')
+ );
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->user->session_begin();
+ $this->user->setup('common');
+
+ if ($this->config['email_enable'])
+ {
+ include ($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
+
+ // functions_messenger.php uses config to determine language paths
+ // Remove when able
+ global $config;
+ $config = $this->config;
+
+ $messenger = new \messenger(false);
+ $messenger->template('installed', $this->install_config->get('user_language', 'en'));
+ $messenger->to($this->config['board_email'], $this->install_config->get('admin_name'));
+ $messenger->anti_abuse_headers($this->config, $this->user);
+ $messenger->assign_vars(array(
+ 'USERNAME' => htmlspecialchars_decode($this->install_config->get('admin_name')),
+ 'PASSWORD' => htmlspecialchars_decode($this->install_config->get('admin_passwd')))
+ );
+ $messenger->send(NOTIFY_EMAIL);
+ }
+
+ // Login admin
+ // Ugly but works
+ $this->auth->login(
+ $this->install_config->get('admin_name'),
+ $this->install_config->get('admin_passwd'),
+ false,
+ true,
+ true
+ );
+
+ $this->iohandler->set_cookie($this->config['cookie_name'] . '_sid', $this->user->session_id);
+ $this->iohandler->set_cookie($this->config['cookie_name'] . '_u', $this->user->cookie_data['u']);
+ $this->iohandler->set_cookie($this->config['cookie_name'] . '_k', $this->user->cookie_data['k']);
+
+ // Create log
+ $this->log->add(
+ 'admin',
+ $this->user->data['user_id'],
+ $this->user->ip,
+ 'LOG_INSTALL_INSTALLED',
+ false,
+ array($this->config['version'])
+ );
+
+ // Remove install_lock
+ @unlink($this->phpbb_root_path . 'cache/install_lock');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_NOTIFY_USER';
+ }
+}
diff --git a/phpBB/phpbb/install/module/install_finish/task/populate_migrations.php b/phpBB/phpbb/install/module/install_finish/task/populate_migrations.php
new file mode 100644
index 0000000000..cebf0f425f
--- /dev/null
+++ b/phpBB/phpbb/install/module/install_finish/task/populate_migrations.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\install_finish\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\container_factory;
+
+/**
+ * Populates migrations
+ */
+class populate_migrations extends \phpbb\install\task_base
+{
+ /**
+ * @var config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\extension\manager
+ */
+ protected $extension_manager;
+
+ /**
+ * @var \phpbb\db\migrator
+ */
+ protected $migrator;
+
+ /**
+ * Constructor
+ *
+ * @param config $config Installer's config
+ * @param container_factory $container phpBB's DI contianer
+ */
+ public function __construct(config $config, container_factory $container)
+ {
+ $this->config = $config;
+ $this->extension_manager = $container->get('ext.manager');
+ $this->migrator = $container->get('migrator');
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ if (!$this->config->get('populate_migration_refresh_before', false))
+ {
+ if ($this->config->get_time_remaining() < 1)
+ {
+ $this->config->set('populate_migration_refresh_before', true);
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ $finder = $this->extension_manager->get_finder();
+
+ $migrations = $finder
+ ->core_path('phpbb/db/migration/data/')
+ ->set_extensions(array())
+ ->get_classes();
+ $this->migrator->populate_migrations($migrations);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_POPULATE_MIGRATIONS';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/install_module.php b/phpBB/phpbb/install/module/obtain_data/install_module.php
new file mode 100644
index 0000000000..deb4be90d8
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/install_module.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data;
+
+class install_module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('install', 0, 'obtain_data');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_step_count()
+ {
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php
new file mode 100644
index 0000000000..d1f1af6b83
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_admin_data.php
@@ -0,0 +1,218 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+
+/**
+ * This class requests and validates admin account data from the user
+ */
+class obtain_admin_data extends \phpbb\install\task_base implements \phpbb\install\task_interface
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $io_handler;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $install_config Installer's config helper
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ */
+ public function __construct(\phpbb\install\helper\config $install_config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler)
+ {
+ $this->install_config = $install_config;
+ $this->io_handler = $iohandler;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Check if data is sent
+ if ($this->io_handler->get_input('submit_admin', false))
+ {
+ $this->process_form();
+ }
+ else
+ {
+ $this->request_form_data();
+ }
+ }
+
+ /**
+ * Process form data
+ */
+ protected function process_form()
+ {
+ // Admin data
+ $admin_name = $this->io_handler->get_input('admin_name', '', true);
+ $admin_pass1 = $this->io_handler->get_input('admin_pass1', '', true);
+ $admin_pass2 = $this->io_handler->get_input('admin_pass2', '', true);
+ $board_email = $this->io_handler->get_input('board_email', '', true);
+
+ $admin_data_valid = $this->check_admin_data($admin_name, $admin_pass1, $admin_pass2, $board_email);
+
+ if ($admin_data_valid)
+ {
+ $this->install_config->set('admin_name', $admin_name);
+ $this->install_config->set('admin_passwd', $admin_pass1);
+ $this->install_config->set('board_email', $board_email);
+ }
+ else
+ {
+ $this->request_form_data(true);
+ }
+ }
+
+ /**
+ * Request data from the user
+ *
+ * @param bool $use_request_data Whether to use submited data
+ *
+ * @throws \phpbb\install\exception\user_interaction_required_exception When the user is required to provide data
+ */
+ protected function request_form_data($use_request_data = false)
+ {
+ if ($use_request_data)
+ {
+ $admin_username = $this->io_handler->get_input('admin_name', '', true);
+ $admin_email = $this->io_handler->get_input('board_email', '', true);
+ }
+ else
+ {
+ $admin_username = '';
+ $admin_email = '';
+ }
+
+ $admin_form = array(
+ 'admin_name' => array(
+ 'label' => 'ADMIN_USERNAME',
+ 'description' => 'ADMIN_USERNAME_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $admin_username,
+ ),
+ 'board_email' => array(
+ 'label' => 'CONTACT_EMAIL',
+ 'type' => 'email',
+ 'default' => $admin_email,
+ ),
+ 'admin_pass1' => array(
+ 'label' => 'ADMIN_PASSWORD',
+ 'description' => 'ADMIN_PASSWORD_EXPLAIN',
+ 'type' => 'password',
+ ),
+ 'admin_pass2' => array(
+ 'label' => 'ADMIN_PASSWORD_CONFIRM',
+ 'type' => 'password',
+ ),
+ 'submit_admin' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ );
+
+ $this->io_handler->add_user_form_group('ADMIN_CONFIG', $admin_form);
+
+ // Require user interaction
+ throw new user_interaction_required_exception();
+ }
+
+ /**
+ * Check admin data
+ *
+ * @param string $username Admin username
+ * @param string $pass1 Admin password
+ * @param string $pass2 Admin password confirmation
+ * @param string $email Admin e-mail address
+ *
+ * @return bool True if data is valid, false otherwise
+ */
+ protected function check_admin_data($username, $pass1, $pass2, $email)
+ {
+ $data_valid = true;
+
+ // Check if none of admin data is empty
+ if (in_array('', array($username, $pass1, $pass2, $email), true))
+ {
+ $this->io_handler->add_error_message('INST_ERR_MISSING_DATA');
+ $data_valid = false;
+ }
+
+ if (utf8_strlen($username) < 3)
+ {
+ $this->io_handler->add_error_message('INST_ERR_USER_TOO_SHORT');
+ $data_valid = false;
+ }
+
+ if (utf8_strlen($username) > 20)
+ {
+ $this->io_handler->add_error_message('INST_ERR_USER_TOO_LONG');
+ $data_valid = false;
+ }
+
+ if ($pass1 !== $pass2 && $pass1 !== '')
+ {
+ $this->io_handler->add_error_message('INST_ERR_PASSWORD_MISMATCH');
+ $data_valid = false;
+ }
+
+ // Test against the default password rules
+ if (utf8_strlen($pass1) < 6)
+ {
+ $this->io_handler->add_error_message('INST_ERR_PASSWORD_TOO_SHORT');
+ $data_valid = false;
+ }
+
+ if (utf8_strlen($pass1) > 30)
+ {
+ $this->io_handler->add_error_message('INST_ERR_PASSWORD_TOO_LONG');
+ $data_valid = false;
+ }
+
+ if (!preg_match('/^' . get_preg_expression('email') . '$/i', $email))
+ {
+ $this->io_handler->add_error_message('INST_ERR_EMAIL_INVALID');
+ $data_valid = false;
+ }
+
+ return $data_valid;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_board_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_board_data.php
new file mode 100644
index 0000000000..ff2a0a2f86
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_board_data.php
@@ -0,0 +1,185 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+
+/**
+ * This class obtains default data from the user related to board (Board name, Board descritpion, etc...)
+ */
+class obtain_board_data extends \phpbb\install\task_base implements \phpbb\install\task_interface
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $io_handler;
+
+ /**
+ * @var \phpbb\language\language_file_helper
+ */
+ protected $language_helper;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $config Installer's config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ * @param \phpbb\language\language_file_helper $lang_helper Language file helper
+ */
+ public function __construct(\phpbb\install\helper\config $config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler,
+ \phpbb\language\language_file_helper $lang_helper)
+ {
+ $this->install_config = $config;
+ $this->io_handler = $iohandler;
+ $this->language_helper = $lang_helper;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Check if data is sent
+ if ($this->io_handler->get_input('submit_board', false))
+ {
+ $this->process_form();
+ }
+ else
+ {
+ $this->request_form_data();
+ }
+ }
+
+ /**
+ * Process form data
+ */
+ protected function process_form()
+ {
+ // Board data
+ $default_lang = $this->io_handler->get_input('default_lang', '');
+ $board_name = $this->io_handler->get_input('board_name', '', true);
+ $board_desc = $this->io_handler->get_input('board_description', '', true);
+
+ // Check default lang
+ $langs = $this->language_helper->get_available_languages();
+ $lang_valid = false;
+
+ foreach ($langs as $lang)
+ {
+ if ($lang['iso'] === $default_lang)
+ {
+ $lang_valid = true;
+ break;
+ }
+ }
+
+ $this->install_config->set('board_name', $board_name);
+ $this->install_config->set('board_description', $board_desc);
+
+ if ($lang_valid)
+ {
+ $this->install_config->set('default_lang', $default_lang);
+ }
+ else
+ {
+ $this->request_form_data(true);
+ }
+ }
+
+ /**
+ * Request data from the user
+ *
+ * @param bool $use_request_data Whether to use submited data
+ *
+ * @throws \phpbb\install\exception\user_interaction_required_exception When the user is required to provide data
+ */
+ protected function request_form_data($use_request_data = false)
+ {
+ if ($use_request_data)
+ {
+ $board_name = $this->io_handler->get_input('board_name', '', true);
+ $board_desc = $this->io_handler->get_input('board_description', '', true);
+ }
+ else
+ {
+ $board_name = '{L_CONFIG_SITENAME}';
+ $board_desc = '{L_CONFIG_SITE_DESC}';
+ }
+
+ // Use language because we only check this to be valid
+ $default_lang = $this->install_config->get('user_language', 'en');
+
+ $langs = $this->language_helper->get_available_languages();
+ $lang_options = array();
+
+ foreach ($langs as $lang)
+ {
+ $lang_options[] = array(
+ 'value' => $lang['iso'],
+ 'label' => $lang['local_name'],
+ 'selected' => ($default_lang === $lang['iso']),
+ );
+ }
+
+ $board_form = array(
+ 'default_lang' => array(
+ 'label' => 'DEFAULT_LANGUAGE',
+ 'type' => 'select',
+ 'options' => $lang_options,
+ ),
+ 'board_name' => array(
+ 'label' => 'BOARD_NAME',
+ 'type' => 'text',
+ 'default' => $board_name,
+ ),
+ 'board_description' => array(
+ 'label' => 'BOARD_DESCRIPTION',
+ 'type' => 'text',
+ 'default' => $board_desc,
+ ),
+ 'submit_board' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ );
+
+ $this->io_handler->add_user_form_group('BOARD_CONFIG', $board_form);
+
+ throw new user_interaction_required_exception();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_database_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_database_data.php
new file mode 100644
index 0000000000..6ec1e612b9
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_database_data.php
@@ -0,0 +1,270 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+
+/**
+ * This class requests and validates database information from the user
+ */
+class obtain_database_data extends \phpbb\install\task_base implements \phpbb\install\task_interface
+{
+ /**
+ * @var \phpbb\install\helper\database
+ */
+ protected $database_helper;
+
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $io_handler;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\database $database_helper Installer's database helper
+ * @param \phpbb\install\helper\config $install_config Installer's config helper
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ */
+ public function __construct(\phpbb\install\helper\database $database_helper,
+ \phpbb\install\helper\config $install_config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler)
+ {
+ $this->database_helper = $database_helper;
+ $this->install_config = $install_config;
+ $this->io_handler = $iohandler;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Check if data is sent
+ if ($this->io_handler->get_input('submit_database', false))
+ {
+ $this->process_form();
+ }
+ else
+ {
+ $this->request_form_data();
+ }
+ }
+
+ /**
+ * Process form data
+ */
+ protected function process_form()
+ {
+ // Collect database data
+ $dbms = $this->io_handler->get_input('dbms', '');
+ $dbhost = $this->io_handler->get_input('dbhost', '', true);
+ $dbport = $this->io_handler->get_input('dbport', '');
+ $dbuser = $this->io_handler->get_input('dbuser', '', true);
+ $dbpasswd = $this->io_handler->get_raw_input('dbpasswd', '', true);
+ $dbname = $this->io_handler->get_input('dbname', '', true);
+ $table_prefix = $this->io_handler->get_input('table_prefix', '', true);
+
+ // Check database data
+ $user_data_vaild = $this->check_database_data($dbms, $dbhost, $dbport, $dbuser, $dbpasswd, $dbname, $table_prefix);
+
+ // Save database data if it is correct
+ if ($user_data_vaild)
+ {
+ $this->install_config->set('dbms', $dbms);
+ $this->install_config->set('dbhost', $dbhost);
+ $this->install_config->set('dbport', $dbport);
+ $this->install_config->set('dbuser', $dbuser);
+ $this->install_config->set('dbpasswd', $dbpasswd);
+ $this->install_config->set('dbname', $dbname);
+ $this->install_config->set('table_prefix', $table_prefix);
+ }
+ else
+ {
+ $this->request_form_data(true);
+ }
+ }
+
+ /**
+ * Request data from the user
+ *
+ * @param bool $use_request_data Whether to use submited data
+ *
+ * @throws \phpbb\install\exception\user_interaction_required_exception When the user is required to provide data
+ */
+ protected function request_form_data($use_request_data = false)
+ {
+ if ($use_request_data)
+ {
+ $dbms = $this->io_handler->get_input('dbms', '');
+ $dbhost = $this->io_handler->get_input('dbhost', '', true);
+ $dbport = $this->io_handler->get_input('dbport', '');
+ $dbuser = $this->io_handler->get_input('dbuser', '');
+ $dbname = $this->io_handler->get_input('dbname', '');
+ $table_prefix = $this->io_handler->get_input('table_prefix', 'phpbb_');
+ }
+ else
+ {
+ $dbms = '';
+ $dbhost = '';
+ $dbport = '';
+ $dbuser = '';
+ $dbname = '';
+ $table_prefix = 'phpbb_';
+ }
+
+ $dbms_select = array();
+ foreach ($this->database_helper->get_available_dbms() as $dbms_key => $dbms_array)
+ {
+ $dbms_select[] = array(
+ 'value' => $dbms_key,
+ 'label' => 'DB_OPTION_' . strtoupper($dbms_key),
+ 'selected' => ($dbms_key === $dbms),
+ );
+ }
+
+ $database_form = array(
+ 'dbms' => array(
+ 'label' => 'DBMS',
+ 'type' => 'select',
+ 'options' => $dbms_select,
+ ),
+ 'dbhost' => array(
+ 'label' => 'DB_HOST',
+ 'description' => 'DB_HOST_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $dbhost,
+ ),
+ 'dbport' => array(
+ 'label' => 'DB_PORT',
+ 'description' => 'DB_PORT_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $dbport,
+ ),
+ 'dbuser' => array(
+ 'label' => 'DB_USERNAME',
+ 'type' => 'text',
+ 'default' => $dbuser,
+ ),
+ 'dbpasswd' => array(
+ 'label' => 'DB_PASSWORD',
+ 'type' => 'password',
+ ),
+ 'dbname' => array(
+ 'label' => 'DB_NAME',
+ 'type' => 'text',
+ 'default' => $dbname,
+ ),
+ 'table_prefix' => array(
+ 'label' => 'TABLE_PREFIX',
+ 'description' => 'TABLE_PREFIX_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $table_prefix,
+ ),
+ 'submit_database' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ );
+
+ $this->io_handler->add_user_form_group('DB_CONFIG', $database_form);
+
+ // Require user interaction
+ throw new user_interaction_required_exception();
+ }
+
+ /**
+ * Check database data
+ *
+ * @param string $dbms Selected database type
+ * @param string $dbhost Database host address
+ * @param int $dbport Database port number
+ * @param string $dbuser Database username
+ * @param string $dbpass Database password
+ * @param string $dbname Database name
+ * @param string $table_prefix Database table prefix
+ *
+ * @return bool True if database data is correct, false otherwise
+ */
+ protected function check_database_data($dbms, $dbhost, $dbport, $dbuser, $dbpass, $dbname, $table_prefix)
+ {
+ $available_dbms = $this->database_helper->get_available_dbms();
+ $data_valid = true;
+
+ // Check if PHP has the database extensions for the specified DBMS
+ if (!isset($available_dbms[$dbms]))
+ {
+ $this->io_handler->add_error_message('INST_ERR_NO_DB');
+ $data_valid = false;
+ }
+
+ // Validate table prefix
+ $prefix_valid = $this->database_helper->validate_table_prefix($dbms, $table_prefix);
+ if (is_array($prefix_valid))
+ {
+ foreach ($prefix_valid as $error)
+ {
+ $this->io_handler->add_error_message(
+ $error['title'],
+ (isset($error['description'])) ? $error['description'] : false
+ );
+ }
+
+ $data_valid = false;
+ }
+
+ // Try to connect to database if all provided data is valid
+ if ($data_valid)
+ {
+ $connect_test = $this->database_helper->check_database_connection($dbms, $dbhost, $dbport, $dbuser, $dbpass, $dbname, $table_prefix);
+ if (is_array($connect_test))
+ {
+ foreach ($connect_test as $error)
+ {
+ $this->io_handler->add_error_message(
+ $error['title'],
+ (isset($error['description'])) ? $error['description'] : false
+ );
+ }
+
+ $data_valid = false;
+ }
+ }
+
+ return $data_valid;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php
new file mode 100644
index 0000000000..7cd0d7bf23
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_email_data.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+
+class obtain_email_data extends \phpbb\install\task_base implements \phpbb\install\task_interface
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $io_handler;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $config Installer's config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ */
+ public function __construct(\phpbb\install\helper\config $config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler)
+ {
+ $this->install_config = $config;
+ $this->io_handler = $iohandler;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // E-mail data
+ $email_enable = $this->io_handler->get_input('email_enable', true);
+ $smtp_delivery = $this->io_handler->get_input('smtp_delivery', '');
+ $smtp_host = $this->io_handler->get_input('smtp_host', '', true);
+ $smtp_port = $this->io_handler->get_input('smtp_port', '');
+ $smtp_auth = $this->io_handler->get_input('smtp_auth', '');
+ $smtp_user = $this->io_handler->get_input('smtp_user', '', true);
+ $smtp_passwd = $this->io_handler->get_input('smtp_pass', '', true);
+
+ $auth_methods = array('PLAIN', 'LOGIN', 'CRAM-MD5', 'DIGEST-MD5', 'POP-BEFORE-SMTP');
+
+ // Check if data is sent
+ if ($this->io_handler->get_input('submit_email', false))
+ {
+ $this->install_config->set('email_enable', $email_enable);
+ $this->install_config->set('smtp_delivery', $smtp_delivery);
+ $this->install_config->set('smtp_host', $smtp_host);
+ $this->install_config->set('smtp_port', $smtp_port);
+ $this->install_config->set('smtp_auth', $smtp_auth);
+ $this->install_config->set('smtp_user', $smtp_user);
+ $this->install_config->set('smtp_pass', $smtp_passwd);
+ }
+ else
+ {
+ $auth_options = array();
+ foreach ($auth_methods as $method)
+ {
+ $auth_options[] = array(
+ 'value' => $method,
+ 'label' => 'SMTP_' . str_replace('-', '_', $method),
+ 'selected' => false,
+ );
+ }
+
+ $email_form = array(
+ 'email_enable' => array(
+ 'label' => 'ENABLE_EMAIL',
+ 'description' => 'ENABLE_EMAIL_EXPLAIN',
+ 'type' => 'radio',
+ 'options' => array(
+ array(
+ 'value' => 1,
+ 'label' => 'ENABLE',
+ 'selected' => true,
+ ),
+ array(
+ 'value' => 0,
+ 'label' => 'DISABLE',
+ 'selected' => false,
+ ),
+ ),
+ ),
+ 'smtp_delivery' => array(
+ 'label' => 'USE_SMTP',
+ 'description' => 'USE_SMTP_EXPLAIN',
+ 'type' => 'radio',
+ 'options' => array(
+ array(
+ 'value' => 0,
+ 'label' => 'NO',
+ 'selected' => true,
+ ),
+ array(
+ 'value' => 1,
+ 'label' => 'YES',
+ 'selected' => false,
+ ),
+ ),
+ ),
+ 'smtp_host' => array(
+ 'label' => 'SMTP_SERVER',
+ 'type' => 'text',
+ 'default' => $smtp_host,
+ ),
+ 'smtp_port' => array(
+ 'label' => 'SMTP_PORT',
+ 'type' => 'text',
+ 'default' => $smtp_port,
+ ),
+ 'smtp_auth' => array(
+ 'label' => 'SMTP_AUTH_METHOD',
+ 'description' => 'SMTP_AUTH_METHOD_EXPLAIN',
+ 'type' => 'select',
+ 'options' => $auth_options,
+ ),
+ 'smtp_user' => array(
+ 'label' => 'SMTP_USERNAME',
+ 'description' => 'SMTP_USERNAME_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $smtp_user,
+ ),
+ 'smtp_pass' => array(
+ 'label' => 'SMTP_PASSWORD',
+ 'description' => 'SMTP_PASSWORD_EXPLAIN',
+ 'type' => 'password',
+ ),
+ 'submit_email' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ );
+
+ $this->io_handler->add_user_form_group('EMAIL_CONFIG', $email_form);
+
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_file_updater_method.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_file_updater_method.php
new file mode 100644
index 0000000000..d5a8855c37
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_file_updater_method.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\task_base;
+
+class obtain_file_updater_method extends task_base
+{
+ /**
+ * @var array Supported compression methods
+ *
+ * Note: .tar is assumed to be supported, but not in the list
+ */
+ protected $available_methods;
+
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $installer_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * Constructor
+ *
+ * @param config $installer_config
+ * @param iohandler_interface $iohandler
+ */
+ public function __construct(config $installer_config, iohandler_interface $iohandler)
+ {
+ $this->installer_config = $installer_config;
+ $this->iohandler = $iohandler;
+
+ $this->available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ return $this->installer_config->get('do_update_files', false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Check if data is sent
+ if ($this->iohandler->get_input('submit_update_file', false))
+ {
+ $supported_methods = array('compression', 'ftp', 'direct_file');
+ $method = $this->iohandler->get_input('method', 'compression');
+ $update_method = (in_array($method, $supported_methods, true)) ? $method : 'compression';
+ $this->installer_config->set('file_update_method', $update_method);
+
+ $compression = $this->iohandler->get_input('compression_method', '.zip');
+ $supported_methods = array_keys($this->available_methods);
+ $supported_methods[] = '.tar';
+ $compression = (in_array($compression, $supported_methods, true)) ? $compression : '.zip';
+ $this->installer_config->set('file_update_compression', $compression);
+ }
+ else
+ {
+ $this->iohandler->add_user_form_group('UPDATE_FILE_METHOD_TITLE', array(
+ 'method' => array(
+ 'label' => 'UPDATE_FILE_METHOD',
+ 'type' => 'select',
+ 'options' => array(
+ array(
+ 'value' => 'compression',
+ 'label' => 'UPDATE_FILE_METHOD_DOWNLOAD',
+ 'selected' => true,
+ ),
+ array(
+ 'value' => 'ftp',
+ 'label' => 'UPDATE_FILE_METHOD_FTP',
+ 'selected' => false,
+ ),
+ array(
+ 'value' => 'direct_file',
+ 'label' => 'UPDATE_FILE_METHOD_FILESYSTEM',
+ 'selected' => false,
+ ),
+ ),
+ ),
+ 'compression_method' => array(
+ 'label' => 'SELECT_DOWNLOAD_FORMAT',
+ 'type' => 'select',
+ 'options' => $this->get_available_compression_methods(),
+ ),
+ 'submit_update_file' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ ));
+
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ /**
+ * Returns form elements in an array of available compression methods
+ *
+ * @return array
+ */
+ protected function get_available_compression_methods()
+ {
+ $methods[] = array(
+ 'value' => '.tar',
+ 'label' => '.tar',
+ 'selected' => true,
+ );
+
+ foreach ($this->available_methods as $type => $module)
+ {
+ if (!@extension_loaded($module))
+ {
+ continue;
+ }
+
+ $methods[] = array(
+ 'value' => $type,
+ 'label' => $type,
+ 'selected' => false,
+ );
+ }
+
+ return $methods;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_server_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_server_data.php
new file mode 100644
index 0000000000..5096ce284e
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_server_data.php
@@ -0,0 +1,202 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+
+/**
+ * This class requests and saves some information about the server
+ */
+class obtain_server_data extends \phpbb\install\task_base implements \phpbb\install\task_interface
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $install_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $io_handler;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\config $config Installer's config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler Installer's input-output handler
+ */
+ public function __construct(\phpbb\install\helper\config $config,
+ \phpbb\install\helper\iohandler\iohandler_interface $iohandler)
+ {
+ $this->install_config = $config;
+ $this->io_handler = $iohandler;
+
+ parent::__construct(true);
+ }
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $cookie_secure = $this->io_handler->is_secure();
+ $server_protocol = ($this->io_handler->is_secure()) ? 'https://' : 'http://';
+ $server_port = $this->io_handler->get_server_variable('SERVER_PORT', 0);
+
+ // HTTP_HOST is having the correct browser url in most cases...
+ $server_name = strtolower(htmlspecialchars_decode($this->io_handler->get_header_variable(
+ 'Host',
+ $this->io_handler->get_server_variable('SERVER_NAME')
+ )));
+
+ // HTTP HOST can carry a port number...
+ if (strpos($server_name, ':') !== false)
+ {
+ $server_name = substr($server_name, 0, strpos($server_name, ':'));
+ }
+
+ $script_path = htmlspecialchars_decode($this->io_handler->get_server_variable('PHP_SELF'));
+
+ if (!$script_path)
+ {
+ $script_path = htmlspecialchars_decode($this->io_handler->get_server_variable('REQUEST_URI'));
+ }
+
+ $script_path = str_replace(array('\\', '//'), '/', $script_path);
+ $script_path = trim(dirname(dirname(dirname($script_path)))); // Because we are in install/app.php/route_name
+
+ // Server data
+ $cookie_secure = $this->io_handler->get_input('cookie_secure', $cookie_secure);
+ $server_protocol = $this->io_handler->get_input('server_protocol', $server_protocol);
+ $force_server_vars = $this->io_handler->get_input('force_server_vars', 0);
+ $server_name = $this->io_handler->get_input('server_name', $server_name, true);
+ $server_port = $this->io_handler->get_input('server_port', $server_port);
+ $script_path = $this->io_handler->get_input('script_path', $script_path, true);
+
+ // Clean up script path
+ if ($script_path !== '/')
+ {
+ // Adjust destination path (no trailing slash)
+ if (substr($script_path, -1) === '/')
+ {
+ $script_path = substr($script_path, 0, -1);
+ }
+
+ $script_path = str_replace(array('../', './'), '', $script_path);
+
+ if ($script_path[0] !== '/')
+ {
+ $script_path = '/' . $script_path;
+ }
+ }
+
+ // Check if data is sent
+ if ($this->io_handler->get_input('submit_server', false))
+ {
+ $this->install_config->set('cookie_secure', $cookie_secure);
+ $this->install_config->set('server_protocol', $server_protocol);
+ $this->install_config->set('force_server_vars', $force_server_vars);
+ $this->install_config->set('server_name', $server_name);
+ $this->install_config->set('server_port', $server_port);
+ $this->install_config->set('script_path', $script_path);
+ }
+ else
+ {
+ // Render form
+ $server_form = array(
+ 'cookie_secure' => array(
+ 'label' => 'COOKIE_SECURE',
+ 'description' => 'COOKIE_SECURE_EXPLAIN',
+ 'type' => 'radio',
+ 'options' => array(
+ array(
+ 'value' => 0,
+ 'label' => 'NO',
+ 'selected' => (!$cookie_secure),
+ ),
+ array(
+ 'value' => 1,
+ 'label' => 'YES',
+ 'selected' => ($cookie_secure),
+ ),
+ ),
+ ),
+ 'force_server_vars' => array(
+ 'label' => 'FORCE_SERVER_VARS',
+ 'description' => 'FORCE_SERVER_VARS_EXPLAIN',
+ 'type' => 'radio',
+ 'options' => array(
+ array(
+ 'value' => 0,
+ 'label' => 'NO',
+ 'selected' => true,
+ ),
+ array(
+ 'value' => 1,
+ 'label' => 'YES',
+ 'selected' => false,
+ ),
+ ),
+ ),
+ 'server_protocol' => array(
+ 'label' => 'SERVER_PROTOCOL',
+ 'description' => 'SERVER_PROTOCOL_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $server_protocol,
+ ),
+ 'server_name' => array(
+ 'label' => 'SERVER_NAME',
+ 'description' => 'SERVER_NAME_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $server_name,
+ ),
+ 'server_port' => array(
+ 'label' => 'SERVER_PORT',
+ 'description' => 'SERVER_PORT_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $server_port,
+ ),
+ 'script_path' => array(
+ 'label' => 'SCRIPT_PATH',
+ 'description' => 'SCRIPT_PATH_EXPLAIN',
+ 'type' => 'text',
+ 'default' => $script_path,
+ ),
+ 'submit_server' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ )
+ );
+
+ $this->io_handler->add_user_form_group('SERVER_CONFIG', $server_form);
+
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_update_files.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_files.php
new file mode 100644
index 0000000000..0cb809154e
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_files.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\task_base;
+
+class obtain_update_files extends task_base
+{
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(config $config, iohandler_interface $iohandler, $phpbb_root_path, $php_ext)
+ {
+ $this->installer_config = $config;
+ $this->iohandler = $iohandler;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ return $this->installer_config->get('do_update_files', false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Load update info file
+ // The file should be checked in the requirements, so we assume that it exists
+ $update_info_file = $this->phpbb_root_path . 'install/update/index.' . $this->php_ext;
+ include($update_info_file);
+ $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
+
+ // If the file is invalid, abort mission
+ if (!$info)
+ {
+ $this->iohandler->add_error_message('WRONG_INFO_FILE_FORMAT');
+ throw new user_interaction_required_exception();
+ }
+
+ // Replace .php with $this->php_ext if needed
+ if ($this->php_ext !== 'php')
+ {
+ $custom_extension = '.' . $this->php_ext;
+ $info['files'] = preg_replace('#\.php$#i', $custom_extension, $info['files']);
+ }
+
+ // Save update info
+ $this->installer_config->set('update_info_unprocessed', $info);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_update_ftp_data.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_ftp_data.php
new file mode 100644
index 0000000000..3c17576c13
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_ftp_data.php
@@ -0,0 +1,163 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\helper\update_helper;
+use phpbb\install\task_base;
+
+class obtain_update_ftp_data extends task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $installer_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param config $installer_config
+ * @param iohandler_interface $iohandler
+ * @param update_helper $update_helper
+ * @param string $php_ext
+ */
+ public function __construct(config $installer_config, iohandler_interface $iohandler, update_helper $update_helper, $php_ext)
+ {
+ $this->installer_config = $installer_config;
+ $this->iohandler = $iohandler;
+ $this->update_helper = $update_helper;
+ $this->php_ext = $php_ext;
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ return ($this->installer_config->get('do_update_files', false) &&
+ ($this->installer_config->get('file_update_method', '') === 'ftp')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ if ($this->iohandler->get_input('submit_ftp', false))
+ {
+ $this->update_helper->include_file('includes/functions_transfer.' . $this->php_ext);
+
+ $method = 'ftp';
+ $methods = \transfer::methods();
+ if (!in_array($method, $methods, true))
+ {
+ $method = $methods[0];
+ }
+
+ $ftp_host = $this->iohandler->get_input('ftp_host', '', true);
+ $ftp_user = $this->iohandler->get_input('ftp_user', '', true);
+ $ftp_pass = htmlspecialchars_decode($this->iohandler->get_input('ftp_pass', '', true));
+ $ftp_path = $this->iohandler->get_input('ftp_path', '', true);
+ $ftp_port = $this->iohandler->get_input('ftp_port', 21);
+ $ftp_time = $this->iohandler->get_input('ftp_timeout', 10);
+
+ $this->installer_config->set('ftp_host', $ftp_host);
+ $this->installer_config->set('ftp_user', $ftp_user);
+ $this->installer_config->set('ftp_pass', $ftp_pass);
+ $this->installer_config->set('ftp_path', $ftp_path);
+ $this->installer_config->set('ftp_port', (int) $ftp_port);
+ $this->installer_config->set('ftp_timeout', (int) $ftp_time);
+ $this->installer_config->set('ftp_method', $method);
+ }
+ else
+ {
+ $this->iohandler->add_user_form_group('FTP_SETTINGS', array(
+ 'ftp_host' => array(
+ 'label' => 'FTP_HOST',
+ 'description' => 'FTP_HOST_EXPLAIN',
+ 'type' => 'text',
+ ),
+ 'ftp_user' => array(
+ 'label' => 'FTP_USERNAME',
+ 'description' => 'FTP_USERNAME_EXPLAIN',
+ 'type' => 'text',
+ ),
+ 'ftp_pass' => array(
+ 'label' => 'FTP_PASSWORD',
+ 'description' => 'FTP_PASSWORD_EXPLAIN',
+ 'type' => 'password',
+ ),
+ 'ftp_path' => array(
+ 'label' => 'FTP_ROOT_PATH',
+ 'description' => 'FTP_ROOT_PATH_EXPLAIN',
+ 'type' => 'text',
+ ),
+ 'ftp_port' => array(
+ 'label' => 'FTP_PORT',
+ 'description' => 'FTP_PORT_EXPLAIN',
+ 'type' => 'text',
+ 'default' => 21,
+ ),
+ 'ftp_timeout' => array(
+ 'label' => 'FTP_TIMEOUT',
+ 'description' => 'FTP_TIMEOUT_EXPLAIN',
+ 'type' => 'text',
+ 'default' => 10,
+ ),
+ 'submit_ftp' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ ));
+
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/task/obtain_update_settings.php b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_settings.php
new file mode 100644
index 0000000000..3b24e8ba40
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/task/obtain_update_settings.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data\task;
+
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\task_base;
+
+class obtain_update_settings extends task_base
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $installer_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * Constructor
+ *
+ * @param config $installer_config
+ * @param iohandler_interface $iohandler
+ */
+ public function __construct(config $installer_config, iohandler_interface $iohandler)
+ {
+ $this->installer_config = $installer_config;
+ $this->iohandler = $iohandler;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Check if data is sent
+ if ($this->iohandler->get_input('submit_update', false))
+ {
+ $update_files = $this->iohandler->get_input('update_type', 'all') === 'all';
+
+ if ($this->installer_config->get('disable_filesystem_update', false) && $update_files)
+ {
+ $this->iohandler->add_error_message('UPDATE_FILES_NOT_FOUND');
+
+ throw new user_interaction_required_exception();
+ }
+
+ $this->installer_config->set('do_update_files', $update_files);
+ }
+ else
+ {
+ if ($this->installer_config->get('disable_filesystem_update', false))
+ {
+ $options[] = array(
+ 'value' => 'db_only',
+ 'label' => 'UPDATE_TYPE_DB_ONLY',
+ 'selected' => true,
+ );
+ }
+ else
+ {
+ $options = array(
+ array(
+ 'value' => 'all',
+ 'label' => 'UPDATE_TYPE_ALL',
+ 'selected' => true,
+ ),
+ array(
+ 'value' => 'db_only',
+ 'label' => 'UPDATE_TYPE_DB_ONLY',
+ 'selected' => false,
+ ),
+ );
+ }
+
+ $this->iohandler->add_user_form_group('UPDATE_TYPE', array(
+ 'update_type' => array(
+ 'label' => 'UPDATE_TYPE',
+ 'type' => 'radio',
+ 'options' => $options,
+ ),
+ 'submit_update' => array(
+ 'label' => 'SUBMIT',
+ 'type' => 'submit',
+ ),
+ ));
+
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/obtain_data/update_module.php b/phpBB/phpbb/install/module/obtain_data/update_module.php
new file mode 100644
index 0000000000..c2f9019d34
--- /dev/null
+++ b/phpBB/phpbb/install/module/obtain_data/update_module.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\obtain_data;
+
+class update_module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('update', 0, 'obtain_data');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_step_count()
+ {
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/install/module/requirements/abstract_requirements_module.php b/phpBB/phpbb/install/module/requirements/abstract_requirements_module.php
new file mode 100644
index 0000000000..121b4ff4e5
--- /dev/null
+++ b/phpBB/phpbb/install/module/requirements/abstract_requirements_module.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\requirements;
+
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\module_base;
+
+/**
+ * Base class for requirements installer module
+ */
+abstract class abstract_requirements_module extends module_base
+{
+ public function run()
+ {
+ $tests_passed = true;
+ foreach ($this->task_collection as $name => $task)
+ {
+ // Check if we can run the task
+ if (!$task->is_essential() && !$task->check_requirements())
+ {
+ continue;
+ }
+
+ if ($this->allow_progress_bar)
+ {
+ $this->install_config->increment_current_task_progress();
+ }
+
+ $test_result = $task->run();
+ $tests_passed = ($tests_passed) ? $test_result : false;
+ }
+
+ // Module finished, so clear task progress
+ $this->install_config->set_finished_task(0);
+
+ // Check if tests have failed
+ if (!$tests_passed)
+ {
+ // If requirements are not met, exit form installer
+ // Set up UI for retesting
+ $this->iohandler->add_user_form_group('', array(
+ 'install' => array(
+ 'label' => 'RETEST_REQUIREMENTS',
+ 'type' => 'submit',
+ ),
+ ));
+
+ // Send the response and quit
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_step_count()
+ {
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/install/module/requirements/install_module.php b/phpBB/phpbb/install/module/requirements/install_module.php
new file mode 100644
index 0000000000..ed0c5fbd94
--- /dev/null
+++ b/phpBB/phpbb/install/module/requirements/install_module.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\requirements;
+
+class install_module extends abstract_requirements_module
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('install', 0, 'requirements');
+ }
+}
diff --git a/phpBB/phpbb/install/module/requirements/task/check_filesystem.php b/phpBB/phpbb/install/module/requirements/task/check_filesystem.php
new file mode 100644
index 0000000000..868af39433
--- /dev/null
+++ b/phpBB/phpbb/install/module/requirements/task/check_filesystem.php
@@ -0,0 +1,279 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\requirements\task;
+
+/**
+ * Checks filesystem requirements
+ */
+class check_filesystem extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * @var array
+ */
+ protected $files_to_check;
+
+ /**
+ * @var bool
+ */
+ protected $tests_passed;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $response;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\filesystem\filesystem_interface $filesystem filesystem handler
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $response response helper
+ * @param string $phpbb_root_path relative path to phpBB's root
+ * @param string $php_ext extension of php files
+ * @param bool $check_config_php Whether or not to check if config.php is writable
+ */
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, \phpbb\install\helper\iohandler\iohandler_interface $response, $phpbb_root_path, $php_ext, $check_config_php = true)
+ {
+ parent::__construct(true);
+
+ $this->filesystem = $filesystem;
+ $this->response = $response;
+ $this->phpbb_root_path = $phpbb_root_path;
+
+ $this->tests_passed = false;
+
+ // Files/Directories to check
+ // All file/directory names must be relative to phpBB's root path
+ $this->files_to_check = array(
+ array(
+ 'path' => 'cache/',
+ 'failable' => false,
+ 'is_file' => false,
+ ),
+ array(
+ 'path' => 'store/',
+ 'failable' => false,
+ 'is_file' => false,
+ ),
+ array(
+ 'path' => 'files/',
+ 'failable' => false,
+ 'is_file' => false,
+ ),
+ array(
+ 'path' => 'images/avatars/upload/',
+ 'failable' => true,
+ 'is_file' => false,
+ ),
+ );
+
+ if ($check_config_php)
+ {
+ $this->files_to_check[] = array(
+ 'path' => "config.$php_ext",
+ 'failable' => false,
+ 'is_file' => true,
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->tests_passed = true;
+
+ // Check files/directories to be writable
+ foreach ($this->files_to_check as $file)
+ {
+ if ($file['is_file'])
+ {
+ $this->check_file($file['path'], $file['failable']);
+ }
+ else
+ {
+ $this->check_dir($file['path'], $file['failable']);
+ }
+ }
+
+ return $this->tests_passed;
+ }
+
+ /**
+ * Sets $this->tests_passed
+ *
+ * @param bool $is_passed
+ */
+ protected function set_test_passed($is_passed)
+ {
+ // If one test failed, tests_passed should be false
+ $this->tests_passed = (!$this->tests_passed) ? false : $is_passed;
+ }
+
+ /**
+ * Check if a file is readable and writable
+ *
+ * @param string $file Filename
+ * @param bool $failable Whether failing test should interrupt installation process
+ */
+ protected function check_file($file, $failable = false)
+ {
+ $path = $this->phpbb_root_path . $file;
+ $exists = $writable = true;
+
+ // Try to create file if it does not exists
+ if (!file_exists($path))
+ {
+ $fp = @fopen($path, 'w');
+ @fclose($fp);
+ try
+ {
+ $this->filesystem->phpbb_chmod($path,
+ \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE
+ );
+ $exists = true;
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
+ }
+
+ if (file_exists($path))
+ {
+ if (!$this->filesystem->is_writable($path))
+ {
+ $writable = false;
+ }
+ }
+ else
+ {
+ $exists = $writable = false;
+ }
+
+ $this->set_test_passed(($exists && $writable) || $failable);
+
+ if (!($exists && $writable))
+ {
+ $title = ($exists) ? 'FILE_NOT_WRITABLE' : 'FILE_NOT_EXISTS';
+ $lang_suffix = '_EXPLAIN';
+ $lang_suffix .= ($failable) ? '_OPTIONAL' : '';
+ $description = array($title . $lang_suffix, $file);
+
+ if ($failable)
+ {
+ $this->response->add_warning_message($title, $description);
+ }
+ else
+ {
+ $this->response->add_error_message($title, $description);
+ }
+ }
+ }
+
+ /**
+ * Check if a directory is readable and writable
+ *
+ * @param string $dir Filename
+ * @param bool $failable Whether failing test should abort the installation process
+ */
+ protected function check_dir($dir, $failable = false)
+ {
+ $path = $this->phpbb_root_path . $dir;
+ $exists = $writable = false;
+
+ // Try to create the directory if it does not exist
+ if (!file_exists($path))
+ {
+ try
+ {
+ $this->filesystem->mkdir($path, 0777);
+ $this->filesystem->phpbb_chmod($path,
+ \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE
+ );
+ $exists = true;
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
+ }
+
+ // Now really check
+ if (file_exists($path) && is_dir($path))
+ {
+ try
+ {
+ $exists = true;
+ $this->filesystem->phpbb_chmod($path,
+ \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE
+ );
+ }
+ catch (\phpbb\filesystem\exception\filesystem_exception $e)
+ {
+ // Do nothing
+ }
+ }
+
+ if ($this->filesystem->is_writable($path))
+ {
+ $writable = true;
+ }
+
+ $this->set_test_passed(($exists && $writable) || $failable);
+
+ if (!($exists && $writable))
+ {
+ $title = ($exists) ? 'DIRECTORY_NOT_WRITABLE' : 'DIRECTORY_NOT_EXISTS';
+ $lang_suffix = '_EXPLAIN';
+ $lang_suffix .= ($failable) ? '_OPTIONAL' : '';
+ $description = array($title . $lang_suffix, $dir);
+
+ if ($failable)
+ {
+ $this->response->add_warning_message($title, $description);
+ }
+ else
+ {
+ $this->response->add_error_message($title, $description);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/requirements/task/check_server_environment.php b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php
new file mode 100644
index 0000000000..29f9777747
--- /dev/null
+++ b/phpBB/phpbb/install/module/requirements/task/check_server_environment.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\requirements\task;
+
+/**
+ * Installer task that checks if the server meats phpBB requirements
+ */
+class check_server_environment extends \phpbb\install\task_base
+{
+ /**
+ * @var \phpbb\install\helper\database
+ */
+ protected $database_helper;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $response_helper;
+
+ /**
+ * @var bool
+ */
+ protected $tests_passed;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\database $database_helper
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $response
+ */
+ public function __construct(\phpbb\install\helper\database $database_helper,
+ \phpbb\install\helper\iohandler\iohandler_interface $response)
+ {
+ $this->database_helper = $database_helper;
+ $this->response_helper = $response;
+ $this->tests_passed = true;
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ //
+ // Check requirements
+ // The error messages should be set in the check_ functions
+ //
+
+ // Check PHP version
+ $this->check_php_version();
+
+ // Check for getimagesize()
+ $this->check_image_size();
+
+ // Check for PCRE support
+ $this->check_pcre();
+
+ // Check for JSON support
+ $this->check_json();
+
+ // XML extension support check
+ $this->check_xml();
+
+ // Check for dbms support
+ $this->check_available_dbms();
+
+ return $this->tests_passed;
+ }
+
+ /**
+ * Sets $this->tests_passed
+ *
+ * @param bool $is_passed
+ */
+ protected function set_test_passed($is_passed)
+ {
+ // If one test failed, tests_passed should be false
+ $this->tests_passed = (!$this->tests_passed) ? false : $is_passed;
+ }
+
+ /**
+ * Check if the requirements for PHP version is met
+ */
+ protected function check_php_version()
+ {
+ $php_version = PHP_VERSION;
+
+ if (version_compare($php_version, '5.4') < 0)
+ {
+ $this->response_helper->add_error_message('PHP_VERSION_REQD', 'PHP_VERSION_REQD_EXPLAIN');
+
+ $this->set_test_passed(false);
+ return;
+ }
+
+ $this->set_test_passed(true);
+ }
+
+ /**
+ * Checks if the installed PHP has getimagesize() available
+ */
+ protected function check_image_size()
+ {
+ if (!@function_exists('getimagesize'))
+ {
+ $this->response_helper->add_error_message('PHP_GETIMAGESIZE_SUPPORT', 'PHP_GETIMAGESIZE_SUPPORT_EXPLAIN');
+
+ $this->set_test_passed(false);
+ return;
+ }
+
+ $this->set_test_passed(true);
+ }
+
+ /**
+ * Checks if the installed PHP supports PCRE
+ */
+ protected function check_pcre()
+ {
+ if (@preg_match('//u', ''))
+ {
+ $this->set_test_passed(true);
+ return;
+ }
+
+ $this->response_helper->add_error_message('PCRE_UTF_SUPPORT', 'PCRE_UTF_SUPPORT_EXPLAIN');
+
+ $this->set_test_passed(false);
+ }
+
+ /**
+ * Checks whether PHP's JSON extension is available or not
+ */
+ protected function check_json()
+ {
+ if (@extension_loaded('json'))
+ {
+ $this->set_test_passed(true);
+ return;
+ }
+
+ $this->response_helper->add_error_message('PHP_JSON_SUPPORT', 'PHP_JSON_SUPPORT_EXPLAIN');
+
+ $this->set_test_passed(false);
+ }
+
+ /**
+ * Checks whether or not the XML PHP extension is available (Required by the text formatter)
+ */
+ protected function check_xml()
+ {
+ if (class_exists('DOMDocument'))
+ {
+ $this->set_test_passed(true);
+ return;
+ }
+
+ $this->response_helper->add_error_message('PHP_XML_SUPPORT', 'PHP_XML_SUPPORT_EXPLAIN');
+
+ $this->set_test_passed(false);
+ }
+
+ /**
+ * Check if any supported DBMS is available
+ */
+ protected function check_available_dbms()
+ {
+ $available_dbms = $this->database_helper->get_available_dbms(false, true);
+
+ if ($available_dbms['ANY_DB_SUPPORT'])
+ {
+ $this->set_test_passed(true);
+ return;
+ }
+
+ $this->response_helper->add_error_message('PHP_SUPPORTED_DB', 'PHP_SUPPORTED_DB_EXPLAIN');
+
+ $this->set_test_passed(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/requirements/task/check_update.php b/phpBB/phpbb/install/module/requirements/task/check_update.php
new file mode 100644
index 0000000000..4eb2c6d75e
--- /dev/null
+++ b/phpBB/phpbb/install/module/requirements/task/check_update.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\requirements\task;
+
+use phpbb\filesystem\filesystem;
+use phpbb\install\helper\config;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\helper\update_helper;
+use phpbb\install\task_base;
+
+/**
+ * Check the availability of updater files and update version
+ */
+class check_update extends task_base
+{
+ /**
+ * @var \phpbb\config\db
+ */
+ protected $config;
+
+ /**
+ * @var filesystem
+ */
+ protected $filesystem;
+
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * @var \phpbb\version_helper
+ */
+ protected $version_helper;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * @var bool
+ */
+ protected $tests_passed;
+
+ /**
+ * Constructor
+ *
+ * @param container_factory $container
+ * @param filesystem $filesystem
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ * @param update_helper $update_helper
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(container_factory $container, filesystem $filesystem, config $config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path, $php_ext)
+ {
+ $this->filesystem = $filesystem;
+ $this->installer_config = $config;
+ $this->iohandler = $iohandler;
+ $this->update_helper = $update_helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ $this->tests_passed = true;
+
+ $this->config = $container->get('config');
+ $this->version_helper = $container->get('version_helper');
+
+ parent::__construct(true);
+ }
+
+ /**
+ * Sets $this->tests_passed
+ *
+ * @param bool $is_passed
+ */
+ protected function set_test_passed($is_passed)
+ {
+ // If one test failed, tests_passed should be false
+ $this->tests_passed = $this->tests_passed && $is_passed;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Array of update files
+ $update_files = array(
+ $this->phpbb_root_path . 'install/update',
+ $this->phpbb_root_path . 'install/update/index.' . $this->php_ext,
+ );
+
+ // Check for a valid update directory
+ if (!$this->filesystem->exists($update_files) || !$this->filesystem->is_readable($update_files))
+ {
+ if ($this->iohandler->get_input('update_type', 'all') === 'all')
+ {
+ $this->iohandler->add_warning_message('UPDATE_FILES_NOT_FOUND');
+ $this->set_test_passed(false);
+ }
+
+ // If there are no update files, we can't check the version etc
+ // However, we can let the users run migrations if they really want to...
+ $this->installer_config->set('disable_filesystem_update', true);
+ return true;
+ }
+
+ // Recover version numbers
+ $update_info = array();
+ @include($this->phpbb_root_path . 'install/update/index.' . $this->php_ext);
+ $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info;
+ $update_version = false;
+
+ if ($info !== false)
+ {
+ $update_version = (!empty($info['version']['to'])) ? trim($info['version']['to']) : false;
+ }
+
+ // Get current and latest version
+ try
+ {
+ $latest_version = $this->version_helper->get_latest_on_current_branch(true);
+ }
+ catch (\RuntimeException $e)
+ {
+ $latest_version = $update_version;
+ }
+
+ $current_version = (!empty($this->config['version_update_from'])) ? $this->config['version_update_from'] : $this->config['version'];
+
+ // Check if the update package
+ if (!$this->update_helper->phpbb_version_compare($current_version, $update_version, '<'))
+ {
+ $this->iohandler->add_error_message('NO_UPDATE_FILES_UP_TO_DATE');
+ $this->tests_passed = false;
+ }
+
+ // Check if the update package works with the installed version
+ if (empty($info['version']['from']) || $info['version']['from'] !== $current_version)
+ {
+ $this->iohandler->add_error_message(array('INCOMPATIBLE_UPDATE_FILES', $current_version, $info['version']['from'], $update_version));
+ $this->tests_passed = false;
+ }
+
+ // check if this is the latest update package
+ if ($this->update_helper->phpbb_version_compare($update_version, $latest_version, '<'))
+ {
+ $this->iohandler->add_warning_message(array('OLD_UPDATE_FILES', $info['version']['from'], $update_version, $latest_version));
+ }
+
+ return $this->tests_passed;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/requirements/update_module.php b/phpBB/phpbb/install/module/requirements/update_module.php
new file mode 100644
index 0000000000..223d12faf3
--- /dev/null
+++ b/phpBB/phpbb/install/module/requirements/update_module.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\requirements;
+
+class update_module extends abstract_requirements_module
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('update', 0, 'requirements');
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_database/module.php b/phpBB/phpbb/install/module/update_database/module.php
new file mode 100644
index 0000000000..ee38afe17d
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_database/module.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_database;
+
+class module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('update', 0, 'update_database');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_step_count()
+ {
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_database/task/update.php b/phpBB/phpbb/install/module/update_database/task/update.php
new file mode 100644
index 0000000000..fb9eb44e6a
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_database/task/update.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_database\task;
+
+use phpbb\db\migration\exception;
+use phpbb\db\output_handler\installer_migrator_output_handler;
+use phpbb\db\output_handler\log_wrapper_migrator_output_handler;
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\task_base;
+
+/**
+ * Database updater task
+ */
+class update extends task_base
+{
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\extension\manager
+ */
+ protected $extension_manager;
+
+ /**
+ * @var \phpbb\filesystem\filesystem
+ */
+ protected $filesystem;
+
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ protected $installer_config;
+
+ /**
+ * @var \phpbb\install\helper\iohandler\iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
+ /**
+ * @var \phpbb\log\log
+ */
+ protected $log;
+
+ /**
+ * @var \phpbb\db\migrator
+ */
+ protected $migrator;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\install\helper\container_factory $container
+ * @param \phpbb\filesystem\filesystem $filesystem
+ * @param \phpbb\install\helper\config $installer_config
+ * @param \phpbb\install\helper\iohandler\iohandler_interface $iohandler
+ * @param \phpbb\language\language $language
+ * @param string $phpbb_root_path
+ */
+ public function __construct(\phpbb\install\helper\container_factory $container, \phpbb\filesystem\filesystem $filesystem, \phpbb\install\helper\config $installer_config, \phpbb\install\helper\iohandler\iohandler_interface $iohandler, \phpbb\language\language $language, $phpbb_root_path)
+ {
+ $this->filesystem = $filesystem;
+ $this->installer_config = $installer_config;
+ $this->iohandler = $iohandler;
+ $this->language = $language;
+ $this->phpbb_root_path = $phpbb_root_path;
+
+ $this->cache = $container->get('cache.driver');
+ $this->config = $container->get('config');
+ $this->extension_manager = $container->get('ext.manager');
+ $this->log = $container->get('log');
+ $this->migrator = $container->get('migrator');
+ $this->user = $container->get('user');
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->language->add_lang('migrator');
+
+ if (!isset($this->config['version_update_from']))
+ {
+ $this->config->set('version_update_from', $this->config['version']);
+ }
+
+ $original_version = $this->config['version_update_from'];
+
+ $this->migrator->set_output_handler(
+ new log_wrapper_migrator_output_handler(
+ $this->language,
+ new installer_migrator_output_handler($this->iohandler),
+ $this->phpbb_root_path . 'store/migrations_' . time() . '.log',
+ $this->filesystem
+ )
+ );
+
+ $this->migrator->create_migrations_table();
+
+ $migrations = $this->extension_manager
+ ->get_finder()
+ ->core_path('phpbb/db/migration/data/')
+ ->extension_directory('/migrations')
+ ->get_classes();
+
+ $this->migrator->set_migrations($migrations);
+
+ $migration_step_count = $this->installer_config->get('database_update_migration_steps', -1);
+ if ($migration_step_count < 0)
+ {
+ $migration_step_count = count($this->migrator->get_installable_migrations()) * 2;
+ $this->installer_config->set('database_update_migration_steps', $migration_step_count);
+ }
+
+ $progress_count = $this->installer_config->get('database_update_count', 0);
+ $restart_progress_bar = ($progress_count === 0); // Only "restart" when the update runs for the first time
+ $this->iohandler->set_task_count($migration_step_count, $restart_progress_bar);
+ $this->installer_config->set_task_progress_count($migration_step_count);
+
+ while (!$this->migrator->finished())
+ {
+ try
+ {
+ $this->migrator->update();
+ $progress_count++;
+
+ $last_run_migration = $this->migrator->get_last_run_migration();
+ if (isset($last_run_migration['effectively_installed']) && $last_run_migration['effectively_installed'])
+ {
+ // We skipped two step, so increment $progress_count by another one
+ $progress_count++;
+ }
+ else if (($last_run_migration['task'] === 'process_schema_step' && !$last_run_migration['state']['migration_schema_done']) ||
+ ($last_run_migration['task'] === 'process_data_step' && !$last_run_migration['state']['migration_data_done']))
+ {
+ // We just run a step that wasn't counted yet so make it count
+ $migration_step_count++;
+ }
+
+ $this->iohandler->set_task_count($migration_step_count);
+ $this->installer_config->set_task_progress_count($migration_step_count);
+ $this->iohandler->set_progress('STAGE_UPDATE_DATABASE', $progress_count);
+ }
+ catch (exception $e)
+ {
+ $msg = $e->getParameters();
+ array_unshift($msg, $e->getMessage());
+
+ $this->iohandler->add_error_message($msg);
+ throw new user_interaction_required_exception();
+ }
+
+ if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0)
+ {
+ $this->installer_config->set('database_update_count', $progress_count);
+ $this->installer_config->set('database_update_migration_steps', $migration_step_count);
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ if ($original_version !== $this->config['version'])
+ {
+ $this->log->add(
+ 'admin',
+ (isset($this->user->data['user_id'])) ? $this->user->data['user_id'] : ANONYMOUS,
+ $this->user->ip,
+ 'LOG_UPDATE_DATABASE',
+ false,
+ array(
+ $original_version,
+ $this->config['version']
+ )
+ );
+ }
+
+ $this->iohandler->add_success_message('INLINE_UPDATE_SUCCESSFUL');
+
+ $this->cache->purge();
+
+ $this->config->increment('assets_version', 1);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_database/task/update_extensions.php b/phpBB/phpbb/install/module/update_database/task/update_extensions.php
new file mode 100644
index 0000000000..0195b9c661
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_database/task/update_extensions.php
@@ -0,0 +1,263 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_database\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\helper\update_helper;
+use phpbb\install\task_base;
+use Symfony\Component\Finder\Finder;
+
+/**
+ * Installs extensions that exist in ext folder upon install
+ */
+class update_extensions extends task_base
+{
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var config
+ */
+ protected $install_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /** @var update_helper */
+ protected $update_helper;
+
+ /**
+ * @var \phpbb\config\db
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\log\log_interface
+ */
+ protected $log;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /** @var \phpbb\extension\manager */
+ protected $extension_manager;
+
+ /** @var Finder */
+ protected $finder;
+
+ /** @var string Extension table */
+ protected $extension_table;
+
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ /**
+ * @var array List of default extensions to update, grouped by version
+ * they were added
+ */
+ static public $default_extensions_update = [
+ '3.2.0-RC2' => ['phpbb/viglink']
+ ];
+
+ /**
+ * Constructor
+ *
+ * @param container_factory $container
+ * @param config $install_config
+ * @param iohandler_interface $iohandler
+ * @param $update_helper $update_helper
+ * @param string $phpbb_root_path phpBB root path
+ */
+ public function __construct(container_factory $container, config $install_config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path)
+ {
+ $this->install_config = $install_config;
+ $this->iohandler = $iohandler;
+ $this->extension_table = $container->get_parameter('tables.ext');
+
+ $this->log = $container->get('log');
+ $this->user = $container->get('user');
+ $this->extension_manager = $container->get('ext.manager');
+ $this->cache = $container->get('cache.driver');
+ $this->config = $container->get('config');
+ $this->db = $container->get('dbal.conn');
+ $this->update_helper = $update_helper;
+ $this->finder = new Finder();
+ $this->finder->in($phpbb_root_path . 'ext/')
+ ->ignoreUnreadableDirs()
+ ->depth('< 3')
+ ->files()
+ ->name('composer.json');
+
+ // Make sure asset version exists in config. Otherwise we might try to
+ // insert the assets_version setting into the database and cause a
+ // duplicate entry error.
+ if (!isset($this->config['assets_version']))
+ {
+ $this->config['assets_version'] = 0;
+ }
+
+ parent::__construct(true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $this->user->session_begin();
+ $this->user->setup(array('common', 'acp/common', 'cli'));
+
+ $update_info = $this->install_config->get('update_info_unprocessed', []);
+ $version_from = !empty($update_info) ? $update_info['version']['from'] : $this->config['version_update_from'];
+
+ if (!empty($version_from))
+ {
+ $update_extensions = $this->iohandler->get_input('update-extensions', []);
+
+ // Create list of default extensions that need to be enabled in update
+ $default_update_extensions = [];
+ foreach (self::$default_extensions_update as $version => $extensions)
+ {
+ if ($this->update_helper->phpbb_version_compare($version_from, $version, '<'))
+ {
+ $default_update_extensions = array_merge($default_update_extensions, $extensions);
+ }
+ }
+
+ $all_available_extensions = $this->extension_manager->all_available();
+ $i = $this->install_config->get('update_extensions_index', 0);
+ $available_extensions = array_slice($all_available_extensions, $i);
+
+ // Update available extensions
+ foreach ($available_extensions as $ext_name => $ext_path)
+ {
+ // Update extensions if:
+ // 1) Extension is currently enabled
+ // 2) Extension was implicitly defined as needing an update
+ // 3) Extension was newly added as default phpBB extension in
+ // this update and should be enabled by default.
+ if ($this->extension_manager->is_enabled($ext_name) ||
+ in_array($ext_name, $update_extensions) ||
+ in_array($ext_name, $default_update_extensions)
+ )
+ {
+ try
+ {
+ $extension_enabled = $this->extension_manager->is_enabled($ext_name);
+ if ($extension_enabled)
+ {
+ $this->extension_manager->disable($ext_name);
+ }
+ $this->extension_manager->enable($ext_name);
+ $extensions = $this->get_extensions();
+
+ if (isset($extensions[$ext_name]) && $extensions[$ext_name]['ext_active'])
+ {
+ // Create log
+ $this->log->add('admin', ANONYMOUS, '', 'LOG_EXT_UPDATE', time(), array($ext_name));
+ $this->iohandler->add_success_message(array('CLI_EXTENSION_UPDATE_SUCCESS', $ext_name));
+ }
+ else
+ {
+ $this->iohandler->add_log_message('CLI_EXTENSION_UPDATE_FAILURE', array($ext_name));
+ }
+
+ // Disable extensions if it was disabled by the admin before
+ if (!$extension_enabled && !in_array($ext_name, $default_update_extensions))
+ {
+ $this->extension_manager->disable($ext_name);
+ }
+ }
+ catch (\Exception $e)
+ {
+ // Add fail log and continue
+ $this->iohandler->add_log_message('CLI_EXTENSION_UPDATE_FAILURE', array($ext_name));
+ }
+ }
+
+ $i++;
+
+ // Stop execution if resource limit is reached
+ if ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0)
+ {
+ break;
+ }
+ }
+
+ $this->install_config->set('update_extensions_index', $i);
+
+ if ($i < count($all_available_extensions))
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ $this->config->delete('version_update_from');
+
+ $this->cache->purge();
+
+ $this->config->increment('assets_version', 1);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return 'TASK_UPDATE_EXTENSIONS';
+ }
+
+ /**
+ * Get extensions from database
+ *
+ * @return array List of extensions
+ */
+ private function get_extensions()
+ {
+ $sql = 'SELECT *
+ FROM ' . $this->extension_table;
+
+ $result = $this->db->sql_query($sql);
+ $extensions_row = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ $extensions = array();
+
+ foreach ($extensions_row as $extension)
+ {
+ $extensions[$extension['ext_name']] = $extension;
+ }
+
+ ksort($extensions);
+
+ return $extensions;
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_filesystem/module.php b/phpBB/phpbb/install/module/update_filesystem/module.php
new file mode 100644
index 0000000000..157c78a1ac
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_filesystem/module.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_filesystem;
+
+class module extends \phpbb\install\module_base
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_navigation_stage_path()
+ {
+ return array('update', 0, 'update_files');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_step_count()
+ {
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php
new file mode 100644
index 0000000000..2f6048b4fd
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_filesystem/task/diff_files.php
@@ -0,0 +1,253 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_filesystem\task;
+
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\helper\update_helper;
+use phpbb\install\task_base;
+
+/**
+ * Merges user made changes into the files
+ */
+class diff_files extends task_base
+{
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * Constructor
+ *
+ * @param container_factory $container
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ * @param update_helper $update_helper
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(container_factory $container, config $config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path, $php_ext)
+ {
+ $this->installer_config = $config;
+ $this->iohandler = $iohandler;
+ $this->update_helper = $update_helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->cache = $container->get('cache.driver');
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ $files_to_diff = $this->installer_config->get('update_files', array());
+ $files_to_diff = (isset($files_to_diff['update_with_diff'])) ? $files_to_diff['update_with_diff'] : array();
+
+ return $this->installer_config->get('do_update_files', false) && count($files_to_diff) > 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Include diff engine
+ $this->update_helper->include_file('includes/diff/diff.' . $this->php_ext);
+ $this->update_helper->include_file('includes/diff/engine.' . $this->php_ext);
+
+ // Set up basic vars
+ $old_path = $this->update_helper->get_path_to_old_update_files();
+ $new_path = $this->update_helper->get_path_to_new_update_files();
+
+ $update_files = $this->installer_config->get('update_files', array());
+ $files_to_diff = $update_files['update_with_diff'];
+
+ // Set progress bar
+ $this->iohandler->set_task_count(count($files_to_diff), true);
+ $this->iohandler->set_progress('UPDATE_FILE_DIFF', 0);
+ $progress_count = $this->installer_config->get('file_diff_update_count', 0);
+
+ // Recover progress
+ $progress_key = $this->installer_config->get('differ_progress_key', -1);
+ $progress_recovered = ($progress_key === -1);
+ $merge_conflicts = $this->installer_config->get('merge_conflict_list', array());
+
+ foreach ($files_to_diff as $key => $filename)
+ {
+ if ($progress_recovered === false)
+ {
+ if ($progress_key === $key)
+ {
+ $progress_recovered = true;
+ }
+
+ continue;
+ }
+
+ // Read in files' content
+ $file_contents = array();
+
+ // Handle the special case when user created a file with the filename that is now new in the core
+ if (file_exists($old_path . $filename))
+ {
+ $file_contents[0] = file_get_contents($old_path . $filename);
+
+ $filenames = array(
+ $this->phpbb_root_path . $filename,
+ $new_path . $filename
+ );
+
+ foreach ($filenames as $file_to_diff)
+ {
+ $file_contents[] = file_get_contents($file_to_diff);
+
+ if ($file_contents[count($file_contents) - 1] === false)
+ {
+ $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff));
+ unset($file_contents);
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ $diff = new \diff3($file_contents[0], $file_contents[1], $file_contents[2]);
+
+ // Handle conflicts
+ if ($diff->get_num_conflicts() !== 0)
+ {
+ $merge_conflicts[] = $filename;
+ }
+
+ if ($diff->merged_output() !== $file_contents[1])
+ {
+ // Save merged output
+ $this->cache->put(
+ '_file_' . md5($filename),
+ base64_encode(implode("\n", $diff->merged_output()))
+ );
+ }
+ else
+ {
+ unset($update_files['update_with_diff'][$key]);
+ }
+
+ unset($file_contents);
+ unset($diff);
+ }
+ else
+ {
+ $new_file_content = file_get_contents($new_path . $filename);
+
+ if ($new_file_content === false)
+ {
+ $this->iohandler->add_error_message(array('FILE_DIFFER_ERROR_FILE_CANNOT_BE_READ', $files_to_diff));
+ unset($new_file_content );
+ throw new user_interaction_required_exception();
+ }
+
+ // Save new file content to cache
+ $this->cache->put(
+ '_file_' . md5($filename),
+ base64_encode($new_file_content)
+ );
+ unset($new_file_content);
+ }
+
+ $progress_count++;
+ $this->iohandler->set_progress('UPDATE_FILE_DIFF', $progress_count);
+
+ if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0)
+ {
+ // Save differ progress
+ $this->installer_config->set('differ_progress_key', $key);
+ $this->installer_config->set('merge_conflict_list', $merge_conflicts);
+ $this->installer_config->set('file_diff_update_count', $progress_count);
+
+ foreach ($update_files as $type => $files)
+ {
+ if (empty($files))
+ {
+ unset($update_files[$type]);
+ }
+ }
+
+ $this->installer_config->set('update_files', $update_files);
+
+ // Request refresh
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ $this->iohandler->finish_progress('ALL_FILES_DIFFED');
+ $this->installer_config->set('merge_conflict_list', $merge_conflicts);
+
+ foreach ($update_files as $type => $files)
+ {
+ if (empty($files))
+ {
+ unset($update_files[$type]);
+ }
+ }
+
+ $this->installer_config->set('update_files', $update_files);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php b/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php
new file mode 100644
index 0000000000..4d7f0e0cdf
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_filesystem/task/download_updated_files.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_filesystem\task;
+
+use phpbb\filesystem\filesystem;
+use phpbb\install\exception\jump_to_restart_point_exception;
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\task_base;
+
+class download_updated_files extends task_base
+{
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var filesystem
+ */
+ protected $filesystem;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * Constructor
+ *
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ * @param filesystem $filesystem
+ */
+ public function __construct(config $config, iohandler_interface $iohandler, filesystem $filesystem)
+ {
+ $this->installer_config = $config;
+ $this->iohandler = $iohandler;
+ $this->filesystem = $filesystem;
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ return $this->installer_config->get('do_update_files', false)
+ && $this->installer_config->get('file_update_method', '') === 'compression';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ if ($this->iohandler->get_input('database_update_submit', false))
+ {
+ // Remove archive
+ $this->filesystem->remove(
+ $this->installer_config->get('update_file_archive', null)
+ );
+
+ $this->installer_config->set('update_file_archive', null);
+ }
+ else if ($this->iohandler->get_input('update_recheck_files_submit', false))
+ {
+ $this->installer_config->set('file_updater_elem_progress', '');
+ $this->installer_config->set('update_files', array());
+ throw new jump_to_restart_point_exception('check_update_files');
+ }
+ else
+ {
+ $file_update_info = $this->installer_config->get('update_files', array());
+
+ // Display download box only if the archive won't be empty
+ if (!empty($file_update_info) && !(isset($file_update_info['delete']) && count($file_update_info) == 1))
+ {
+ // Render download box
+ $this->iohandler->add_download_link(
+ 'phpbb_installer_update_file_download',
+ 'DOWNLOAD_UPDATE_METHOD',
+ 'DOWNLOAD_UPDATE_METHOD_EXPLAIN'
+ );
+ }
+
+ // Add form to continue update
+ $this->iohandler->add_user_form_group('UPDATE_CONTINUE_UPDATE_PROCESS', array(
+ 'update_recheck_files_submit' => array(
+ 'label' => 'UPDATE_RECHECK_UPDATE_FILES',
+ 'type' => 'submit',
+ 'is_secondary' => empty($file_update_info),
+ ),
+ 'database_update_submit' => array(
+ 'label' => 'UPDATE_CONTINUE_UPDATE_PROCESS',
+ 'type' => 'submit',
+ 'disabled' => !empty($file_update_info),
+ ),
+ ));
+
+ throw new user_interaction_required_exception();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_filesystem/task/file_check.php b/phpBB/phpbb/install/module/update_filesystem/task/file_check.php
new file mode 100644
index 0000000000..9daa8530c6
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_filesystem/task/file_check.php
@@ -0,0 +1,248 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_filesystem\task;
+
+use phpbb\filesystem\filesystem;
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\helper\update_helper;
+use phpbb\install\task_base;
+
+/**
+ * Updater task performing file checking
+ */
+class file_check extends task_base
+{
+ /**
+ * @var filesystem
+ */
+ protected $filesystem;
+
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Construct
+ *
+ * @param filesystem $filesystem
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ * @param update_helper $update_helper
+ * @param string $phpbb_root_path
+ */
+ public function __construct(filesystem $filesystem, config $config, iohandler_interface $iohandler, update_helper $update_helper, $phpbb_root_path)
+ {
+ $this->filesystem = $filesystem;
+ $this->installer_config = $config;
+ $this->iohandler = $iohandler;
+ $this->update_helper = $update_helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ return $this->installer_config->get('do_update_files', false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ if (!$this->installer_config->has_restart_point('check_update_files'))
+ {
+ $this->installer_config->create_progress_restart_point('check_update_files');
+ }
+
+ $old_path = $this->update_helper->get_path_to_old_update_files();
+ $new_path = $this->update_helper->get_path_to_new_update_files();
+
+ $update_info = $this->installer_config->get('update_info', array());
+ $file_update_info = $this->installer_config->get('update_files', array());
+
+ if (empty($update_info))
+ {
+ $root_path = $this->phpbb_root_path;
+
+ $update_info = $this->installer_config->get('update_info_unprocessed', array());
+
+ $file_update_info = array();
+ $file_update_info['update_without_diff'] = array_diff($update_info['binary'], $update_info['deleted']);
+
+ foreach ($file_update_info['update_without_diff'] as $key => $binary_file)
+ {
+ $new_file = $new_path . $binary_file;
+ $file = $this->phpbb_root_path . $binary_file;
+
+ if (!$this->filesystem->exists($file))
+ {
+ continue;
+ }
+
+ if (md5_file($file) === md5_file($new_file))
+ {
+ // File already up to date
+ unset($file_update_info['update_without_diff'][$key]);
+ }
+ }
+
+ // Remove update without diff info if empty
+ if (count($file_update_info['update_without_diff']) < 1)
+ {
+ unset($file_update_info['update_without_diff']);
+ }
+
+ // Filter out files that are already deleted
+ $file_update_info['delete'] = array_filter(
+ $update_info['deleted'],
+ function ($filename) use ($root_path)
+ {
+ return file_exists($root_path . $filename);
+ }
+ );
+
+ // Remove files to delete list if empty
+ if (count($file_update_info['delete']) < 1)
+ {
+ unset($file_update_info['delete']);
+ }
+ }
+
+ $progress_count = $this->installer_config->get('file_check_progress_count', 0);
+ $task_count = count($update_info['files']);
+ $this->iohandler->set_task_count($task_count);
+ $this->iohandler->set_progress('UPDATE_CHECK_FILES', 0);
+
+ // Create list of default extensions that should have been added prior
+ // to this update
+ $default_update_extensions = [];
+ foreach (\phpbb\install\module\update_database\task\update_extensions::$default_extensions_update as $version => $extensions)
+ {
+ if ($this->update_helper->phpbb_version_compare($update_info['version']['from'], $version, '>='))
+ {
+ $default_update_extensions = array_merge($default_update_extensions, $extensions);
+ }
+ }
+
+ foreach ($update_info['files'] as $key => $filename)
+ {
+ $old_file = $old_path . $filename;
+ $new_file = $new_path . $filename;
+ $file = $this->phpbb_root_path . $filename;
+
+ if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0)
+ {
+ // Save progress
+ $this->installer_config->set('update_info', $update_info);
+ $this->installer_config->set('file_check_progress_count', $progress_count);
+ $this->installer_config->set('update_files', $file_update_info);
+
+ // Request refresh
+ throw new resource_limit_reached_exception();
+ }
+
+ $progress_count++;
+ $this->iohandler->set_progress('UPDATE_CHECK_FILES', $progress_count);
+
+ // Do not copy default extension again if the previous version was
+ // packaged with it but it does not exist (e.g. deleted by admin)
+ if (strpos($file, $this->phpbb_root_path . 'ext/') !== false)
+ {
+ $skip_file = false;
+ foreach ($default_update_extensions as $ext_name)
+ {
+ if (strpos($file, $this->phpbb_root_path . 'ext/' . $ext_name) !== false &&
+ !$this->filesystem->exists($this->phpbb_root_path . 'ext/' . $ext_name . '/composer.json'))
+ {
+ $skip_file = true;
+ break;
+ }
+ }
+
+ if ($skip_file)
+ {
+ continue;
+ }
+ }
+
+ if (!$this->filesystem->exists($file))
+ {
+ $file_update_info['new'][] = $filename;
+ }
+ else
+ {
+ $file_checksum = md5_file($file);
+
+ if ($file_checksum === md5_file($new_file))
+ {
+ // File already up to date
+ continue;
+ }
+ else if ($this->filesystem->exists($old_file) && $file_checksum === md5_file($old_file))
+ {
+ // No need to diff the file
+ $file_update_info['update_without_diff'][] = $filename;
+ }
+ else
+ {
+ $file_update_info['update_with_diff'][] = $filename;
+ }
+ }
+
+ unset($update_info['files'][$key]);
+ }
+
+ $this->installer_config->set('update_files', $file_update_info);
+ $this->installer_config->set('update_info', array());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_filesystem/task/show_file_status.php b/phpBB/phpbb/install/module/update_filesystem/task/show_file_status.php
new file mode 100644
index 0000000000..0e82f91553
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_filesystem/task/show_file_status.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_filesystem\task;
+
+use phpbb\filesystem\filesystem;
+use phpbb\install\exception\user_interaction_required_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\file_updater\factory;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\task_base;
+
+class show_file_status extends task_base
+{
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var filesystem
+ */
+ protected $filesystem;
+
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var \phpbb\install\helper\file_updater\compression_file_updater
+ */
+ protected $file_updater;
+
+ /**
+ * Constructor
+ *
+ * @param container_factory $container
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ * @param filesystem $filesystem
+ * @param factory $file_updater_factory
+ */
+ public function __construct(container_factory $container, config $config, iohandler_interface $iohandler, filesystem $filesystem, factory $file_updater_factory)
+ {
+ $this->installer_config = $config;
+ $this->iohandler = $iohandler;
+ $this->filesystem = $filesystem;
+
+ $this->cache = $container->get('cache.driver');
+
+ // Initialize compression file updater
+ $this->file_updater = $file_updater_factory->get('compression');
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ return $this->installer_config->get('do_update_files', false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ if (!$this->iohandler->get_input('submit_continue_file_update', false))
+ {
+ // Handle merge conflicts
+ $merge_conflicts = $this->installer_config->get('merge_conflict_list', array());
+
+ // Create archive for merge conflicts
+ if (!empty($merge_conflicts))
+ {
+ $compression_method = $this->installer_config->get('file_update_compression', '');
+ $conflict_archive = $this->file_updater->init($compression_method);
+ $this->installer_config->set('update_file_conflict_archive', $conflict_archive);
+
+ foreach ($merge_conflicts as $filename)
+ {
+ $this->file_updater->create_new_file(
+ $filename,
+ base64_decode($this->cache->get('_file_' . md5($filename))),
+ true
+ );
+ }
+
+ // Render download box
+ $this->iohandler->add_download_link(
+ 'phpbb_installer_update_conflict_download',
+ 'DOWNLOAD_CONFLICTS',
+ 'DOWNLOAD_CONFLICTS_EXPLAIN'
+ );
+
+ $this->file_updater->close();
+ }
+
+ // Render update file statuses
+ $file_update_info = $this->installer_config->get('update_files', array());
+ $file_status = array(
+ 'deleted' => (!isset($file_update_info['delete'])) ? array() : $file_update_info['delete'],
+ 'new' => (!isset($file_update_info['new'])) ? array() : $file_update_info['new'],
+ 'conflict' => $this->installer_config->get('merge_conflict_list', array()),
+ 'modified' => (!isset($file_update_info['update_with_diff'])) ? array() : $file_update_info['update_with_diff'],
+ 'not_modified' => (!isset($file_update_info['update_without_diff'])) ? array() : $file_update_info['update_without_diff'],
+ );
+
+ $this->iohandler->render_update_file_status($file_status);
+
+ // Add form to continue update
+ $this->iohandler->add_user_form_group('UPDATE_CONTINUE_FILE_UPDATE', array(
+ 'submit_continue_file_update' => array(
+ 'label' => 'UPDATE_CONTINUE_FILE_UPDATE',
+ 'type' => 'submit',
+ ),
+ ));
+
+ // Show results to the user
+ throw new user_interaction_required_exception();
+ }
+ else
+ {
+ $conflict_archive_path = $this->installer_config->get('update_file_conflict_archive', null);
+
+ // Remove archive
+ if ($conflict_archive_path !== null && $this->filesystem->exists($conflict_archive_path))
+ {
+ $this->filesystem->remove($conflict_archive_path);
+ }
+
+ $this->installer_config->set('update_file_conflict_archive', null);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module/update_filesystem/task/update_files.php b/phpBB/phpbb/install/module/update_filesystem/task/update_files.php
new file mode 100644
index 0000000000..fbb465cc66
--- /dev/null
+++ b/phpBB/phpbb/install/module/update_filesystem/task/update_files.php
@@ -0,0 +1,294 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install\module\update_filesystem\task;
+
+use phpbb\exception\runtime_exception;
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\container_factory;
+use phpbb\install\helper\file_updater\factory;
+use phpbb\install\helper\file_updater\file_updater_interface;
+use phpbb\install\helper\iohandler\iohandler_interface;
+use phpbb\install\helper\update_helper;
+use phpbb\install\task_base;
+
+/**
+ * File updater task
+ */
+class update_files extends task_base
+{
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var config
+ */
+ protected $installer_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var factory
+ */
+ protected $factory;
+
+ /**
+ * @var file_updater_interface
+ */
+ protected $file_updater;
+
+ /**
+ * @var update_helper
+ */
+ protected $update_helper;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param container_factory $container
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ * @param factory $file_updater_factory
+ * @param update_helper $update_helper
+ * @param string $phpbb_root_path
+ */
+ public function __construct(container_factory $container, config $config, iohandler_interface $iohandler, factory $file_updater_factory, update_helper $update_helper, $phpbb_root_path)
+ {
+ $this->factory = $file_updater_factory;
+ $this->installer_config = $config;
+ $this->iohandler = $iohandler;
+ $this->update_helper = $update_helper;
+ $this->phpbb_root_path = $phpbb_root_path;
+
+ $this->cache = $container->get('cache.driver');
+ $this->file_updater = null;
+
+ parent::__construct(false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function check_requirements()
+ {
+ return $this->installer_config->get('do_update_files', false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ $new_path = $this->update_helper->get_path_to_new_update_files();
+
+ $file_update_info = $this->installer_config->get('update_files', array());
+
+ $update_type_progress = $this->installer_config->get('file_updater_type_progress', '');
+ $update_elem_progress = $this->installer_config->get('file_updater_elem_progress', '');
+ $type_progress_found = false;
+ $elem_progress_found = false;
+
+ // Progress bar
+ $task_count = 0;
+ foreach ($file_update_info as $sub_array)
+ {
+ $task_count += count($sub_array);
+ }
+
+ // Everything is up to date, so just continue
+ if ($task_count === 0)
+ {
+ return;
+ }
+
+ $progress_count = $this->installer_config->get('file_update_progress_count', 0);
+ $this->iohandler->set_task_count($task_count, true);
+ $this->iohandler->set_progress('UPDATE_UPDATING_FILES', 0);
+
+ $this->file_updater = $this->get_file_updater();
+
+ // File updater fallback logic
+ try
+ {
+ // Update files
+ foreach ($file_update_info as $type => $file_update_vector)
+ {
+ if (!$type_progress_found)
+ {
+ if ($type === $update_type_progress || empty($update_elem_progress))
+ {
+ $type_progress_found = true;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ foreach ($file_update_vector as $path)
+ {
+ if (!$elem_progress_found)
+ {
+ if ($path === $update_elem_progress || empty($update_elem_progress))
+ {
+ $elem_progress_found = true;
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ switch ($type)
+ {
+ case 'delete':
+ $this->file_updater->delete_file($path);
+ break;
+ case 'new':
+ $this->file_updater->create_new_file($path, $new_path . $path);
+ break;
+ case 'update_without_diff':
+ $this->file_updater->update_file($path, $new_path . $path);
+ break;
+ case 'update_with_diff':
+ $this->file_updater->update_file(
+ $path,
+ base64_decode($this->cache->get('_file_' . md5($path))),
+ true
+ );
+ break;
+ }
+
+ // Save progress
+ $this->installer_config->set('file_updater_type_progress', $type);
+ $this->installer_config->set('file_updater_elem_progress', $path);
+ $progress_count++;
+ $this->iohandler->set_progress('UPDATE_UPDATING_FILES', $progress_count);
+
+ if ($this->installer_config->get_time_remaining() <= 0 || $this->installer_config->get_memory_remaining() <= 0)
+ {
+ // Request refresh
+ throw new resource_limit_reached_exception();
+ }
+ }
+ }
+
+ $this->iohandler->finish_progress('UPDATE_UPDATING_FILES');
+ }
+ catch (runtime_exception $e)
+ {
+ if ($e instanceof resource_limit_reached_exception)
+ {
+ throw new resource_limit_reached_exception();
+ }
+
+ $current_method = $this->installer_config->get('file_update_method', '');
+
+ // File updater failed, try to fallback to download file update mode
+ if ($current_method !== 'compression')
+ {
+ $this->iohandler->add_warning_message(array(
+ 'UPDATE_FILE_UPDATER_HAS_FAILED',
+ $current_method,
+ 'compression'
+ ));
+ $this->installer_config->set('file_update_method', 'compression');
+
+ // We only want a simple refresh here
+ throw new resource_limit_reached_exception();
+ }
+ else
+ {
+ // Nowhere to fallback to :(
+ // Due to the way the installer handles fatal errors, we need to throw a low level exception
+ throw new runtime_exception('UPDATE_FILE_UPDATERS_HAVE_FAILED');
+ }
+ }
+
+ $file_updater_method = $this->installer_config->get('file_update_method', '');
+ if ($file_updater_method === 'compression' || $file_updater_method === 'ftp')
+ {
+ $this->file_updater->close();
+ }
+ }
+
+ /**
+ * Get file updater
+ *
+ * @param null|string $file_updater_method Name of the file updater to use
+ *
+ * @return file_updater_interface File updater
+ */
+ protected function get_file_updater($file_updater_method = null)
+ {
+ $file_updater_method = ($file_updater_method === null) ? $this->installer_config->get('file_update_method', '') : $file_updater_method;
+
+ if ($file_updater_method === 'compression')
+ {
+ $compression_method = $this->installer_config->get('file_update_compression', '');
+
+ /** @var \phpbb\install\helper\file_updater\compression_file_updater $file_updater */
+ $file_updater = $this->factory->get('compression');
+ $archive_path = $file_updater->init($compression_method);
+ $this->installer_config->set('update_file_archive', $archive_path);
+ }
+ else if ($file_updater_method === 'ftp')
+ {
+ /** @var \phpbb\install\helper\file_updater\ftp_file_updater $file_updater */
+ $file_updater = $this->factory->get('ftp');
+ $file_updater->init(
+ $this->installer_config->get('ftp_method', ''),
+ $this->installer_config->get('ftp_host', ''),
+ $this->installer_config->get('ftp_user', ''),
+ $this->installer_config->get('ftp_pass', ''),
+ $this->installer_config->get('ftp_path', ''),
+ $this->installer_config->get('ftp_port', 0),
+ $this->installer_config->get('ftp_timeout', 10)
+ );
+ }
+ else
+ {
+ /** @var file_updater_interface $file_updater */
+ $file_updater = $this->factory->get('direct_file');
+ }
+
+ return $file_updater;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/phpBB/phpbb/install/module_base.php b/phpBB/phpbb/install/module_base.php
new file mode 100644
index 0000000000..93c10bd656
--- /dev/null
+++ b/phpBB/phpbb/install/module_base.php
@@ -0,0 +1,213 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install;
+
+use phpbb\di\ordered_service_collection;
+use phpbb\install\exception\resource_limit_reached_exception;
+use phpbb\install\helper\config;
+use phpbb\install\helper\iohandler\iohandler_interface;
+
+/**
+ * Base class for installer module
+ */
+abstract class module_base implements module_interface
+{
+ /**
+ * @var config
+ */
+ protected $install_config;
+
+ /**
+ * @var iohandler_interface
+ */
+ protected $iohandler;
+
+ /**
+ * @var bool
+ */
+ protected $is_essential;
+
+ /**
+ * Array of tasks for installer module
+ *
+ * @var ordered_service_collection
+ */
+ protected $task_collection;
+
+ /**
+ * @var array
+ */
+ protected $task_step_count;
+
+ /**
+ * @var bool
+ */
+ protected $allow_progress_bar;
+
+ /**
+ * Installer module constructor
+ *
+ * @param ordered_service_collection $tasks array of installer tasks for installer module
+ * @param bool $essential flag indicating whether the module is essential or not
+ * @param bool $allow_progress_bar flag indicating whether or not to send progress information from within the module
+ */
+ public function __construct(ordered_service_collection $tasks, $essential = true, $allow_progress_bar = true)
+ {
+ $this->task_collection = $tasks;
+ $this->is_essential = $essential;
+ $this->allow_progress_bar = $allow_progress_bar;
+ }
+
+ /**
+ * Dependency getter
+ *
+ * @param config $config
+ * @param iohandler_interface $iohandler
+ */
+ public function setup(config $config, iohandler_interface $iohandler)
+ {
+ $this->install_config = $config;
+ $this->iohandler = $iohandler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_essential()
+ {
+ return $this->is_essential;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Overwrite this method if your task is non-essential!
+ */
+ public function check_requirements()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run()
+ {
+ // Recover install progress
+ $task_index = $this->recover_progress();
+ $iterator = $this->task_collection->getIterator();
+
+ if ($task_index < $iterator->count())
+ {
+ $iterator->seek($task_index);
+ }
+ else
+ {
+ $this->install_config->set_finished_task(0);
+ return;
+ }
+
+ while ($iterator->valid())
+ {
+ $task = $iterator->current();
+ $name = $iterator->key();
+
+ // Check if we can run the task
+ if (!$task->is_essential() && !$task->check_requirements())
+ {
+ $this->iohandler->add_log_message(array(
+ 'SKIP_TASK',
+ $name,
+ ));
+
+ $this->install_config->increment_current_task_progress($this->task_step_count[$name]);
+ }
+ else
+ {
+ // Send progress information
+ if ($this->allow_progress_bar)
+ {
+ $this->iohandler->set_progress(
+ $task->get_task_lang_name(),
+ $this->install_config->get_current_task_progress()
+ );
+
+ $this->iohandler->send_response();
+ }
+
+ $task->run();
+
+ if ($this->allow_progress_bar)
+ {
+ // Only increment progress by one, as if a task has more than one steps
+ // then that should be incremented in the task itself
+ $this->install_config->increment_current_task_progress();
+ }
+ }
+
+ $task_index++;
+ $this->install_config->set_finished_task($task_index);
+ $iterator->next();
+
+ // Send progress information
+ if ($this->allow_progress_bar)
+ {
+ $this->iohandler->set_progress(
+ $task->get_task_lang_name(),
+ $this->install_config->get_current_task_progress()
+ );
+ }
+
+ $this->iohandler->send_response();
+
+ // Stop execution if resource limit is reached
+ if ($iterator->valid() && ($this->install_config->get_time_remaining() <= 0 || $this->install_config->get_memory_remaining() <= 0))
+ {
+ throw new resource_limit_reached_exception();
+ }
+ }
+
+ // Module finished, so clear task progress
+ $this->install_config->set_finished_task(0);
+ }
+
+ /**
+ * Returns the next task's name
+ *
+ * @return string Index of the array element of the next task
+ */
+ protected function recover_progress()
+ {
+ $progress_array = $this->install_config->get_progress_data();
+ return $progress_array['last_task_index'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_step_count()
+ {
+ $task_step_count = 0;
+ $task_class_names = $this->task_collection->get_service_classes();
+
+ foreach ($task_class_names as $name => $task_class)
+ {
+ $step_count = $task_class::get_step_count();
+ $task_step_count += $step_count;
+ $this->task_step_count[$name] = $step_count;
+ }
+
+ return $task_step_count;
+ }
+}
diff --git a/phpBB/phpbb/install/module_interface.php b/phpBB/phpbb/install/module_interface.php
new file mode 100644
index 0000000000..a2d61e3958
--- /dev/null
+++ b/phpBB/phpbb/install/module_interface.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install;
+
+/**
+ * Interface for installer modules
+ *
+ * An installer module is a task collection which executes installer tasks.
+ */
+interface module_interface
+{
+ /**
+ * Checks if the execution of the module is essential to install phpBB or it can be skipped
+ *
+ * Note: Please note that all the non-essential modules have to implement check_requirements()
+ * method.
+ *
+ * @return bool true if the module is essential, false otherwise
+ */
+ public function is_essential();
+
+ /**
+ * Checks requirements for the tasks
+ *
+ * Note: Only need to be implemented for non-essential tasks, as essential tasks
+ * requirements should be checked in the requirements install module.
+ *
+ * @return bool true if the task's requirements are met
+ */
+ public function check_requirements();
+
+ /**
+ * Executes the task
+ *
+ * @return null
+ */
+ public function run();
+
+ /**
+ * Returns the number of tasks in the module
+ *
+ * @return int
+ */
+ public function get_step_count();
+
+ /**
+ * Returns an array to the correct navigation stage
+ *
+ * @return array
+ */
+ public function get_navigation_stage_path();
+}
diff --git a/phpBB/phpbb/install/task_base.php b/phpBB/phpbb/install/task_base.php
new file mode 100644
index 0000000000..b5199be4af
--- /dev/null
+++ b/phpBB/phpbb/install/task_base.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install;
+
+/**
+ * Base class for installer task
+ */
+abstract class task_base implements task_interface
+{
+ /**
+ * @var bool
+ */
+ protected $is_essential;
+
+ /**
+ * Constructor
+ *
+ * @param bool $essential
+ */
+ public function __construct($essential = true)
+ {
+ $this->is_essential = $essential;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_essential()
+ {
+ return $this->is_essential;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Note: Overwrite this method if your task is non-essential!
+ */
+ public function check_requirements()
+ {
+ return true;
+ }
+}
diff --git a/phpBB/phpbb/install/task_interface.php b/phpBB/phpbb/install/task_interface.php
new file mode 100644
index 0000000000..794cb16482
--- /dev/null
+++ b/phpBB/phpbb/install/task_interface.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\install;
+
+/**
+ * Interface for installer tasks
+ */
+interface task_interface
+{
+ /**
+ * Returns the number of steps the task contains
+ *
+ * This is a helper method to provide a better progress bar for the front-end.
+ *
+ * @return int The number of steps that the task contains
+ */
+ static public function get_step_count();
+
+ /**
+ * Checks if the task is essential to install phpBB or it can be skipped
+ *
+ * Note: Please note that all the non-essential modules have to implement check_requirements()
+ * method.
+ *
+ * @return bool true if the task is essential, false otherwise
+ */
+ public function is_essential();
+
+ /**
+ * Checks requirements for the tasks
+ *
+ * Note: Only need to be implemented for non-essential tasks, as essential tasks
+ * requirements should be checked in the requirements install module.
+ *
+ * @return bool true if the task's requirements are met
+ */
+ public function check_requirements();
+
+ /**
+ * Executes the task
+ */
+ public function run();
+
+ /**
+ * Returns the language key of the name of the task
+ *
+ * @return string
+ */
+ public function get_task_lang_name();
+}
diff --git a/phpBB/phpbb/install/updater_configuration.php b/phpBB/phpbb/install/updater_configuration.php
new file mode 100644
index 0000000000..5c1c29f1da
--- /dev/null
+++ b/phpBB/phpbb/install/updater_configuration.php
@@ -0,0 +1,44 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\install;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+class updater_configuration implements ConfigurationInterface
+{
+
+ /**
+ * Generates the configuration tree builder.
+ *
+ * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
+ */
+ public function getConfigTreeBuilder()
+ {
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('updater');
+ $rootNode
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->enumNode('type')->values(['all','db_only'])->defaultValue('all')->end()
+ ->arrayNode('extensions')
+ ->prototype('scalar')->end()
+ ->defaultValue([])
+ ->end()
+ ->end()
+ ;
+
+ return $treeBuilder;
+ }
+}
diff --git a/phpBB/phpbb/language/exception/invalid_plural_rule_exception.php b/phpBB/phpbb/language/exception/invalid_plural_rule_exception.php
new file mode 100644
index 0000000000..94e3466208
--- /dev/null
+++ b/phpBB/phpbb/language/exception/invalid_plural_rule_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\language\exception;
+
+/**
+ * Thrown when nonexistent plural rule is specified
+ */
+class invalid_plural_rule_exception extends language_exception
+{
+
+}
diff --git a/phpBB/phpbb/language/exception/language_exception.php b/phpBB/phpbb/language/exception/language_exception.php
new file mode 100644
index 0000000000..b1258414aa
--- /dev/null
+++ b/phpBB/phpbb/language/exception/language_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\language\exception;
+
+/**
+ * Base exception class for language exceptions
+ */
+class language_exception extends \phpbb\exception\runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/language/exception/language_file_not_found.php b/phpBB/phpbb/language/exception/language_file_not_found.php
new file mode 100644
index 0000000000..89364267eb
--- /dev/null
+++ b/phpBB/phpbb/language/exception/language_file_not_found.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\language\exception;
+
+/**
+ * This exception is thrown when the language file is not found
+ */
+class language_file_not_found extends language_exception
+{
+
+}
diff --git a/phpBB/phpbb/language/language.php b/phpBB/phpbb/language/language.php
new file mode 100644
index 0000000000..51e6d0b185
--- /dev/null
+++ b/phpBB/phpbb/language/language.php
@@ -0,0 +1,673 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\language;
+
+use phpbb\language\exception\invalid_plural_rule_exception;
+
+/**
+ * Wrapper class for loading translations
+ */
+class language
+{
+ /**
+ * Global fallback language
+ *
+ * ISO code of the language to fallback to when the specified language entries
+ * cannot be found.
+ *
+ * @var string
+ */
+ const FALLBACK_LANGUAGE = 'en';
+
+ /**
+ * @var array List of common language files
+ */
+ protected $common_language_files;
+
+ /**
+ * @var bool
+ */
+ protected $common_language_files_loaded;
+
+ /**
+ * @var string ISO code of the default board language
+ */
+ protected $default_language;
+
+ /**
+ * @var string ISO code of the User's language
+ */
+ protected $user_language;
+
+ /**
+ * @var array Language fallback array (the order is important)
+ */
+ protected $language_fallback;
+
+ /**
+ * @var array Array of language variables
+ */
+ protected $lang;
+
+ /**
+ * @var array Loaded language sets
+ */
+ protected $loaded_language_sets;
+
+ /**
+ * @var \phpbb\language\language_file_loader Language file loader
+ */
+ protected $loader;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\language\language_file_loader $loader Language file loader
+ * @param array|null $common_modules Array of common language modules to load (optional)
+ */
+ public function __construct(language_file_loader $loader, $common_modules = null)
+ {
+ $this->loader = $loader;
+
+ // Set up default information
+ $this->user_language = false;
+ $this->default_language = false;
+ $this->lang = array();
+ $this->loaded_language_sets = array(
+ 'core' => array(),
+ 'ext' => array(),
+ );
+
+ // Common language files
+ if (is_array($common_modules))
+ {
+ $this->common_language_files = $common_modules;
+ }
+ else
+ {
+ $this->common_language_files = array(
+ 'common',
+ );
+ }
+
+ $this->common_language_files_loaded = false;
+
+ $this->language_fallback = array(self::FALLBACK_LANGUAGE);
+ }
+
+ /**
+ * Function to set user's language to display.
+ *
+ * @param string $user_lang_iso ISO code of the User's language
+ * @param bool $reload Whether or not to reload language files
+ */
+ public function set_user_language($user_lang_iso, $reload = false)
+ {
+ $this->user_language = $user_lang_iso;
+
+ $this->set_fallback_array($reload);
+ }
+
+ /**
+ * Function to set the board's default language to display.
+ *
+ * @param string $default_lang_iso ISO code of the board's default language
+ * @param bool $reload Whether or not to reload language files
+ */
+ public function set_default_language($default_lang_iso, $reload = false)
+ {
+ $this->default_language = $default_lang_iso;
+
+ $this->set_fallback_array($reload);
+ }
+
+ /**
+ * Returns language array
+ *
+ * Note: This function is needed for the BC purposes, until \phpbb\user::lang[] is
+ * not removed.
+ *
+ * @return array Array of loaded language strings
+ */
+ public function get_lang_array()
+ {
+ // Load common language files if they not loaded yet
+ if (!$this->common_language_files_loaded)
+ {
+ $this->load_common_language_files();
+ }
+
+ return $this->lang;
+ }
+
+ /**
+ * Add Language Items
+ *
+ * Examples:
+ * <code>
+ * $component = array('posting');
+ * $component = array('posting', 'viewtopic')
+ * $component = 'posting'
+ * </code>
+ *
+ * @param string|array $component The name of the language component to load
+ * @param string|null $extension_name Name of the extension to load component from, or null for core file
+ */
+ public function add_lang($component, $extension_name = null)
+ {
+ // Load common language files if they not loaded yet
+ // This needs to be here to correctly merge language arrays
+ if (!$this->common_language_files_loaded)
+ {
+ $this->load_common_language_files();
+ }
+
+ if (!is_array($component))
+ {
+ if (!is_null($extension_name))
+ {
+ $this->load_extension($extension_name, $component);
+ }
+ else
+ {
+ $this->load_core_file($component);
+ }
+ }
+ else
+ {
+ foreach ($component as $lang_file)
+ {
+ $this->add_lang($lang_file, $extension_name);
+ }
+ }
+ }
+
+ /**
+ * @param $key array|string The language key we want to know more about. Can be string or array.
+ *
+ * @return bool Returns whether the language key is set.
+ */
+ public function is_set($key)
+ {
+ // Load common language files if they not loaded yet
+ if (!$this->common_language_files_loaded)
+ {
+ $this->load_common_language_files();
+ }
+
+ if (is_array($key))
+ {
+ $lang = &$this->lang[array_shift($key)];
+
+ foreach ($key as $_key)
+ {
+ $lang = &$lang[$_key];
+ }
+ }
+ else
+ {
+ $lang = &$this->lang[$key];
+ }
+
+ return isset($lang);
+ }
+
+ /**
+ * Advanced language substitution
+ *
+ * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms.
+ * Params are the language key and the parameters to be substituted.
+ * This function/functionality is inspired by SHS` and Ashe.
+ *
+ * Example call: <samp>$user->lang('NUM_POSTS_IN_QUEUE', 1);</samp>
+ *
+ * If the first parameter is an array, the elements are used as keys and subkeys to get the language entry:
+ * Example: <samp>$user->lang(array('datetime', 'AGO'), 1)</samp> uses $user->lang['datetime']['AGO'] as language entry.
+ *
+ * @return string Return localized string or the language key if the translation is not available
+ */
+ public function lang()
+ {
+ $args = func_get_args();
+ $key = array_shift($args);
+
+ return $this->lang_array($key, $args);
+ }
+
+ /**
+ * Returns the raw value associated to a language key or the language key no translation is available.
+ * No parameter substitution is performed, can be a string or an array.
+ *
+ * @param string|array $key Language key
+ *
+ * @return array|string
+ */
+ public function lang_raw($key)
+ {
+ // Load common language files if they not loaded yet
+ if (!$this->common_language_files_loaded)
+ {
+ $this->load_common_language_files();
+ }
+
+ if (is_array($key))
+ {
+ $lang = &$this->lang[array_shift($key)];
+
+ foreach ($key as $_key)
+ {
+ $lang = &$lang[$_key];
+ }
+ }
+ else
+ {
+ $lang = &$this->lang[$key];
+ }
+
+ // Return if language string does not exist
+ if (!isset($lang) || (!is_string($lang) && !is_array($lang)))
+ {
+ return $key;
+ }
+
+ return $lang;
+ }
+
+ /**
+ * Act like lang() but takes a key and an array of parameters instead of using variadic
+ *
+ * @param string|array $key Language key
+ * @param array $args Parameters
+ *
+ * @return string
+ */
+ public function lang_array($key, $args = array())
+ {
+ $lang = $this->lang_raw($key);
+
+ if ($lang === $key)
+ {
+ return $key;
+ }
+
+ // If the language entry is a string, we simply mimic sprintf() behaviour
+ if (is_string($lang))
+ {
+ if (count($args) === 0)
+ {
+ return $lang;
+ }
+
+ // Replace key with language entry and simply pass along...
+ return vsprintf($lang, $args);
+ }
+ else if (count($lang) == 0)
+ {
+ // If the language entry is an empty array, we just return the language key
+ return $key;
+ }
+
+ // It is an array... now handle different nullar/singular/plural forms
+ $key_found = false;
+
+ // We now get the first number passed and will select the key based upon this number
+ for ($i = 0, $num_args = count($args); $i < $num_args; $i++)
+ {
+ if (is_int($args[$i]) || is_float($args[$i]))
+ {
+ if ($args[$i] == 0 && isset($lang[0]))
+ {
+ // We allow each translation using plural forms to specify a version for the case of 0 things,
+ // so that "0 users" may be displayed as "No users".
+ $key_found = 0;
+ break;
+ }
+ else
+ {
+ $use_plural_form = $this->get_plural_form($args[$i]);
+ if (isset($lang[$use_plural_form]))
+ {
+ // The key we should use exists, so we use it.
+ $key_found = $use_plural_form;
+ }
+ else
+ {
+ // If the key we need to use does not exist, we fall back to the previous one.
+ $numbers = array_keys($lang);
+
+ foreach ($numbers as $num)
+ {
+ if ($num > $use_plural_form)
+ {
+ break;
+ }
+
+ $key_found = $num;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form)
+ if ($key_found === false)
+ {
+ $numbers = array_keys($lang);
+ $key_found = end($numbers);
+ }
+
+ // Use the language string we determined and pass it to sprintf()
+ return vsprintf($lang[$key_found], $args);
+ }
+
+ /**
+ * Loads common language files
+ */
+ protected function load_common_language_files()
+ {
+ if (!$this->common_language_files_loaded)
+ {
+ foreach ($this->common_language_files as $lang_file)
+ {
+ $this->load_core_file($lang_file);
+ }
+
+ $this->common_language_files_loaded = true;
+ }
+ }
+
+ /**
+ * Determine which plural form we should use.
+ *
+ * For some languages this is not as simple as for English.
+ *
+ * @param int|float $number The number we want to get the plural case for. Float numbers are floored.
+ * @param int|bool $force_rule False to use the plural rule of the language package
+ * or an integer to force a certain plural rule
+ *
+ * @return int The plural-case we need to use for the number plural-rule combination
+ *
+ * @throws \phpbb\language\exception\invalid_plural_rule_exception When $force_rule has an invalid value
+ */
+ public function get_plural_form($number, $force_rule = false)
+ {
+ $number = (int) $number;
+ $plural_rule = ($force_rule !== false) ? $force_rule : ((isset($this->lang['PLURAL_RULE'])) ? $this->lang['PLURAL_RULE'] : 1);
+
+ if ($plural_rule > 15 || $plural_rule < 0)
+ {
+ throw new invalid_plural_rule_exception('INVALID_PLURAL_RULE', array(
+ 'plural_rule' => $plural_rule,
+ ));
+ }
+
+ /**
+ * The following plural rules are based on a list published by the Mozilla Developer Network
+ * https://developer.mozilla.org/en/Localization_and_Plurals
+ */
+ switch ($plural_rule)
+ {
+ case 0:
+ /**
+ * Families: Asian (Chinese, Japanese, Korean, Vietnamese), Persian, Turkic/Altaic (Turkish), Thai, Lao
+ * 1 - everything: 0, 1, 2, ...
+ */
+ return 1;
+
+ case 1:
+ /**
+ * Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan)
+ * 1 - 1
+ * 2 - everything else: 0, 2, 3, ...
+ */
+ return ($number === 1) ? 1 : 2;
+
+ case 2:
+ /**
+ * Families: Romanic (French, Brazilian Portuguese)
+ * 1 - 0, 1
+ * 2 - everything else: 2, 3, ...
+ */
+ return (($number === 0) || ($number === 1)) ? 1 : 2;
+
+ case 3:
+ /**
+ * Families: Baltic (Latvian)
+ * 1 - 0
+ * 2 - ends in 1, not 11: 1, 21, ... 101, 121, ...
+ * 3 - everything else: 2, 3, ... 10, 11, 12, ... 20, 22, ...
+ */
+ return ($number === 0) ? 1 : ((($number % 10 === 1) && ($number % 100 != 11)) ? 2 : 3);
+
+ case 4:
+ /**
+ * Families: Celtic (Scottish Gaelic)
+ * 1 - is 1 or 11: 1, 11
+ * 2 - is 2 or 12: 2, 12
+ * 3 - others between 3 and 19: 3, 4, ... 10, 13, ... 18, 19
+ * 4 - everything else: 0, 20, 21, ...
+ */
+ return ($number === 1 || $number === 11) ? 1 : (($number === 2 || $number === 12) ? 2 : (($number >= 3 && $number <= 19) ? 3 : 4));
+
+ case 5:
+ /**
+ * Families: Romanic (Romanian)
+ * 1 - 1
+ * 2 - is 0 or ends in 01-19: 0, 2, 3, ... 19, 101, 102, ... 119, 201, ...
+ * 3 - everything else: 20, 21, ...
+ */
+ return ($number === 1) ? 1 : ((($number === 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 2 : 3);
+
+ case 6:
+ /**
+ * Families: Baltic (Lithuanian)
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
+ * 2 - ends in 0 or ends in 10-20: 0, 10, 11, 12, ... 19, 20, 30, 40, ...
+ * 3 - everything else: 2, 3, ... 8, 9, 22, 23, ... 29, 32, 33, ...
+ */
+ return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 < 2) || (($number % 100 >= 10) && ($number % 100 < 20))) ? 2 : 3);
+
+ case 7:
+ /**
+ * Families: Slavic (Croatian, Serbian, Russian, Ukrainian)
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ...
+ * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ...
+ * 3 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26, ...
+ */
+ return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 2 : 3);
+
+ case 8:
+ /**
+ * Families: Slavic (Slovak, Czech)
+ * 1 - 1
+ * 2 - 2, 3, 4
+ * 3 - everything else: 0, 5, 6, 7, ...
+ */
+ return ($number === 1) ? 1 : ((($number >= 2) && ($number <= 4)) ? 2 : 3);
+
+ case 9:
+ /**
+ * Families: Slavic (Polish)
+ * 1 - 1
+ * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... 104, 122, ...
+ * 3 - everything else: 0, 5, 6, ... 11, 12, 13, 14, 15, ... 20, 21, 25, ...
+ */
+ return ($number === 1) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 2 : 3);
+
+ case 10:
+ /**
+ * Families: Slavic (Slovenian, Sorbian)
+ * 1 - ends in 01: 1, 101, 201, ...
+ * 2 - ends in 02: 2, 102, 202, ...
+ * 3 - ends in 03-04: 3, 4, 103, 104, 203, 204, ...
+ * 4 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, ...
+ */
+ return ($number % 100 === 1) ? 1 : (($number % 100 === 2) ? 2 : ((($number % 100 === 3) || ($number % 100 === 4)) ? 3 : 4));
+
+ case 11:
+ /**
+ * Families: Celtic (Irish Gaeilge)
+ * 1 - 1
+ * 2 - 2
+ * 3 - is 3-6: 3, 4, 5, 6
+ * 4 - is 7-10: 7, 8, 9, 10
+ * 5 - everything else: 0, 11, 12, ...
+ */
+ return ($number === 1) ? 1 : (($number === 2) ? 2 : (($number >= 3 && $number <= 6) ? 3 : (($number >= 7 && $number <= 10) ? 4 : 5)));
+
+ case 12:
+ /**
+ * Families: Semitic (Arabic)
+ * 1 - 1
+ * 2 - 2
+ * 3 - ends in 03-10: 3, 4, ... 10, 103, 104, ... 110, 203, 204, ...
+ * 4 - ends in 11-99: 11, ... 99, 111, 112, ...
+ * 5 - everything else: 100, 101, 102, 200, 201, 202, ...
+ * 6 - 0
+ */
+ return ($number === 1) ? 1 : (($number === 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : (($number != 0) ? 5 : 6))));
+
+ case 13:
+ /**
+ * Families: Semitic (Maltese)
+ * 1 - 1
+ * 2 - is 0 or ends in 01-10: 0, 2, 3, ... 9, 10, 101, 102, ...
+ * 3 - ends in 11-19: 11, 12, ... 18, 19, 111, 112, ...
+ * 4 - everything else: 20, 21, ...
+ */
+ return ($number === 1) ? 1 : ((($number === 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 2 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 3 : 4));
+
+ case 14:
+ /**
+ * Families: Slavic (Macedonian)
+ * 1 - ends in 1: 1, 11, 21, ...
+ * 2 - ends in 2: 2, 12, 22, ...
+ * 3 - everything else: 0, 3, 4, ... 10, 13, 14, ... 20, 23, ...
+ */
+ return ($number % 10 === 1) ? 1 : (($number % 10 === 2) ? 2 : 3);
+
+ case 15:
+ /**
+ * Families: Icelandic
+ * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, 131, ...
+ * 2 - everything else: 0, 2, 3, ... 10, 11, 12, ... 20, 22, ...
+ */
+ return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : 2;
+ }
+ }
+
+ /**
+ * Returns the ISO code of the used language
+ *
+ * @return string The ISO code of the currently used language
+ */
+ public function get_used_language()
+ {
+ return $this->language_fallback[0];
+ }
+
+ /**
+ * Returns language fallback data
+ *
+ * @param bool $reload Whether or not to reload language files
+ *
+ * @return array
+ */
+ protected function set_fallback_array($reload = false)
+ {
+ $fallback_array = array();
+
+ if ($this->user_language)
+ {
+ $fallback_array[] = $this->user_language;
+ }
+
+ if ($this->default_language)
+ {
+ $fallback_array[] = $this->default_language;
+ }
+
+ $fallback_array[] = self::FALLBACK_LANGUAGE;
+
+ $this->language_fallback = $fallback_array;
+
+ if ($reload)
+ {
+ $this->reload_language_files();
+ }
+ }
+
+ /**
+ * Load core language file
+ *
+ * @param string $component Name of the component to load
+ */
+ protected function load_core_file($component)
+ {
+ // Check if the component is already loaded
+ if (isset($this->loaded_language_sets['core'][$component]))
+ {
+ return;
+ }
+
+ $this->loader->load($component, $this->language_fallback, $this->lang);
+ $this->loaded_language_sets['core'][$component] = true;
+ }
+
+ /**
+ * Load extension language file
+ *
+ * @param string $extension_name Name of the extension to load language from
+ * @param string $component Name of the component to load
+ */
+ protected function load_extension($extension_name, $component)
+ {
+ // Check if the component is already loaded
+ if (isset($this->loaded_language_sets['ext'][$extension_name][$component]))
+ {
+ return;
+ }
+
+ $this->loader->load_extension($extension_name, $component, $this->language_fallback, $this->lang);
+ $this->loaded_language_sets['ext'][$extension_name][$component] = true;
+ }
+
+ /**
+ * Reload language files
+ */
+ protected function reload_language_files()
+ {
+ $loaded_files = $this->loaded_language_sets;
+ $this->loaded_language_sets = array(
+ 'core' => array(),
+ 'ext' => array(),
+ );
+
+ // Reload core files
+ foreach ($loaded_files['core'] as $component => $value)
+ {
+ $this->load_core_file($component);
+ }
+
+ // Reload extension files
+ foreach ($loaded_files['ext'] as $ext_name => $ext_info)
+ {
+ foreach ($ext_info as $ext_component => $value)
+ {
+ $this->load_extension($ext_name, $ext_component);
+ }
+ }
+ }
+}
diff --git a/phpBB/phpbb/language/language_file_helper.php b/phpBB/phpbb/language/language_file_helper.php
new file mode 100644
index 0000000000..85de034fb8
--- /dev/null
+++ b/phpBB/phpbb/language/language_file_helper.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\language;
+
+use Symfony\Component\Finder\Finder;
+
+/**
+ * Helper class for language file related functions
+ */
+class language_file_helper
+{
+ /**
+ * @var string Path to phpBB's root
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Constructor
+ *
+ * @param string $phpbb_root_path Path to phpBB's root
+ */
+ public function __construct($phpbb_root_path)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ /**
+ * Returns available languages
+ *
+ * @return array
+ */
+ public function get_available_languages()
+ {
+ // Find available language packages
+ $finder = new Finder();
+ $finder->files()
+ ->name('iso.txt')
+ ->depth('== 1')
+ ->followLinks()
+ ->in($this->phpbb_root_path . 'language');
+
+ $available_languages = array();
+ foreach ($finder as $file)
+ {
+ $path = $file->getRelativePath();
+ $info = explode("\n", $file->getContents());
+
+ $available_languages[] = array(
+ // Get the name of the directory containing iso.txt
+ 'iso' => $path,
+
+ // Recover data from file
+ 'name' => trim($info[0]),
+ 'local_name' => trim($info[1]),
+ 'author' => trim($info[2])
+ );
+ }
+
+ return $available_languages;
+ }
+}
diff --git a/phpBB/phpbb/language/language_file_loader.php b/phpBB/phpbb/language/language_file_loader.php
new file mode 100644
index 0000000000..b6816afd16
--- /dev/null
+++ b/phpBB/phpbb/language/language_file_loader.php
@@ -0,0 +1,206 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\language;
+
+use \phpbb\language\exception\language_file_not_found;
+
+/**
+ * Language file loader
+ */
+class language_file_loader
+{
+ /**
+ * @var string Path to phpBB's root
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string Extension of PHP files
+ */
+ protected $php_ext;
+
+ /**
+ * @var \phpbb\extension\manager Extension manager
+ */
+ protected $extension_manager;
+
+ /**
+ * Constructor
+ *
+ * @param string $phpbb_root_path Path to phpBB's root
+ * @param string $php_ext Extension of PHP files
+ */
+ public function __construct($phpbb_root_path, $php_ext)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+
+ $this->extension_manager = null;
+ }
+
+ /**
+ * Extension manager setter
+ *
+ * @param \phpbb\extension\manager $extension_manager Extension manager
+ */
+ public function set_extension_manager(\phpbb\extension\manager $extension_manager)
+ {
+ $this->extension_manager = $extension_manager;
+ }
+
+ /**
+ * Loads language array for the given component
+ *
+ * @param string $component Name of the language component
+ * @param string|array $locale ISO code of the language to load, or array of ISO codes if you want to
+ * specify additional language fallback steps
+ * @param array $lang Array reference containing language strings
+ */
+ public function load($component, $locale, &$lang)
+ {
+ $locale = (array) $locale;
+
+ // Determine path to language directory
+ $path = $this->phpbb_root_path . 'language/';
+
+ $this->load_file($path, $component, $locale, $lang);
+ }
+
+ /**
+ * Loads language array for the given extension component
+ *
+ * @param string $extension Name of the extension
+ * @param string $component Name of the language component
+ * @param string|array $locale ISO code of the language to load, or array of ISO codes if you want to
+ * specify additional language fallback steps
+ * @param array $lang Array reference containing language strings
+ */
+ public function load_extension($extension, $component, $locale, &$lang)
+ {
+ // Check if extension manager was loaded
+ if ($this->extension_manager === null)
+ {
+ // If not, let's return
+ return;
+ }
+
+ $locale = (array) $locale;
+
+ // Determine path to language directory
+ $path = $this->extension_manager->get_extension_path($extension, true) . 'language/';
+
+ $this->load_file($path, $component, $locale, $lang);
+ }
+
+ /**
+ * Prepares language file loading
+ *
+ * @param string $path Path to search for file in
+ * @param string $component Name of the language component
+ * @param array $locale Array containing language fallback options
+ * @param array $lang Array reference of language strings
+ */
+ protected function load_file($path, $component, $locale, &$lang)
+ {
+ // This is BC stuff and not the best idea as it makes language fallback
+ // implementation quite hard like below.
+ if (strpos($this->phpbb_root_path . $component, $path) === 0)
+ {
+ // Filter out the path
+ $path_diff = str_replace($path, '', dirname($this->phpbb_root_path . $component));
+ $language_file = basename($component, '.' . $this->php_ext);
+ $component = '';
+
+ // This step is needed to resolve language/en/subdir style $component
+ // $path already points to the language base directory so we need to eliminate
+ // the first directory from the path (that should be the language directory)
+ $path_diff_parts = explode('/', $path_diff);
+
+ if (count($path_diff_parts) > 1)
+ {
+ array_shift($path_diff_parts);
+ $component = implode('/', $path_diff_parts) . '/';
+ }
+
+ $component .= $language_file;
+ }
+
+ // Determine filename
+ $filename = $component . '.' . $this->php_ext;
+
+ // Determine path to file
+ $file_path = $this->get_language_file_path($path, $filename, $locale);
+
+ // Load language array
+ $this->load_language_file($file_path, $lang);
+ }
+
+ /**
+ * This function implements language fallback logic
+ *
+ * @param string $path Path to language directory
+ * @param string $filename Filename to load language strings from
+ *
+ * @return string Relative path to language file
+ *
+ * @throws language_file_not_found When the path to the file cannot be resolved
+ */
+ protected function get_language_file_path($path, $filename, $locales)
+ {
+ $language_file_path = $filename;
+
+ // Language fallback logic
+ foreach ($locales as $locale)
+ {
+ $language_file_path = $path . $locale . '/' . $filename;
+
+ // If we are in install, try to use the updated version, when available
+ if (defined('IN_INSTALL'))
+ {
+ $install_language_path = str_replace('language/', 'install/update/new/language/', $language_file_path);
+ if (file_exists($install_language_path))
+ {
+ return $install_language_path;
+ }
+ }
+
+ if (file_exists($language_file_path))
+ {
+ return $language_file_path;
+ }
+ }
+
+ // The language file is not exist
+ throw new language_file_not_found('Language file ' . $language_file_path . ' couldn\'t be opened.');
+ }
+
+ /**
+ * Loads language file
+ *
+ * @param string $path Path to language file to load
+ * @param array $lang Reference of the array of language strings
+ */
+ protected function load_language_file($path, &$lang)
+ {
+ // Do not suppress error if in DEBUG mode
+ if (defined('DEBUG'))
+ {
+ include $path;
+ }
+ else
+ {
+ @include $path;
+ }
+ }
+}
diff --git a/phpBB/phpbb/log/dummy.php b/phpBB/phpbb/log/dummy.php
new file mode 100644
index 0000000000..5c2d145e15
--- /dev/null
+++ b/phpBB/phpbb/log/dummy.php
@@ -0,0 +1,81 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\log;
+
+/**
+* Dummy logger
+*/
+class dummy implements log_interface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function is_enabled($type = '')
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disable($type = '')
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function enable($type = '')
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add($mode, $user_id, $log_ip, $log_operation, $log_time = false, $additional_data = array())
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete($mode, $conditions = array())
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_logs($mode, $count_logs = true, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $log_time = 0, $sort_by = 'l.log_time DESC', $keywords = '')
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_log_count()
+ {
+ return 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_valid_offset()
+ {
+ return 0;
+ }
+}
diff --git a/phpBB/phpbb/log/log.php b/phpBB/phpbb/log/log.php
index 8f199cd931..5333fe2bdf 100644
--- a/phpBB/phpbb/log/log.php
+++ b/phpBB/phpbb/log/log.php
@@ -27,7 +27,7 @@ class log implements \phpbb\log\log_interface
/**
* An array with the disabled log types. Logs of such types will not be
- * added when add_log() is called.
+ * added when add() is called.
* @var array
*/
protected $disabled_types;
@@ -223,7 +223,7 @@ class log implements \phpbb\log\log_interface
return false;
}
- if ($log_time == false)
+ if ($log_time === false)
{
$log_time = time();
}
@@ -249,10 +249,13 @@ class log implements \phpbb\log\log_interface
unset($additional_data['forum_id']);
$topic_id = isset($additional_data['topic_id']) ? (int) $additional_data['topic_id'] : 0;
unset($additional_data['topic_id']);
+ $post_id = isset($additional_data['post_id']) ? (int) $additional_data['post_id'] : 0;
+ unset($additional_data['post_id']);
$sql_ary += array(
'log_type' => LOG_MOD,
'forum_id' => $forum_id,
'topic_id' => $topic_id,
+ 'post_id' => $post_id,
'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
);
break;
@@ -388,7 +391,7 @@ class log implements \phpbb\log\log_interface
{
$sql_where .= ' AND ';
- if (is_array($field_value) && sizeof($field_value) == 2 && !is_array($field_value[1]))
+ if (is_array($field_value) && count($field_value) == 2 && !is_array($field_value[1]))
{
$sql_where .= $field . ' ' . $field_value[0] . ' ' . $field_value[1];
}
@@ -643,6 +646,7 @@ class log implements \phpbb\log\log_interface
'time' => (int) $row['log_time'],
'forum_id' => (int) $row['forum_id'],
'topic_id' => (int) $row['topic_id'],
+ 'post_id' => (int) $row['post_id'],
'viewforum' => ($row['forum_id'] && $this->auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$this->phpbb_root_path}viewforum.{$this->php_ext}", 'f=' . $row['forum_id']) : false,
'action' => (isset($this->user->lang[$row['log_operation']])) ? $row['log_operation'] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
@@ -685,9 +689,9 @@ class log implements \phpbb\log\log_interface
}
}
- if (($num_args - sizeof($log_data_ary)) > 0)
+ if (($num_args - count($log_data_ary)) > 0)
{
- $log_data_ary = array_merge($log_data_ary, array_fill(0, $num_args - sizeof($log_data_ary), ''));
+ $log_data_ary = array_merge($log_data_ary, array_fill(0, $num_args - count($log_data_ary), ''));
}
$lang_arguments = array_merge(array($log[$i]['action']), $log_data_ary);
@@ -736,18 +740,19 @@ class log implements \phpbb\log\log_interface
$vars = array('log', 'topic_id_list', 'reportee_id_list');
extract($this->dispatcher->trigger_event('core.get_logs_get_additional_data', compact($vars)));
- if (sizeof($topic_id_list))
+ if (count($topic_id_list))
{
$topic_auth = $this->get_topic_auth($topic_id_list);
foreach ($log as $key => $row)
{
$log[$key]['viewtopic'] = (isset($topic_auth['f_read'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", 'f=' . $topic_auth['f_read'][$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
+ $log[$key]['viewpost'] = (isset($topic_auth['f_read'][$row['topic_id']]) && $row['post_id']) ? append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", 'f=' . $topic_auth['f_read'][$row['topic_id']] . '&amp;t=' . $row['topic_id'] . '&amp;p=' . $row['post_id'] . '#p' . $row['post_id']) : false;
$log[$key]['viewlogs'] = (isset($topic_auth['m_'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}mcp.{$this->php_ext}", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $this->user->session_id) : false;
}
}
- if (sizeof($reportee_id_list))
+ if (count($reportee_id_list))
{
$reportee_data_list = $this->get_reportee_data($reportee_id_list);
@@ -833,7 +838,7 @@ class log implements \phpbb\log\log_interface
$keywords_pattern = array();
// Build pattern and keywords...
- for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
+ for ($i = 0, $num_keywords = count($keywords); $i < $num_keywords; $i++)
{
$keywords_pattern[] = preg_quote($keywords[$i], '#');
$keywords[$i] = $this->db->sql_like_expression($this->db->get_any_char() . $keywords[$i] . $this->db->get_any_char());
@@ -928,6 +933,20 @@ class log implements \phpbb\log\log_interface
$forum_auth['f_read'][$row['topic_id']] = $row['forum_id'];
}
+ /**
+ * Allow modifying SQL query after topic data is retrieved (inside loop).
+ *
+ * @event core.phpbb_log_get_topic_auth_sql_after
+ * @var array forum_auth Forum permissions
+ * @var array row One row of data from SQL query
+ * @since 3.2.2-RC1
+ */
+ $vars = array(
+ 'forum_auth',
+ 'row',
+ );
+ extract($this->dispatcher->trigger_event('core.phpbb_log_get_topic_auth_sql_after', compact($vars)));
+
if ($this->auth->acl_gets('a_', 'm_', $row['forum_id']))
{
$forum_auth['m_'][$row['topic_id']] = $row['forum_id'];
diff --git a/phpBB/phpbb/log/log_interface.php b/phpBB/phpbb/log/log_interface.php
index 5932f722aa..86286e6f88 100644
--- a/phpBB/phpbb/log/log_interface.php
+++ b/phpBB/phpbb/log/log_interface.php
@@ -32,8 +32,8 @@ interface log_interface
* Disable log
*
* This function allows disabling the log system or parts of it, for this
- * page call. When add_log is called and the type is disabled,
- * the log will not be added to the database.
+ * page call. When add() is called and the type is disabled, the log will
+ * not be added to the database.
*
* @param mixed $type The log type we want to disable. Empty to
* disable all logs. Can also be an array of types.
@@ -57,12 +57,12 @@ interface log_interface
/**
* Adds a log entry to the database
*
- * @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
- * @param int $user_id User ID of the user
- * @param string $log_ip IP address of the user
- * @param string $log_operation Name of the operation
- * @param int $log_time Timestamp when the log entry was added, if empty time() will be used
- * @param array $additional_data More arguments can be added, depending on the log_type
+ * @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+ * @param int $user_id User ID of the user
+ * @param string $log_ip IP address of the user
+ * @param string $log_operation Name of the operation
+ * @param int|bool $log_time Timestamp when the log entry was added. If false, time() will be used
+ * @param array $additional_data More arguments can be added, depending on the log_type
*
* @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
*/
diff --git a/phpBB/phpbb/log/null.php b/phpBB/phpbb/log/null.php
deleted file mode 100644
index baa78895ea..0000000000
--- a/phpBB/phpbb/log/null.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-namespace phpbb\log;
-
-/**
-* Null logger
-*/
-class null implements log_interface
-{
- /**
- * {@inheritdoc}
- */
- public function is_enabled($type = '')
- {
- return false;
- }
-
- /**
- * {@inheritdoc}
- */
- public function disable($type = '')
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function enable($type = '')
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function add($mode, $user_id, $log_ip, $log_operation, $log_time = false, $additional_data = array())
- {
- return false;
- }
-
- /**
- * {@inheritdoc}
- */
- public function delete($mode, $conditions = array())
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function get_logs($mode, $count_logs = true, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $log_time = 0, $sort_by = 'l.log_time DESC', $keywords = '')
- {
- return array();
- }
-
- /**
- * {@inheritdoc}
- */
- public function get_log_count()
- {
- return 0;
- }
-
- /**
- * {@inheritdoc}
- */
- public function get_valid_offset()
- {
- return 0;
- }
-}
diff --git a/phpBB/phpbb/message/admin_form.php b/phpBB/phpbb/message/admin_form.php
index 96b8d3499e..ae1c1d8614 100644
--- a/phpBB/phpbb/message/admin_form.php
+++ b/phpBB/phpbb/message/admin_form.php
@@ -22,6 +22,9 @@ class admin_form extends form
/** @var \phpbb\config\db_text */
protected $config_text;
+ /** @var \phpbb\event\dispatcher_interface */
+ protected $dispatcher;
+
/** @var string */
protected $subject;
/** @var string */
@@ -37,13 +40,15 @@ class admin_form extends form
* @param \phpbb\config\db_text $config_text
* @param \phpbb\db\driver\driver_interface $db
* @param \phpbb\user $user
+ * @param \phpbb\event\dispatcher_interface $dispatcher
* @param string $phpbb_root_path
* @param string $phpEx
*/
- public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\config\db_text $config_text, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, $phpbb_root_path, $phpEx)
+ public function __construct(\phpbb\auth\auth $auth, \phpbb\config\config $config, \phpbb\config\db_text $config_text, \phpbb\db\driver\driver_interface $db, \phpbb\user $user, \phpbb\event\dispatcher_interface $dispatcher, $phpbb_root_path, $phpEx)
{
parent::__construct($auth, $config, $db, $user, $phpbb_root_path, $phpEx);
$this->config_text = $config_text;
+ $this->dispatcher = $dispatcher;
}
/**
@@ -91,6 +96,29 @@ class admin_form extends form
$this->errors[] = $this->user->lang['EMPTY_MESSAGE_EMAIL'];
}
+ $subject = $this->subject;
+ $body = $this->body;
+ $errors = $this->errors;
+
+ /**
+ * You can use this event to modify subject and/or body and add new errors.
+ *
+ * @event core.message_admin_form_submit_before
+ * @var string subject Message subject
+ * @var string body Message body
+ * @var array errors Form errors
+ * @since 3.2.6-RC1
+ */
+ $vars = [
+ 'subject',
+ 'body',
+ 'errors',
+ ];
+ extract($this->dispatcher->trigger_event('core.message_admin_form_submit_before', compact($vars)));
+ $this->subject = $subject;
+ $this->body = $body;
+ $this->errors = $errors;
+
if ($this->user->data['is_registered'])
{
$this->message->set_sender_from_user($this->user);
diff --git a/phpBB/phpbb/message/form.php b/phpBB/phpbb/message/form.php
index 21d4de0b4d..6573a04f8b 100644
--- a/phpBB/phpbb/message/form.php
+++ b/phpBB/phpbb/message/form.php
@@ -136,10 +136,10 @@ abstract class form
{
if (!check_form_key('memberlist_email'))
{
- $this->errors[] = 'FORM_INVALID';
+ $this->errors[] = $this->user->lang('FORM_INVALID');
}
- if (!sizeof($this->errors))
+ if (!count($this->errors))
{
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_emailtime = ' . time() . '
@@ -169,7 +169,7 @@ abstract class form
add_form_key('memberlist_email');
$template->assign_vars(array(
- 'ERROR_MESSAGE' => (sizeof($this->errors)) ? implode('<br />', $this->errors) : '',
+ 'ERROR_MESSAGE' => (count($this->errors)) ? implode('<br />', $this->errors) : '',
));
}
}
diff --git a/phpBB/phpbb/message/message.php b/phpBB/phpbb/message/message.php
index 5fd24b542e..fa701d1c77 100644
--- a/phpBB/phpbb/message/message.php
+++ b/phpBB/phpbb/message/message.php
@@ -209,7 +209,7 @@ class message
*/
public function cc_sender()
{
- if (!sizeof($this->recipients))
+ if (!count($this->recipients))
{
trigger_error('No email recipients specified');
}
@@ -238,7 +238,7 @@ class message
*/
public function send(\messenger $messenger, $contact)
{
- if (!sizeof($this->recipients))
+ if (!count($this->recipients))
{
return;
}
@@ -271,7 +271,7 @@ class message
'MESSAGE' => htmlspecialchars_decode($this->body))
);
- if (sizeof($this->template_vars))
+ if (count($this->template_vars))
{
$messenger->assign_vars($this->template_vars);
}
diff --git a/phpBB/phpbb/message/topic_form.php b/phpBB/phpbb/message/topic_form.php
index 174643bb81..dbb883c142 100644
--- a/phpBB/phpbb/message/topic_form.php
+++ b/phpBB/phpbb/message/topic_form.php
@@ -71,6 +71,14 @@ class topic_form extends form
if (!$this->auth->acl_get('f_read', $this->topic_row['forum_id']))
{
+ if ($this->user->data['user_id'] != ANONYMOUS)
+ {
+ send_status_line(403, 'Forbidden');
+ }
+ else
+ {
+ send_status_line(401, 'Unauthorized');
+ }
return 'SORRY_AUTH_READ';
}
diff --git a/phpBB/phpbb/module/exception/module_exception.php b/phpBB/phpbb/module/exception/module_exception.php
new file mode 100644
index 0000000000..8ad75112bc
--- /dev/null
+++ b/phpBB/phpbb/module/exception/module_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\module\exception;
+
+class module_exception extends \phpbb\exception\runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/module/exception/module_not_found_exception.php b/phpBB/phpbb/module/exception/module_not_found_exception.php
new file mode 100644
index 0000000000..2d485e7b35
--- /dev/null
+++ b/phpBB/phpbb/module/exception/module_not_found_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\module\exception;
+
+class module_not_found_exception extends module_exception
+{
+
+}
diff --git a/phpBB/phpbb/module/module_manager.php b/phpBB/phpbb/module/module_manager.php
new file mode 100644
index 0000000000..00df33f62f
--- /dev/null
+++ b/phpBB/phpbb/module/module_manager.php
@@ -0,0 +1,564 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\module;
+
+use phpbb\module\exception\module_exception;
+use phpbb\module\exception\module_not_found_exception;
+
+class module_manager
+{
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\extension\manager
+ */
+ protected $extension_manager;
+
+ /**
+ * @var string
+ */
+ protected $modules_table;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\cache\driver\driver_interface $cache Cache driver
+ * @param \phpbb\db\driver\driver_interface $db Database driver
+ * @param \phpbb\extension\manager $ext_manager Extension manager
+ * @param string $modules_table Module database table's name
+ * @param string $phpbb_root_path Path to phpBB's root
+ * @param string $php_ext Extension of PHP files
+ */
+ public function __construct(\phpbb\cache\driver\driver_interface $cache, \phpbb\db\driver\driver_interface $db, \phpbb\extension\manager $ext_manager, $modules_table, $phpbb_root_path, $php_ext)
+ {
+ $this->cache = $cache;
+ $this->db = $db;
+ $this->extension_manager = $ext_manager;
+ $this->modules_table = $modules_table;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Get row for specified module
+ *
+ * @param int $module_id ID of the module
+ * @param string $module_class Class of the module (acp, ucp, mcp etc...)
+ *
+ * @return array Array of data fetched from the database
+ *
+ * @throws \phpbb\module\exception\module_not_found_exception When there is no module with $module_id
+ */
+ public function get_module_row($module_id, $module_class)
+ {
+ $module_id = (int) $module_id;
+
+ $sql = 'SELECT *
+ FROM ' . $this->modules_table . "
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND module_id = $module_id";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$row)
+ {
+ throw new module_not_found_exception('NO_MODULE');
+ }
+
+ return $row;
+ }
+
+ /**
+ * Get available module information from module files
+ *
+ * @param string $module_class Class of the module (acp, ucp, mcp etc...)
+ * @param string $module ID of module
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
+ *
+ * @return array Array with module information gathered from module info files.
+ */
+ public function get_module_infos($module_class, $module = '', $use_all_available = false)
+ {
+ $directory = $this->phpbb_root_path . 'includes/' . $module_class . '/info/';
+ $fileinfo = array();
+
+ $finder = $this->extension_manager->get_finder($use_all_available);
+
+ $modules = $finder
+ ->extension_suffix('_module')
+ ->extension_directory("/$module_class")
+ ->core_path("includes/$module_class/info/")
+ ->core_prefix($module_class . '_')
+ ->get_classes(true);
+
+ foreach ($modules as $cur_module)
+ {
+ // Skip entries we do not need if we know the module we are
+ // looking for
+ if ($module && strpos(str_replace('\\', '_', $cur_module), $module) === false && $module !== $cur_module)
+ {
+ continue;
+ }
+
+ $info_class = preg_replace('/_module$/', '_info', $cur_module);
+
+ // If the class does not exist it might be following the old
+ // format. phpbb_acp_info_acp_foo needs to be turned into
+ // acp_foo_info and the respective file has to be included
+ // manually because it does not support auto loading
+ $old_info_class_file = str_replace("phpbb_{$module_class}_info_", '', $cur_module);
+ $old_info_class = $old_info_class_file . '_info';
+
+ if (class_exists($old_info_class))
+ {
+ $info_class = $old_info_class;
+ }
+ else if (!class_exists($info_class))
+ {
+ $info_class = $old_info_class;
+
+ // need to check class exists again because previous checks triggered autoloading
+ if (!class_exists($info_class) && file_exists($directory . $old_info_class_file . '.' . $this->php_ext))
+ {
+ include($directory . $old_info_class_file . '.' . $this->php_ext);
+ }
+ }
+
+ if (class_exists($info_class))
+ {
+ $info = new $info_class();
+ $module_info = $info->module();
+
+ $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $cur_module;
+
+ $fileinfo[$main_class] = $module_info;
+ }
+ }
+
+ ksort($fileinfo);
+
+ return $fileinfo;
+ }
+
+ /**
+ * Get module branch
+ *
+ * @param int $module_id ID of the module
+ * @param string $module_class Class of the module (acp, ucp, mcp etc...)
+ * @param string $type Type of branch (Expected values: all, parents or children)
+ * @param bool $include_module Whether or not to include the specified module with $module_id
+ *
+ * @return array Returns an array containing the modules in the specified branch type.
+ */
+ public function get_module_branch($module_id, $module_class, $type = 'all', $include_module = true)
+ {
+ $module_id = (int) $module_id;
+
+ switch ($type)
+ {
+ case 'parents':
+ $condition = 'm1.left_id BETWEEN m2.left_id AND m2.right_id';
+ break;
+
+ case 'children':
+ $condition = 'm2.left_id BETWEEN m1.left_id AND m1.right_id';
+ break;
+
+ default:
+ $condition = 'm2.left_id BETWEEN m1.left_id AND m1.right_id OR m1.left_id BETWEEN m2.left_id AND m2.right_id';
+ break;
+ }
+
+ $rows = array();
+
+ $sql = 'SELECT m2.*
+ FROM ' . $this->modules_table . ' m1
+ LEFT JOIN ' . $this->modules_table . " m2 ON ($condition)
+ WHERE m1.module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND m2.module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND m1.module_id = $module_id
+ ORDER BY m2.left_id";
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (!$include_module && $row['module_id'] == $module_id)
+ {
+ continue;
+ }
+
+ $rows[] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $rows;
+ }
+
+ /**
+ * Remove modules cache file
+ *
+ * @param string $module_class Class of the module (acp, ucp, mcp etc...)
+ */
+ public function remove_cache_file($module_class)
+ {
+ // Sanitise for future path use, it's escaped as appropriate for queries
+ $cache_class = str_replace(array('.', '/', '\\'), '', basename($module_class));
+ $this->cache->destroy('_modules_' . $cache_class);
+ $this->cache->destroy('sql', $this->modules_table);
+ }
+
+ /**
+ * Update/Add module
+ *
+ * @param array &$module_data The module data
+ *
+ * @throws \phpbb\module\exception\module_not_found_exception When parent module or the category is not exist
+ */
+ public function update_module_data(&$module_data)
+ {
+ if (!isset($module_data['module_id']))
+ {
+ // no module_id means we're creating a new category/module
+ if ($module_data['parent_id'])
+ {
+ $sql = 'SELECT left_id, right_id
+ FROM ' . $this->modules_table . "
+ WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
+ AND module_id = " . (int) $module_data['parent_id'];
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$row)
+ {
+ throw new module_not_found_exception('PARENT_NOT_EXIST');
+ }
+
+ // Workaround
+ $row['left_id'] = (int) $row['left_id'];
+ $row['right_id'] = (int) $row['right_id'];
+
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET left_id = left_id + 2, right_id = right_id + 2
+ WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
+ AND left_id > {$row['right_id']}";
+ $this->db->sql_query($sql);
+
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET right_id = right_id + 2
+ WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
+ AND {$row['left_id']} BETWEEN left_id AND right_id";
+ $this->db->sql_query($sql);
+
+ $module_data['left_id'] = (int) $row['right_id'];
+ $module_data['right_id'] = (int) $row['right_id'] + 1;
+ }
+ else
+ {
+ $sql = 'SELECT MAX(right_id) AS right_id
+ FROM ' . $this->modules_table . "
+ WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $module_data['left_id'] = (int) $row['right_id'] + 1;
+ $module_data['right_id'] = (int) $row['right_id'] + 2;
+ }
+
+ $sql = 'INSERT INTO ' . $this->modules_table . ' ' . $this->db->sql_build_array('INSERT', $module_data);
+ $this->db->sql_query($sql);
+
+ $module_data['module_id'] = $this->db->sql_nextid();
+ }
+ else
+ {
+ $row = $this->get_module_row($module_data['module_id'], $module_data['module_class']);
+
+ if ($module_data['module_basename'] && !$row['module_basename'])
+ {
+ // we're turning a category into a module
+ $branch = $this->get_module_branch($module_data['module_id'], $module_data['module_class'], 'children', false);
+
+ if (count($branch))
+ {
+ throw new module_not_found_exception('NO_CATEGORY_TO_MODULE');
+ }
+ }
+
+ if ($row['parent_id'] != $module_data['parent_id'])
+ {
+ $this->move_module($module_data['module_id'], $module_data['parent_id'], $module_data['module_class']);
+ }
+
+ $update_ary = $module_data;
+ unset($update_ary['module_id']);
+
+ $sql = 'UPDATE ' . $this->modules_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $update_ary) . "
+ WHERE module_class = '" . $this->db->sql_escape($module_data['module_class']) . "'
+ AND module_id = " . (int) $module_data['module_id'];
+ $this->db->sql_query($sql);
+ }
+ }
+
+ /**
+ * Move module around the tree
+ *
+ * @param int $from_module_id ID of the current parent module
+ * @param int $to_parent_id ID of the target parent module
+ * @param string $module_class Class of the module (acp, ucp, mcp etc...)
+ *
+ * @throws \phpbb\module\exception\module_not_found_exception If the module specified to move modules from does not
+ * have any children.
+ */
+ public function move_module($from_module_id, $to_parent_id, $module_class)
+ {
+ $moved_modules = $this->get_module_branch($from_module_id, $module_class, 'children');
+
+ if (empty($moved_modules))
+ {
+ throw new module_not_found_exception();
+ }
+
+ $from_data = $moved_modules[0];
+ $diff = count($moved_modules) * 2;
+
+ $moved_ids = array();
+ for ($i = 0, $size = count($moved_modules); $i < $size; ++$i)
+ {
+ $moved_ids[] = $moved_modules[$i]['module_id'];
+ }
+
+ // Resync parents
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET right_id = right_id - $diff
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND left_id < " . (int) $from_data['right_id'] . '
+ AND right_id > ' . (int) $from_data['right_id'];
+ $this->db->sql_query($sql);
+
+ // Resync righthand side of tree
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET left_id = left_id - $diff, right_id = right_id - $diff
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND left_id > " . (int) $from_data['right_id'];
+ $this->db->sql_query($sql);
+
+ if ($to_parent_id > 0)
+ {
+ $to_data = $this->get_module_row($to_parent_id, $module_class);
+
+ // Resync new parents
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET right_id = right_id + $diff
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND " . (int) $to_data['right_id'] . ' BETWEEN left_id AND right_id
+ AND ' . $this->db->sql_in_set('module_id', $moved_ids, true);
+ $this->db->sql_query($sql);
+
+ // Resync the righthand side of the tree
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET left_id = left_id + $diff, right_id = right_id + $diff
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND left_id > " . (int) $to_data['right_id'] . '
+ AND ' . $this->db->sql_in_set('module_id', $moved_ids, true);
+ $this->db->sql_query($sql);
+
+ // Resync moved branch
+ $to_data['right_id'] += $diff;
+ if ($to_data['right_id'] > $from_data['right_id'])
+ {
+ $diff = '+ ' . ($to_data['right_id'] - $from_data['right_id'] - 1);
+ }
+ else
+ {
+ $diff = '- ' . abs($to_data['right_id'] - $from_data['right_id'] - 1);
+ }
+ }
+ else
+ {
+ $sql = 'SELECT MAX(right_id) AS right_id
+ FROM ' . $this->modules_table . "
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND " . $this->db->sql_in_set('module_id', $moved_ids, true);
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $diff = '+ ' . (int) ($row['right_id'] - $from_data['left_id'] + 1);
+ }
+
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET left_id = left_id $diff, right_id = right_id $diff
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND " . $this->db->sql_in_set('module_id', $moved_ids);
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Remove module from tree
+ *
+ * @param int $module_id ID of the module to delete
+ * @param string $module_class Class of the module (acp, ucp, mcp etc...)
+ *
+ * @throws \phpbb\module\exception\module_exception When the specified module cannot be removed
+ */
+ public function delete_module($module_id, $module_class)
+ {
+ $module_id = (int) $module_id;
+
+ $row = $this->get_module_row($module_id, $module_class);
+
+ $branch = $this->get_module_branch($module_id, $module_class, 'children', false);
+
+ if (count($branch))
+ {
+ throw new module_exception('CANNOT_REMOVE_MODULE');
+ }
+
+ // If not move
+ $diff = 2;
+ $sql = 'DELETE FROM ' . $this->modules_table . "
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND module_id = $module_id";
+ $this->db->sql_query($sql);
+
+ $row['right_id'] = (int) $row['right_id'];
+ $row['left_id'] = (int) $row['left_id'];
+
+ // Resync tree
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET right_id = right_id - $diff
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND left_id < {$row['right_id']} AND right_id > {$row['right_id']}";
+ $this->db->sql_query($sql);
+
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET left_id = left_id - $diff, right_id = right_id - $diff
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND left_id > {$row['right_id']}";
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * Move module position by $steps up/down
+ *
+ * @param array $module_row Array of module data
+ * @param string $module_class Class of the module (acp, ucp, mcp etc...)
+ * @param string $action Direction of moving (valid values: move_up or move_down)
+ * @param int $steps Number of steps to move module
+ *
+ * @return string Returns the language name of the module
+ *
+ * @throws \phpbb\module\exception\module_not_found_exception When the specified module does not exists
+ */
+ public function move_module_by($module_row, $module_class, $action = 'move_up', $steps = 1)
+ {
+ /**
+ * Fetch all the siblings between the module's current spot
+ * and where we want to move it to. If there are less than $steps
+ * siblings between the current spot and the target then the
+ * module will move as far as possible
+ */
+ $sql = 'SELECT module_id, left_id, right_id, module_langname
+ FROM ' . $this->modules_table . "
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND parent_id = " . (int) $module_row['parent_id'] . '
+ AND ' . (($action == 'move_up') ? 'right_id < ' . (int) $module_row['right_id'] . ' ORDER BY right_id DESC' : 'left_id > ' . (int) $module_row['left_id'] . ' ORDER BY left_id ASC');
+ $result = $this->db->sql_query_limit($sql, $steps);
+
+ $target = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $target = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ if (!count($target))
+ {
+ // The module is already on top or bottom
+ throw new module_not_found_exception();
+ }
+
+ /**
+ * $left_id and $right_id define the scope of the nodes that are affected by the move.
+ * $diff_up and $diff_down are the values to substract or add to each node's left_id
+ * and right_id in order to move them up or down.
+ * $move_up_left and $move_up_right define the scope of the nodes that are moving
+ * up. Other nodes in the scope of ($left_id, $right_id) are considered to move down.
+ */
+ if ($action == 'move_up')
+ {
+ $left_id = (int) $target['left_id'];
+ $right_id = (int) $module_row['right_id'];
+
+ $diff_up = (int) ($module_row['left_id'] - $target['left_id']);
+ $diff_down = (int) ($module_row['right_id'] + 1 - $module_row['left_id']);
+
+ $move_up_left = (int) $module_row['left_id'];
+ $move_up_right = (int) $module_row['right_id'];
+ }
+ else
+ {
+ $left_id = (int) $module_row['left_id'];
+ $right_id = (int) $target['right_id'];
+
+ $diff_up = (int) ($module_row['right_id'] + 1 - $module_row['left_id']);
+ $diff_down = (int) ($target['right_id'] - $module_row['right_id']);
+
+ $move_up_left = (int) ($module_row['right_id'] + 1);
+ $move_up_right = (int) $target['right_id'];
+ }
+
+ // Now do the dirty job
+ $sql = 'UPDATE ' . $this->modules_table . "
+ SET left_id = left_id + CASE
+ WHEN left_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
+ ELSE {$diff_down}
+ END,
+ right_id = right_id + CASE
+ WHEN right_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
+ ELSE {$diff_down}
+ END
+ WHERE module_class = '" . $this->db->sql_escape($module_class) . "'
+ AND left_id BETWEEN {$left_id} AND {$right_id}
+ AND right_id BETWEEN {$left_id} AND {$right_id}";
+ $this->db->sql_query($sql);
+
+ $this->remove_cache_file($module_class);
+
+ return $target['module_langname'];
+ }
+}
diff --git a/phpBB/phpbb/notification/exception.php b/phpBB/phpbb/notification/exception.php
index 83c4526df7..e416438061 100644
--- a/phpBB/phpbb/notification/exception.php
+++ b/phpBB/phpbb/notification/exception.php
@@ -17,10 +17,6 @@ namespace phpbb\notification;
* Notifications exception
*/
-class exception extends \Exception
+class exception extends \phpbb\exception\runtime_exception
{
- public function __toString()
- {
- return $this->getMessage();
- }
}
diff --git a/phpBB/phpbb/notification/manager.php b/phpBB/phpbb/notification/manager.php
index f5663f4b34..52c650df5d 100644
--- a/phpBB/phpbb/notification/manager.php
+++ b/phpBB/phpbb/notification/manager.php
@@ -26,7 +26,7 @@ class manager
/** @var array */
protected $subscription_types;
- /** @var array */
+ /** @var method\method_interface[] */
protected $notification_methods;
/** @var ContainerInterface */
@@ -35,9 +35,6 @@ class manager
/** @var \phpbb\user_loader */
protected $user_loader;
- /** @var \phpbb\config\config */
- protected $config;
-
/** @var \phpbb\event\dispatcher_interface */
protected $phpbb_dispatcher;
@@ -47,22 +44,16 @@ class manager
/** @var \phpbb\cache\service */
protected $cache;
+ /** @var \phpbb\language\language */
+ protected $language;
+
/** @var \phpbb\user */
protected $user;
/** @var string */
- protected $phpbb_root_path;
-
- /** @var string */
- protected $php_ext;
-
- /** @var string */
protected $notification_types_table;
/** @var string */
- protected $notifications_table;
-
- /** @var string */
protected $user_notifications_table;
/**
@@ -72,43 +63,37 @@ class manager
* @param array $notification_methods
* @param ContainerInterface $phpbb_container
* @param \phpbb\user_loader $user_loader
- * @param \phpbb\config\config $config
* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher
* @param \phpbb\db\driver\driver_interface $db
* @param \phpbb\cache\service $cache
+ * @param \phpbb\language\language $language
* @param \phpbb\user $user
- * @param string $phpbb_root_path
- * @param string $php_ext
* @param string $notification_types_table
- * @param string $notifications_table
* @param string $user_notifications_table
*
* @return \phpbb\notification\manager
*/
- public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\config\config $config, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
+ public function __construct($notification_types, $notification_methods, ContainerInterface $phpbb_container, \phpbb\user_loader $user_loader, \phpbb\event\dispatcher_interface $phpbb_dispatcher, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\language\language $language, \phpbb\user $user, $notification_types_table, $user_notifications_table)
{
$this->notification_types = $notification_types;
$this->notification_methods = $notification_methods;
$this->phpbb_container = $phpbb_container;
$this->user_loader = $user_loader;
- $this->config = $config;
$this->phpbb_dispatcher = $phpbb_dispatcher;
$this->db = $db;
$this->cache = $cache;
+ $this->language = $language;
$this->user = $user;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
-
$this->notification_types_table = $notification_types_table;
- $this->notifications_table = $notifications_table;
$this->user_notifications_table = $user_notifications_table;
}
/**
- * Load the user's notifications
+ * Load the user's notifications for a given method
*
+ * @param string $method_name
* @param array $options Optional options to control what notifications are loaded
* notification_id Notification id to load (or array of notification ids)
* user_id User id to load notifications for (Default: $user->data['user_id'])
@@ -123,27 +108,21 @@ class manager
* 'notifications' array of notification type objects
* 'unread_count' number of unread notifications the user has if count_unread is true in the options
* 'total_count' number of notifications the user has if count_total is true in the options
+ * @throws \phpbb\notification\exception when the method doesn't refer to a class extending \phpbb\notification\method\method_interface
*/
- public function load_notifications(array $options = array())
+ public function load_notifications($method_name, array $options = array())
{
- // Merge default options
- $options = array_merge(array(
- 'notification_id' => false,
- 'user_id' => $this->user->data['user_id'],
- 'order_by' => 'notification_time',
- 'order_dir' => 'DESC',
- 'limit' => 0,
- 'start' => 0,
- 'all_unread' => false,
- 'count_unread' => false,
- 'count_total' => false,
- ), $options);
-
- // If all_unread, count_unread must be true
- $options['count_unread'] = ($options['all_unread']) ? true : $options['count_unread'];
+ $method = $this->get_method_class($method_name);
- // Anonymous users and bots never receive notifications
- if ($options['user_id'] == $this->user->data['user_id'] && ($this->user->data['user_id'] == ANONYMOUS || $this->user->data['user_type'] == USER_IGNORE))
+ if (! $method instanceof \phpbb\notification\method\method_interface)
+ {
+ throw new \phpbb\notification\exception($this->language->lang('NOTIFICATION_METHOD_INVALID', $method_name));
+ }
+ else if ($method->is_available())
+ {
+ return $method->load_notifications($options);
+ }
+ else
{
return array(
'notifications' => array(),
@@ -151,172 +130,112 @@ class manager
'total_count' => 0,
);
}
+ }
- $notifications = $user_ids = array();
- $load_special = array();
- $total_count = $unread_count = 0;
+ /**
+ * Mark notifications read or unread for all available methods
+ *
+ * @param bool|string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to mark read for all item types
+ * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
+ * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ *
+ * @deprecated since 3.2
+ */
+ public function mark_notifications_read($notification_type_name, $item_id, $user_id, $time = false)
+ {
+ $this->mark_notifications($notification_type_name, $item_id, $user_id, $time);
+ }
- if ($options['count_unread'])
+ /**
+ * Mark notifications read or unread for all available methods
+ *
+ * @param bool|string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to mark read for all item types
+ * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
+ * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
+ */
+ public function mark_notifications($notification_type_name, $item_id, $user_id, $time = false, $mark_read = true)
+ {
+ if (is_array($notification_type_name))
{
- // Get the total number of unread notifications
- $sql = 'SELECT COUNT(n.notification_id) AS unread_count
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.user_id = ' . (int) $options['user_id'] . '
- AND n.notification_read = 0
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1';
- $result = $this->db->sql_query($sql);
- $unread_count = (int) $this->db->sql_fetchfield('unread_count');
- $this->db->sql_freeresult($result);
+ $notification_type_id = $this->get_notification_type_ids($notification_type_name);
}
-
- if ($options['count_total'])
+ else if ($notification_type_name !== false)
{
- // Get the total number of notifications
- $sql = 'SELECT COUNT(n.notification_id) AS total_count
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.user_id = ' . (int) $options['user_id'] . '
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1';
- $result = $this->db->sql_query($sql);
- $total_count = (int) $this->db->sql_fetchfield('total_count');
- $this->db->sql_freeresult($result);
+ $notification_type_id = $this->get_notification_type_id($notification_type_name);
}
-
- if (!$options['count_total'] || $total_count)
+ else
{
- $rowset = array();
- $selected_unread_count = 0;
-
- // Get the main notifications
- $sql = 'SELECT n.*, nt.notification_type_name
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.user_id = ' . (int) $options['user_id'] .
- (($options['notification_id']) ? ' AND ' . $this->db->sql_in_set('n.notification_id', $options['notification_id']) : '') . '
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1
- ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
- $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $rowset[$row['notification_id']] = $row;
- $selected_unread_count += (int) !$row['notification_read'];
- }
- $this->db->sql_freeresult($result);
-
- // Get all unread notifications
- if ($selected_unread_count < $unread_count && $options['all_unread'] && !empty($rowset))
- {
- $sql = 'SELECT n.*, nt.notification_type_name
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.user_id = ' . (int) $options['user_id'] . '
- AND n.notification_read = 0
- AND ' . $this->db->sql_in_set('n.notification_id', array_keys($rowset), true) . '
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1
- ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
- $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $rowset[$row['notification_id']] = $row;
- }
- $this->db->sql_freeresult($result);
- }
-
- foreach ($rowset as $row)
- {
- $notification = $this->get_item_type_class($row['notification_type_name'], $row);
-
- // Array of user_ids to query all at once
- $user_ids = array_merge($user_ids, $notification->users_to_query());
-
- // Some notification types also require querying additional tables themselves
- if (!isset($load_special[$row['notification_type_name']]))
- {
- $load_special[$row['notification_type_name']] = array();
- }
- $load_special[$row['notification_type_name']] = array_merge($load_special[$row['notification_type_name']], $notification->get_load_special());
-
- $notifications[$row['notification_id']] = $notification;
- }
-
- $this->user_loader->load_users($user_ids);
-
- // Allow each type to load its own special items
- foreach ($load_special as $item_type => $data)
- {
- $item_class = $this->get_item_type_class($item_type);
-
- $item_class->load_special($data, $notifications);
- }
+ $notification_type_id = false;
}
- return array(
- 'notifications' => $notifications,
- 'unread_count' => $unread_count,
- 'total_count' => $total_count,
- );
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method)
+ {
+ $method->mark_notifications($notification_type_id, $item_id, $user_id, $time, $mark_read);
+ }
}
/**
- * Mark notifications read
- *
- * @param bool|string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to mark read for all item types
- * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
- * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
- * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
- */
- public function mark_notifications_read($notification_type_name, $item_id, $user_id, $time = false)
+ * Mark notifications read or unread from a parent identifier for all available methods
+ *
+ * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param bool|int|array $item_parent_id Item parent id or array of item parent ids. False to mark read for all item parent ids
+ * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ *
+ * @deprecated since 3.2
+ */
+ public function mark_notifications_read_by_parent($notification_type_name, $item_parent_id, $user_id, $time = false)
{
- $time = ($time !== false) ? $time : time();
-
- $sql = 'UPDATE ' . $this->notifications_table . "
- SET notification_read = 1
- WHERE notification_time <= " . (int) $time .
- (($notification_type_name !== false) ? ' AND ' . $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : '') .
- (($user_id !== false) ? ' AND ' . $this->db->sql_in_set('user_id', $user_id) : '') .
- (($item_id !== false) ? ' AND ' . $this->db->sql_in_set('item_id', $item_id) : '');
- $this->db->sql_query($sql);
+ $this->mark_notifications_by_parent($notification_type_name, $item_parent_id, $user_id, $time);
}
/**
- * Mark notifications read from a parent identifier
+ * Mark notifications read or unread from a parent identifier for all available methods
*
* @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
* @param bool|int|array $item_parent_id Item parent id or array of item parent ids. False to mark read for all item parent ids
* @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
* @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
*/
- public function mark_notifications_read_by_parent($notification_type_name, $item_parent_id, $user_id, $time = false)
+ public function mark_notifications_by_parent($notification_type_name, $item_parent_id, $user_id, $time = false, $mark_read = true)
{
- $time = ($time !== false) ? $time : time();
-
- $sql = 'UPDATE ' . $this->notifications_table . "
- SET notification_read = 1
- WHERE notification_time <= " . (int) $time .
- (($notification_type_name !== false) ? ' AND ' . $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : '') .
- (($item_parent_id !== false) ? ' AND ' . $this->db->sql_in_set('item_parent_id', $item_parent_id, false, true) : '') .
- (($user_id !== false) ? ' AND ' . $this->db->sql_in_set('user_id', $user_id) : '');
- $this->db->sql_query($sql);
+ if (is_array($notification_type_name))
+ {
+ $notification_type_id = $this->get_notification_type_ids($notification_type_name);
+ }
+ else
+ {
+ $notification_type_id = $this->get_notification_type_id($notification_type_name);
+ }
+
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method)
+ {
+ $method->mark_notifications_by_parent($notification_type_id, $item_parent_id, $user_id, $time, $mark_read);
+ }
}
/**
- * Mark notifications read
+ * Mark notifications read or unread for a given method
*
+ * @param string $method_name
* @param int|array $notification_id Notification id or array of notification ids.
* @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
*/
- public function mark_notifications_read_by_id($notification_id, $time = false)
+ public function mark_notifications_by_id($method_name, $notification_id, $time = false, $mark_read = true)
{
- $time = ($time !== false) ? $time : time();
+ $method = $this->get_method_class($method_name);
- $sql = 'UPDATE ' . $this->notifications_table . "
- SET notification_read = 1
- WHERE notification_time <= " . (int) $time . '
- AND ' . $this->db->sql_in_set('notification_id', $notification_id);
- $this->db->sql_query($sql);
+ if ($method instanceof \phpbb\notification\method\method_interface && $method->is_available())
+ {
+ $method->mark_notifications_by_id($notification_id, $time, $mark_read);
+ }
}
/**
@@ -350,8 +269,6 @@ class manager
return $notified_users;
}
- $item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
-
// find out which users want to receive this type of notification
$notify_users = $this->get_item_type_class($notification_type_name)->find_users_for_notification($data, $options);
@@ -404,27 +321,25 @@ class manager
$item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
$user_ids = array();
- $notification_objects = $notification_methods = array();
+ $notification_methods = array();
// Never send notifications to the anonymous user!
unset($notify_users[ANONYMOUS]);
// Make sure not to send new notifications to users who've already been notified about this item
// This may happen when an item was added, but now new users are able to see the item
- $sql = 'SELECT n.user_id
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.notification_type_id = ' . (int) $notification_type_id . '
- AND n.item_id = ' . (int) $item_id . '
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1';
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
+ // We remove each user which was already notified by at least one method.
+ /** @var method\method_interface $method */
+ foreach ($this->get_subscription_methods_instances() as $method)
{
- unset($notify_users[$row['user_id']]);
+ $notified_users = $method->get_notified_users($notification_type_id, array('item_id' => $item_id));
+ foreach ($notified_users as $user => $notifications)
+ {
+ unset($notify_users[$user]);
+ }
}
- $this->db->sql_freeresult($result);
- if (!sizeof($notify_users))
+ if (!count($notify_users))
{
return;
}
@@ -434,8 +349,6 @@ class manager
$pre_create_data = $notification->pre_create_insert_array($data, $notify_users);
unset($notification);
- $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->notifications_table);
-
// Go through each user so we can insert a row in the DB and then notify them by their desired means
foreach ($notify_users as $user => $methods)
{
@@ -443,8 +356,8 @@ class manager
$notification->user_id = (int) $user;
- // Insert notification row using buffer.
- $insert_buffer->insert($notification->create_insert_array($data, $pre_create_data));
+ // Generate the insert_array
+ $notification->create_insert_array($data, $pre_create_data);
// Users are needed to send notifications
$user_ids = array_merge($user_ids, $notification->users_to_query());
@@ -452,20 +365,15 @@ class manager
foreach ($methods as $method)
{
// setup the notification methods and add the notification to the queue
- if ($method) // blank means we just insert it as a notification, but do not notify them by any other means
+ if (!isset($notification_methods[$method]))
{
- if (!isset($notification_methods[$method]))
- {
- $notification_methods[$method] = $this->get_method_class($method);
- }
-
- $notification_methods[$method]->add_to_queue($notification);
+ $notification_methods[$method] = $this->get_method_class($method);
}
+
+ $notification_methods[$method]->add_to_queue($notification);
}
}
- $insert_buffer->flush();
-
// We need to load all of the users to send notifications
$this->user_loader->load_users($user_ids);
@@ -477,12 +385,13 @@ class manager
}
/**
- * Update a notification
+ * Update notification
*
* @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
* @param array $data Data specific for this type that will be updated
+ * @param array $options
*/
- public function update_notifications($notification_type_name, $data)
+ public function update_notifications($notification_type_name, array $data, array $options = array())
{
if (is_array($notification_type_name))
{
@@ -494,27 +403,28 @@ class manager
return;
}
- $notification = $this->get_item_type_class($notification_type_name);
+ $this->update_notification($this->get_item_type_class($notification_type_name), $data, $options);
+ }
- // Allow the notifications class to over-ride the update_notifications functionality
- if (method_exists($notification, 'update_notifications'))
+ /**
+ * Update a notification
+ *
+ * @param \phpbb\notification\type\type_interface $notification The notification
+ * @param array $data Data specific for this type that will be updated
+ * @param array $options
+ */
+ public function update_notification(\phpbb\notification\type\type_interface $notification, array $data, array $options = array())
+ {
+ if (empty($options))
{
- // Return False to over-ride the rest of the update
- if ($notification->update_notifications($data) === false)
- {
- return;
- }
+ $options['item_id'] = $notification->get_item_id($data);
}
- $notification_type_id = $this->get_notification_type_id($notification_type_name);
- $item_id = $notification->get_item_id($data);
- $update_array = $notification->create_update_array($data);
-
- $sql = 'UPDATE ' . $this->notifications_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $update_array) . '
- WHERE notification_type_id = ' . (int) $notification_type_id . '
- AND item_id = ' . (int) $item_id;
- $this->db->sql_query($sql);
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method)
+ {
+ $method->update_notification($notification, $data, $options);
+ }
}
/**
@@ -523,14 +433,15 @@ class manager
* @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $item_id is identical for the specified types)
* @param int|array $item_id Identifier within the type (or array of ids)
* @param mixed $parent_id Parent identifier within the type (or array of ids), used in combination with item_id if specified (Default: false; not checked)
+ * @param mixed $user_id User id (Default: false; not checked)
*/
- public function delete_notifications($notification_type_name, $item_id, $parent_id = false)
+ public function delete_notifications($notification_type_name, $item_id, $parent_id = false, $user_id = false)
{
if (is_array($notification_type_name))
{
foreach ($notification_type_name as $type)
{
- $this->delete_notifications($type, $item_id, $parent_id);
+ $this->delete_notifications($type, $item_id, $parent_id, $user_id);
}
return;
@@ -538,11 +449,11 @@ class manager
$notification_type_id = $this->get_notification_type_id($notification_type_name);
- $sql = 'DELETE FROM ' . $this->notifications_table . '
- WHERE notification_type_id = ' . (int) $notification_type_id . '
- AND ' . $this->db->sql_in_set('item_id', $item_id) .
- (($parent_id !== false) ? ' AND ' . $this->db->sql_in_set('item_parent_id', $parent_id) : '');
- $this->db->sql_query($sql);
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method)
+ {
+ $method->delete_notifications($notification_type_id, $item_id, $parent_id, $user_id);
+ }
}
/**
@@ -558,14 +469,16 @@ class manager
foreach ($this->notification_types as $type_name => $data)
{
+ /** @var type\base $type */
$type = $this->get_item_type_class($type_name);
if ($type instanceof \phpbb\notification\type\type_interface && $type->is_available())
{
$options = array_merge(array(
- 'id' => $type->get_type(),
- 'lang' => 'NOTIFICATION_TYPE_' . strtoupper($type->get_type()),
- 'group' => 'NOTIFICATION_GROUP_MISCELLANEOUS',
+ 'type' => $type,
+ 'id' => $type->get_type(),
+ 'lang' => 'NOTIFICATION_TYPE_' . strtoupper($type->get_type()),
+ 'group' => 'NOTIFICATION_GROUP_MISCELLANEOUS',
), (($type::$notification_option !== false) ? $type::$notification_option : array()));
$this->subscription_types[$options['group']][$options['id']] = $options;
@@ -593,16 +506,56 @@ class manager
{
$subscription_methods = array();
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method_name => $method)
+ {
+ $subscription_methods[$method_name] = array(
+ 'method' => $method,
+ 'id' => $method->get_type(),
+ 'lang' => str_replace('.', '_', strtoupper($method->get_type())),
+ );
+ }
+
+ return $subscription_methods;
+ }
+
+ /**
+ * Get all of the subscription methods
+ *
+ * @return array Array of method's instances
+ */
+ private function get_subscription_methods_instances()
+ {
+ $subscription_methods = array();
+
foreach ($this->notification_methods as $method_name => $data)
{
$method = $this->get_method_class($method_name);
- if ($method instanceof \phpbb\notification\method\method_interface && $method->is_available())
+ if ($method instanceof \phpbb\notification\method\method_interface)
+ {
+ $subscription_methods[$method_name] = $method;
+ }
+ }
+
+ return $subscription_methods;
+ }
+
+ /**
+ * Get all of the available subscription methods
+ *
+ * @return array Array of method's instances
+ */
+ private function get_available_subscription_methods()
+ {
+ $subscription_methods = array();
+
+ /** @var method\method_interface $method */
+ foreach ($this->get_subscription_methods_instances() as $method_name => $method)
+ {
+ if ($method->is_available())
{
- $subscription_methods[$method_name] = array(
- 'id' => $method->get_type(),
- 'lang' => str_replace('.', '_', strtoupper($method->get_type())),
- );
+ $subscription_methods[$method_name] = $method;
}
}
@@ -646,9 +599,10 @@ class manager
*/
public function get_global_subscriptions($user_id = false)
{
- $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
+ $user_id = $user_id ?: $this->user->data['user_id'];
$subscriptions = array();
+ $default_methods = $this->get_default_methods();
$user_notifications = $this->get_user_notifications($user_id);
@@ -656,29 +610,32 @@ class manager
{
foreach ($types as $id => $type)
{
-
- if (empty($user_notifications[$id]))
- {
- // No rows at all, default to ''
- $subscriptions[$id] = array('');
- }
- else
+ $type_subscriptions = $default_methods;
+ if (!empty($user_notifications[$id]))
{
foreach ($user_notifications[$id] as $user_notification)
{
+ $key = array_search($user_notification['method'], $type_subscriptions, true);
if (!$user_notification['notify'])
{
+ if ($key !== false)
+ {
+ unset($type_subscriptions[$key]);
+ }
+
continue;
}
-
- if (!isset($subscriptions[$id]))
+ else if ($key === false)
{
- $subscriptions[$id] = array();
+ $type_subscriptions[] = $user_notification['method'];
}
-
- $subscriptions[$id][] = $user_notification['method'];
}
}
+
+ if (!empty($type_subscriptions))
+ {
+ $subscriptions[$id] = $type_subscriptions;
+ }
}
}
@@ -690,15 +647,20 @@ class manager
*
* @param string $item_type Type identifier of the subscription
* @param int $item_id The id of the item
- * @param string $method The method of the notification e.g. '', 'email', or 'jabber'
+ * @param string $method The method of the notification e.g. 'board', 'email', or 'jabber'
+ * (if null a subscription will be added for all the defaults methods)
* @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
*/
- public function add_subscription($item_type, $item_id = 0, $method = '', $user_id = false)
+ public function add_subscription($item_type, $item_id = 0, $method = null, $user_id = false)
{
- if ($method !== '')
+ if ($method === null)
{
- // Make sure to subscribe them to the base subscription
- $this->add_subscription($item_type, $item_id, '', $user_id);
+ foreach ($this->get_default_methods() as $method_name)
+ {
+ $this->add_subscription($item_type, $item_id, $method_name, $user_id);
+ }
+
+ return;
}
$user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
@@ -742,33 +704,23 @@ class manager
*
* @param string $item_type Type identifier of the subscription
* @param int $item_id The id of the item
- * @param string $method The method of the notification e.g. '', 'email', or 'jabber'
+ * @param string $method The method of the notification e.g. 'board', 'email', or 'jabber'
* @param bool|int $user_id The user_id to add the subscription for (bool false for current user)
*/
- public function delete_subscription($item_type, $item_id = 0, $method = '', $user_id = false)
+ public function delete_subscription($item_type, $item_id = 0, $method = null, $user_id = false)
{
- $user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
-
- // If no method, make sure that no other notification methods for this item are selected before deleting
- if ($method === '')
+ if ($method === null)
{
- $sql = 'SELECT COUNT(*) as num_notifications
- FROM ' . $this->user_notifications_table . "
- WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
- AND item_id = " . (int) $item_id . '
- AND user_id = ' .(int) $user_id . "
- AND method <> ''
- AND notify = 1";
- $this->db->sql_query($sql);
- $num_notifications = $this->db->sql_fetchfield('num_notifications');
- $this->db->sql_freeresult();
-
- if ($num_notifications)
+ foreach ($this->get_default_methods() as $method_name)
{
- return;
+ $this->delete_subscription($item_type, $item_id, $method_name, $user_id);
}
+
+ return;
}
+ $user_id = $user_id ?: $this->user->data['user_id'];
+
$sql = 'UPDATE ' . $this->user_notifications_table . "
SET notify = 0
WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
@@ -828,15 +780,12 @@ class manager
{
$notification_type_id = $this->get_notification_type_id($notification_type_name);
- $sql = 'DELETE FROM ' . $this->notifications_table . '
- WHERE notification_type_id = ' . (int) $notification_type_id;
- $this->db->sql_query($sql);
-
- $sql = 'DELETE FROM ' . $this->notification_types_table . '
- WHERE notification_type_id = ' . (int) $notification_type_id;
- $this->db->sql_query($sql);
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method)
+ {
+ $method->purge_notifications($notification_type_id);
+ }
- $this->cache->destroy('notification_type_ids');
}
catch (\phpbb\notification\exception $e)
{
@@ -869,17 +818,40 @@ class manager
*/
public function prune_notifications($timestamp, $only_read = true)
{
- $sql = 'DELETE FROM ' . $this->notifications_table . '
- WHERE notification_time < ' . (int) $timestamp .
- (($only_read) ? ' AND notification_read = 1' : '');
- $this->db->sql_query($sql);
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method)
+ {
+ $method->prune_notifications($timestamp, $only_read);
+ }
+ }
- $this->config->set('read_notification_last_gc', time(), false);
+ /**
+ * Helper to get the list of methods enabled by default
+ *
+ * @return method\method_interface[]
+ */
+ public function get_default_methods()
+ {
+ $default_methods = array();
+
+ foreach ($this->notification_methods as $method)
+ {
+ if ($method->is_enabled_by_default() && $method->is_available())
+ {
+ $default_methods[] = $method->get_type();
+ }
+ }
+
+ return $default_methods;
}
/**
- * Helper to get the notifications item type class and set it up
- */
+ * Helper to get the notifications item type class and set it up
+ *
+ * @param string $notification_type_name
+ * @param array $data
+ * @return type\type_interface
+ */
public function get_item_type_class($notification_type_name, $data = array())
{
$item = $this->load_object($notification_type_name);
@@ -890,16 +862,22 @@ class manager
}
/**
- * Helper to get the notifications method class and set it up
- */
+ * Helper to get the notifications method class and set it up
+ *
+ * @param string $method_name
+ * @return method\method_interface
+ */
public function get_method_class($method_name)
{
return $this->load_object($method_name);
}
/**
- * Helper to load objects (notification types/methods)
- */
+ * Helper to load objects (notification types/methods)
+ *
+ * @param string $object_name
+ * @return method\method_interface|type\type_interface
+ */
protected function load_object($object_name)
{
$object = $this->phpbb_container->get($object_name);
@@ -921,32 +899,20 @@ class manager
*/
public function get_notification_type_id($notification_type_name)
{
- $notification_type_ids = $this->cache->get('notification_type_ids');
-
- $this->db->sql_transaction('begin');
-
- if ($notification_type_ids === false)
+ $sql = 'SELECT notification_type_id, notification_type_name
+ FROM ' . $this->notification_types_table;
+ $result = $this->db->sql_query($sql, 604800); // cache for one week
+ while ($row = $this->db->sql_fetchrow($result))
{
- $notification_type_ids = array();
-
- $sql = 'SELECT notification_type_id, notification_type_name
- FROM ' . $this->notification_types_table;
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- $notification_type_ids[$row['notification_type_name']] = (int) $row['notification_type_id'];
- }
- $this->db->sql_freeresult($result);
-
- $this->cache->put('notification_type_ids', $notification_type_ids);
+ $notification_type_ids[$row['notification_type_name']] = (int) $row['notification_type_id'];
}
+ $this->db->sql_freeresult($result);
if (!isset($notification_type_ids[$notification_type_name]))
{
if (!isset($this->notification_types[$notification_type_name]) && !isset($this->notification_types['notification.type.' . $notification_type_name]))
{
- $this->db->sql_transaction('rollback');
- throw new \phpbb\notification\exception($this->user->lang('NOTIFICATION_TYPE_NOT_EXIST', $notification_type_name));
+ throw new \phpbb\notification\exception('NOTIFICATION_TYPE_NOT_EXIST', array($notification_type_name));
}
$sql = 'INSERT INTO ' . $this->notification_types_table . ' ' . $this->db->sql_build_array('INSERT', array(
@@ -955,13 +921,13 @@ class manager
));
$this->db->sql_query($sql);
+ // expose new notification type ID for this request
$notification_type_ids[$notification_type_name] = (int) $this->db->sql_nextid();
- $this->cache->put('notification_type_ids', $notification_type_ids);
+ // destroy cache, we have a new addition which we have to to load next time
+ $this->cache->destroy('sql', $this->notification_types_table);
}
- $this->db->sql_transaction('commit');
-
return $notification_type_ids[$notification_type_name];
}
@@ -987,4 +953,26 @@ class manager
return $notification_type_ids;
}
+
+ /**
+ * Find the users which are already notified
+ *
+ * @param bool|string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to retrieve all item types
+ * @param array $options
+ * @return array The list of the notified users
+ */
+ public function get_notified_users($notification_type_name, array $options)
+ {
+ $notification_type_id = $this->get_notification_type_id($notification_type_name);
+
+ $notified_users = array();
+
+ /** @var method\method_interface $method */
+ foreach ($this->get_available_subscription_methods() as $method)
+ {
+ $notified_users = $notified_users + $method->get_notified_users($notification_type_id, $options);
+ }
+
+ return $notified_users;
+ }
}
diff --git a/phpBB/phpbb/notification/method/base.php b/phpBB/phpbb/notification/method/base.php
index 6ee1d2984a..4a183ca508 100644
--- a/phpBB/phpbb/notification/method/base.php
+++ b/phpBB/phpbb/notification/method/base.php
@@ -21,36 +21,6 @@ abstract class base implements \phpbb\notification\method\method_interface
/** @var \phpbb\notification\manager */
protected $notification_manager;
- /** @var \phpbb\user_loader */
- protected $user_loader;
-
- /** @var \phpbb\db\driver\driver_interface */
- protected $db;
-
- /** @var \phpbb\cache\driver\driver_interface */
- protected $cache;
-
- /** @var \phpbb\template\template */
- protected $template;
-
- /** @var \phpbb\extension\manager */
- protected $extension_manager;
-
- /** @var \phpbb\user */
- protected $user;
-
- /** @var \phpbb\auth\auth */
- protected $auth;
-
- /** @var \phpbb\config\config */
- protected $config;
-
- /** @var string */
- protected $phpbb_root_path;
-
- /** @var string */
- protected $php_ext;
-
/**
* Queue of messages to be sent
*
@@ -59,38 +29,43 @@ abstract class base implements \phpbb\notification\method\method_interface
protected $queue = array();
/**
- * Notification Method Base Constructor
+ * Set notification manager (required)
*
- * @param \phpbb\user_loader $user_loader
- * @param \phpbb\db\driver\driver_interface $db
- * @param \phpbb\cache\driver\driver_interface $cache
- * @param \phpbb\user $user
- * @param \phpbb\auth\auth $auth
- * @param \phpbb\config\config $config
- * @param string $phpbb_root_path
- * @param string $php_ext
- * @return \phpbb\notification\method\base
+ * @param \phpbb\notification\manager $notification_manager
*/
- public function __construct(\phpbb\user_loader $user_loader, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, $user, \phpbb\auth\auth $auth, \phpbb\config\config $config, $phpbb_root_path, $php_ext)
+ public function set_notification_manager(\phpbb\notification\manager $notification_manager)
{
- $this->user_loader = $user_loader;
- $this->db = $db;
- $this->cache = $cache;
- $this->user = $user;
- $this->auth = $auth;
- $this->config = $config;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
+ $this->notification_manager = $notification_manager;
}
/**
- * Set notification manager (required)
+ * Is the method enable by default?
*
- * @param \phpbb\notification\manager $notification_manager
+ * @return bool
*/
- public function set_notification_manager(\phpbb\notification\manager $notification_manager)
+ public function is_enabled_by_default()
{
- $this->notification_manager = $notification_manager;
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_notified_users($notification_type_id, array $options)
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function load_notifications(array $options = array())
+ {
+ return array(
+ 'notifications' => array(),
+ 'unread_count' => 0,
+ 'total_count' => 0,
+ );
}
/**
@@ -104,6 +79,55 @@ abstract class base implements \phpbb\notification\method\method_interface
}
/**
+ * {@inheritdoc}
+ */
+ public function update_notification($notification, array $data, array $options)
+ {
+ }
+
+ /**
+ * {@inheritdoc
+ */
+ public function mark_notifications($notification_type_id, $item_id, $user_id, $time = false, $mark_read = true)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mark_notifications_by_parent($notification_type_id, $item_parent_id, $user_id, $time = false, $mark_read = true)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mark_notifications_by_id($notification_id, $time = false, $mark_read = true)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete_notifications($notification_type_id, $item_id, $parent_id = false, $user_id = false)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prune_notifications($timestamp, $only_read = true)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function purge_notifications($notification_type_id)
+ {
+ }
+
+ /**
* Empty the queue
*/
protected function empty_queue()
diff --git a/phpBB/phpbb/notification/method/board.php b/phpBB/phpbb/notification/method/board.php
new file mode 100644
index 0000000000..faa53576e0
--- /dev/null
+++ b/phpBB/phpbb/notification/method/board.php
@@ -0,0 +1,399 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\notification\method;
+
+/**
+* In Board notification method class
+* This class handles in board notifications. This method is enabled by default.
+*
+* @package notifications
+*/
+class board extends \phpbb\notification\method\base
+{
+ /** @var \phpbb\user_loader */
+ protected $user_loader;
+
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ /** @var \phpbb\cache\driver\driver_interface */
+ protected $cache;
+
+ /** @var \phpbb\user */
+ protected $user;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /** @var string */
+ protected $notification_types_table;
+
+ /** @var string */
+ protected $notifications_table;
+
+ /**
+ * Notification Method Board Constructor
+ *
+ * @param \phpbb\user_loader $user_loader
+ * @param \phpbb\db\driver\driver_interface $db
+ * @param \phpbb\cache\driver\driver_interface $cache
+ * @param \phpbb\user $user
+ * @param \phpbb\config\config $config
+ * @param string $notification_types_table
+ * @param string $notifications_table
+ */
+ public function __construct(\phpbb\user_loader $user_loader, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, \phpbb\user $user, \phpbb\config\config $config, $notification_types_table, $notifications_table)
+ {
+ $this->user_loader = $user_loader;
+ $this->db = $db;
+ $this->cache = $cache;
+ $this->user = $user;
+ $this->config = $config;
+ $this->notification_types_table = $notification_types_table;
+ $this->notifications_table = $notifications_table;
+
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add_to_queue(\phpbb\notification\type\type_interface $notification)
+ {
+ $this->queue[] = $notification;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_type()
+ {
+ return 'notification.method.board';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_available()
+ {
+ return $this->config['allow_board_notifications'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_enabled_by_default()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_notified_users($notification_type_id, array $options)
+ {
+ $notified_users = array();
+ $sql = 'SELECT n.*
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.notification_type_id = ' . (int) $notification_type_id .
+ (isset($options['item_id']) ? ' AND n.item_id = ' . (int) $options['item_id'] : '') .
+ (isset($options['item_parent_id']) ? ' AND n.item_parent_id = ' . (int) $options['item_parent_id'] : '') .
+ (isset($options['user_id']) ? ' AND n.user_id = ' . (int) $options['user_id'] : '') .
+ (isset($options['read']) ? ' AND n.notification_read = ' . (int) $options['read'] : '') .'
+ AND nt.notification_type_id = n.notification_type_id
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $notified_users[$row['user_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $notified_users;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function load_notifications(array $options = array())
+ {
+ // Merge default options
+ $options = array_merge(array(
+ 'notification_id' => false,
+ 'user_id' => $this->user->data['user_id'],
+ 'order_by' => 'notification_time',
+ 'order_dir' => 'DESC',
+ 'limit' => 0,
+ 'start' => 0,
+ 'all_unread' => false,
+ 'count_unread' => false,
+ 'count_total' => false,
+ ), $options);
+
+ // If all_unread, count_unread must be true
+ $options['count_unread'] = ($options['all_unread']) ? true : $options['count_unread'];
+
+ // Anonymous users and bots never receive notifications
+ if ($options['user_id'] == $this->user->data['user_id'] && ($this->user->data['user_id'] == ANONYMOUS || $this->user->data['user_type'] == USER_IGNORE))
+ {
+ return array(
+ 'notifications' => array(),
+ 'unread_count' => 0,
+ 'total_count' => 0,
+ );
+ }
+
+ $notifications = $user_ids = array();
+ $load_special = array();
+ $total_count = $unread_count = 0;
+
+ if ($options['count_unread'])
+ {
+ // Get the total number of unread notifications
+ $sql = 'SELECT COUNT(n.notification_id) AS unread_count
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] . '
+ AND n.notification_read = 0
+ AND nt.notification_type_id = n.notification_type_id
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ $unread_count = (int) $this->db->sql_fetchfield('unread_count');
+ $this->db->sql_freeresult($result);
+ }
+
+ if ($options['count_total'])
+ {
+ // Get the total number of notifications
+ $sql = 'SELECT COUNT(n.notification_id) AS total_count
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] . '
+ AND nt.notification_type_id = n.notification_type_id
+ AND nt.notification_type_enabled = 1';
+ $result = $this->db->sql_query($sql);
+ $total_count = (int) $this->db->sql_fetchfield('total_count');
+ $this->db->sql_freeresult($result);
+ }
+
+ if (!$options['count_total'] || $total_count)
+ {
+ $rowset = array();
+
+ // Get the main notifications
+ $sql = 'SELECT n.*, nt.notification_type_name
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] .
+ (($options['notification_id']) ? ((is_array($options['notification_id'])) ? ' AND ' . $this->db->sql_in_set('n.notification_id', $options['notification_id']) : ' AND n.notification_id = ' . (int) $options['notification_id']) : '') . '
+ AND nt.notification_type_id = n.notification_type_id
+ AND nt.notification_type_enabled = 1
+ ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
+ $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $rowset[$row['notification_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ // Get all unread notifications
+ if ($unread_count && $options['all_unread'] && !empty($rowset))
+ {
+ $sql = 'SELECT n.*, nt.notification_type_name
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.user_id = ' . (int) $options['user_id'] . '
+ AND n.notification_read = 0
+ AND ' . $this->db->sql_in_set('n.notification_id', array_keys($rowset), true) . '
+ AND nt.notification_type_id = n.notification_type_id
+ AND nt.notification_type_enabled = 1
+ ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
+ $result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $rowset[$row['notification_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+ }
+
+ foreach ($rowset as $row)
+ {
+ $notification = $this->notification_manager->get_item_type_class($row['notification_type_name'], $row);
+
+ // Array of user_ids to query all at once
+ $user_ids = array_merge($user_ids, $notification->users_to_query());
+
+ // Some notification types also require querying additional tables themselves
+ if (!isset($load_special[$row['notification_type_name']]))
+ {
+ $load_special[$row['notification_type_name']] = array();
+ }
+ $load_special[$row['notification_type_name']] = array_merge($load_special[$row['notification_type_name']], $notification->get_load_special());
+
+ $notifications[$row['notification_id']] = $notification;
+ }
+
+ $this->user_loader->load_users($user_ids);
+
+ // Allow each type to load its own special items
+ foreach ($load_special as $item_type => $data)
+ {
+ $item_class = $this->notification_manager->get_item_type_class($item_type);
+
+ $item_class->load_special($data, $notifications);
+ }
+ }
+
+ return array(
+ 'notifications' => $notifications,
+ 'unread_count' => $unread_count,
+ 'total_count' => $total_count,
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function notify()
+ {
+ $insert_buffer = new \phpbb\db\sql_insert_buffer($this->db, $this->notifications_table);
+
+ /** @var \phpbb\notification\type\type_interface $notification */
+ foreach ($this->queue as $notification)
+ {
+ $data = $notification->get_insert_array();
+ $insert_buffer->insert($data);
+ }
+
+ $insert_buffer->flush();
+
+ // We're done, empty the queue
+ $this->empty_queue();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function update_notification($notification, array $data, array $options)
+ {
+ // Allow the notifications class to over-ride the update_notifications functionality
+ if (method_exists($notification, 'update_notifications'))
+ {
+ // Return False to over-ride the rest of the update
+ if ($notification->update_notifications($data) === false)
+ {
+ return;
+ }
+ }
+
+ $notification_type_id = $this->notification_manager->get_notification_type_id($notification->get_type());
+ $update_array = $notification->create_update_array($data);
+
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $update_array) . '
+ WHERE notification_type_id = ' . (int) $notification_type_id .
+ (isset($options['item_id']) ? ' AND item_id = ' . (int) $options['item_id'] : '') .
+ (isset($options['item_parent_id']) ? ' AND item_parent_id = ' . (int) $options['item_parent_id'] : '') .
+ (isset($options['user_id']) ? ' AND user_id = ' . (int) $options['user_id'] : '') .
+ (isset($options['read']) ? ' AND notification_read = ' . (int) $options['read'] : '');
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mark_notifications($notification_type_id, $item_id, $user_id, $time = false, $mark_read = true)
+ {
+ $time = ($time !== false) ? $time : time();
+
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET notification_read = ' . ($mark_read ? 1 : 0) . '
+ WHERE notification_time <= ' . (int) $time .
+ (($notification_type_id !== false) ? ' AND ' .
+ (is_array($notification_type_id) ? $this->db->sql_in_set('notification_type_id', $notification_type_id) : 'notification_type_id = ' . $notification_type_id) : '') .
+ (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '') .
+ (($item_id !== false) ? ' AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) : '');
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mark_notifications_by_parent($notification_type_id, $item_parent_id, $user_id, $time = false, $mark_read = true)
+ {
+ $time = ($time !== false) ? $time : time();
+
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET notification_read = ' . ($mark_read ? 1 : 0) . '
+ WHERE notification_time <= ' . (int) $time .
+ (($notification_type_id !== false) ? ' AND ' .
+ (is_array($notification_type_id) ? $this->db->sql_in_set('notification_type_id', $notification_type_id) : 'notification_type_id = ' . $notification_type_id) : '') .
+ (($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id, false, true) : 'item_parent_id = ' . (int) $item_parent_id) : '') .
+ (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '');
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function mark_notifications_by_id($notification_id, $time = false, $mark_read = true)
+ {
+ $time = ($time !== false) ? $time : time();
+
+ $sql = 'UPDATE ' . $this->notifications_table . '
+ SET notification_read = ' . ($mark_read ? 1 : 0) . '
+ WHERE notification_time <= ' . (int) $time . '
+ AND ' . ((is_array($notification_id)) ? $this->db->sql_in_set('notification_id', $notification_id) : 'notification_id = ' . (int) $notification_id);
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function delete_notifications($notification_type_id, $item_id, $parent_id = false, $user_id = false)
+ {
+ $sql = 'DELETE FROM ' . $this->notifications_table . '
+ WHERE notification_type_id = ' . (int) $notification_type_id . '
+ AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) .
+ (($parent_id !== false) ? ' AND ' . ((is_array($parent_id) ? $this->db->sql_in_set('item_parent_id', $parent_id) : 'item_parent_id = ' . (int) $parent_id)) : '') .
+ (($user_id !== false) ? ' AND ' . ((is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id)) : '');
+ $this->db->sql_query($sql);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function prune_notifications($timestamp, $only_read = true)
+ {
+ $sql = 'DELETE FROM ' . $this->notifications_table . '
+ WHERE notification_time < ' . (int) $timestamp .
+ (($only_read) ? ' AND notification_read = 1' : '');
+ $this->db->sql_query($sql);
+
+ $this->config->set('read_notification_last_gc', time(), false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function purge_notifications($notification_type_id)
+ {
+ $sql = 'DELETE FROM ' . $this->notifications_table . '
+ WHERE notification_type_id = ' . (int) $notification_type_id;
+ $this->db->sql_query($sql);
+
+ $sql = 'DELETE FROM ' . $this->notification_types_table . '
+ WHERE notification_type_id = ' . (int) $notification_type_id;
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', $this->notification_types_table);
+ }
+}
diff --git a/phpBB/phpbb/notification/method/email.php b/phpBB/phpbb/notification/method/email.php
index a4b93bc85c..6376d13dc7 100644
--- a/phpBB/phpbb/notification/method/email.php
+++ b/phpBB/phpbb/notification/method/email.php
@@ -13,6 +13,8 @@
namespace phpbb\notification\method;
+use phpbb\notification\type\type_interface;
+
/**
* Email notification method class
* This class handles sending emails for notifications
@@ -20,6 +22,29 @@ namespace phpbb\notification\method;
class email extends \phpbb\notification\method\messenger_base
{
+ /** @var \phpbb\user */
+ protected $user;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /**
+ * Notification Method email Constructor
+ *
+ * @param \phpbb\user_loader $user_loader
+ * @param \phpbb\user $user
+ * @param \phpbb\config\config $config
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\user_loader $user_loader, \phpbb\user $user, \phpbb\config\config $config, $phpbb_root_path, $php_ext)
+ {
+ parent::__construct($user_loader, $phpbb_root_path, $php_ext);
+
+ $this->user = $user;
+ $this->config = $config;
+ }
+
/**
* Get notification method name
*
@@ -33,10 +58,14 @@ class email extends \phpbb\notification\method\messenger_base
/**
* Is this method available for the user?
* This is checked on the notifications options
+ *
+ * @param type_interface $notification_type An optional instance of a notification type. If provided, this
+ * method additionally checks if the type provides an email template.
+ * @return bool
*/
- public function is_available()
+ public function is_available(type_interface $notification_type = null)
{
- return $this->config['email_enable'] && $this->user->data['user_email'];
+ return parent::is_available($notification_type) && $this->config['email_enable'] && !empty($this->user->data['user_email']);
}
/**
diff --git a/phpBB/phpbb/notification/method/jabber.php b/phpBB/phpbb/notification/method/jabber.php
index 09f186e3ca..81fdb378e2 100644
--- a/phpBB/phpbb/notification/method/jabber.php
+++ b/phpBB/phpbb/notification/method/jabber.php
@@ -13,6 +13,8 @@
namespace phpbb\notification\method;
+use phpbb\notification\type\type_interface;
+
/**
* Jabber notification method class
* This class handles sending Jabber messages for notifications
@@ -20,6 +22,29 @@ namespace phpbb\notification\method;
class jabber extends \phpbb\notification\method\messenger_base
{
+ /** @var \phpbb\user */
+ protected $user;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /**
+ * Notification Method jabber Constructor
+ *
+ * @param \phpbb\user_loader $user_loader
+ * @param \phpbb\user $user
+ * @param \phpbb\config\config $config
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\user_loader $user_loader, \phpbb\user $user, \phpbb\config\config $config, $phpbb_root_path, $php_ext)
+ {
+ parent::__construct($user_loader, $phpbb_root_path, $php_ext);
+
+ $this->user = $user;
+ $this->config = $config;
+ }
+
/**
* Get notification method name
*
@@ -33,10 +58,14 @@ class jabber extends \phpbb\notification\method\messenger_base
/**
* Is this method available for the user?
* This is checked on the notifications options
+ *
+ * @param type_interface $notification_type An optional instance of a notification type. If provided, this
+ * method additionally checks if the type provides an email template.
+ * @return bool
*/
- public function is_available()
+ public function is_available(type_interface $notification_type = null)
{
- return ($this->global_available() && $this->user->data['user_jabber']);
+ return parent::is_available($notification_type) && $this->global_available() && $this->user->data['user_jabber'];
}
/**
@@ -61,6 +90,6 @@ class jabber extends \phpbb\notification\method\messenger_base
return;
}
- return $this->notify_using_messenger(NOTIFY_IM, 'short/');
+ $this->notify_using_messenger(NOTIFY_IM, 'short/');
}
}
diff --git a/phpBB/phpbb/notification/method/messenger_base.php b/phpBB/phpbb/notification/method/messenger_base.php
index 0bfbfd6b02..f82017b70e 100644
--- a/phpBB/phpbb/notification/method/messenger_base.php
+++ b/phpBB/phpbb/notification/method/messenger_base.php
@@ -13,12 +13,50 @@
namespace phpbb\notification\method;
+use phpbb\notification\type\type_interface;
+
/**
* Abstract notification method handling email and jabber notifications
* using the phpBB messenger.
*/
abstract class messenger_base extends \phpbb\notification\method\base
{
+ /** @var \phpbb\user_loader */
+ protected $user_loader;
+
+ /** @var string */
+ protected $phpbb_root_path;
+
+ /** @var string */
+ protected $php_ext;
+
+ /**
+ * Notification Method Board Constructor
+ *
+ * @param \phpbb\user_loader $user_loader
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\user_loader $user_loader, $phpbb_root_path, $php_ext)
+ {
+ $this->user_loader = $user_loader;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Is this method available for the user?
+ * This is checked on the notifications options
+ *
+ * @param type_interface $notification_type An optional instance of a notification type. This method returns false
+ * only if the type is provided and if it doesn't provide an email template.
+ * @return bool
+ */
+ public function is_available(type_interface $notification_type = null)
+ {
+ return $notification_type === null || $notification_type->get_email_template() !== false;
+ }
+
/**
* Notify using phpBB messenger
*
@@ -49,7 +87,7 @@ abstract class messenger_base extends \phpbb\notification\method\base
$banned_users = phpbb_get_banned_user_ids($user_ids);
// Load all the users we need
- $this->user_loader->load_users($user_ids);
+ $this->user_loader->load_users(array_diff($user_ids, $banned_users), array(USER_IGNORE));
// Load the messenger
if (!class_exists('messenger'))
@@ -57,9 +95,9 @@ abstract class messenger_base extends \phpbb\notification\method\base
include($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
}
$messenger = new \messenger();
- $board_url = generate_board_url();
// Time to go through the queue and send emails
+ /** @var \phpbb\notification\type\type_interface $notification */
foreach ($this->queue as $notification)
{
if ($notification->get_email_template() === false)
@@ -69,7 +107,7 @@ abstract class messenger_base extends \phpbb\notification\method\base
$user = $this->user_loader->get_user($notification->user_id);
- if ($user['user_type'] == USER_IGNORE || ($user['user_type'] == USER_INACTIVE && $user['user_inactive_reason'] == INACTIVE_MANUAL) || in_array($notification->user_id, $banned_users))
+ if ($user['user_type'] == USER_INACTIVE && $user['user_inactive_reason'] == INACTIVE_MANUAL)
{
continue;
}
diff --git a/phpBB/phpbb/notification/method/method_interface.php b/phpBB/phpbb/notification/method/method_interface.php
index 76b0de179c..c2e4940485 100644
--- a/phpBB/phpbb/notification/method/method_interface.php
+++ b/phpBB/phpbb/notification/method/method_interface.php
@@ -26,12 +26,48 @@ interface method_interface
public function get_type();
/**
+ * Is the method enable by default?
+ *
+ * @return bool
+ */
+ public function is_enabled_by_default();
+
+ /**
* Is this method available for the user?
* This is checked on the notifications options
*/
public function is_available();
/**
+ * Return the list of the users already notified
+ *
+ * @param int $notification_type_id Type of the notification
+ * @param array $options
+ * @return array User
+ */
+ public function get_notified_users($notification_type_id, array $options);
+
+ /**
+ * Load the user's notifications
+ *
+ * @param array $options Optional options to control what notifications are loaded
+ * notification_id Notification id to load (or array of notification ids)
+ * user_id User id to load notifications for (Default: $user->data['user_id'])
+ * order_by Order by (Default: notification_time)
+ * order_dir Order direction (Default: DESC)
+ * limit Number of notifications to load (Default: 5)
+ * start Notifications offset (Default: 0)
+ * all_unread Load all unread notifications? If set to true, count_unread is set to true (Default: false)
+ * count_unread Count all unread notifications? (Default: false)
+ * count_total Count all notifications? (Default: false)
+ * @return array Array of information based on the request with keys:
+ * 'notifications' array of notification type objects
+ * 'unread_count' number of unread notifications the user has if count_unread is true in the options
+ * 'total_count' number of notifications the user has if count_total is true in the options
+ */
+ public function load_notifications(array $options = array());
+
+ /**
* Add a notification to the queue
*
* @param \phpbb\notification\type\type_interface $notification
@@ -42,4 +78,72 @@ interface method_interface
* Parse the queue and notify the users
*/
public function notify();
+
+ /**
+ * Update a notification
+ *
+ * @param \phpbb\notification\type\type_interface $notification Notification to update
+ * @param array $data Data specific for this type that will be updated
+ * @param array $options
+ */
+ public function update_notification($notification, array $data, array $options);
+
+ /**
+ * Mark notifications read or unread
+ *
+ * @param bool|string $notification_type_id Type identifier of item types. False to mark read for all item types
+ * @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
+ * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
+ */
+ public function mark_notifications($notification_type_id, $item_id, $user_id, $time = false, $mark_read = true);
+
+ /**
+ * Mark notifications read or unread from a parent identifier
+ *
+ * @param string $notification_type_id Type identifier of item types
+ * @param bool|int|array $item_parent_id Item parent id or array of item parent ids. False to mark read for all item parent ids
+ * @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
+ */
+ public function mark_notifications_by_parent($notification_type_id, $item_parent_id, $user_id, $time = false, $mark_read = true);
+
+ /**
+ * Mark notifications read or unread
+ *
+ * @param int $notification_id Notification id of notification ids.
+ * @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
+ * @param bool $mark_read Define if the notification as to be set to True or False. (Default: True)
+ */
+ public function mark_notifications_by_id($notification_id, $time = false, $mark_read = true);
+
+ /**
+ * Delete a notification
+ *
+ * @param string $notification_type_id Type identifier of item types
+ * @param int|array $item_id Identifier within the type (or array of ids)
+ * @param mixed $parent_id Parent identifier within the type (or array of ids), used in combination with item_id if specified (Default: false; not checked)
+ * @param mixed $user_id User id (Default: false; not checked)
+ */
+ public function delete_notifications($notification_type_id, $item_id, $parent_id = false, $user_id = false);
+
+ /**
+ * Delete all notifications older than a certain time
+ *
+ * @param int $timestamp Unix timestamp to delete all notifications that were created before
+ * @param bool $only_read True (default) to only prune read notifications
+ */
+ public function prune_notifications($timestamp, $only_read = true);
+
+ /**
+ * Purge all notifications of a certain type
+ *
+ * This should be called when an extension which has notification types
+ * is purged so that all those notifications are removed
+ *
+ * @param string $notification_type_id Type identifier of the subscription
+ */
+ public function purge_notifications($notification_type_id);
}
diff --git a/phpBB/phpbb/notification/type/admin_activate_user.php b/phpBB/phpbb/notification/type/admin_activate_user.php
index 7c5c18aa47..78c10ac36a 100644
--- a/phpBB/phpbb/notification/type/admin_activate_user.php
+++ b/phpBB/phpbb/notification/type/admin_activate_user.php
@@ -36,11 +36,27 @@ class admin_activate_user extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'lang' => 'NOTIFICATION_TYPE_ADMIN_ACTIVATE_USER',
'group' => 'NOTIFICATION_GROUP_ADMINISTRATION',
);
+ /** @var \phpbb\user_loader */
+ protected $user_loader;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ public function set_config(\phpbb\config\config $config)
+ {
+ $this->config = $config;
+ }
+
+ public function set_user_loader(\phpbb\user_loader $user_loader)
+ {
+ $this->user_loader = $user_loader;
+ }
+
/**
* {@inheritdoc}
*/
@@ -52,7 +68,7 @@ class admin_activate_user extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static function get_item_id($user)
+ static public function get_item_id($user)
{
return (int) $user['user_id'];
}
@@ -60,7 +76,7 @@ class admin_activate_user extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static function get_item_parent_id($post)
+ static public function get_item_parent_id($post)
{
return 0;
}
@@ -114,7 +130,7 @@ class admin_activate_user extends \phpbb\notification\type\base
{
$username = $this->user_loader->get_username($this->item_id, 'no_profile');
- return $this->user->lang($this->language_key, $username);
+ return $this->language->lang($this->language_key, $username);
}
/**
@@ -159,11 +175,11 @@ class admin_activate_user extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public function create_insert_array($user, $pre_create_data)
+ public function create_insert_array($user, $pre_create_data = array())
{
$this->set_data('user_actkey', $user['user_actkey']);
$this->notification_time = $user['user_regdate'];
- return parent::create_insert_array($user, $pre_create_data);
+ parent::create_insert_array($user, $pre_create_data);
}
}
diff --git a/phpBB/phpbb/notification/type/approve_post.php b/phpBB/phpbb/notification/type/approve_post.php
index 5760c12166..e4b111e4da 100644
--- a/phpBB/phpbb/notification/type/approve_post.php
+++ b/phpBB/phpbb/notification/type/approve_post.php
@@ -50,7 +50,7 @@ class approve_post extends \phpbb\notification\type\post
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'moderation_queue',
'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
'group' => 'NOTIFICATION_GROUP_POSTING',
@@ -79,7 +79,7 @@ class approve_post extends \phpbb\notification\type\post
), $options);
$users = array();
- $users[$post['poster_id']] = array('');
+ $users[$post['poster_id']] = $this->notification_manager->get_default_methods();
return $this->get_authorised_recipients(array_keys($users), $post['forum_id'], array_merge($options, array(
'item_type' => static::$notification_option['id'],
@@ -107,21 +107,24 @@ class approve_post extends \phpbb\notification\type\post
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
$this->set_data('post_subject', $post['post_subject']);
- $data = parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = time();
+ }
- $this->notification_time = $data['notification_time'] = time();
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/approve_topic.php b/phpBB/phpbb/notification/type/approve_topic.php
index 26e51bf9cd..f8a3fdec6f 100644
--- a/phpBB/phpbb/notification/type/approve_topic.php
+++ b/phpBB/phpbb/notification/type/approve_topic.php
@@ -50,7 +50,7 @@ class approve_topic extends \phpbb\notification\type\topic
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'moderation_queue',
'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
'group' => 'NOTIFICATION_GROUP_POSTING',
@@ -79,7 +79,7 @@ class approve_topic extends \phpbb\notification\type\topic
), $options);
$users = array();
- $users[$post['poster_id']] = array('');
+ $users[$post['poster_id']] = $this->notification_manager->get_default_methods();
return $this->get_authorised_recipients(array_keys($users), $post['forum_id'], array_merge($options, array(
'item_type' => static::$notification_option['id'],
@@ -107,19 +107,23 @@ class approve_topic extends \phpbb\notification\type\topic
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
- $data = parent::create_insert_array($post, $pre_create_data);
- $this->notification_time = $data['notification_time'] = time();
+ parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = time();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/base.php b/phpBB/phpbb/notification/type/base.php
index 4ead06071e..77ed7f2b09 100644
--- a/phpBB/phpbb/notification/type/base.php
+++ b/phpBB/phpbb/notification/type/base.php
@@ -21,17 +21,11 @@ abstract class base implements \phpbb\notification\type\type_interface
/** @var \phpbb\notification\manager */
protected $notification_manager;
- /** @var \phpbb\user_loader */
- protected $user_loader;
-
/** @var \phpbb\db\driver\driver_interface */
protected $db;
- /** @var \phpbb\cache\driver\driver_interface */
- protected $cache;
-
- /** @var \phpbb\template\template */
- protected $template;
+ /** @var \phpbb\language\language */
+ protected $language;
/** @var \phpbb\user */
protected $user;
@@ -39,9 +33,6 @@ abstract class base implements \phpbb\notification\type\type_interface
/** @var \phpbb\auth\auth */
protected $auth;
- /** @var \phpbb\config\config */
- protected $config;
-
/** @var string */
protected $phpbb_root_path;
@@ -49,12 +40,6 @@ abstract class base implements \phpbb\notification\type\type_interface
protected $php_ext;
/** @var string */
- protected $notification_types_table;
-
- /** @var string */
- protected $notifications_table;
-
- /** @var string */
protected $user_notifications_table;
/**
@@ -63,7 +48,7 @@ abstract class base implements \phpbb\notification\type\type_interface
* @var bool|array False if the service should use its default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = false;
+ static public $notification_option = false;
/**
* The notification_type_id, set upon creation of the class
@@ -74,7 +59,7 @@ abstract class base implements \phpbb\notification\type\type_interface
protected $notification_type_id;
/**
- * Indentification data
+ * Identification data
* notification_type_id - ID of the item type (auto generated, from notification types table)
* item_id - ID of the item (e.g. post_id, msg_id)
* item_parent_id - Parent item id (ex: for topic => forum_id, for post => topic_id, etc)
@@ -89,35 +74,26 @@ abstract class base implements \phpbb\notification\type\type_interface
private $data = array();
/**
- * Notification Type Base Constructor
- *
- * @param \phpbb\user_loader $user_loader
- * @param \phpbb\db\driver\driver_interface $db
- * @param \phpbb\cache\driver\driver_interface $cache
- * @param \phpbb\user $user
- * @param \phpbb\auth\auth $auth
- * @param \phpbb\config\config $config
- * @param string $phpbb_root_path
- * @param string $php_ext
- * @param string $notification_types_table
- * @param string $notifications_table
- * @param string $user_notifications_table
- * @return \phpbb\notification\type\base
- */
- public function __construct(\phpbb\user_loader $user_loader, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, $user, \phpbb\auth\auth $auth, \phpbb\config\config $config, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
+ * Notification Type Base Constructor
+ *
+ * @param \phpbb\db\driver\driver_interface $db
+ * @param \phpbb\language\language $language
+ * @param \phpbb\user $user
+ * @param \phpbb\auth\auth $auth
+ * @param string $phpbb_root_path
+ * @param string $php_ext
+ * @param string $user_notifications_table
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\language\language $language, \phpbb\user $user, \phpbb\auth\auth $auth, $phpbb_root_path, $php_ext, $user_notifications_table)
{
- $this->user_loader = $user_loader;
$this->db = $db;
- $this->cache = $cache;
+ $this->language = $language;
$this->user = $user;
$this->auth = $auth;
- $this->config = $config;
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = $php_ext;
- $this->notification_types_table = $notification_types_table;
- $this->notifications_table = $notifications_table;
$this->user_notifications_table = $user_notifications_table;
}
@@ -207,12 +183,7 @@ abstract class base implements \phpbb\notification\type\type_interface
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $type_data Data unique to this notification type
- * @param array $pre_create_data Data from pre_create_insert_array()
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($type_data, $pre_create_data = array())
{
@@ -225,9 +196,15 @@ abstract class base implements \phpbb\notification\type\type_interface
'notification_time' => time(),
'notification_read' => false,
- 'notification_data' => array(),
+ 'notification_data' => array(),
), $this->data);
+ }
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
$data = $this->data;
$data['notification_data'] = serialize($data['notification_data']);
@@ -244,7 +221,8 @@ abstract class base implements \phpbb\notification\type\type_interface
*/
public function create_update_array($type_data)
{
- $data = $this->create_insert_array($type_data);
+ $this->create_insert_array($type_data);
+ $data = $this->get_insert_array();
// Unset data unique to each row
unset(
@@ -330,6 +308,7 @@ abstract class base implements \phpbb\notification\type\type_interface
* URL to unsubscribe to this notification (fall back)
*
* @param string|bool $method Method name to unsubscribe from (email|jabber|etc), False to unsubscribe from all notifications for this item
+ * @return false
*/
public function get_unsubscribe_url($method = false)
{
@@ -397,8 +376,11 @@ abstract class base implements \phpbb\notification\type\type_interface
}
/**
- * Load the special items (fall back)
- */
+ * Load the special items (fall back)
+ *
+ * @param array $data
+ * @param array $notifications
+ */
public function load_special($data, $notifications)
{
return;
@@ -415,10 +397,12 @@ abstract class base implements \phpbb\notification\type\type_interface
}
/**
- * Pre create insert array function (fall back)
- *
- * @return array
- */
+ * Pre create insert array function (fall back)
+ *
+ * @param array $type_data
+ * @param array $notify_users
+ * @return array
+ */
public function pre_create_insert_array($type_data, $notify_users)
{
return array();
@@ -429,13 +413,13 @@ abstract class base implements \phpbb\notification\type\type_interface
*/
/**
- * Find the users who want to receive notifications (helper)
- *
- * @param array $user_ids User IDs to check if they want to receive notifications
- * (Bool False to check all users besides anonymous and bots (USER_IGNORE))
- *
- * @return array
- */
+ * Find the users who want to receive notifications (helper)
+ *
+ * @param array|bool $user_ids User IDs to check if they want to receive notifications
+ * (Bool False to check all users besides anonymous and bots (USER_IGNORE))
+ * @param array $options
+ * @return array
+ */
protected function check_user_notification_options($user_ids = false, $options = array())
{
$options = array_merge(array(
@@ -465,7 +449,7 @@ abstract class base implements \phpbb\notification\type\type_interface
return array();
}
- $rowset = $resulting_user_ids = array();
+ $rowset = $output = array();
$sql = 'SELECT user_id, method, notify
FROM ' . $this->user_notifications_table . '
@@ -476,9 +460,7 @@ abstract class base implements \phpbb\notification\type\type_interface
while ($row = $this->db->sql_fetchrow($result))
{
- $resulting_user_ids[] = $row['user_id'];
-
- if (!$row['notify'] || (isset($options['ignore_users'][$row['user_id']]) && in_array($row['method'], $options['ignore_users'][$row['user_id']])))
+ if (isset($options['ignore_users'][$row['user_id']]) && in_array($row['method'], $options['ignore_users'][$row['user_id']]))
{
continue;
}
@@ -487,22 +469,47 @@ abstract class base implements \phpbb\notification\type\type_interface
{
$rowset[$row['user_id']] = array();
}
+ $rowset[$row['user_id']][$row['method']] = $row['notify'];
- $rowset[$row['user_id']][] = $row['method'];
+ if (!isset($output[$row['user_id']]))
+ {
+ $output[$row['user_id']] = array();
+ }
+ if ($row['notify'])
+ {
+ $output[$row['user_id']][] = $row['method'];
+ }
}
$this->db->sql_freeresult($result);
+ $default_methods = $this->notification_manager->get_default_methods();
+
foreach ($user_ids as $user_id)
{
- if (!in_array($user_id, $resulting_user_ids) && !isset($options['ignore_users'][$user_id]))
+ if (isset($options['ignore_users'][$user_id]))
+ {
+ continue;
+ }
+ if (!array_key_exists($user_id, $rowset))
+ {
+ // No rows at all for this user, use the default methods
+ $output[$user_id] = $default_methods;
+ }
+ else
{
- // No rows at all for this user, default to ''
- $rowset[$user_id] = array('');
+ foreach ($default_methods as $default_method)
+ {
+ if (!array_key_exists($default_method, $rowset[$user_id]))
+ {
+ // No user preference for this type recorded, but it should be enabled by default.
+ $output[$user_id][] = $default_method;
+ }
+ }
}
}
- return $rowset;
+ return $output;
}
/**
@@ -516,22 +523,23 @@ abstract class base implements \phpbb\notification\type\type_interface
{
$this->notification_read = (bool) !$unread;
- $where = array(
- 'notification_type_id = ' . (int) $this->notification_type_id,
- 'item_id = ' . (int) $this->item_id,
- 'user_id = ' . (int) $this->user_id,
- );
- $where = implode(' AND ', $where);
-
if ($return)
{
+ $where = array(
+ 'notification_type_id = ' . (int) $this->notification_type_id,
+ 'item_id = ' . (int) $this->item_id,
+ 'user_id = ' . (int) $this->user_id,
+ );
+
+ $where = implode(' AND ', $where);
return $where;
}
+ else
+ {
+ $this->notification_manager->mark_notifications($this->get_type(), (int) $this->item_id, (int) $this->user_id, false, $this->notification_read);
+ }
- $sql = 'UPDATE ' . $this->notifications_table . '
- SET notification_read = ' . (int) $this->notification_read . '
- WHERE ' . $where;
- $this->db->sql_query($sql);
+ return null;
}
/**
diff --git a/phpBB/phpbb/notification/type/bookmark.php b/phpBB/phpbb/notification/type/bookmark.php
index 1626add22c..ebbb961c57 100644
--- a/phpBB/phpbb/notification/type/bookmark.php
+++ b/phpBB/phpbb/notification/type/bookmark.php
@@ -43,7 +43,7 @@ class bookmark extends \phpbb\notification\type\post
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'lang' => 'NOTIFICATION_TYPE_BOOKMARK',
'group' => 'NOTIFICATION_GROUP_POSTING',
);
@@ -91,31 +91,27 @@ class bookmark extends \phpbb\notification\type\post
}
// Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
- $update_notifications = array();
- $sql = 'SELECT n.*
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
- AND n.item_parent_id = ' . (int) static::get_item_parent_id($post) . '
- AND n.notification_read = 0
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1';
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
+ $notified_users = $this->notification_manager->get_notified_users($this->get_type(), array(
+ 'item_parent_id' => static::get_item_parent_id($post),
+ 'read' => 0,
+ ));
+
+ foreach ($notified_users as $user => $notification_data)
{
- // Do not create a new notification
- unset($notify_users[$row['user_id']]);
+ unset($notify_users[$user]);
- $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row);
+ /** @var bookmark $notification */
+ $notification = $this->notification_manager->get_item_type_class($this->get_type(), $notification_data);
$update_responders = $notification->add_responders($post);
if (!empty($update_responders))
{
- $sql = 'UPDATE ' . $this->notifications_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $update_responders) . '
- WHERE notification_id = ' . $row['notification_id'];
- $this->db->sql_query($sql);
+ $this->notification_manager->update_notification($notification, $update_responders, array(
+ 'item_parent_id' => self::get_item_parent_id($post),
+ 'read' => 0,
+ 'user_id' => $user,
+ ));
}
}
- $this->db->sql_freeresult($result);
return $notify_users;
}
diff --git a/phpBB/phpbb/notification/type/disapprove_post.php b/phpBB/phpbb/notification/type/disapprove_post.php
index 6c7bcbcaee..2d908eb254 100644
--- a/phpBB/phpbb/notification/type/disapprove_post.php
+++ b/phpBB/phpbb/notification/type/disapprove_post.php
@@ -60,7 +60,7 @@ class disapprove_post extends \phpbb\notification\type\approve_post
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'moderation_queue',
'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
'group' => 'NOTIFICATION_GROUP_POSTING',
@@ -73,7 +73,7 @@ class disapprove_post extends \phpbb\notification\type\approve_post
*/
public function get_title()
{
- return $this->user->lang($this->language_key);
+ return $this->language->lang($this->language_key);
}
/**
@@ -83,7 +83,7 @@ class disapprove_post extends \phpbb\notification\type\approve_post
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('topic_title'))
);
@@ -96,7 +96,7 @@ class disapprove_post extends \phpbb\notification\type\approve_post
*/
public function get_reason()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
$this->get_data('disapprove_reason')
);
@@ -125,21 +125,24 @@ class disapprove_post extends \phpbb\notification\type\approve_post
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
$this->set_data('disapprove_reason', $post['disapprove_reason']);
- $data = parent::create_insert_array($post);
+ parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = time();
+ }
- $this->notification_time = $data['notification_time'] = time();
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/disapprove_topic.php b/phpBB/phpbb/notification/type/disapprove_topic.php
index efa5eb7ecd..c2522fb562 100644
--- a/phpBB/phpbb/notification/type/disapprove_topic.php
+++ b/phpBB/phpbb/notification/type/disapprove_topic.php
@@ -60,7 +60,7 @@ class disapprove_topic extends \phpbb\notification\type\approve_topic
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'moderation_queue',
'lang' => 'NOTIFICATION_TYPE_MODERATION_QUEUE',
'group' => 'NOTIFICATION_GROUP_POSTING',
@@ -73,7 +73,7 @@ class disapprove_topic extends \phpbb\notification\type\approve_topic
*/
public function get_title()
{
- return $this->user->lang($this->language_key);
+ return $this->language->lang($this->language_key);
}
/**
@@ -83,7 +83,7 @@ class disapprove_topic extends \phpbb\notification\type\approve_topic
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('topic_title'))
);
@@ -96,7 +96,7 @@ class disapprove_topic extends \phpbb\notification\type\approve_topic
*/
public function get_reason()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
$this->get_data('disapprove_reason')
);
@@ -125,21 +125,24 @@ class disapprove_topic extends \phpbb\notification\type\approve_topic
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
$this->set_data('disapprove_reason', $post['disapprove_reason']);
- $data = parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = time();
+ }
- $this->notification_time = $data['notification_time'] = time();
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/group_request.php b/phpBB/phpbb/notification/type/group_request.php
index 96bfc86322..28a9e73bf9 100644
--- a/phpBB/phpbb/notification/type/group_request.php
+++ b/phpBB/phpbb/notification/type/group_request.php
@@ -26,10 +26,18 @@ class group_request extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'lang' => 'NOTIFICATION_TYPE_GROUP_REQUEST',
);
+ /** @var \phpbb\user_loader */
+ protected $user_loader;
+
+ public function set_user_loader(\phpbb\user_loader $user_loader)
+ {
+ $this->user_loader = $user_loader;
+ }
+
/**
* {@inheritdoc}
*/
@@ -50,7 +58,7 @@ class group_request extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static function get_item_id($group)
+ static public function get_item_id($group)
{
return (int) $group['user_id'];
}
@@ -58,7 +66,7 @@ class group_request extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static function get_item_parent_id($group)
+ static public function get_item_parent_id($group)
{
// Group id is the parent
return (int) $group['group_id'];
@@ -106,7 +114,7 @@ class group_request extends \phpbb\notification\type\base
{
$username = $this->user_loader->get_username($this->item_id, 'no_profile');
- return $this->user->lang('NOTIFICATION_GROUP_REQUEST', $username, $this->get_data('group_name'));
+ return $this->language->lang('NOTIFICATION_GROUP_REQUEST', $username, $this->get_data('group_name'));
}
/**
@@ -156,6 +164,6 @@ class group_request extends \phpbb\notification\type\base
{
$this->set_data('group_name', $group['group_name']);
- return parent::create_insert_array($group, $pre_create_data);
+ parent::create_insert_array($group, $pre_create_data);
}
}
diff --git a/phpBB/phpbb/notification/type/group_request_approved.php b/phpBB/phpbb/notification/type/group_request_approved.php
index d284046ffa..f55d28bafd 100644
--- a/phpBB/phpbb/notification/type/group_request_approved.php
+++ b/phpBB/phpbb/notification/type/group_request_approved.php
@@ -34,7 +34,7 @@ class group_request_approved extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static function get_item_id($group)
+ static public function get_item_id($group)
{
return (int) $group['group_id'];
}
@@ -42,7 +42,7 @@ class group_request_approved extends \phpbb\notification\type\base
/**
* {@inheritdoc}
*/
- public static function get_item_parent_id($group)
+ static public function get_item_parent_id($group)
{
return 0;
}
@@ -58,7 +58,7 @@ class group_request_approved extends \phpbb\notification\type\base
foreach ($group['user_ids'] as $user_id)
{
- $users[$user_id] = array('');
+ $users[$user_id] = $this->notification_manager->get_default_methods();
}
return $users;
@@ -69,7 +69,7 @@ class group_request_approved extends \phpbb\notification\type\base
*/
public function get_title()
{
- return $this->user->lang('NOTIFICATION_GROUP_REQUEST_APPROVED', $this->get_data('group_name'));
+ return $this->language->lang('NOTIFICATION_GROUP_REQUEST_APPROVED', $this->get_data('group_name'));
}
/**
@@ -87,7 +87,7 @@ class group_request_approved extends \phpbb\notification\type\base
{
$this->set_data('group_name', $group['group_name']);
- return parent::create_insert_array($group, $pre_create_data);
+ parent::create_insert_array($group, $pre_create_data);
}
/**
diff --git a/phpBB/phpbb/notification/type/pm.php b/phpBB/phpbb/notification/type/pm.php
index d2f34f95d0..c51586afb9 100644
--- a/phpBB/phpbb/notification/type/pm.php
+++ b/phpBB/phpbb/notification/type/pm.php
@@ -36,10 +36,26 @@ class pm extends \phpbb\notification\type\base
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'lang' => 'NOTIFICATION_TYPE_PM',
);
+ /** @var \phpbb\user_loader */
+ protected $user_loader;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ public function set_config(\phpbb\config\config $config)
+ {
+ $this->config = $config;
+ }
+
+ public function set_user_loader(\phpbb\user_loader $user_loader)
+ {
+ $this->user_loader = $user_loader;
+ }
+
/**
* Is available
*/
@@ -53,7 +69,7 @@ class pm extends \phpbb\notification\type\base
*
* @param array $pm The data from the private message
*/
- public static function get_item_id($pm)
+ static public function get_item_id($pm)
{
return (int) $pm['msg_id'];
}
@@ -63,7 +79,7 @@ class pm extends \phpbb\notification\type\base
*
* @param array $pm The data from the pm
*/
- public static function get_item_parent_id($pm)
+ static public function get_item_parent_id($pm)
{
// No parent
return 0;
@@ -83,7 +99,7 @@ class pm extends \phpbb\notification\type\base
'ignore_users' => array(),
), $options);
- if (!sizeof($pm['recipients']))
+ if (!count($pm['recipients']))
{
return array();
}
@@ -112,7 +128,7 @@ class pm extends \phpbb\notification\type\base
{
$username = $this->user_loader->get_username($this->get_data('from_user_id'), 'no_profile');
- return $this->user->lang('NOTIFICATION_PM', $username);
+ return $this->language->lang('NOTIFICATION_PM', $username);
}
/**
@@ -122,7 +138,7 @@ class pm extends \phpbb\notification\type\base
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
$this->get_data('message_subject')
);
@@ -176,13 +192,7 @@ class pm extends \phpbb\notification\type\base
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $pm Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($pm, $pre_create_data = array())
{
@@ -190,6 +200,6 @@ class pm extends \phpbb\notification\type\base
$this->set_data('message_subject', $pm['message_subject']);
- return parent::create_insert_array($pm, $pre_create_data);
+ parent::create_insert_array($pm, $pre_create_data);
}
}
diff --git a/phpBB/phpbb/notification/type/post.php b/phpBB/phpbb/notification/type/post.php
index 2969da550d..254f4c07b3 100644
--- a/phpBB/phpbb/notification/type/post.php
+++ b/phpBB/phpbb/notification/type/post.php
@@ -50,11 +50,27 @@ class post extends \phpbb\notification\type\base
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'lang' => 'NOTIFICATION_TYPE_POST',
'group' => 'NOTIFICATION_GROUP_POSTING',
);
+ /** @var \phpbb\user_loader */
+ protected $user_loader;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ public function set_config(\phpbb\config\config $config)
+ {
+ $this->config = $config;
+ }
+
+ public function set_user_loader(\phpbb\user_loader $user_loader)
+ {
+ $this->user_loader = $user_loader;
+ }
+
/**
* Is available
*/
@@ -67,8 +83,9 @@ class post extends \phpbb\notification\type\base
* Get the id of the item
*
* @param array $post The data from the post
+ * @return int The post id
*/
- public static function get_item_id($post)
+ static public function get_item_id($post)
{
return (int) $post['post_id'];
}
@@ -77,8 +94,9 @@ class post extends \phpbb\notification\type\base
* Get the id of the parent
*
* @param array $post The data from the post
+ * @return int The topic id
*/
- public static function get_item_parent_id($post)
+ static public function get_item_parent_id($post)
{
return (int) $post['topic_id'];
}
@@ -131,31 +149,27 @@ class post extends \phpbb\notification\type\base
}
// Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
- $update_notifications = array();
- $sql = 'SELECT n.*
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
- AND n.item_parent_id = ' . (int) static::get_item_parent_id($post) . '
- AND n.notification_read = 0
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1';
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
+ $notified_users = $this->notification_manager->get_notified_users($this->get_type(), array(
+ 'item_parent_id' => static::get_item_parent_id($post),
+ 'read' => 0,
+ ));
+
+ foreach ($notified_users as $user => $notification_data)
{
- // Do not create a new notification
- unset($notify_users[$row['user_id']]);
+ unset($notify_users[$user]);
- $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row);
+ /** @var post $notification */
+ $notification = $this->notification_manager->get_item_type_class($this->get_type(), $notification_data);
$update_responders = $notification->add_responders($post);
if (!empty($update_responders))
{
- $sql = 'UPDATE ' . $this->notifications_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $update_responders) . '
- WHERE notification_id = ' . $row['notification_id'];
- $this->db->sql_query($sql);
+ $this->notification_manager->update_notification($notification, $update_responders, array(
+ 'item_parent_id' => self::get_item_parent_id($post),
+ 'read' => 0,
+ 'user_id' => $user,
+ ));
}
}
- $this->db->sql_freeresult($result);
return $notify_users;
}
@@ -188,9 +202,9 @@ class post extends \phpbb\notification\type\base
'username' => $this->get_data('post_username'),
)), $responders);
- $responders_cnt = sizeof($responders);
+ $responders_cnt = count($responders);
$responders = $this->trim_user_ary($responders);
- $trimmed_responders_cnt = $responders_cnt - sizeof($responders);
+ $trimmed_responders_cnt = $responders_cnt - count($responders);
foreach ($responders as $responder)
{
@@ -206,14 +220,14 @@ class post extends \phpbb\notification\type\base
if ($trimmed_responders_cnt > 20)
{
- $usernames[] = $this->user->lang('NOTIFICATION_MANY_OTHERS');
+ $usernames[] = $this->language->lang('NOTIFICATION_MANY_OTHERS');
}
else if ($trimmed_responders_cnt)
{
- $usernames[] = $this->user->lang('NOTIFICATION_X_OTHERS', $trimmed_responders_cnt);
+ $usernames[] = $this->language->lang('NOTIFICATION_X_OTHERS', $trimmed_responders_cnt);
}
- return $this->user->lang(
+ return $this->language->lang(
$this->language_key,
phpbb_generate_string_list($usernames, $this->user),
$responders_cnt
@@ -227,7 +241,7 @@ class post extends \phpbb\notification\type\base
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('topic_title'))
);
@@ -323,7 +337,7 @@ class post extends \phpbb\notification\type\base
*/
public function trim_user_ary($users)
{
- if (sizeof($users) > 4)
+ if (count($users) > 4)
{
array_splice($users, 3);
}
@@ -343,7 +357,7 @@ class post extends \phpbb\notification\type\base
*/
public function pre_create_insert_array($post, $notify_users)
{
- if (!sizeof($notify_users) || !$this->inherit_read_status)
+ if (!count($notify_users) || !$this->inherit_read_status)
{
return array();
}
@@ -363,13 +377,7 @@ class post extends \phpbb\notification\type\base
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
@@ -394,13 +402,14 @@ class post extends \phpbb\notification\type\base
$this->notification_read = true;
}
- return parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
}
/**
* Add responders to the notification
*
* @param mixed $post
+ * @return array Array of responder data
*/
public function add_responders($post)
{
@@ -417,7 +426,7 @@ class post extends \phpbb\notification\type\base
// Do not add more than 25 responders,
// we trim the username list to "a, b, c and x others" anyway
// so there is no use to add all of them anyway.
- if (sizeof($responders) > 25)
+ if (count($responders) > 25)
{
return array();
}
@@ -447,6 +456,12 @@ class post extends \phpbb\notification\type\base
return array();
}
- return array('notification_data' => $serialized_data);
+ $data_array = array_merge(array(
+ 'post_time' => $post['post_time'],
+ 'post_id' => $post['post_id'],
+ 'topic_id' => $post['topic_id']
+ ), $this->get_data(false));
+
+ return $data_array;
}
}
diff --git a/phpBB/phpbb/notification/type/post_in_queue.php b/phpBB/phpbb/notification/type/post_in_queue.php
index 5832c99cd2..2d556fc9c8 100644
--- a/phpBB/phpbb/notification/type/post_in_queue.php
+++ b/phpBB/phpbb/notification/type/post_in_queue.php
@@ -43,7 +43,7 @@ class post_in_queue extends \phpbb\notification\type\post
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'notification.type.needs_approval',
'lang' => 'NOTIFICATION_TYPE_IN_MODERATION_QUEUE',
'group' => 'NOTIFICATION_GROUP_MODERATION',
@@ -131,19 +131,22 @@ class post_in_queue extends \phpbb\notification\type\post
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
- $data = parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = time();
+ }
- $this->notification_time = $data['notification_time'] = time();
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/quote.php b/phpBB/phpbb/notification/type/quote.php
index 2732cb84e4..323c18b204 100644
--- a/phpBB/phpbb/notification/type/quote.php
+++ b/phpBB/phpbb/notification/type/quote.php
@@ -21,6 +21,11 @@ namespace phpbb\notification\type;
class quote extends \phpbb\notification\type\post
{
/**
+ * @var \phpbb\textformatter\utils_interface
+ */
+ protected $utils;
+
+ /**
* Get notification type name
*
* @return string
@@ -31,13 +36,6 @@ class quote extends \phpbb\notification\type\post
}
/**
- * regular expression to match to find usernames
- *
- * @var string
- */
- protected static $regular_expression_match = '#\[quote=&quot;(.+?)&quot;#';
-
- /**
* Language key used to output the text
*
* @var string
@@ -50,7 +48,7 @@ class quote extends \phpbb\notification\type\post
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'lang' => 'NOTIFICATION_TYPE_QUOTE',
'group' => 'NOTIFICATION_GROUP_POSTING',
);
@@ -77,17 +75,16 @@ class quote extends \phpbb\notification\type\post
'ignore_users' => array(),
), $options);
- $usernames = false;
- preg_match_all(static::$regular_expression_match, $post['post_text'], $usernames);
+ $usernames = $this->utils->get_outermost_quote_authors($post['post_text']);
- if (empty($usernames[1]))
+ if (empty($usernames))
{
return array();
}
- $usernames[1] = array_unique($usernames[1]);
+ $usernames = array_unique($usernames);
- $usernames = array_map('utf8_clean_string', $usernames[1]);
+ $usernames = array_map('utf8_clean_string', $usernames);
$users = array();
@@ -109,32 +106,23 @@ class quote extends \phpbb\notification\type\post
* Update a notification
*
* @param array $post Data specific for this type that will be updated
+ * @return true
*/
public function update_notifications($post)
{
- $old_notifications = array();
- $sql = 'SELECT n.user_id
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
- WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
- AND n.item_id = ' . static::get_item_id($post) . '
- AND nt.notification_type_id = n.notification_type_id
- AND nt.notification_type_enabled = 1';
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- $old_notifications[] = $row['user_id'];
- }
- $this->db->sql_freeresult($result);
+ $old_notifications = $this->notification_manager->get_notified_users($this->get_type(), array(
+ 'item_id' => static::get_item_id($post),
+ ));
// Find the new users to notify
$notifications = $this->find_users_for_notification($post);
// Find the notifications we must delete
- $remove_notifications = array_diff($old_notifications, array_keys($notifications));
+ $remove_notifications = array_diff(array_keys($old_notifications), array_keys($notifications));
// Find the notifications we must add
$add_notifications = array();
- foreach (array_diff(array_keys($notifications), $old_notifications) as $user_id)
+ foreach (array_diff(array_keys($notifications), array_keys($old_notifications)) as $user_id)
{
$add_notifications[$user_id] = $notifications[$user_id];
}
@@ -145,11 +133,7 @@ class quote extends \phpbb\notification\type\post
// Remove the necessary notifications
if (!empty($remove_notifications))
{
- $sql = 'DELETE FROM ' . $this->notifications_table . '
- WHERE notification_type_id = ' . (int) $this->notification_type_id . '
- AND item_id = ' . static::get_item_id($post) . '
- AND ' . $this->db->sql_in_set('user_id', $remove_notifications);
- $this->db->sql_query($sql);
+ $this->notification_manager->delete_notifications($this->get_type(), static::get_item_id($post), false, $remove_notifications);
}
// return true to continue with the update code in the notifications service (this will update the rest of the notifications)
@@ -187,4 +171,14 @@ class quote extends \phpbb\notification\type\post
'AUTHOR_NAME' => htmlspecialchars_decode($user_data['username']),
));
}
+
+ /**
+ * Set the utils service used to retrieve quote authors
+ *
+ * @param \phpbb\textformatter\utils_interface $utils
+ */
+ public function set_utils(\phpbb\textformatter\utils_interface $utils)
+ {
+ $this->utils = $utils;
+ }
}
diff --git a/phpBB/phpbb/notification/type/report_pm.php b/phpBB/phpbb/notification/type/report_pm.php
index fc39623c5c..444f98270d 100644
--- a/phpBB/phpbb/notification/type/report_pm.php
+++ b/phpBB/phpbb/notification/type/report_pm.php
@@ -60,7 +60,7 @@ class report_pm extends \phpbb\notification\type\pm
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'notification.type.report',
'lang' => 'NOTIFICATION_TYPE_REPORT',
'group' => 'NOTIFICATION_GROUP_MODERATION',
@@ -70,8 +70,9 @@ class report_pm extends \phpbb\notification\type\pm
* Get the id of the parent
*
* @param array $pm The data from the pm
+ * @return int The report id
*/
- public static function get_item_parent_id($pm)
+ static public function get_item_parent_id($pm)
{
return (int) $pm['report_id'];
}
@@ -141,13 +142,16 @@ class report_pm extends \phpbb\notification\type\pm
*/
public function get_email_template_variables()
{
- $user_data = $this->user_loader->get_user($this->get_data('reporter_id'));
+ $user_data = $this->user_loader->get_user($this->get_data('from_user_id'));
return array(
- 'AUTHOR_NAME' => htmlspecialchars_decode($user_data['username']),
- 'SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('message_subject'))),
+ 'AUTHOR_NAME' => htmlspecialchars_decode($user_data['username']),
+ 'SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('message_subject'))),
- 'U_VIEW_REPORT' => generate_board_url() . "mcp.{$this->php_ext}?r={$this->item_parent_id}&amp;i=pm_reports&amp;mode=pm_report_details",
+ /** @deprecated 3.2.6-RC1 (to be removed in 4.0.0) use {SUBJECT} instead in report_pm.txt */
+ 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('message_subject'))),
+
+ 'U_VIEW_REPORT' => generate_board_url() . "/mcp.{$this->php_ext}?r={$this->item_parent_id}&amp;i=pm_reports&amp;mode=pm_report_details",
);
}
@@ -168,11 +172,11 @@ class report_pm extends \phpbb\notification\type\pm
*/
public function get_title()
{
- $this->user->add_lang('mcp');
+ $this->language->add_lang('mcp');
$username = $this->user_loader->get_username($this->get_data('reporter_id'), 'no_profile');
- return $this->user->lang(
+ return $this->language->lang(
$this->language_key,
$username
);
@@ -185,7 +189,7 @@ class report_pm extends \phpbb\notification\type\pm
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('message_subject'))
);
@@ -200,21 +204,21 @@ class report_pm extends \phpbb\notification\type\pm
{
if ($this->get_data('report_text'))
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
$this->get_data('report_text')
);
}
- if (isset($this->user->lang[$this->get_data('reason_title')]))
+ if ($this->language->is_set($this->get_data('reason_title')))
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
- $this->user->lang[$this->get_data('reason_title')]
+ $this->language->lang($this->get_data('reason_title'))
);
}
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
$this->get_data('reason_description')
);
@@ -235,17 +239,13 @@ class report_pm extends \phpbb\notification\type\pm
*/
public function users_to_query()
{
- return array($this->get_data('reporter_id'));
- }
+ return array(
+ $this->get_data('from_user_id'),
+ $this->get_data('reporter_id'),
+ ); }
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
@@ -254,6 +254,6 @@ class report_pm extends \phpbb\notification\type\pm
$this->set_data('reason_description', $post['reason_description']);
$this->set_data('report_text', $post['report_text']);
- return parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
}
}
diff --git a/phpBB/phpbb/notification/type/report_pm_closed.php b/phpBB/phpbb/notification/type/report_pm_closed.php
index 1c99db60c3..5e98eb5feb 100644
--- a/phpBB/phpbb/notification/type/report_pm_closed.php
+++ b/phpBB/phpbb/notification/type/report_pm_closed.php
@@ -64,7 +64,7 @@ class report_pm_closed extends \phpbb\notification\type\pm
return array();
}
- return array($pm['reporter'] => array(''));
+ return array($pm['reporter'] => $this->notification_manager->get_default_methods());
}
/**
@@ -106,7 +106,7 @@ class report_pm_closed extends \phpbb\notification\type\pm
{
$username = $this->user_loader->get_username($this->get_data('closer_id'), 'no_profile');
- return $this->user->lang(
+ return $this->language->lang(
$this->language_key,
$username
);
@@ -119,7 +119,7 @@ class report_pm_closed extends \phpbb\notification\type\pm
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('message_subject'))
);
@@ -144,21 +144,24 @@ class report_pm_closed extends \phpbb\notification\type\pm
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $pm PM Data
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($pm, $pre_create_data = array())
{
$this->set_data('closer_id', $pm['closer_id']);
- $data = parent::create_insert_array($pm, $pre_create_data);
+ parent::create_insert_array($pm, $pre_create_data);
+
+ $this->notification_time = time();
+ }
- $this->notification_time = $data['notification_time'] = time();
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/report_post.php b/phpBB/phpbb/notification/type/report_post.php
index aed31e8642..84a5241417 100644
--- a/phpBB/phpbb/notification/type/report_post.php
+++ b/phpBB/phpbb/notification/type/report_post.php
@@ -66,7 +66,7 @@ class report_post extends \phpbb\notification\type\post_in_queue
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id' and 'lang')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'notification.type.report',
'lang' => 'NOTIFICATION_TYPE_REPORT',
'group' => 'NOTIFICATION_GROUP_MODERATION',
@@ -139,11 +139,11 @@ class report_post extends \phpbb\notification\type\post_in_queue
*/
public function get_title()
{
- $this->user->add_lang('mcp');
+ $this->language->add_lang('mcp');
$username = $this->user_loader->get_username($this->get_data('reporter_id'), 'no_profile');
- return $this->user->lang(
+ return $this->language->lang(
$this->language_key,
$username
);
@@ -156,7 +156,7 @@ class report_post extends \phpbb\notification\type\post_in_queue
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('post_subject'))
);
@@ -171,21 +171,21 @@ class report_post extends \phpbb\notification\type\post_in_queue
{
if ($this->get_data('report_text'))
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
$this->get_data('report_text')
);
}
- if (isset($this->user->lang[$this->get_data('reason_title')]))
+ if ($this->language->is_set($this->get_data('reason_title')))
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
- $this->user->lang[$this->get_data('reason_title')]
+ $this->language->lang($this->get_data('reason_title'))
);
}
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REASON',
$this->get_data('reason_description')
);
@@ -210,13 +210,7 @@ class report_post extends \phpbb\notification\type\post_in_queue
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
@@ -225,6 +219,6 @@ class report_post extends \phpbb\notification\type\post_in_queue
$this->set_data('reason_description', $post['reason_description']);
$this->set_data('report_text', $post['report_text']);
- return parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
}
}
diff --git a/phpBB/phpbb/notification/type/report_post_closed.php b/phpBB/phpbb/notification/type/report_post_closed.php
index 3f4378628b..165034d57e 100644
--- a/phpBB/phpbb/notification/type/report_post_closed.php
+++ b/phpBB/phpbb/notification/type/report_post_closed.php
@@ -71,7 +71,7 @@ class report_post_closed extends \phpbb\notification\type\post
return array();
}
- return array($post['reporter'] => array(''));
+ return array($post['reporter'] => $this->notification_manager->get_default_methods());
}
/**
@@ -113,7 +113,7 @@ class report_post_closed extends \phpbb\notification\type\post
{
$username = $this->user_loader->get_username($this->get_data('closer_id'), 'no_profile');
- return $this->user->lang(
+ return $this->language->lang(
$this->language_key,
$username
);
@@ -126,7 +126,7 @@ class report_post_closed extends \phpbb\notification\type\post
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('post_subject'))
);
@@ -151,21 +151,24 @@ class report_post_closed extends \phpbb\notification\type\post
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
$this->set_data('closer_id', $post['closer_id']);
- $data = parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
+
+ $this->notification_time = time();
+ }
- $this->notification_time = $data['notification_time'] = time();
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/topic.php b/phpBB/phpbb/notification/type/topic.php
index fb08a9eee1..5c42afa8c8 100644
--- a/phpBB/phpbb/notification/type/topic.php
+++ b/phpBB/phpbb/notification/type/topic.php
@@ -50,11 +50,27 @@ class topic extends \phpbb\notification\type\base
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'lang' => 'NOTIFICATION_TYPE_TOPIC',
'group' => 'NOTIFICATION_GROUP_POSTING',
);
+ /** @var \phpbb\user_loader */
+ protected $user_loader;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ public function set_config(\phpbb\config\config $config)
+ {
+ $this->config = $config;
+ }
+
+ public function set_user_loader(\phpbb\user_loader $user_loader)
+ {
+ $this->user_loader = $user_loader;
+ }
+
/**
* Is available
*/
@@ -67,8 +83,9 @@ class topic extends \phpbb\notification\type\base
* Get the id of the item
*
* @param array $post The data from the post
+ * @return int The topic id
*/
- public static function get_item_id($post)
+ static public function get_item_id($post)
{
return (int) $post['topic_id'];
}
@@ -77,8 +94,9 @@ class topic extends \phpbb\notification\type\base
* Get the id of the parent
*
* @param array $post The data from the post
+ * @return int The forum id
*/
- public static function get_item_parent_id($post)
+ static public function get_item_parent_id($post)
{
return (int) $post['forum_id'];
}
@@ -138,7 +156,7 @@ class topic extends \phpbb\notification\type\base
$username = $this->user_loader->get_username($this->get_data('poster_id'), 'no_profile');
}
- return $this->user->lang(
+ return $this->language->lang(
$this->language_key,
$username
);
@@ -151,7 +169,7 @@ class topic extends \phpbb\notification\type\base
*/
public function get_reference()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_REFERENCE',
censor_text($this->get_data('topic_title'))
);
@@ -164,7 +182,7 @@ class topic extends \phpbb\notification\type\base
*/
public function get_forum()
{
- return $this->user->lang(
+ return $this->language->lang(
'NOTIFICATION_FORUM',
$this->get_data('forum_name')
);
@@ -243,7 +261,7 @@ class topic extends \phpbb\notification\type\base
*/
public function pre_create_insert_array($post, $notify_users)
{
- if (!sizeof($notify_users) || !$this->inherit_read_status)
+ if (!count($notify_users) || !$this->inherit_read_status)
{
return array();
}
@@ -263,13 +281,7 @@ class topic extends \phpbb\notification\type\base
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $post Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($post, $pre_create_data = array())
{
@@ -290,6 +302,6 @@ class topic extends \phpbb\notification\type\base
$this->notification_read = true;
}
- return parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
}
}
diff --git a/phpBB/phpbb/notification/type/topic_in_queue.php b/phpBB/phpbb/notification/type/topic_in_queue.php
index 6e57b9ac0c..2d732b9cd7 100644
--- a/phpBB/phpbb/notification/type/topic_in_queue.php
+++ b/phpBB/phpbb/notification/type/topic_in_queue.php
@@ -43,7 +43,7 @@ class topic_in_queue extends \phpbb\notification\type\topic
* @var bool|array False if the service should use it's default data
* Array of data (including keys 'id', 'lang', and 'group')
*/
- public static $notification_option = array(
+ static public $notification_option = array(
'id' => 'notification.type.needs_approval',
'lang' => 'NOTIFICATION_TYPE_IN_MODERATION_QUEUE',
'group' => 'NOTIFICATION_GROUP_MODERATION',
@@ -123,19 +123,22 @@ class topic_in_queue extends \phpbb\notification\type\topic
}
/**
- * Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
- *
- * @param array $topic Data from submit_post
- * @param array $pre_create_data Data from pre_create_insert_array()
- *
- * @return array Array of data ready to be inserted into the database
+ * {@inheritdoc}
*/
public function create_insert_array($topic, $pre_create_data = array())
{
- $data = parent::create_insert_array($topic, $pre_create_data);
+ parent::create_insert_array($topic, $pre_create_data);
+
+ $this->notification_time = time();
+ }
- $this->notification_time = $data['notification_time'] = time();
+ /**
+ * {@inheritdoc}
+ */
+ public function get_insert_array()
+ {
+ $data = parent::get_insert_array();
+ $data['notification_time'] = $this->notification_time;
return $data;
}
diff --git a/phpBB/phpbb/notification/type/type_interface.php b/phpBB/phpbb/notification/type/type_interface.php
index 5c5a110836..f9f832bdda 100644
--- a/phpBB/phpbb/notification/type/type_interface.php
+++ b/phpBB/phpbb/notification/type/type_interface.php
@@ -37,14 +37,14 @@ interface type_interface
*
* @param array $type_data The type specific data
*/
- public static function get_item_id($type_data);
+ static public function get_item_id($type_data);
/**
* Get the id of the parent
*
* @param array $type_data The type specific data
*/
- public static function get_item_parent_id($type_data);
+ static public function get_item_parent_id($type_data);
/**
* Is this type available to the current user (defines whether or not it will be shown in the UCP Edit notification options)
@@ -177,14 +177,18 @@ interface type_interface
/**
* Function for preparing the data for insertion in an SQL query
- * (The service handles insertion)
*
* @param array $type_data The type specific data
* @param array $pre_create_data Data from pre_create_insert_array()
+ */
+ public function create_insert_array($type_data, $pre_create_data);
+
+ /**
+ * Function for getting the data for insertion in an SQL query
*
* @return array Array of data ready to be inserted into the database
*/
- public function create_insert_array($type_data, $pre_create_data);
+ public function get_insert_array();
/**
* Function for preparing the data for update in an SQL query
@@ -202,7 +206,7 @@ interface type_interface
* @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
* @return string
*/
- public function mark_read($return);
+ public function mark_read($return = false);
/**
* Mark this item unread
@@ -210,5 +214,5 @@ interface type_interface
* @param bool $return True to return a string containing the SQL code to update this item, False to execute it (Default: False)
* @return string
*/
- public function mark_unread($return);
+ public function mark_unread($return = false);
}
diff --git a/phpBB/phpbb/pagination.php b/phpBB/phpbb/pagination.php
index 7a81c25ad2..a7086f6691 100644
--- a/phpBB/phpbb/pagination.php
+++ b/phpBB/phpbb/pagination.php
@@ -46,7 +46,7 @@ class pagination
/**
* Generate a pagination link based on the url and the page information
*
- * @param string $base_url is url prepended to all links generated within the function
+ * @param string|array $base_url is url prepended to all links generated within the function
* If you use page numbers inside your controller route, base_url should contains a placeholder (%d)
* for the page. Also be sure to specify the pagination path information into the start_name argument
* @param string $on_page is the page for which we want to generate the link
@@ -69,7 +69,7 @@ class pagination
* set $generate_page_link_override to the new URL value
*
* @event core.pagination_generate_page_link
- * @var string base_url is url prepended to all links generated within the function
+ * @var string|array base_url is url prepended to all links generated within the function
* If you use page numbers inside your controller route, base_url should contains a placeholder (%d)
* for the page. Also be sure to specify the pagination path information into the start_name argument
* @var string on_page is the page for which we want to generate the link
@@ -120,7 +120,7 @@ class pagination
* Generate template rendered pagination
* Allows full control of rendering of pagination with the template
*
- * @param string $base_url is url prepended to all links generated within the function
+ * @param string|array $base_url is url prepended to all links generated within the function
* If you use page numbers inside your controller route, base_url should contains a placeholder (%d)
* for the page. Also be sure to specify the pagination path information into the start_name argument
* @param string $block_var_name is the name assigned to the pagination data block within the template (example: <!-- BEGIN pagination -->)
@@ -132,10 +132,15 @@ class pagination
* @param int $start the item which should be considered currently active, used to determine the page we're on
* @param bool $reverse_count determines whether we weight display of the list towards the start (false) or end (true) of the list
* @param bool $ignore_on_page decides whether we enable an active (unlinked) item, used primarily for embedded lists
- * @return null
+ * @return void
*/
public function generate_template_pagination($base_url, $block_var_name, $start_name, $num_items, $per_page, $start = 1, $reverse_count = false, $ignore_on_page = false)
{
+ if (empty($base_url))
+ {
+ return;
+ }
+
$total_pages = ceil($num_items / $per_page);
$on_page = $this->get_on_page($per_page, $start);
$u_previous_page = $u_next_page = '';
@@ -284,7 +289,7 @@ class pagination
*/
public function get_on_page($per_page, $start)
{
- return floor($start / $per_page) + 1;
+ return floor((int) $start / (int) $per_page) + 1;
}
/**
diff --git a/phpBB/phpbb/passwords/driver/base.php b/phpBB/phpbb/passwords/driver/base.php
index fd07a61bf4..0997b5b700 100644
--- a/phpBB/phpbb/passwords/driver/base.php
+++ b/phpBB/phpbb/passwords/driver/base.php
@@ -13,7 +13,7 @@
namespace phpbb\passwords\driver;
-abstract class base implements driver_interface
+abstract class base implements rehashable_driver_interface
{
/** @var \phpbb\config\config */
protected $config;
@@ -21,7 +21,7 @@ abstract class base implements driver_interface
/** @var \phpbb\passwords\driver\helper */
protected $helper;
- /** @var driver name */
+ /** @var string Driver name */
protected $name;
/**
@@ -53,6 +53,14 @@ abstract class base implements driver_interface
}
/**
+ * {@inheritdoc}
+ */
+ public function needs_rehash($hash)
+ {
+ return false;
+ }
+
+ /**
* {@inheritdoc}
*/
public function get_settings_only($hash, $full = false)
diff --git a/phpBB/phpbb/passwords/driver/bcrypt.php b/phpBB/phpbb/passwords/driver/bcrypt.php
index eab1c3d569..eb1aeeeb76 100644
--- a/phpBB/phpbb/passwords/driver/bcrypt.php
+++ b/phpBB/phpbb/passwords/driver/bcrypt.php
@@ -17,6 +17,24 @@ class bcrypt extends base
{
const PREFIX = '$2a$';
+ /** @var int Hashing cost factor */
+ protected $cost_factor;
+
+ /**
+ * Constructor of passwords driver object
+ *
+ * @param \phpbb\config\config $config phpBB config
+ * @param \phpbb\passwords\driver\helper $helper Password driver helper
+ * @param int $cost_factor Hashing cost factor (optional)
+ */
+ public function __construct(\phpbb\config\config $config, helper $helper, $cost_factor = 10)
+ {
+ parent::__construct($config, $helper);
+
+ // Don't allow cost factor to be below default setting
+ $this->cost_factor = max(10, $cost_factor);
+ }
+
/**
* {@inheritdoc}
*/
@@ -26,6 +44,18 @@ class bcrypt extends base
}
/**
+ * {@inheritdoc}
+ */
+ public function needs_rehash($hash)
+ {
+ preg_match('/^' . preg_quote($this->get_prefix()) . '([0-9]+)\$/', $hash, $matches);
+
+ list(, $cost_factor) = $matches;
+
+ return empty($cost_factor) || $this->cost_factor !== intval($cost_factor);
+ }
+
+ /**
* {@inheritdoc}
*/
public function hash($password, $salt = '')
@@ -46,7 +76,7 @@ class bcrypt extends base
if ($salt == '')
{
- $salt = $prefix . '10$' . $this->get_random_salt();
+ $salt = $prefix . $this->cost_factor . '$' . $this->get_random_salt();
}
$hash = crypt($password, $salt);
diff --git a/phpBB/phpbb/passwords/driver/md5_phpbb2.php b/phpBB/phpbb/passwords/driver/md5_phpbb2.php
index bd8cc51e5a..b38b041d6c 100644
--- a/phpBB/phpbb/passwords/driver/md5_phpbb2.php
+++ b/phpBB/phpbb/passwords/driver/md5_phpbb2.php
@@ -95,7 +95,7 @@ class md5_phpbb2 extends base
// in phpBB2 passwords were used exactly as they were sent, with addslashes applied
$password_old_format = isset($_REQUEST['password']) ? (string) $_REQUEST['password'] : '';
- $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format;
+ $password_old_format = addslashes($password_old_format);
$password_new_format = $this->request->variable('password', '', true);
if ($super_globals_disabled)
diff --git a/phpBB/phpbb/passwords/driver/rehashable_driver_interface.php b/phpBB/phpbb/passwords/driver/rehashable_driver_interface.php
new file mode 100644
index 0000000000..ca30748502
--- /dev/null
+++ b/phpBB/phpbb/passwords/driver/rehashable_driver_interface.php
@@ -0,0 +1,25 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\passwords\driver;
+
+interface rehashable_driver_interface extends driver_interface
+{
+ /**
+ * Check if password needs to be rehashed
+ *
+ * @param string $hash Hash to check for rehash
+ * @return bool True if password needs to be rehashed, false if not
+ */
+ public function needs_rehash($hash);
+}
diff --git a/phpBB/phpbb/passwords/manager.php b/phpBB/phpbb/passwords/manager.php
index aa9147ecf4..fad76a9fe5 100644
--- a/phpBB/phpbb/passwords/manager.php
+++ b/phpBB/phpbb/passwords/manager.php
@@ -50,21 +50,47 @@ class manager
protected $config;
/**
+ * @var bool Whether or not initialized() has been called
+ */
+ private $initialized = false;
+
+ /**
+ * @var array Hashing driver service collection
+ */
+ private $hashing_algorithms;
+
+ /**
+ * @var array List of default driver types
+ */
+ private $defaults;
+
+ /**
* Construct a passwords object
*
- * @param \phpbb\config\config $config phpBB configuration
- * @param array $hashing_algorithms Hashing driver
- * service collection
- * @param \phpbb\passwords\helper $helper Passwords helper object
- * @param array $defaults List of default driver types
+ * @param \phpbb\config\config $config phpBB configuration
+ * @param array $hashing_algorithms Hashing driver service collection
+ * @param \phpbb\passwords\helper $helper Passwords helper object
+ * @param array $defaults List of default driver types
*/
public function __construct(\phpbb\config\config $config, $hashing_algorithms, helper $helper, $defaults)
{
$this->config = $config;
$this->helper = $helper;
+ $this->hashing_algorithms = $hashing_algorithms;
+ $this->defaults = $defaults;
+ }
- $this->fill_type_map($hashing_algorithms);
- $this->register_default_type($defaults);
+ /**
+ * Initialize the internal state
+ */
+ protected function initialize()
+ {
+ if (!$this->initialized)
+ {
+ $this->initialized = true;
+ $this->fill_type_map($this->hashing_algorithms);
+ $this->register_default_type($this->defaults);
+ }
}
/**
@@ -144,9 +170,11 @@ class manager
return false;
}
+ $this->initialize();
+
// Be on the lookout for multiple hashing algorithms
// 2 is correct: H\2a > 2, H\P > 2
- if (strlen($match[1]) > 2)
+ if (strlen($match[1]) > 2 && strpos($match[1], '\\') !== false)
{
$hash_types = explode('\\', $match[1]);
$return_ary = array();
@@ -192,6 +220,8 @@ class manager
return false;
}
+ $this->initialize();
+
// Try to retrieve algorithm by service name if type doesn't
// start with dollar sign
if (!is_array($type) && strpos($type, '$') !== 0 && isset($this->algorithms[$type]))
@@ -242,6 +272,8 @@ class manager
return false;
}
+ $this->initialize();
+
// First find out what kind of hash we're dealing with
$stored_hash_type = $this->detect_algorithm($hash);
if ($stored_hash_type == false)
@@ -265,7 +297,14 @@ class manager
}
else
{
- $this->convert_flag = false;
+ if ($stored_hash_type instanceof driver\rehashable_driver_interface)
+ {
+ $this->convert_flag = $stored_hash_type->needs_rehash($hash);
+ }
+ else
+ {
+ $this->convert_flag = false;
+ }
}
// Check all legacy hash types if prefix is $CP$
@@ -297,6 +336,8 @@ class manager
*/
public function combined_hash_password($password_hash, $type)
{
+ $this->initialize();
+
$data = array(
'prefix' => '$',
'settings' => '$',
diff --git a/phpBB/phpbb/path_helper.php b/phpBB/phpbb/path_helper.php
index 5400c1c5a6..5b6db35f23 100644
--- a/phpBB/phpbb/path_helper.php
+++ b/phpBB/phpbb/path_helper.php
@@ -21,7 +21,7 @@ class path_helper
/** @var \phpbb\symfony_request */
protected $symfony_request;
- /** @var \phpbb\filesystem */
+ /** @var \phpbb\filesystem\filesystem_interface */
protected $filesystem;
/** @var \phpbb\request\request_interface */
@@ -43,13 +43,13 @@ class path_helper
* Constructor
*
* @param \phpbb\symfony_request $symfony_request
- * @param \phpbb\filesystem $filesystem
+ * @param \phpbb\filesystem\filesystem_interface $filesystem
* @param \phpbb\request\request_interface $request
* @param string $phpbb_root_path Relative path to phpBB root
* @param string $php_ext PHP file extension
* @param mixed $adm_relative_path Relative path admin path to adm/ root
*/
- public function __construct(\phpbb\symfony_request $symfony_request, \phpbb\filesystem $filesystem, \phpbb\request\request_interface $request, $phpbb_root_path, $php_ext, $adm_relative_path = null)
+ public function __construct(\phpbb\symfony_request $symfony_request, \phpbb\filesystem\filesystem_interface $filesystem, \phpbb\request\request_interface $request, $phpbb_root_path, $php_ext, $adm_relative_path = null)
{
$this->symfony_request = $symfony_request;
$this->filesystem = $filesystem;
@@ -100,11 +100,18 @@ class path_helper
*/
public function update_web_root_path($path)
{
+ $web_root_path = $this->get_web_root_path();
+
+ // Removes the web root path if it is already present
+ if (strpos($path, $web_root_path) === 0)
+ {
+ $path = $this->phpbb_root_path . substr($path, strlen($web_root_path));
+ }
+
if (strpos($path, $this->phpbb_root_path) === 0)
{
$path = substr($path, strlen($this->phpbb_root_path));
- $web_root_path = $this->get_web_root_path();
if (substr($web_root_path, -8) === 'app.php/' && substr($path, 0, 7) === 'app.php')
{
$path = substr($path, 8);
@@ -489,4 +496,17 @@ class path_helper
return $page;
}
+
+ /**
+ * Tells if the router is currently in use (if the current page is a route or not)
+ *
+ * @return bool
+ */
+ public function is_router_used()
+ {
+ // Script name URI (e.g. phpBB/app.php)
+ $script_name = $this->symfony_request->getScriptName();
+
+ return basename($script_name) === 'app.' . $this->php_ext;
+ }
}
diff --git a/phpBB/phpbb/permissions.php b/phpBB/phpbb/permissions.php
index e75476f59b..236535cc6a 100644
--- a/phpBB/phpbb/permissions.php
+++ b/phpBB/phpbb/permissions.php
@@ -234,6 +234,7 @@ class permissions
'u_savedrafts' => array('lang' => 'ACL_U_SAVEDRAFTS', 'cat' => 'post'),
'u_chgcensors' => array('lang' => 'ACL_U_CHGCENSORS', 'cat' => 'post'),
'u_sig' => array('lang' => 'ACL_U_SIG', 'cat' => 'post'),
+ 'u_emoji' => array('lang' => 'ACL_U_EMOJI', 'cat' => 'post'),
'u_sendpm' => array('lang' => 'ACL_U_SENDPM', 'cat' => 'pm'),
'u_masspm' => array('lang' => 'ACL_U_MASSPM', 'cat' => 'pm'),
@@ -260,6 +261,7 @@ class permissions
// Forum Permissions
'f_list' => array('lang' => 'ACL_F_LIST', 'cat' => 'actions'),
+ 'f_list_topics' => array('lang' => 'ACL_F_LIST_TOPICS', 'cat' => 'actions'),
'f_read' => array('lang' => 'ACL_F_READ', 'cat' => 'actions'),
'f_search' => array('lang' => 'ACL_F_SEARCH', 'cat' => 'actions'),
'f_subscribe' => array('lang' => 'ACL_F_SUBSCRIBE', 'cat' => 'actions'),
@@ -273,6 +275,7 @@ class permissions
'f_post' => array('lang' => 'ACL_F_POST', 'cat' => 'post'),
'f_sticky' => array('lang' => 'ACL_F_STICKY', 'cat' => 'post'),
'f_announce' => array('lang' => 'ACL_F_ANNOUNCE', 'cat' => 'post'),
+ 'f_announce_global' => array('lang' => 'ACL_F_ANNOUNCE_GLOBAL', 'cat' => 'post'),
'f_reply' => array('lang' => 'ACL_F_REPLY', 'cat' => 'post'),
'f_edit' => array('lang' => 'ACL_F_EDIT', 'cat' => 'post'),
'f_delete' => array('lang' => 'ACL_F_DELETE', 'cat' => 'post'),
diff --git a/phpBB/phpbb/plupload/plupload.php b/phpBB/phpbb/plupload/plupload.php
index 04d681cea6..5a5b8a1874 100644
--- a/phpBB/phpbb/plupload/plupload.php
+++ b/phpBB/phpbb/plupload/plupload.php
@@ -39,7 +39,7 @@ class plupload
protected $user;
/**
- * @var \phpbb\php\ini
+ * @var \bantu\IniGetWrapper\IniGetWrapper
*/
protected $php_ini;
@@ -67,10 +67,10 @@ class plupload
* @param \phpbb\config\config $config
* @param \phpbb\request\request_interface $request
* @param \phpbb\user $user
- * @param \phpbb\php\ini $php_ini
+ * @param \bantu\IniGetWrapper\IniGetWrapper $php_ini
* @param \phpbb\mimetype\guesser $mimetype_guesser
*/
- public function __construct($phpbb_root_path, \phpbb\config\config $config, \phpbb\request\request_interface $request, \phpbb\user $user, \phpbb\php\ini $php_ini, \phpbb\mimetype\guesser $mimetype_guesser)
+ public function __construct($phpbb_root_path, \phpbb\config\config $config, \phpbb\request\request_interface $request, \phpbb\user $user, \bantu\IniGetWrapper\IniGetWrapper $php_ini, \phpbb\mimetype\guesser $mimetype_guesser)
{
$this->phpbb_root_path = $phpbb_root_path;
$this->config = $config;
@@ -216,38 +216,36 @@ class plupload
}
/**
- * Looks at the list of allowed extensions and generates a string
- * appropriate for use in configuring plupload with
- *
- * @param \phpbb\cache\service $cache
- * @param string $forum_id The ID of the forum
- *
- * @return string
- */
+ * Looks at the list of allowed extensions and generates a string
+ * appropriate for use in configuring plupload with
+ *
+ * @param \phpbb\cache\service $cache Cache service object
+ * @param string $forum_id The forum identifier
+ *
+ * @return string
+ */
public function generate_filter_string(\phpbb\cache\service $cache, $forum_id)
{
+ $groups = [];
+ $filters = [];
+
$attach_extensions = $cache->obtain_attach_extensions($forum_id);
unset($attach_extensions['_allowed_']);
- $groups = array();
// Re-arrange the extension array to $groups[$group_name][]
foreach ($attach_extensions as $extension => $extension_info)
{
- if (!isset($groups[$extension_info['group_name']]))
- {
- $groups[$extension_info['group_name']] = array();
- }
-
- $groups[$extension_info['group_name']][] = $extension;
+ $groups[$extension_info['group_name']]['extensions'][] = $extension;
+ $groups[$extension_info['group_name']]['max_file_size'] = (int) $extension_info['max_filesize'];
}
- $filters = array();
- foreach ($groups as $group => $extensions)
+ foreach ($groups as $group => $group_info)
{
$filters[] = sprintf(
- "{title: '%s', extensions: '%s'}",
+ "{title: '%s', extensions: '%s', max_file_size: %s}",
addslashes(ucfirst(strtolower($group))),
- addslashes(implode(',', $extensions))
+ addslashes(implode(',', $group_info['extensions'])),
+ $group_info['max_file_size']
);
}
@@ -276,22 +274,37 @@ class plupload
}
/**
- * Checks various php.ini values and the maximum file size to determine
- * the maximum size chunks a file can be split up into for upload
- *
- * @return int
- */
+ * Checks various php.ini values to determine the maximum chunk
+ * size a file should be split into for upload.
+ *
+ * The intention is to calculate a value which reflects whatever
+ * the most restrictive limit is set to. And to then set the chunk
+ * size to half that value, to ensure any required transfer overhead
+ * and POST data remains well within the limit. Or, if all of the
+ * limits are set to unlimited, the chunk size will also be unlimited.
+ *
+ * @return int
+ *
+ * @access public
+ */
public function get_chunk_size()
{
- $max = min(
- $this->php_ini->get_bytes('upload_max_filesize'),
- $this->php_ini->get_bytes('post_max_size'),
- max(1, $this->php_ini->get_bytes('memory_limit')),
- $this->config['max_filesize']
- );
+ $max = 0;
+
+ $limits = [
+ $this->php_ini->getBytes('memory_limit'),
+ $this->php_ini->getBytes('upload_max_filesize'),
+ $this->php_ini->getBytes('post_max_size'),
+ ];
+
+ foreach ($limits as $limit_type)
+ {
+ if ($limit_type > 0)
+ {
+ $max = ($max !== 0) ? min($limit_type, $max) : $limit_type;
+ }
+ }
- // Use half of the maximum possible to leave plenty of room for other
- // POST data.
return floor($max / 2);
}
@@ -303,7 +316,7 @@ class plupload
$this->temporary_directory,
$this->config['plupload_salt'],
md5($file_name),
- \filespec::get_extension($file_name)
+ \phpbb\files\filespec::get_extension($file_name)
);
}
diff --git a/phpBB/phpbb/profilefields/manager.php b/phpBB/phpbb/profilefields/manager.php
index ea4b24af56..35b18ddf07 100644
--- a/phpBB/phpbb/profilefields/manager.php
+++ b/phpBB/phpbb/profilefields/manager.php
@@ -230,7 +230,7 @@ class manager
*/
public function update_profile_field_data($user_id, $cp_data)
{
- if (!sizeof($cp_data))
+ if (!count($cp_data))
{
return;
}
@@ -258,7 +258,7 @@ class manager
*/
public function generate_profile_fields_template_headlines($restrict_option = '')
{
- if (!sizeof($this->profile_cache))
+ if (!count($this->profile_cache))
{
$this->build_cache();
}
@@ -318,12 +318,12 @@ class manager
$user_ids = array($user_ids);
}
- if (!sizeof($this->profile_cache))
+ if (!count($this->profile_cache))
{
$this->build_cache();
}
- if (!sizeof($user_ids))
+ if (!count($user_ids))
{
return array();
}
@@ -486,7 +486,7 @@ class manager
$sql = 'SELECT f.field_type, f.field_ident, f.field_default_value, l.lang_default_value
FROM ' . $this->fields_language_table . ' l, ' . $this->fields_table . ' f
WHERE l.lang_id = ' . $this->user->get_iso_lang_id() . '
- ' . ((sizeof($sql_not_in)) ? ' AND ' . $this->db->sql_in_set('f.field_ident', $sql_not_in, true) : '') . '
+ ' . ((count($sql_not_in)) ? ' AND ' . $this->db->sql_in_set('f.field_ident', $sql_not_in, true) : '') . '
AND l.field_id = f.field_id';
$result = $this->db->sql_query($sql);
diff --git a/phpBB/phpbb/profilefields/type/type_bool.php b/phpBB/phpbb/profilefields/type/type_bool.php
index f6f3f17a6c..9c09e27bc4 100644
--- a/phpBB/phpbb/profilefields/type/type_bool.php
+++ b/phpBB/phpbb/profilefields/type/type_bool.php
@@ -398,7 +398,7 @@ class type_bool extends type_base
public function display_options(&$template_vars, &$field_data)
{
// Initialize these array elements if we are creating a new field
- if (!sizeof($field_data['lang_options']))
+ if (!count($field_data['lang_options']))
{
// No options have been defined for a boolean field.
$field_data['lang_options'][0] = '';
diff --git a/phpBB/phpbb/profilefields/type/type_date.php b/phpBB/phpbb/profilefields/type/type_date.php
index 63a0c79a3d..5a1a6dbd5c 100644
--- a/phpBB/phpbb/profilefields/type/type_date.php
+++ b/phpBB/phpbb/profilefields/type/type_date.php
@@ -72,7 +72,7 @@ class type_date extends type_base
'lang_options' => $field_data['lang_options'],
);
- $always_now = request_var('always_now', -1);
+ $always_now = $this->request->variable('always_now', -1);
if ($always_now == -1)
{
$s_checked = ($field_data['field_default_value'] == 'now') ? true : false;
diff --git a/phpBB/phpbb/profilefields/type/type_dropdown.php b/phpBB/phpbb/profilefields/type/type_dropdown.php
index 17ae89e1b2..d54404bbb4 100644
--- a/phpBB/phpbb/profilefields/type/type_dropdown.php
+++ b/phpBB/phpbb/profilefields/type/type_dropdown.php
@@ -282,7 +282,7 @@ class type_dropdown extends type_base
*/
public function validate_options_on_submit($error, $field_data)
{
- if (!sizeof($field_data['lang_options']))
+ if (!count($field_data['lang_options']))
{
$error[] = $this->user->lang['NO_FIELD_ENTRIES'];
}
@@ -298,7 +298,7 @@ class type_dropdown extends type_base
if ($step == 2 && $key == 'field_maxlen')
{
// Get the number of options if this key is 'field_maxlen'
- return sizeof(explode("\n", $this->request->variable('lang_options', '', true)));
+ return count(explode("\n", $this->request->variable('lang_options', '', true)));
}
return parent::get_excluded_options($key, $action, $current_value, $field_data, $step);
@@ -310,7 +310,7 @@ class type_dropdown extends type_base
public function display_options(&$template_vars, &$field_data)
{
// Initialize these array elements if we are creating a new field
- if (!sizeof($field_data['lang_options']))
+ if (!count($field_data['lang_options']))
{
// No options have been defined for the dropdown menu
$field_data['lang_options'] = array();
diff --git a/phpBB/phpbb/profilefields/type/type_url.php b/phpBB/phpbb/profilefields/type/type_url.php
index 375cf5b19a..37815b66a5 100644
--- a/phpBB/phpbb/profilefields/type/type_url.php
+++ b/phpBB/phpbb/profilefields/type/type_url.php
@@ -64,11 +64,24 @@ class type_url extends type_string
return false;
}
- if (!preg_match('#^' . get_preg_expression('url') . '$#iu', $field_value))
+ if (!preg_match('#^' . get_preg_expression('url_http') . '$#iu', $field_value))
{
return $this->user->lang('FIELD_INVALID_URL', $this->get_field_name($field_data['lang_name']));
}
return false;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public function get_profile_value($field_value, $field_data)
+ {
+ if (!preg_match('#^' . get_preg_expression('url_http') . '$#iu', $field_value))
+ {
+ return null;
+ }
+
+ return parent::get_profile_value($field_value, $field_data);
+ }
}
diff --git a/phpBB/phpbb/report/controller/report.php b/phpBB/phpbb/report/controller/report.php
new file mode 100644
index 0000000000..0aa6833dfa
--- /dev/null
+++ b/phpBB/phpbb/report/controller/report.php
@@ -0,0 +1,319 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\controller;
+
+use phpbb\exception\http_exception;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
+class report
+{
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /**
+ * @var \phpbb\template\template
+ */
+ protected $template;
+
+ /**
+ * @var \phpbb\controller\helper
+ */
+ protected $helper;
+
+ /**
+ * @var \phpbb\request\request_interface
+ */
+ protected $request;
+
+ /**
+ * @var \phpbb\captcha\factory
+ */
+ protected $captcha_factory;
+
+ /**
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * @var \phpbb\report\report_handler_interface
+ */
+ protected $report_handler;
+
+ /**
+ * @var \phpbb\report\report_reason_list_provider
+ */
+ protected $report_reason_provider;
+
+ public function __construct(\phpbb\config\config $config, \phpbb\user $user, \phpbb\template\template $template, \phpbb\controller\helper $helper, \phpbb\request\request_interface $request, \phpbb\captcha\factory $captcha_factory, \phpbb\report\handler_factory $report_factory, \phpbb\report\report_reason_list_provider $ui_provider, $phpbb_root_path, $php_ext)
+ {
+ $this->config = $config;
+ $this->user = $user;
+ $this->template = $template;
+ $this->helper = $helper;
+ $this->request = $request;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ $this->captcha_factory = $captcha_factory;
+ $this->report_handler = $report_factory;
+
+ // User interface factory
+ $this->report_reason_provider = $ui_provider;
+ }
+
+ /**
+ * Controller for /path_to_entities/{id}/report routes
+ *
+ * Because of how phpBB organizes routes $mode must be set in the route config.
+ *
+ * @param int $id ID of the entity to report
+ * @param string $mode
+ * @return \Symfony\Component\HttpFoundation\Response a Symfony response object
+ * @throws \phpbb\exception\http_exception when $mode or $id is invalid for some reason
+ */
+ public function handle($id, $mode)
+ {
+ // Get report handler
+ $this->report_handler = $this->report_handler->get_instance($mode);
+
+ $this->user->add_lang('mcp');
+
+ $user_notify = ($this->user->data['is_registered']) ? $this->request->variable('notify', 0) : false;
+ $reason_id = $this->request->variable('reason_id', 0);
+ $report_text = $this->request->variable('report_text', '', true);
+
+ $submit = $this->request->variable('submit', '');
+ $cancel = $this->request->variable('cancel', '');
+
+ $error = array();
+ $s_hidden_fields = '';
+
+ $redirect_url = append_sid(
+ $this->phpbb_root_path . ( ($mode === 'pm') ? 'ucp' : 'viewtopic' ) . ".{$this->php_ext}",
+ ($mode == 'pm') ? "i=pm&mode=view&p=$id" : "p=$id"
+ );
+ $redirect_url .= ($mode === 'post') ? "#p$id" : '';
+
+ // Set up CAPTCHA if necessary
+ if ($this->config['enable_post_confirm'] && !$this->user->data['is_registered'])
+ {
+ $captcha = $this->captcha_factory->get_instance($this->config['captcha_plugin']);
+ $captcha->init(CONFIRM_REPORT);
+ }
+
+ //Has the report been cancelled?
+ if (!empty($cancel))
+ {
+ return new RedirectResponse($redirect_url, 302);
+ }
+
+ // Check CAPTCHA, if the form was submited
+ if (!empty($submit) && isset($captcha))
+ {
+ $captcha_template_array = $this->check_captcha($captcha);
+ $error = $captcha_template_array['error'];
+ $s_hidden_fields = $captcha_template_array['hidden_fields'];
+ }
+
+ // Handle request
+ try
+ {
+ if (!empty($submit) && count($error) === 0)
+ {
+ $this->report_handler->add_report(
+ (int) $id,
+ (int) $reason_id,
+ (string) $report_text,
+ (int) $user_notify
+ );
+
+ // Send success message
+ switch ($mode)
+ {
+ case 'pm':
+ $lang_return = $this->user->lang['RETURN_PM'];
+ $lang_success = $this->user->lang['PM_REPORTED_SUCCESS'];
+ break;
+ case 'post':
+ $lang_return = $this->user->lang['RETURN_TOPIC'];
+ $lang_success = $this->user->lang['POST_REPORTED_SUCCESS'];
+ break;
+ }
+
+ $this->helper->assign_meta_refresh_var(3, $redirect_url);
+ $message = $lang_success . '<br /><br />' . sprintf($lang_return, '<a href="' . $redirect_url . '">', '</a>');
+ return $this->helper->message($message);
+ }
+ else
+ {
+ $this->report_handler->validate_report_request($id);
+ }
+ }
+ catch (\phpbb\report\exception\pm_reporting_disabled_exception $exception)
+ {
+ throw new http_exception(404, 'PAGE_NOT_FOUND');
+ }
+ catch (\phpbb\report\exception\already_reported_exception $exception)
+ {
+ switch ($mode)
+ {
+ case 'pm':
+ $message = $this->user->lang['ALREADY_REPORTED_PM'];
+ $message .= '<br /><br />' . sprintf($this->user->lang['RETURN_PM'], '<a href="' . $redirect_url . '">', '</a>');
+ break;
+ case 'post':
+ $message = $this->user->lang['ALREADY_REPORTED'];
+ $message .= '<br /><br />' . sprintf($this->user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
+ break;
+ }
+
+ return $this->helper->message($message);
+ }
+ catch (\phpbb\report\exception\report_permission_denied_exception $exception)
+ {
+ $message = $exception->getMessage();
+ if (isset($this->user->lang[$message]))
+ {
+ $message = $this->user->lang[$message];
+ }
+
+ throw new http_exception(403, $message);
+ }
+ catch (\phpbb\report\exception\entity_not_found_exception $exception)
+ {
+ $message = $exception->getMessage();
+ if (isset($this->user->lang[$message]))
+ {
+ $message = $this->user->lang[$message];
+ }
+
+ throw new http_exception(404, $message);
+ }
+ catch (\phpbb\report\exception\empty_report_exception $exception)
+ {
+ $error[] = $this->user->lang['EMPTY_REPORT'];
+ }
+ catch (\phpbb\report\exception\invalid_report_exception $exception)
+ {
+ return $this->helper->message($exception->getMessage());
+ }
+
+ // Setting up an rendering template
+ $page_title = ($mode === 'pm') ? $this->user->lang['REPORT_MESSAGE'] : $this->user->lang['REPORT_POST'];
+ $this->assign_template_data(
+ $mode,
+ $id,
+ $reason_id,
+ $report_text,
+ $user_notify,
+ $error,
+ $s_hidden_fields,
+ ( isset($captcha) ? $captcha : false )
+ );
+
+ return $this->helper->render('report_body.html', $page_title);
+ }
+
+ /**
+ * Assigns template variables
+ *
+ * @param int $mode
+ * @param int $id
+ * @param int $reason_id
+ * @param string $report_text
+ * @param mixed $user_notify
+ * @param array $error
+ * @param string $s_hidden_fields
+ * @param mixed $captcha
+ * @return null
+ */
+ protected function assign_template_data($mode, $id, $reason_id, $report_text, $user_notify, $error = array(), $s_hidden_fields = '', $captcha = false)
+ {
+ if ($captcha !== false && $captcha->is_solved() === false)
+ {
+ $this->template->assign_vars(array(
+ 'S_CONFIRM_CODE' => true,
+ 'CAPTCHA_TEMPLATE' => $captcha->get_template(),
+ ));
+ }
+
+ $this->report_reason_provider->display_reasons($reason_id);
+
+ switch ($mode)
+ {
+ case 'pm':
+ $report_route = $this->helper->route('phpbb_report_pm_controller', array('id' => $id));
+ break;
+ case 'post':
+ $report_route = $this->helper->route('phpbb_report_post_controller', array('id' => $id));
+ break;
+ }
+
+ $this->template->assign_vars(array(
+ 'ERROR' => (count($error) > 0) ? implode('<br />', $error) : '',
+ 'S_REPORT_POST' => ($mode === 'pm') ? false : true,
+ 'REPORT_TEXT' => $report_text,
+ 'S_HIDDEN_FIELDS' => (!empty($s_hidden_fields)) ? $s_hidden_fields : null,
+ 'S_REPORT_ACTION' => $report_route,
+
+ 'S_NOTIFY' => $user_notify,
+ 'S_CAN_NOTIFY' => ($this->user->data['is_registered']) ? true : false,
+ 'S_IN_REPORT' => true,
+ ));
+ }
+
+ /**
+ * Check CAPTCHA
+ *
+ * @param object $captcha A phpBB CAPTCHA object
+ * @return array template variables which ensures that CAPTCHA's work correctly
+ */
+ protected function check_captcha($captcha)
+ {
+ $error = array();
+ $captcha_hidden_fields = '';
+
+ $visual_confirmation_response = $captcha->validate();
+ if ($visual_confirmation_response)
+ {
+ $error[] = $visual_confirmation_response;
+ }
+
+ if (count($error) === 0)
+ {
+ $captcha->reset();
+ }
+ else if ($captcha->is_solved() !== false)
+ {
+ $captcha_hidden_fields = build_hidden_fields($captcha->get_hidden_fields());
+ }
+
+ return array(
+ 'error' => $error,
+ 'hidden_fields' => $captcha_hidden_fields,
+ );
+ }
+}
diff --git a/phpBB/phpbb/report/exception/already_reported_exception.php b/phpBB/phpbb/report/exception/already_reported_exception.php
new file mode 100644
index 0000000000..54174044fe
--- /dev/null
+++ b/phpBB/phpbb/report/exception/already_reported_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\exception;
+
+class already_reported_exception extends invalid_report_exception
+{
+
+}
diff --git a/phpBB/phpbb/report/exception/empty_report_exception.php b/phpBB/phpbb/report/exception/empty_report_exception.php
new file mode 100644
index 0000000000..8c968dca80
--- /dev/null
+++ b/phpBB/phpbb/report/exception/empty_report_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\exception;
+
+class empty_report_exception extends invalid_report_exception
+{
+ public function __construct()
+ {
+ parent::__construct('EMPTY_REPORT');
+ }
+}
diff --git a/phpBB/phpbb/report/exception/entity_not_found_exception.php b/phpBB/phpbb/report/exception/entity_not_found_exception.php
new file mode 100644
index 0000000000..732aa58a13
--- /dev/null
+++ b/phpBB/phpbb/report/exception/entity_not_found_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\exception;
+
+class entity_not_found_exception extends invalid_report_exception
+{
+
+}
diff --git a/phpBB/phpbb/report/exception/factory_invalid_argument_exception.php b/phpBB/phpbb/report/exception/factory_invalid_argument_exception.php
new file mode 100644
index 0000000000..19de91eea3
--- /dev/null
+++ b/phpBB/phpbb/report/exception/factory_invalid_argument_exception.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\exception;
+
+use \phpbb\exception\runtime_exception;
+
+class factory_invalid_argument_exception extends runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/report/exception/invalid_report_exception.php b/phpBB/phpbb/report/exception/invalid_report_exception.php
new file mode 100644
index 0000000000..03ff0a872d
--- /dev/null
+++ b/phpBB/phpbb/report/exception/invalid_report_exception.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\exception;
+
+use \phpbb\exception\runtime_exception;
+
+class invalid_report_exception extends runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/report/exception/pm_reporting_disabled_exception.php b/phpBB/phpbb/report/exception/pm_reporting_disabled_exception.php
new file mode 100644
index 0000000000..2c8ab8cf84
--- /dev/null
+++ b/phpBB/phpbb/report/exception/pm_reporting_disabled_exception.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\exception;
+
+class pm_reporting_disabled_exception extends invalid_report_exception
+{
+ public function __construct()
+ {
+
+ }
+}
diff --git a/phpBB/phpbb/report/exception/report_permission_denied_exception.php b/phpBB/phpbb/report/exception/report_permission_denied_exception.php
new file mode 100644
index 0000000000..c7069288b8
--- /dev/null
+++ b/phpBB/phpbb/report/exception/report_permission_denied_exception.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report\exception;
+
+class report_permission_denied_exception extends invalid_report_exception
+{
+
+}
diff --git a/phpBB/phpbb/report/handler_factory.php b/phpBB/phpbb/report/handler_factory.php
new file mode 100644
index 0000000000..ec229aac54
--- /dev/null
+++ b/phpBB/phpbb/report/handler_factory.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report;
+
+use phpbb\report\exception\factory_invalid_argument_exception;
+
+class handler_factory
+{
+ /**
+ * @var \Symfony\Component\DependencyInjection\ContainerInterface
+ */
+ protected $container;
+
+ /**
+ * Constructor
+ *
+ * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+ */
+ public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container)
+ {
+ $this->container = $container;
+ }
+
+ /**
+ * Return a new instance of an appropriate report handler
+ *
+ * @param string $type
+ * @return \phpbb\report\report_handler_interface
+ * @throws \phpbb\report\exception\factory_invalid_argument_exception if $type is not valid
+ */
+ public function get_instance($type)
+ {
+ switch ($type)
+ {
+ case 'pm':
+ return $this->container->get('phpbb.report.handlers.report_handler_pm');
+ break;
+ case 'post':
+ return $this->container->get('phpbb.report.handlers.report_handler_post');
+ break;
+ }
+
+ throw new factory_invalid_argument_exception();
+ }
+}
diff --git a/phpBB/phpbb/report/report_handler.php b/phpBB/phpbb/report/report_handler.php
new file mode 100644
index 0000000000..854318c559
--- /dev/null
+++ b/phpBB/phpbb/report/report_handler.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report;
+
+abstract class report_handler implements report_handler_interface
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\event\dispatcher_interface
+ */
+ protected $dispatcher;
+
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\auth\auth
+ */
+ protected $auth;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /**
+ * @var \phpbb\notification\manager
+ */
+ protected $notifications;
+
+ /**
+ * @var array
+ */
+ protected $report_data;
+
+ /**
+ * Construtor
+ *
+ * @param \phpbb\db\driver\driver_interface $db
+ * @param \phpbb\event\dispatcher_interface $dispatcher
+ * @param \phpbb\config\db $config
+ * @param \phpbb\auth\auth $auth
+ * @param \phpbb\user $user
+ * @param \phpbb\notification\manager $notification
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\config\config $config, \phpbb\auth\auth $auth, \phpbb\user $user, \phpbb\notification\manager $notification)
+ {
+ $this->db = $db;
+ $this->dispatcher = $dispatcher;
+ $this->config = $config;
+ $this->auth = $auth;
+ $this->user = $user;
+ $this->notifications = $notification;
+ $this->report_data = array();
+ }
+
+ /**
+ * Creates a report entity in the database
+ *
+ * @param array $report_data
+ * @return int the ID of the created entity
+ */
+ protected function create_report(array $report_data)
+ {
+ $sql_ary = array(
+ 'reason_id' => (int) $report_data['reason_id'],
+ 'post_id' => $report_data['post_id'],
+ 'pm_id' => $report_data['pm_id'],
+ 'user_id' => (int) $this->user->data['user_id'],
+ 'user_notify' => (int) $report_data['user_notify'],
+ 'report_closed' => 0,
+ 'report_time' => (int) time(),
+ 'report_text' => (string) $report_data['report_text'],
+ 'reported_post_text' => $report_data['reported_post_text'],
+ 'reported_post_uid' => $report_data['reported_post_uid'],
+ 'reported_post_bitfield' => $report_data['reported_post_bitfield'],
+ 'reported_post_enable_bbcode' => $report_data['reported_post_enable_bbcode'],
+ 'reported_post_enable_smilies' => $report_data['reported_post_enable_smilies'],
+ 'reported_post_enable_magic_url' => $report_data['reported_post_enable_magic_url'],
+ );
+
+ $sql = 'INSERT INTO ' . REPORTS_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
+ $this->db->sql_query($sql);
+
+ return $this->db->sql_nextid();
+ }
+}
diff --git a/phpBB/phpbb/report/report_handler_interface.php b/phpBB/phpbb/report/report_handler_interface.php
new file mode 100644
index 0000000000..8dafc392d0
--- /dev/null
+++ b/phpBB/phpbb/report/report_handler_interface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report;
+
+interface report_handler_interface
+{
+ /**
+ * Reports a message
+ *
+ * @param int $id
+ * @param int $reason_id
+ * @param string $report_text
+ * @param int $user_notify
+ * @return null
+ * @throws \phpbb\report\exception\empty_report_exception when the given report is empty
+ * @throws \phpbb\report\exception\already_reported_exception when the entity is already reported
+ * @throws \phpbb\report\exception\entity_not_found_exception when the entity does not exist or the user does not have viewing permissions for it
+ * @throws \phpbb\report\exception\invalid_report_exception when the entity cannot be reported for some other reason
+ */
+ public function add_report($id, $reason_id, $report_text, $user_notify);
+
+ /**
+ * Checks if the message is reportable
+ *
+ * @param int $id
+ * @return null
+ * @throws \phpbb\report\exception\already_reported_exception when the entity is already reported
+ * @throws \phpbb\report\exception\entity_not_found_exception when the entity does not exist or the user does not have viewing permissions for it
+ * @throws \phpbb\report\exception\invalid_report_exception when the entity cannot be reported for some other reason
+ */
+ public function validate_report_request($id);
+}
diff --git a/phpBB/phpbb/report/report_handler_pm.php b/phpBB/phpbb/report/report_handler_pm.php
new file mode 100644
index 0000000000..774ca329ad
--- /dev/null
+++ b/phpBB/phpbb/report/report_handler_pm.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report;
+
+use phpbb\report\exception\empty_report_exception;
+use phpbb\report\exception\already_reported_exception;
+use phpbb\report\exception\pm_reporting_disabled_exception;
+use phpbb\report\exception\entity_not_found_exception;
+
+class report_handler_pm extends report_handler
+{
+ /**
+ * {@inheritdoc}
+ * @throws \phpbb\report\exception\pm_reporting_disabled_exception when PM reporting is disabled on the board
+ */
+ public function add_report($id, $reason_id, $report_text, $user_notify)
+ {
+ // Cast the input variables
+ $id = (int) $id;
+ $reason_id = (int) $reason_id;
+ $report_text = (string) $report_text;
+ $user_notify = (int) $user_notify;
+
+ $this->validate_report_request($id);
+
+ $sql = 'SELECT *
+ FROM ' . REPORTS_REASONS_TABLE . "
+ WHERE reason_id = $reason_id";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$row || (empty($report_text) && strtolower($row['reason_title']) === 'other'))
+ {
+ throw new empty_report_exception();
+ }
+
+ $report_data = array(
+ 'reason_id' => $reason_id,
+ 'post_id' => 0,
+ 'pm_id' => $id,
+ 'user_notify' => $user_notify,
+ 'report_text' => $report_text,
+ 'reported_post_text' => $this->report_data['message_text'],
+ 'reported_post_uid' => $this->report_data['bbcode_uid'],
+ 'reported_post_bitfield' => $this->report_data['bbcode_bitfield'],
+ 'reported_post_enable_bbcode' => $this->report_data['enable_bbcode'],
+ 'reported_post_enable_smilies' => $this->report_data['enable_smilies'],
+ 'reported_post_enable_magic_url' => $this->report_data['enable_magic_url'],
+ );
+
+ $report_id = $this->create_report($report_data);
+
+ $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
+ SET message_reported = 1
+ WHERE msg_id = ' . $id;
+ $this->db->sql_query($sql);
+
+ $sql_ary = array(
+ 'msg_id' => $id,
+ 'user_id' => ANONYMOUS,
+ 'author_id' => (int) $this->report_data['author_id'],
+ 'pm_deleted' => 0,
+ 'pm_new' => 0,
+ 'pm_unread' => 0,
+ 'pm_replied' => 0,
+ 'pm_marked' => 0,
+ 'pm_forwarded' => 0,
+ 'folder_id' => PRIVMSGS_INBOX,
+ );
+
+ $sql = 'INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
+ $this->db->sql_query($sql);
+
+ $this->notifications->add_notifications('notification.type.report_pm', array_merge($this->report_data, $row, array(
+ 'report_text' => $report_text,
+ 'from_user_id' => $this->report_data['author_id'],
+ 'report_id' => $report_id,
+ )));
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws \phpbb\report\exception\pm_reporting_disabled_exception when PM reporting is disabled on the board
+ */
+ public function validate_report_request($id)
+ {
+ $id = (int) $id;
+
+ // Check if reporting PMs is enabled
+ if (!$this->config['allow_pm_report'])
+ {
+ throw new pm_reporting_disabled_exception();
+ }
+ else if ($id <= 0)
+ {
+ throw new entity_not_found_exception('NO_POST_SELECTED');
+ }
+
+ // Grab all relevant data
+ $sql = 'SELECT p.*, pt.*
+ FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . " pt
+ WHERE p.msg_id = $id
+ AND p.msg_id = pt.msg_id
+ AND (p.author_id = " . $this->user->data['user_id'] . "
+ OR pt.user_id = " . $this->user->data['user_id'] . ")";
+ $result = $this->db->sql_query($sql);
+ $report_data = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ // Check if message exists
+ if (!$report_data)
+ {
+ $this->user->add_lang('ucp');
+ throw new entity_not_found_exception('NO_MESSAGE');
+ }
+
+ // Check if message is already reported
+ if ($report_data['message_reported'])
+ {
+ throw new already_reported_exception();
+ }
+
+ $this->report_data = $report_data;
+ }
+}
diff --git a/phpBB/phpbb/report/report_handler_post.php b/phpBB/phpbb/report/report_handler_post.php
new file mode 100644
index 0000000000..52f09683ce
--- /dev/null
+++ b/phpBB/phpbb/report/report_handler_post.php
@@ -0,0 +1,175 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report;
+
+use phpbb\report\exception\invalid_report_exception;
+use phpbb\report\exception\empty_report_exception;
+use phpbb\report\exception\already_reported_exception;
+use phpbb\report\exception\entity_not_found_exception;
+use phpbb\report\exception\report_permission_denied_exception;
+
+class report_handler_post extends report_handler
+{
+ /**
+ * @var array
+ */
+ protected $forum_data;
+
+ /**
+ * {@inheritdoc}
+ * @throws \phpbb\report\exception\report_permission_denied_exception when the user does not have permission to report the post
+ */
+ public function add_report($id, $reason_id, $report_text, $user_notify)
+ {
+ // Cast the input variables
+ $id = (int) $id;
+ $reason_id = (int) $reason_id;
+ $report_text = (string) $report_text;
+ $user_notify = (int) $user_notify;
+
+ $this->validate_report_request($id);
+
+ $sql = 'SELECT *
+ FROM ' . REPORTS_REASONS_TABLE . "
+ WHERE reason_id = $reason_id";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$row || (empty($report_text) && strtolower($row['reason_title']) === 'other'))
+ {
+ throw new empty_report_exception();
+ }
+
+ $report_data = array(
+ 'reason_id' => $reason_id,
+ 'post_id' => $id,
+ 'pm_id' => 0,
+ 'user_notify' => $user_notify,
+ 'report_text' => $report_text,
+ 'reported_post_text' => $this->report_data['post_text'],
+ 'reported_post_uid' => $this->report_data['bbcode_uid'],
+ 'reported_post_bitfield' => $this->report_data['bbcode_bitfield'],
+ 'reported_post_enable_bbcode' => $this->report_data['enable_bbcode'],
+ 'reported_post_enable_smilies' => $this->report_data['enable_smilies'],
+ 'reported_post_enable_magic_url' => $this->report_data['enable_magic_url'],
+ );
+
+ $this->create_report($report_data);
+
+ $sql = 'UPDATE ' . POSTS_TABLE . '
+ SET post_reported = 1
+ WHERE post_id = ' . $id;
+ $this->db->sql_query($sql);
+
+ if (!$this->report_data['topic_reported'])
+ {
+ $sql = 'UPDATE ' . TOPICS_TABLE . '
+ SET topic_reported = 1
+ WHERE topic_id = ' . $this->report_data['topic_id'] . '
+ OR topic_moved_id = ' . $this->report_data['topic_id'];
+ $this->db->sql_query($sql);
+ }
+
+ $this->notifications->add_notifications('notification.type.report_post', array_merge($this->report_data, $row, $this->forum_data, array(
+ 'report_text' => $report_text,
+ )));
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws \phpbb\report\exception\report_permission_denied_exception when the user does not have permission to report the post
+ */
+ public function validate_report_request($id)
+ {
+ $id = (int) $id;
+
+ // Check if id is valid
+ if ($id <= 0)
+ {
+ throw new entity_not_found_exception('NO_POST_SELECTED');
+ }
+
+ // Grab all relevant data
+ $sql = 'SELECT t.*, p.*
+ FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t
+ WHERE p.post_id = $id
+ AND p.topic_id = t.topic_id";
+ $result = $this->db->sql_query($sql);
+ $report_data = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$report_data)
+ {
+ throw new entity_not_found_exception('POST_NOT_EXIST');
+ }
+
+ $forum_id = (int) $report_data['forum_id'];
+
+ $sql = 'SELECT *
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_id = ' . $forum_id;
+ $result = $this->db->sql_query($sql);
+ $forum_data = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$forum_data)
+ {
+ throw new invalid_report_exception('FORUM_NOT_EXIST');
+ }
+
+ $acl_check_ary = array(
+ 'f_list' => 'POST_NOT_EXIST',
+ 'f_read' => 'USER_CANNOT_READ',
+ 'f_report' => 'USER_CANNOT_REPORT'
+ );
+
+ /**
+ * This event allows you to do extra auth checks and verify if the user
+ * has the required permissions
+ *
+ * @event core.report_post_auth
+ * @var array forum_data All data available from the forums table on this post's forum
+ * @var array report_data All data available from the topics and the posts tables on this post (and its topic)
+ * @var array acl_check_ary An array with the ACL to be tested. The evaluation is made in the same order as the array is sorted
+ * The key is the ACL name and the value is the language key for the error message.
+ * @since 3.1.3-RC1
+ */
+ $vars = array(
+ 'forum_data',
+ 'report_data',
+ 'acl_check_ary',
+ );
+ extract($this->dispatcher->trigger_event('core.report_post_auth', compact($vars)));
+
+ $this->auth->acl($this->user->data);
+
+ foreach ($acl_check_ary as $acl => $error)
+ {
+ if (!$this->auth->acl_get($acl, $forum_id))
+ {
+ throw new report_permission_denied_exception($error);
+ }
+ }
+ unset($acl_check_ary);
+
+ if ($report_data['post_reported'])
+ {
+ throw new already_reported_exception();
+ }
+
+ $this->report_data = $report_data;
+ $this->forum_data = $forum_data;
+ }
+}
diff --git a/phpBB/phpbb/report/report_reason_list_provider.php b/phpBB/phpbb/report/report_reason_list_provider.php
new file mode 100644
index 0000000000..388a61d577
--- /dev/null
+++ b/phpBB/phpbb/report/report_reason_list_provider.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\report;
+
+class report_reason_list_provider
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var \phpbb\template\template
+ */
+ protected $template;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\db\driver\driver_interface $db
+ * @param \phpbb\template\template $template
+ * @param \phpbb\user $user
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\template\template $template, \phpbb\user $user)
+ {
+ $this->db = $db;
+ $this->template = $template;
+ $this->user = $user;
+ }
+
+ /**
+ * Sets template variables to render report reasons select HTML input
+ *
+ * @param int $reason_id
+ * @return null
+ */
+ public function display_reasons($reason_id = 0)
+ {
+ $sql = 'SELECT *
+ FROM ' . REPORTS_REASONS_TABLE . '
+ ORDER BY reason_order ASC';
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // If the reason is defined within the language file, we will use the localized version, else just use the database entry...
+ if (isset($this->user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])]) && isset($this->user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])]))
+ {
+ $row['reason_description'] = $this->user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])];
+ $row['reason_title'] = $this->user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])];
+ }
+
+ $this->template->assign_block_vars('reason', array(
+ 'ID' => $row['reason_id'],
+ 'TITLE' => $row['reason_title'],
+ 'DESCRIPTION' => $row['reason_description'],
+ 'S_SELECTED' => ($row['reason_id'] == $reason_id) ? true : false,
+ ));
+ }
+ $this->db->sql_freeresult($result);
+ }
+}
diff --git a/phpBB/phpbb/request/deactivated_super_global.php b/phpBB/phpbb/request/deactivated_super_global.php
index b6cad59be4..ab56240b14 100644
--- a/phpBB/phpbb/request/deactivated_super_global.php
+++ b/phpBB/phpbb/request/deactivated_super_global.php
@@ -56,7 +56,7 @@ class deactivated_super_global implements \ArrayAccess, \Countable, \IteratorAgg
$file = '';
$line = 0;
- $message = 'Illegal use of $' . $this->name . '. You must use the request class or request_var() to access input data. Found in %s on line %d. This error message was generated by deactivated_super_global.';
+ $message = 'Illegal use of $' . $this->name . '. You must use the request class to access input data. Found in %s on line %d. This error message was generated by deactivated_super_global.';
$backtrace = debug_backtrace();
if (isset($backtrace[1]))
diff --git a/phpBB/phpbb/request/request.php b/phpBB/phpbb/request/request.php
index 00ff9064cb..a0267d1370 100644
--- a/phpBB/phpbb/request/request.php
+++ b/phpBB/phpbb/request/request.php
@@ -150,8 +150,6 @@ class request implements \phpbb\request\request_interface
return;
}
- $this->type_cast_helper->add_magic_quotes($value);
-
// setting to null means unsetting
if ($value === null)
{
@@ -219,6 +217,51 @@ class request implements \phpbb\request\request_interface
}
/**
+ * {@inheritdoc}
+ */
+ public function raw_variable($var_name, $default, $super_global = \phpbb\request\request_interface::REQUEST)
+ {
+ $path = false;
+
+ // deep direct access to multi dimensional arrays
+ if (is_array($var_name))
+ {
+ $path = $var_name;
+ // make sure at least the variable name is specified
+ if (empty($path))
+ {
+ return (is_array($default)) ? array() : $default;
+ }
+ // the variable name is the first element on the path
+ $var_name = array_shift($path);
+ }
+
+ if (!isset($this->input[$super_global][$var_name]))
+ {
+ return (is_array($default)) ? array() : $default;
+ }
+ $var = $this->input[$super_global][$var_name];
+
+ if ($path)
+ {
+ // walk through the array structure and find the element we are looking for
+ foreach ($path as $key)
+ {
+ if (is_array($var) && isset($var[$key]))
+ {
+ $var = $var[$key];
+ }
+ else
+ {
+ return (is_array($default)) ? array() : $default;
+ }
+ }
+ }
+
+ return $var;
+ }
+
+ /**
* Shortcut method to retrieve SERVER variables.
*
* Also fall back to getenv(), some CGI setups may need it (probably not, but
@@ -363,41 +406,14 @@ class request implements \phpbb\request\request_interface
*/
protected function _variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST, $trim = true)
{
- $path = false;
-
- // deep direct access to multi dimensional arrays
- if (is_array($var_name))
- {
- $path = $var_name;
- // make sure at least the variable name is specified
- if (empty($path))
- {
- return (is_array($default)) ? array() : $default;
- }
- // the variable name is the first element on the path
- $var_name = array_shift($path);
- }
+ $var = $this->raw_variable($var_name, $default, $super_global);
- if (!isset($this->input[$super_global][$var_name]))
+ // Return prematurely if raw variable is empty array or the same as
+ // the default. Using strict comparison to ensure that one can't
+ // prevent proper type checking on any input variable
+ if ($var === array() || $var === $default)
{
- return (is_array($default)) ? array() : $default;
- }
- $var = $this->input[$super_global][$var_name];
-
- if ($path)
- {
- // walk through the array structure and find the element we are looking for
- foreach ($path as $key)
- {
- if (is_array($var) && isset($var[$key]))
- {
- $var = $var[$key];
- }
- else
- {
- return (is_array($default)) ? array() : $default;
- }
- }
+ return $var;
}
$this->type_cast_helper->recursive_set_var($var, $default, $multibyte, $trim);
diff --git a/phpBB/phpbb/request/request_interface.php b/phpBB/phpbb/request/request_interface.php
index 47b3b3a4ed..3bfa8bb424 100644
--- a/phpBB/phpbb/request/request_interface.php
+++ b/phpBB/phpbb/request/request_interface.php
@@ -65,6 +65,28 @@ interface request_interface
public function variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST);
/**
+ * Get a variable without trimming strings and without escaping.
+ * This method MUST NOT be used with queries.
+ * Same functionality as variable(), except does not run trim() on strings
+ * and does not escape input.
+ * This method should only be used when the raw input is needed without
+ * any escaping, i.e. for database password during the installation.
+ *
+ * @param string|array $var_name The form variable's name from which data shall be retrieved.
+ * If the value is an array this may be an array of indizes which will give
+ * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
+ * then specifying array("var", 1) as the name will return "a".
+ * @param mixed $default A default value that is returned if the variable was not set.
+ * This function will always return a value of the same type as the default.
+ * @param \phpbb\request\request_interface::POST|GET|REQUEST|COOKIE $super_global
+ * Specifies which super global should be used
+ *
+ * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
+ * the same as that of $default. If the variable is not set $default is returned.
+ */
+ public function raw_variable($var_name, $default, $super_global = \phpbb\request\request_interface::REQUEST);
+
+ /**
* Shortcut method to retrieve SERVER variables.
*
* @param string|array $var_name See \phpbb\request\request_interface::variable
diff --git a/phpBB/phpbb/request/type_cast_helper.php b/phpBB/phpbb/request/type_cast_helper.php
index bc654e6182..912494998d 100644
--- a/phpBB/phpbb/request/type_cast_helper.php
+++ b/phpBB/phpbb/request/type_cast_helper.php
@@ -18,69 +18,6 @@ namespace phpbb\request;
*/
class type_cast_helper implements \phpbb\request\type_cast_helper_interface
{
-
- /**
- * @var string Whether slashes need to be stripped from input
- */
- protected $strip;
-
- /**
- * Initialises the type cast helper class.
- * All it does is find out whether magic quotes are turned on.
- */
- public function __construct()
- {
- if (version_compare(PHP_VERSION, '5.4.0-dev', '>='))
- {
- $this->strip = false;
- }
- else
- {
- $this->strip = (@get_magic_quotes_gpc()) ? true : false;
- }
- }
-
- /**
- * Recursively applies addslashes to a variable.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function addslashes_recursively(&$var)
- {
- if (is_string($var))
- {
- $var = addslashes($var);
- }
- else if (is_array($var))
- {
- $var_copy = $var;
- $var = array();
- foreach ($var_copy as $key => $value)
- {
- if (is_string($key))
- {
- $key = addslashes($key);
- }
- $var[$key] = $value;
-
- $this->addslashes_recursively($var[$key]);
- }
- }
- }
-
- /**
- * Recursively applies addslashes to a variable if magic quotes are turned on.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function add_magic_quotes(&$var)
- {
- if ($this->strip)
- {
- $this->addslashes_recursively($var);
- }
- }
-
/**
* Set variable $result to a particular type.
*
@@ -129,8 +66,6 @@ class type_cast_helper implements \phpbb\request\type_cast_helper_interface
$result = preg_replace('/[\x80-\xFF]/', '?', $result);
}
}
-
- $result = ($this->strip) ? stripslashes($result) : $result;
}
}
@@ -172,7 +107,6 @@ class type_cast_helper implements \phpbb\request\type_cast_helper_interface
}
list($default_key, $default_value) = each($default);
- $value_type = gettype($default_value);
$key_type = gettype($default_key);
$_var = $var;
diff --git a/phpBB/phpbb/request/type_cast_helper_interface.php b/phpBB/phpbb/request/type_cast_helper_interface.php
index 2cb28d021f..9671573bf1 100644
--- a/phpBB/phpbb/request/type_cast_helper_interface.php
+++ b/phpBB/phpbb/request/type_cast_helper_interface.php
@@ -19,20 +19,6 @@ namespace phpbb\request;
interface type_cast_helper_interface
{
/**
- * Recursively applies addslashes to a variable.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function addslashes_recursively(&$var);
-
- /**
- * Recursively applies addslashes to a variable if magic quotes are turned on.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function add_magic_quotes(&$var);
-
- /**
* Set variable $result to a particular type.
*
* @param mixed &$result The variable to fill
diff --git a/phpBB/phpbb/routing/file_locator.php b/phpBB/phpbb/routing/file_locator.php
new file mode 100644
index 0000000000..64efcc6c76
--- /dev/null
+++ b/phpBB/phpbb/routing/file_locator.php
@@ -0,0 +1,33 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\routing;
+
+use phpbb\filesystem\filesystem_interface;
+use Symfony\Component\Config\FileLocator;
+
+class file_locator extends FileLocator
+{
+ public function __construct(filesystem_interface $filesystem, $paths = [])
+ {
+ $paths = (array) $paths;
+ $absolute_paths = [];
+
+ foreach ($paths as $path)
+ {
+ $absolute_paths[] = $filesystem->realpath($path);
+ }
+
+ parent::__construct($absolute_paths);
+ }
+}
diff --git a/phpBB/phpbb/routing/helper.php b/phpBB/phpbb/routing/helper.php
new file mode 100644
index 0000000000..c15608dce5
--- /dev/null
+++ b/phpBB/phpbb/routing/helper.php
@@ -0,0 +1,162 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\routing;
+
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Routing\RequestContext;
+
+/**
+* Controller helper class, contains methods that do things for controllers
+*/
+class helper
+{
+ /**
+ * config object
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * phpBB router
+ * @var \phpbb\routing\router
+ */
+ protected $router;
+
+ /**
+ * @var \phpbb\symfony_request
+ */
+ protected $symfony_request;
+
+ /**
+ * @var \phpbb\request\request_interface
+ */
+ protected $request;
+
+ /**
+ * @var \phpbb\filesystem The filesystem object
+ */
+ protected $filesystem;
+
+ /**
+ * phpBB root path
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * PHP file extension
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\config\config $config Config object
+ * @param \phpbb\routing\router $router phpBB router
+ * @param \phpbb\symfony_request $symfony_request Symfony Request object
+ * @param \phpbb\request\request_interface $request phpBB request object
+ * @param \phpbb\filesystem\filesystem $filesystem The filesystem object
+ * @param string $phpbb_root_path phpBB root path
+ * @param string $php_ext PHP file extension
+ */
+ public function __construct(\phpbb\config\config $config, \phpbb\routing\router $router, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem\filesystem $filesystem, $phpbb_root_path, $php_ext)
+ {
+ $this->config = $config;
+ $this->router = $router;
+ $this->symfony_request = $symfony_request;
+ $this->request = $request;
+ $this->filesystem = $filesystem;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ }
+
+ /**
+ * Generate a URL to a route
+ *
+ * @param string $route Name of the route to travel
+ * @param array $params String or array of additional url parameters
+ * @param bool $is_amp Is url using &amp; (true) or & (false)
+ * @param string|bool $session_id Possibility to use a custom session id instead of the global one
+ * @param bool|string $reference_type The type of reference to be generated (one of the constants)
+ * @return string The URL already passed through append_sid()
+ */
+ public function route($route, array $params = array(), $is_amp = true, $session_id = false, $reference_type = UrlGeneratorInterface::ABSOLUTE_PATH)
+ {
+ $anchor = '';
+ if (isset($params['#']))
+ {
+ $anchor = '#' . $params['#'];
+ unset($params['#']);
+ }
+
+ $context = new RequestContext();
+ $context->fromRequest($this->symfony_request);
+
+ if ($this->config['force_server_vars'])
+ {
+ $context->setHost($this->config['server_name']);
+ $context->setScheme(substr($this->config['server_protocol'], 0, -3));
+ $context->setHttpPort($this->config['server_port']);
+ $context->setHttpsPort($this->config['server_port']);
+ $context->setBaseUrl(rtrim($this->config['script_path'], '/'));
+ }
+
+ $script_name = $this->symfony_request->getScriptName();
+ $page_name = substr($script_name, -1, 1) == '/' ? '' : utf8_basename($script_name);
+
+ $base_url = $context->getBaseUrl();
+
+ // Append page name if base URL does not contain it
+ if (!empty($page_name) && strpos($base_url, '/' . $page_name) === false)
+ {
+ $base_url .= '/' . $page_name;
+ }
+
+ // If enable_mod_rewrite is false we need to replace the current front-end by app.php, otherwise we need to remove it.
+ $base_url = str_replace('/' . $page_name, empty($this->config['enable_mod_rewrite']) ? '/app.' . $this->php_ext : '', $base_url);
+
+ // We need to update the base url to move to the directory of the app.php file if the current script is not app.php
+ if ($page_name !== 'app.php' && !$this->config['force_server_vars'])
+ {
+ if (empty($this->config['enable_mod_rewrite']))
+ {
+ $base_url = str_replace('/app.' . $this->php_ext, '/' . $this->phpbb_root_path . 'app.' . $this->php_ext, $base_url);
+ }
+ else
+ {
+ $base_url .= preg_replace(get_preg_expression('path_remove_dot_trailing_slash'), '$2', $this->phpbb_root_path);
+ }
+ }
+
+ $base_url = $this->request->escape($this->filesystem->clean_path($base_url), true);
+
+ $context->setBaseUrl($base_url);
+
+ $this->router->setContext($context);
+ $route_url = $this->router->generate($route, $params, $reference_type);
+
+ if ($is_amp)
+ {
+ $route_url = str_replace(array('&amp;', '&'), array('&', '&amp;'), $route_url);
+ }
+
+ if ($reference_type === UrlGeneratorInterface::RELATIVE_PATH && empty($this->config['enable_mod_rewrite']))
+ {
+ $route_url = 'app.' . $this->php_ext . '/' . $route_url;
+ }
+
+ return append_sid($route_url . $anchor, false, $is_amp, $session_id, true);
+ }
+}
diff --git a/phpBB/phpbb/routing/loader_resolver.php b/phpBB/phpbb/routing/loader_resolver.php
new file mode 100644
index 0000000000..13fbc6405c
--- /dev/null
+++ b/phpBB/phpbb/routing/loader_resolver.php
@@ -0,0 +1,50 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\routing;
+
+use Symfony\Component\Config\Loader\LoaderResolverInterface;
+
+/**
+ * @see Symfony\Component\Config\Loader\LoaderResolver
+ */
+class loader_resolver implements LoaderResolverInterface
+{
+ /**
+ * @var \Symfony\Component\Config\Loader\LoaderInterface[] An array of LoaderInterface objects
+ */
+ protected $loaders = [];
+
+ public function __construct($loaders = [])
+ {
+ $this->loaders = $loaders;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function resolve($resource, $type = null)
+ {
+ /** @var \Symfony\Component\Config\Loader\LoaderInterface $loader */
+ foreach ($this->loaders as $loader)
+ {
+ if ($loader->supports($resource, $type))
+ {
+ $loader->setResolver($this);
+ return $loader;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/phpBB/phpbb/routing/resources_locator/chained_resources_locator.php b/phpBB/phpbb/routing/resources_locator/chained_resources_locator.php
new file mode 100644
index 0000000000..db9abf2095
--- /dev/null
+++ b/phpBB/phpbb/routing/resources_locator/chained_resources_locator.php
@@ -0,0 +1,47 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\routing\resources_locator;
+
+class chained_resources_locator implements resources_locator_interface
+{
+ /**
+ * @var resources_locator_interface[]
+ */
+ protected $locators;
+
+ /**
+ * Construct method
+ *
+ * @param resources_locator_interface[] $locators Locators
+ */
+ public function __construct($locators)
+ {
+ $this->locators = $locators;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function locate_resources()
+ {
+ $resources = [];
+
+ foreach ($this->locators as $locator)
+ {
+ $resources = array_merge($resources, $locator->locate_resources());
+ }
+
+ return $resources;
+ }
+}
diff --git a/phpBB/phpbb/routing/resources_locator/default_resources_locator.php b/phpBB/phpbb/routing/resources_locator/default_resources_locator.php
new file mode 100644
index 0000000000..90c3877007
--- /dev/null
+++ b/phpBB/phpbb/routing/resources_locator/default_resources_locator.php
@@ -0,0 +1,105 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\routing\resources_locator;
+
+use phpbb\extension\manager;
+
+/**
+ * Locates the yaml routing resources located in the default locations
+ */
+class default_resources_locator implements resources_locator_interface
+{
+ /**
+ * phpBB root path
+ *
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Name of the current environment
+ *
+ * @var string
+ */
+ protected $environment;
+
+ /**
+ * Extension manager
+ *
+ * @var manager
+ */
+ protected $extension_manager;
+
+ /**
+ * Construct method
+ *
+ * @param string $phpbb_root_path phpBB root path
+ * @param string $environment Name of the current environment
+ * @param manager $extension_manager Extension manager
+ */
+ public function __construct($phpbb_root_path, $environment, manager $extension_manager = null)
+ {
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->environment = $environment;
+ $this->extension_manager = $extension_manager;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function locate_resources()
+ {
+ $resources = [['config/' . $this->environment . '/routing/environment.yml', 'yaml']];
+
+ $resources = $this->append_ext_resources($resources);
+
+ return $resources;
+ }
+
+ /**
+ * Append extension resources to an array of resouces
+ *
+ * @see resources_locator_interface::locate_resources()
+ *
+ * @param mixed[] $resources List of resources
+ *
+ * @return mixed[] List of resources
+ */
+ protected function append_ext_resources(array $resources)
+ {
+ if ($this->extension_manager !== null)
+ {
+ foreach ($this->extension_manager->all_enabled(false) as $path)
+ {
+ if (file_exists($this->phpbb_root_path . $path . 'config/' . $this->environment . '/routing/environment.yml'))
+ {
+ $resources[] = [$path . 'config/' . $this->environment . '/routing/environment.yml', 'yaml'];
+ }
+ else if (!is_dir($this->phpbb_root_path . $path . 'config/' . $this->environment))
+ {
+ if (file_exists($this->phpbb_root_path . $path . 'config/default/routing/environment.yml'))
+ {
+ $resources[] = [$path . 'config/default/routing/environment.yml', 'yaml'];
+ }
+ else if (!is_dir($this->phpbb_root_path . $path . 'config/default/routing') && file_exists($this->phpbb_root_path . $path . 'config/routing.yml'))
+ {
+ $resources[] = [$path . 'config/routing.yml', 'yaml'];
+ }
+ }
+ }
+ }
+
+ return $resources;
+ }
+}
diff --git a/phpBB/phpbb/routing/resources_locator/installer_resources_locator.php b/phpBB/phpbb/routing/resources_locator/installer_resources_locator.php
new file mode 100644
index 0000000000..42cd0f11af
--- /dev/null
+++ b/phpBB/phpbb/routing/resources_locator/installer_resources_locator.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\routing\resources_locator;
+
+use phpbb\filesystem\filesystem_interface;
+
+/**
+ * Locates the yaml routing resources taking update directories into consideration
+ */
+class installer_resources_locator implements resources_locator_interface
+{
+ /**
+ * phpBB's filesystem handler
+ *
+ * @var filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * phpBB root path
+ *
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Name of the current environment
+ *
+ * @var string
+ */
+ protected $environment;
+
+ /**
+ * Construct method
+ *
+ * @param filesystem_interface $filesystem phpBB's filesystem handler
+ * @param string $phpbb_root_path phpBB root path
+ * @param string $environment Name of the current environment
+ */
+ public function __construct(filesystem_interface $filesystem, $phpbb_root_path, $environment)
+ {
+ $this->filesystem = $filesystem;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->environment = $environment;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function locate_resources()
+ {
+ if ($this->filesystem->exists($this->phpbb_root_path . 'install/update/new/config'))
+ {
+ $resources = array(
+ array('install/update/new/config/' . $this->environment . '/routing/environment.yml', 'yaml')
+ );
+ }
+ else
+ {
+ $resources = array(
+ array('config/' . $this->environment . '/routing/environment.yml', 'yaml')
+ );
+ }
+
+ return $resources;
+ }
+}
diff --git a/phpBB/phpbb/routing/resources_locator/resources_locator_interface.php b/phpBB/phpbb/routing/resources_locator/resources_locator_interface.php
new file mode 100644
index 0000000000..46335cb288
--- /dev/null
+++ b/phpBB/phpbb/routing/resources_locator/resources_locator_interface.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\routing\resources_locator;
+
+interface resources_locator_interface
+{
+ /**
+ * Locates a list of resources used to load the routes
+ *
+ * Each entry of the list can be either the resource or an array composed of 2 elements:
+ * the resource and its type.
+ *
+ * @return mixed[] List of resources
+ */
+ public function locate_resources();
+}
diff --git a/phpBB/phpbb/routing/router.php b/phpBB/phpbb/routing/router.php
new file mode 100644
index 0000000000..f19886fb0b
--- /dev/null
+++ b/phpBB/phpbb/routing/router.php
@@ -0,0 +1,395 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\routing;
+
+use phpbb\routing\resources_locator\resources_locator_interface;
+use Symfony\Component\Config\ConfigCache;
+use Symfony\Component\Config\Loader\LoaderInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+use Symfony\Component\Filesystem\Exception\IOException;
+use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper;
+use Symfony\Component\Routing\Generator\UrlGenerator;
+use Symfony\Component\Routing\Matcher\Dumper\PhpMatcherDumper;
+use Symfony\Component\Routing\Matcher\UrlMatcher;
+use Symfony\Component\Routing\RequestContext;
+use Symfony\Component\Routing\RouteCollection;
+use Symfony\Component\Routing\RouterInterface;
+
+/**
+ * Integration of all pieces of the routing system for easier use.
+ */
+class router implements RouterInterface
+{
+ /**
+ * @var ContainerInterface
+ */
+ protected $container;
+
+ /**
+ * @var resources_locator_interface
+ */
+ protected $resources_locator;
+
+ /**
+ * @var LoaderInterface
+ */
+ protected $loader;
+
+ /**
+ * PHP file extensions
+ *
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface|null
+ */
+ protected $matcher;
+
+ /**
+ * @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface|null
+ */
+ protected $generator;
+
+ /**
+ * @var RequestContext
+ */
+ protected $context;
+
+ /**
+ * @var RouteCollection
+ */
+ protected $route_collection;
+
+ /**
+ * @var string
+ */
+ protected $cache_dir;
+
+ /**
+ * Construct method
+ *
+ * @param ContainerInterface $container DI container
+ * @param resources_locator_interface $resources_locator Resources locator
+ * @param LoaderInterface $loader Resources loader
+ * @param string $php_ext PHP file extension
+ * @param string $cache_dir phpBB cache directory
+ */
+ public function __construct(ContainerInterface $container, resources_locator_interface $resources_locator, LoaderInterface $loader, $php_ext, $cache_dir)
+ {
+ $this->container = $container;
+ $this->resources_locator = $resources_locator;
+ $this->loader = $loader;
+ $this->php_ext = $php_ext;
+ $this->context = new RequestContext();
+ $this->cache_dir = $cache_dir;
+ }
+
+ /**
+ * Get the list of routes
+ *
+ * @return RouteCollection Get the route collection
+ */
+ public function get_routes()
+ {
+ if ($this->route_collection === null /*|| $this->route_collection->count() === 0*/)
+ {
+ $this->route_collection = new RouteCollection;
+ foreach ($this->resources_locator->locate_resources() as $resource)
+ {
+ if (is_array($resource))
+ {
+ $this->route_collection->addCollection($this->loader->load($resource[0], $resource[1]));
+ }
+ else
+ {
+ $this->route_collection->addCollection($this->loader->load($resource));
+ }
+ }
+
+ $this->resolveParameters($this->route_collection);
+ }
+
+ return $this->route_collection;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRouteCollection()
+ {
+ return $this->get_routes();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setContext(RequestContext $context)
+ {
+ $this->context = $context;
+
+ if ($this->matcher !== null)
+ {
+ $this->get_matcher()->setContext($context);
+ }
+ if ($this->generator !== null)
+ {
+ $this->get_generator()->setContext($context);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContext()
+ {
+ return $this->context;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
+ {
+ return $this->get_generator()->generate($name, $parameters, $referenceType);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function match($pathinfo)
+ {
+ return $this->get_matcher()->match($pathinfo);
+ }
+
+ /**
+ * Gets the UrlMatcher instance associated with this Router.
+ *
+ * @return \Symfony\Component\Routing\Matcher\UrlMatcherInterface A UrlMatcherInterface instance
+ */
+ public function get_matcher()
+ {
+ if ($this->matcher !== null)
+ {
+ return $this->matcher;
+ }
+
+ $this->create_dumped_url_matcher();
+
+ return $this->matcher;
+ }
+
+ /**
+ * Creates a new dumped URL Matcher (dump it if necessary)
+ */
+ protected function create_dumped_url_matcher()
+ {
+ try
+ {
+ $cache = new ConfigCache("{$this->cache_dir}url_matcher.{$this->php_ext}", defined('DEBUG'));
+ if (!$cache->isFresh())
+ {
+ $dumper = new PhpMatcherDumper($this->get_routes());
+
+ $options = array(
+ 'class' => 'phpbb_url_matcher',
+ 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher',
+ );
+
+ $cache->write($dumper->dump($options), $this->get_routes()->getResources());
+ }
+
+ require_once($cache->getPath());
+
+ $this->matcher = new \phpbb_url_matcher($this->context);
+ }
+ catch (IOException $e)
+ {
+ $this->create_new_url_matcher();
+ }
+ }
+
+ /**
+ * Creates a new URL Matcher
+ */
+ protected function create_new_url_matcher()
+ {
+ $this->matcher = new UrlMatcher($this->get_routes(), $this->context);
+ }
+
+ /**
+ * Gets the UrlGenerator instance associated with this Router.
+ *
+ * @return \Symfony\Component\Routing\Generator\UrlGeneratorInterface A UrlGeneratorInterface instance
+ */
+ public function get_generator()
+ {
+ if ($this->generator !== null)
+ {
+ return $this->generator;
+ }
+
+ $this->create_dumped_url_generator();
+
+ return $this->generator;
+ }
+
+ /**
+ * Creates a new dumped URL Generator (dump it if necessary)
+ */
+ protected function create_dumped_url_generator()
+ {
+ try
+ {
+ $cache = new ConfigCache("{$this->cache_dir}url_generator.{$this->php_ext}", defined('DEBUG'));
+ if (!$cache->isFresh())
+ {
+ $dumper = new PhpGeneratorDumper($this->get_routes());
+
+ $options = array(
+ 'class' => 'phpbb_url_generator',
+ 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator',
+ );
+
+ $cache->write($dumper->dump($options), $this->get_routes()->getResources());
+ }
+
+ require_once($cache->getPath());
+
+ $this->generator = new \phpbb_url_generator($this->context);
+ }
+ catch (IOException $e)
+ {
+ $this->create_new_url_generator();
+ }
+ }
+
+ /**
+ * Creates a new URL Generator
+ */
+ protected function create_new_url_generator()
+ {
+ $this->generator = new UrlGenerator($this->get_routes(), $this->context);
+ }
+
+ /**
+ * Replaces placeholders with service container parameter values in:
+ * - the route defaults,
+ * - the route requirements,
+ * - the route path,
+ * - the route host,
+ * - the route schemes,
+ * - the route methods.
+ *
+ * @param RouteCollection $collection
+ */
+ protected function resolveParameters(RouteCollection $collection)
+ {
+ /** @var \Symfony\Component\Routing\Route $route */
+ foreach ($collection as $route)
+ {
+ foreach ($route->getDefaults() as $name => $value)
+ {
+ $route->setDefault($name, $this->resolve($value));
+ }
+
+ $requirements = $route->getRequirements();
+ unset($requirements['_scheme']);
+ unset($requirements['_method']);
+
+ foreach ($requirements as $name => $value)
+ {
+ $route->setRequirement($name, $this->resolve($value));
+ }
+
+ $route->setPath($this->resolve($route->getPath()));
+ $route->setHost($this->resolve($route->getHost()));
+
+ $schemes = array();
+ foreach ($route->getSchemes() as $scheme)
+ {
+ $schemes = array_merge($schemes, explode('|', $this->resolve($scheme)));
+ }
+
+ $route->setSchemes($schemes);
+ $methods = array();
+ foreach ($route->getMethods() as $method)
+ {
+ $methods = array_merge($methods, explode('|', $this->resolve($method)));
+ }
+
+ $route->setMethods($methods);
+ $route->setCondition($this->resolve($route->getCondition()));
+ }
+ }
+
+ /**
+ * Recursively replaces placeholders with the service container parameters.
+ *
+ * @param mixed $value The source which might contain "%placeholders%"
+ *
+ * @return mixed The source with the placeholders replaced by the container
+ * parameters. Arrays are resolved recursively.
+ *
+ * @throws ParameterNotFoundException When a placeholder does not exist as a container parameter
+ * @throws RuntimeException When a container value is not a string or a numeric value
+ */
+ private function resolve($value)
+ {
+ if (is_array($value))
+ {
+ foreach ($value as $key => $val)
+ {
+ $value[$key] = $this->resolve($val);
+ }
+
+ return $value;
+ }
+
+ if (!is_string($value))
+ {
+ return $value;
+ }
+
+ $container = $this->container;
+ $escapedValue = preg_replace_callback('/%%|%([^%\s]++)%/', function ($match) use ($container, $value)
+ {
+ // skip %%
+ if (!isset($match[1]))
+ {
+ return '%%';
+ }
+
+ $resolved = $container->getParameter($match[1]);
+ if (is_string($resolved) || is_numeric($resolved))
+ {
+ return (string) $resolved;
+ }
+
+ throw new RuntimeException(sprintf(
+ 'The container parameter "%s", used in the route configuration value "%s", '.
+ 'must be a string or numeric, but it is of type %s.',
+ $match[1],
+ $value,
+ gettype($resolved)
+ )
+ );
+ }, $value);
+
+ return str_replace('%%', '%', $escapedValue);
+ }
+}
diff --git a/phpBB/phpbb/search/base.php b/phpBB/phpbb/search/base.php
index d9313dddab..e7d0774b6c 100644
--- a/phpBB/phpbb/search/base.php
+++ b/phpBB/phpbb/search/base.php
@@ -133,7 +133,7 @@ class base
{
global $cache, $config, $db, $user;
- $length = min(sizeof($id_ary), $config['search_block_size']);
+ $length = min(count($id_ary), $config['search_block_size']);
// nothing to cache so exit
if (!$length)
@@ -148,7 +148,7 @@ class base
if (!($store = $cache->get('_search_results_' . $search_key)))
{
// add the current keywords to the recent searches in the cache which are listed on the search page
- if (!empty($keywords) || sizeof($author_ary))
+ if (!empty($keywords) || count($author_ary))
{
$sql = 'SELECT search_time
FROM ' . SEARCH_RESULTS_TABLE . '
@@ -201,7 +201,7 @@ class base
$store += $store_ids;
// if the cache is too big
- if (sizeof($store) - 2 > 20 * $config['search_block_size'])
+ if (count($store) - 2 > 20 * $config['search_block_size'])
{
// remove everything in front of two blocks in front of the current start index
for ($i = 0, $n = $id_range[0] - 2 * $config['search_block_size']; $i < $n; $i++)
@@ -243,7 +243,7 @@ class base
global $db, $cache, $config;
// clear all searches that searched for the specified words
- if (sizeof($words))
+ if (count($words))
{
$sql_where = '';
foreach ($words as $word)
@@ -264,7 +264,7 @@ class base
}
// clear all searches that searched for the specified authors
- if (is_array($authors) && sizeof($authors))
+ if (is_array($authors) && count($authors))
{
$sql_where = '';
foreach ($authors as $author)
@@ -286,7 +286,7 @@ class base
$sql = 'DELETE
FROM ' . SEARCH_RESULTS_TABLE . '
- WHERE search_time < ' . (time() - $config['search_store_results']);
+ WHERE search_time < ' . (time() - (int) $config['search_store_results']);
$db->sql_query($sql);
}
}
diff --git a/phpBB/phpbb/search/fulltext_mysql.php b/phpBB/phpbb/search/fulltext_mysql.php
index 64a63e83e0..1105d0892f 100644
--- a/phpBB/phpbb/search/fulltext_mysql.php
+++ b/phpBB/phpbb/search/fulltext_mysql.php
@@ -188,7 +188,7 @@ class fulltext_mysql extends \phpbb\search\base
}
$sql = 'SHOW VARIABLES
- LIKE \'ft\_%\'';
+ LIKE \'%ft\_%\'';
$result = $this->db->sql_query($sql);
$mysql_info = array();
@@ -198,8 +198,16 @@ class fulltext_mysql extends \phpbb\search\base
}
$this->db->sql_freeresult($result);
- set_config('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']);
- set_config('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']);
+ if ($engine === 'MyISAM')
+ {
+ $this->config->set('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']);
+ $this->config->set('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']);
+ }
+ else if ($engine === 'InnoDB')
+ {
+ $this->config->set('fulltext_mysql_max_word_len', $mysql_info['innodb_ft_max_token_size']);
+ $this->config->set('fulltext_mysql_min_word_len', $mysql_info['innodb_ft_min_token_size']);
+ }
return false;
}
@@ -232,9 +240,9 @@ class fulltext_mysql extends \phpbb\search\base
$this->split_words = $matches[1];
// We limit the number of allowed keywords to minimize load on the database
- if ($this->config['max_num_search_keywords'] && sizeof($this->split_words) > $this->config['max_num_search_keywords'])
+ if ($this->config['max_num_search_keywords'] && count($this->split_words) > $this->config['max_num_search_keywords'])
{
- trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', (int) $this->config['max_num_search_keywords'], sizeof($this->split_words)));
+ trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', (int) $this->config['max_num_search_keywords'], count($this->split_words)));
}
// to allow phrase search, we need to concatenate quoted words
@@ -361,7 +369,7 @@ class fulltext_mysql extends \phpbb\search\base
// remove too short or too long words
$text = array_values($text);
- for ($i = 0, $n = sizeof($text); $i < $n; $i++)
+ for ($i = 0, $n = count($text); $i < $n; $i++)
{
$text[$i] = trim($text[$i]);
if (utf8_strlen($text[$i]) < $this->config['fulltext_mysql_min_word_len'] || utf8_strlen($text[$i]) > $this->config['fulltext_mysql_max_word_len'])
@@ -563,12 +571,12 @@ class fulltext_mysql extends \phpbb\search\base
$sql_select = ($type == 'posts') ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id';
$sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : '';
$field = ($type == 'posts') ? 'post_id' : 'topic_id';
- if (sizeof($author_ary) && $author_name)
+ if (count($author_ary) && $author_name)
{
// first one matches post of registered users, second one guests and deleted users
$sql_author = ' AND (' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')';
}
- else if (sizeof($author_ary))
+ else if (count($author_ary))
{
$sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary);
}
@@ -580,7 +588,7 @@ class fulltext_mysql extends \phpbb\search\base
$sql_where_options = $sql_sort_join;
$sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : '';
$sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : '';
- $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
+ $sql_where_options .= (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
$sql_where_options .= ' AND ' . $post_visibility;
$sql_where_options .= $sql_author;
$sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
@@ -591,6 +599,7 @@ class fulltext_mysql extends \phpbb\search\base
WHERE MATCH ($sql_match) AGAINST ('" . $this->db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE)
$sql_where_options
ORDER BY $sql_sort";
+ $this->db->sql_return_on_error(true);
$result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
while ($row = $this->db->sql_fetchrow($result))
@@ -602,7 +611,7 @@ class fulltext_mysql extends \phpbb\search\base
$id_ary = array_unique($id_ary);
// if the total result count is not cached yet, retrieve it from the db
- if (!$result_count)
+ if (!$result_count && count($id_ary))
{
$sql_found_rows = 'SELECT FOUND_ROWS() as result_count';
$result = $this->db->sql_query($sql_found_rows);
@@ -659,7 +668,7 @@ class fulltext_mysql extends \phpbb\search\base
public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page)
{
// No author? No posts
- if (!sizeof($author_ary))
+ if (!count($author_ary))
{
return 0;
}
@@ -736,7 +745,7 @@ class fulltext_mysql extends \phpbb\search\base
{
$sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
}
- $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
+ $sql_fora = (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
$sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : '';
$sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
$sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : '';
@@ -889,7 +898,7 @@ class fulltext_mysql extends \phpbb\search\base
$id_ary = array_unique($id_ary);
}
- if (sizeof($id_ary))
+ if (count($id_ary))
{
$this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir);
$id_ary = array_slice($id_ary, 0, $per_page);
@@ -917,6 +926,34 @@ class fulltext_mysql extends \phpbb\search\base
$words = array_unique(array_merge($split_text, $split_title));
+ /**
+ * Event to modify method arguments and words before the MySQL search index is updated
+ *
+ * @event core.search_mysql_index_before
+ * @var string mode Contains the post mode: edit, post, reply, quote
+ * @var int post_id The id of the post which is modified/created
+ * @var string message New or updated post content
+ * @var string subject New or updated post subject
+ * @var int poster_id Post author's user id
+ * @var int forum_id The id of the forum in which the post is located
+ * @var array words List of words added to the index
+ * @var array split_text Array of words from the message
+ * @var array split_title Array of words from the title
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'post_id',
+ 'message',
+ 'subject',
+ 'poster_id',
+ 'forum_id',
+ 'words',
+ 'split_text',
+ 'split_title',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_index_before', compact($vars)));
+
unset($split_text);
unset($split_title);
@@ -942,7 +979,7 @@ class fulltext_mysql extends \phpbb\search\base
// destroy too old cached search results
$this->destroy_cache(array());
- set_config('search_last_gc', time(), true);
+ $this->config->set('search_last_gc', time(), false);
}
/**
@@ -996,12 +1033,37 @@ class fulltext_mysql extends \phpbb\search\base
$alter_list[] = $alter_entry;
}
- if (sizeof($alter_list))
+ $sql_queries = [];
+
+ foreach ($alter_list as $alter)
{
- foreach ($alter_list as $alter)
- {
- $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter));
- }
+ $sql_queries[] = 'ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter);
+ }
+
+ if (!isset($this->stats['post_text']))
+ {
+ $sql_queries[] = 'ALTER TABLE ' . POSTS_TABLE . ' ADD FULLTEXT post_text (post_text)';
+ }
+
+ $stats = $this->stats;
+
+ /**
+ * Event to modify SQL queries before the MySQL search index is created
+ *
+ * @event core.search_mysql_create_index_before
+ * @var array sql_queries Array with queries for creating the search index
+ * @var array stats Array with statistics of the current index (read only)
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'sql_queries',
+ 'stats',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_create_index_before', compact($vars)));
+
+ foreach ($sql_queries as $sql_query)
+ {
+ $this->db->sql_query($sql_query);
}
$this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
@@ -1039,9 +1101,37 @@ class fulltext_mysql extends \phpbb\search\base
$alter[] = 'DROP INDEX post_content';
}
- if (sizeof($alter))
+ if (isset($this->stats['post_text']))
{
- $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter));
+ $alter[] = 'DROP INDEX post_text';
+ }
+
+ $sql_queries = [];
+
+ if (count($alter))
+ {
+ $sql_queries[] = 'ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter);
+ }
+
+ $stats = $this->stats;
+
+ /**
+ * Event to modify SQL queries before the MySQL search index is deleted
+ *
+ * @event core.search_mysql_delete_index_before
+ * @var array sql_queries Array with queries for deleting the search index
+ * @var array stats Array with statistics of the current index (read only)
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'sql_queries',
+ 'stats',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_mysql_delete_index_before', compact($vars)));
+
+ foreach ($sql_queries as $sql_query)
+ {
+ $this->db->sql_query($sql_query);
}
$this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
@@ -1059,7 +1149,7 @@ class fulltext_mysql extends \phpbb\search\base
$this->get_stats();
}
- return isset($this->stats['post_subject']) && isset($this->stats['post_content']);
+ return isset($this->stats['post_subject']) && isset($this->stats['post_content']) && isset($this->stats['post_text']);
}
/**
@@ -1103,6 +1193,10 @@ class fulltext_mysql extends \phpbb\search\base
{
$this->stats['post_subject'] = $row;
}
+ else if ($row['Key_name'] == 'post_text')
+ {
+ $this->stats['post_text'] = $row;
+ }
else if ($row['Key_name'] == 'post_content')
{
$this->stats['post_content'] = $row;
diff --git a/phpBB/phpbb/search/fulltext_native.php b/phpBB/phpbb/search/fulltext_native.php
index 63b0b24edf..c83de75eed 100644
--- a/phpBB/phpbb/search/fulltext_native.php
+++ b/phpBB/phpbb/search/fulltext_native.php
@@ -18,6 +18,13 @@ namespace phpbb\search;
*/
class fulltext_native extends \phpbb\search\base
{
+ const UTF8_HANGUL_FIRST = "\xEA\xB0\x80";
+ const UTF8_HANGUL_LAST = "\xED\x9E\xA3";
+ const UTF8_CJK_FIRST = "\xE4\xB8\x80";
+ const UTF8_CJK_LAST = "\xE9\xBE\xBB";
+ const UTF8_CJK_B_FIRST = "\xF0\xA0\x80\x80";
+ const UTF8_CJK_B_LAST = "\xF0\xAA\x9B\x96";
+
/**
* Associative array holding index stats
* @var array
@@ -99,7 +106,7 @@ class fulltext_native extends \phpbb\search\base
protected $user;
/**
- * Initialises the fulltext_native search backend with min/max word length and makes sure the UTF-8 normalizer is loaded
+ * Initialises the fulltext_native search backend with min/max word length
*
* @param boolean|string &$error is passed by reference and should either be set to false on success or an error message on failure
* @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object
@@ -113,15 +120,11 @@ class fulltext_native extends \phpbb\search\base
$this->phpbb_dispatcher = $phpbb_dispatcher;
$this->user = $user;
- $this->word_length = array('min' => $this->config['fulltext_native_min_chars'], 'max' => $this->config['fulltext_native_max_chars']);
+ $this->word_length = array('min' => (int) $this->config['fulltext_native_min_chars'], 'max' => (int) $this->config['fulltext_native_max_chars']);
/**
* Load the UTF tools
*/
- if (!class_exists('utf_normalizer'))
- {
- include($this->phpbb_root_path . 'includes/utf/utf_normalizer.' . $this->php_ext);
- }
if (!function_exists('utf8_decode_ncr'))
{
include($this->phpbb_root_path . 'includes/utf/utf_tools.' . $this->php_ext);
@@ -187,7 +190,7 @@ class fulltext_native extends \phpbb\search\base
*/
public function split_keywords($keywords, $terms)
{
- $tokens = '+-|()*';
+ $tokens = '+-|()* ';
$keywords = trim($this->cleanup($keywords, $tokens));
@@ -221,12 +224,10 @@ class fulltext_native extends \phpbb\search\base
$keywords[$i] = '|';
break;
case '*':
- if ($i === 0 || ($keywords[$i - 1] !== '*' && strcspn($keywords[$i - 1], $tokens) === 0))
+ // $i can never be 0 here since $open_bracket is initialised to false
+ if (strpos($tokens, $keywords[$i - 1]) !== false && ($i + 1 === $n || strpos($tokens, $keywords[$i + 1]) !== false))
{
- if ($i === $n - 1 || ($keywords[$i + 1] !== '*' && strcspn($keywords[$i + 1], $tokens) === 0))
- {
- $keywords = substr($keywords, 0, $i) . substr($keywords, $i + 1);
- }
+ $keywords[$i] = '|';
}
break;
}
@@ -261,7 +262,7 @@ class fulltext_native extends \phpbb\search\base
}
}
- if ($open_bracket)
+ if ($open_bracket !== false)
{
$keywords .= ')';
}
@@ -282,7 +283,7 @@ class fulltext_native extends \phpbb\search\base
);
$keywords = preg_replace($match, $replace, $keywords);
- $num_keywords = sizeof(explode(' ', $keywords));
+ $num_keywords = count(explode(' ', $keywords));
// We limit the number of allowed keywords to minimize load on the database
if ($this->config['max_num_search_keywords'] && $num_keywords > $this->config['max_num_search_keywords'])
@@ -298,12 +299,26 @@ class fulltext_native extends \phpbb\search\base
$words = array();
preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $words);
- if (sizeof($words[1]))
+ if (count($words[1]))
{
$keywords = '(' . implode('|', $words[1]) . ')';
}
}
+ // Remove non trailing wildcards from each word to prevent a full table scan (it's now using the database index)
+ $match = '#\*(?!$|\s)#';
+ $replace = '$1';
+ $keywords = preg_replace($match, $replace, $keywords);
+
+ // Only allow one wildcard in the search query to limit the database load
+ $match = '#\*#';
+ $replace = '$1';
+ $count_wildcards = substr_count($keywords, '*');
+
+ // Reverse the string to remove all wildcards except the first one
+ $keywords = strrev(preg_replace($match, $replace, strrev($keywords), $count_wildcards - 1));
+ unset($count_wildcards);
+
// set the search_query which is shown to the user
$this->search_query = $keywords;
@@ -313,7 +328,7 @@ class fulltext_native extends \phpbb\search\base
$common_ids = $words = array();
- if (sizeof($exact_words))
+ if (count($exact_words))
{
$sql = 'SELECT word_id, word_text, word_common
FROM ' . SEARCH_WORDLIST_TABLE . '
@@ -349,9 +364,6 @@ class fulltext_native extends \phpbb\search\base
$this->must_not_contain_ids = array();
$this->must_exclude_one_ids = array();
- $mode = '';
- $ignore_no_id = true;
-
foreach ($query as $word)
{
if (empty($word))
@@ -409,8 +421,16 @@ class fulltext_native extends \phpbb\search\base
{
if (strpos($word_part, '*') !== false)
{
- $id_words[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word_part)) . '\'';
- $non_common_words[] = $word_part;
+ $len = utf8_strlen(str_replace('*', '', $word_part));
+ if ($len >= $this->word_length['min'] && $len <= $this->word_length['max'])
+ {
+ $id_words[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word_part)) . '\'';
+ $non_common_words[] = $word_part;
+ }
+ else
+ {
+ $this->common_words[] = $word_part;
+ }
}
else if (isset($words[$word_part]))
{
@@ -426,10 +446,10 @@ class fulltext_native extends \phpbb\search\base
}
}
}
- if (sizeof($id_words))
+ if (count($id_words))
{
sort($id_words);
- if (sizeof($id_words) > 1)
+ if (count($id_words) > 1)
{
$this->{$mode . '_ids'}[] = $id_words;
}
@@ -440,7 +460,7 @@ class fulltext_native extends \phpbb\search\base
}
}
// throw an error if we shall not ignore unexistant words
- else if (!$ignore_no_id && sizeof($non_common_words))
+ else if (!$ignore_no_id && count($non_common_words))
{
trigger_error(sprintf($this->user->lang['WORDS_IN_NO_POST'], implode($this->user->lang['COMMA_SEPARATOR'], $non_common_words)));
}
@@ -480,7 +500,7 @@ class fulltext_native extends \phpbb\search\base
}
// Return true if all words are not common words
- if (sizeof($exact_words) - sizeof($this->common_words) > 0)
+ if (count($exact_words) - count($this->common_words) > 0)
{
return true;
}
@@ -594,7 +614,6 @@ class fulltext_native extends \phpbb\search\base
$id_ary = array();
$sql_where = array();
- $group_by = false;
$m_num = 0;
$w_num = 0;
@@ -717,7 +736,7 @@ class fulltext_native extends \phpbb\search\base
}
}
- if (sizeof($this->must_not_contain_ids))
+ if (count($this->must_not_contain_ids))
{
$sql_array['LEFT_JOIN'][] = array(
'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num),
@@ -827,7 +846,7 @@ class fulltext_native extends \phpbb\search\base
$sql_where[] = 'p.topic_id = ' . $topic_id;
}
- if (sizeof($author_ary))
+ if (count($author_ary))
{
if ($author_name)
{
@@ -841,7 +860,7 @@ class fulltext_native extends \phpbb\search\base
$sql_where[] = $sql_author;
}
- if (sizeof($ex_fid_ary))
+ if (count($ex_fid_ary))
{
$sql_where[] = $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true);
}
@@ -879,7 +898,6 @@ class fulltext_native extends \phpbb\search\base
break;
- case 'sqlite':
case 'sqlite3':
$sql_array_count['SELECT'] = ($type == 'posts') ? 'DISTINCT p.post_id' : 'DISTINCT p.topic_id';
$sql = 'SELECT COUNT(' . (($type == 'posts') ? 'post_id' : 'topic_id') . ') as total_results
@@ -1012,7 +1030,7 @@ class fulltext_native extends \phpbb\search\base
public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page)
{
// No author? No posts
- if (!sizeof($author_ary))
+ if (!count($author_ary))
{
return 0;
}
@@ -1084,7 +1102,7 @@ class fulltext_native extends \phpbb\search\base
{
$sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
}
- $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
+ $sql_fora = (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
$sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
$sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : '';
$sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : '';
@@ -1186,7 +1204,7 @@ class fulltext_native extends \phpbb\search\base
}
else
{
- if ($this->db->get_sql_layer() == 'sqlite' || $this->db->get_sql_layer() == 'sqlite3')
+ if ($this->db->get_sql_layer() == 'sqlite3')
{
$sql = 'SELECT COUNT(topic_id) as total_results
FROM (SELECT DISTINCT t.topic_id';
@@ -1203,7 +1221,7 @@ class fulltext_native extends \phpbb\search\base
$post_visibility
$sql_fora
AND t.topic_id = p.topic_id
- $sql_time" . (($this->db->get_sql_layer() == 'sqlite' || $this->db->get_sql_layer() == 'sqlite3') ? ')' : '');
+ $sql_time" . ($this->db->get_sql_layer() == 'sqlite3' ? ')' : '');
}
$result = $this->db->sql_query($sql);
@@ -1291,7 +1309,7 @@ class fulltext_native extends \phpbb\search\base
$this->db->sql_freeresult($result);
}
- if (sizeof($id_ary))
+ if (count($id_ary))
{
$this->save_ids($search_key, '', $author_ary, $total_results, $id_ary, $start, $sort_dir);
$id_ary = array_slice($id_ary, 0, $per_page);
@@ -1325,7 +1343,6 @@ class fulltext_native extends \phpbb\search\base
$match[] = '#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?[0-9a-z]{5,})\]#';
$min = $this->word_length['min'];
- $max = $this->word_length['max'];
$isset_min = $min - 1;
@@ -1361,9 +1378,9 @@ class fulltext_native extends \phpbb\search\base
* Note: this could be optimized. If the codepoint is lower than Hangul's range
* we know that it will also be lower than CJK ranges
*/
- if ((strncmp($word, UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, UTF8_HANGUL_LAST, 3) > 0)
- && (strncmp($word, UTF8_CJK_FIRST, 3) < 0 || strncmp($word, UTF8_CJK_LAST, 3) > 0)
- && (strncmp($word, UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, UTF8_CJK_B_LAST, 4) > 0))
+ if ((strncmp($word, self::UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, self::UTF8_HANGUL_LAST, 3) > 0)
+ && (strncmp($word, self::UTF8_CJK_FIRST, 3) < 0 || strncmp($word, self::UTF8_CJK_LAST, 3) > 0)
+ && (strncmp($word, self::UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, self::UTF8_CJK_B_LAST, 4) > 0))
{
$word = strtok(' ');
continue;
@@ -1436,6 +1453,38 @@ class fulltext_native extends \phpbb\search\base
$words['del']['post'] = array();
$words['del']['title'] = array();
}
+
+ /**
+ * Event to modify method arguments and words before the native search index is updated
+ *
+ * @event core.search_native_index_before
+ * @var string mode Contains the post mode: edit, post, reply, quote
+ * @var int post_id The id of the post which is modified/created
+ * @var string message New or updated post content
+ * @var string subject New or updated post subject
+ * @var int poster_id Post author's user id
+ * @var int forum_id The id of the forum in which the post is located
+ * @var array words Grouped lists of words added to or remove from the index
+ * @var array split_text Array of words from the message
+ * @var array split_title Array of words from the title
+ * @var array cur_words Array of words currently in the index for comparing to new words
+ * when mode is edit. Empty for other modes.
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'post_id',
+ 'message',
+ 'subject',
+ 'poster_id',
+ 'forum_id',
+ 'words',
+ 'split_text',
+ 'split_title',
+ 'cur_words',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_native_index_before', compact($vars)));
+
unset($split_text);
unset($split_title);
@@ -1446,7 +1495,7 @@ class fulltext_native extends \phpbb\search\base
// individual arrays of added and removed words for text and title. What
// we need to do now is add the new words (if they don't already exist)
// and then add (or remove) matches between the words and this post
- if (sizeof($unique_add_words))
+ if (count($unique_add_words))
{
$sql = 'SELECT word_id, word_text
FROM ' . SEARCH_WORDLIST_TABLE . '
@@ -1462,7 +1511,7 @@ class fulltext_native extends \phpbb\search\base
$new_words = array_diff($unique_add_words, array_keys($word_ids));
$this->db->sql_transaction('begin');
- if (sizeof($new_words))
+ if (count($new_words))
{
$sql_ary = array();
@@ -1486,7 +1535,7 @@ class fulltext_native extends \phpbb\search\base
{
$title_match = ($word_in == 'title') ? 1 : 0;
- if (sizeof($word_ary))
+ if (count($word_ary))
{
$sql_in = array();
foreach ($word_ary as $word)
@@ -1515,7 +1564,7 @@ class fulltext_native extends \phpbb\search\base
{
$title_match = ($word_in == 'title') ? 1 : 0;
- if (sizeof($word_ary))
+ if (count($word_ary))
{
$sql = 'INSERT INTO ' . SEARCH_WORDMATCH_TABLE . ' (post_id, word_id, title_match)
SELECT ' . (int) $post_id . ', word_id, ' . (int) $title_match . '
@@ -1546,7 +1595,7 @@ class fulltext_native extends \phpbb\search\base
*/
public function index_remove($post_ids, $author_ids, $forum_ids)
{
- if (sizeof($post_ids))
+ if (count($post_ids))
{
$sql = 'SELECT w.word_id, w.word_text, m.title_match
FROM ' . SEARCH_WORDMATCH_TABLE . ' m, ' . SEARCH_WORDLIST_TABLE . ' w
@@ -1569,7 +1618,7 @@ class fulltext_native extends \phpbb\search\base
}
$this->db->sql_freeresult($result);
- if (sizeof($title_word_ids))
+ if (count($title_word_ids))
{
$sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
SET word_count = word_count - 1
@@ -1578,7 +1627,7 @@ class fulltext_native extends \phpbb\search\base
$this->db->sql_query($sql);
}
- if (sizeof($message_word_ids))
+ if (count($message_word_ids))
{
$sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
SET word_count = word_count - 1
@@ -1608,7 +1657,7 @@ class fulltext_native extends \phpbb\search\base
// carry on ... it's okay ... I know when I'm not wanted boo hoo
if (!$this->config['fulltext_native_load_upd'])
{
- set_config('search_last_gc', time(), true);
+ $this->config->set('search_last_gc', time(), false);
return;
}
@@ -1633,7 +1682,7 @@ class fulltext_native extends \phpbb\search\base
}
$this->db->sql_freeresult($result);
- if (sizeof($sql_in))
+ if (count($sql_in))
{
// Flag the words
$sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
@@ -1643,7 +1692,7 @@ class fulltext_native extends \phpbb\search\base
// by setting search_last_gc to the new time here we make sure that if a user reloads because the
// following query takes too long, he won't run into it again
- set_config('search_last_gc', time(), true);
+ $this->config->set('search_last_gc', time(), false);
// Delete the matches
$sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . '
@@ -1653,13 +1702,13 @@ class fulltext_native extends \phpbb\search\base
unset($sql_in);
}
- if (sizeof($destroy_cache_words))
+ if (count($destroy_cache_words))
{
// destroy cached search results containing any of the words that are now common or were removed
$this->destroy_cache(array_unique($destroy_cache_words));
}
- set_config('search_last_gc', time(), true);
+ $this->config->set('search_last_gc', time(), false);
}
/**
@@ -1667,21 +1716,43 @@ class fulltext_native extends \phpbb\search\base
*/
public function delete_index($acp_module, $u_action)
{
+ $sql_queries = [];
+
switch ($this->db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
- $this->db->sql_query('DELETE FROM ' . SEARCH_WORDLIST_TABLE);
- $this->db->sql_query('DELETE FROM ' . SEARCH_WORDMATCH_TABLE);
- $this->db->sql_query('DELETE FROM ' . SEARCH_RESULTS_TABLE);
+ $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDLIST_TABLE;
+ $sql_queries[] = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE;
+ $sql_queries[] = 'DELETE FROM ' . SEARCH_RESULTS_TABLE;
break;
default:
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDLIST_TABLE);
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDMATCH_TABLE);
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
+ $sql_queries[] = 'TRUNCATE TABLE ' . SEARCH_WORDLIST_TABLE;
+ $sql_queries[] = 'TRUNCATE TABLE ' . SEARCH_WORDMATCH_TABLE;
+ $sql_queries[] = 'TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE;
break;
}
+
+ $stats = $this->stats;
+
+ /**
+ * Event to modify SQL queries before the native search index is deleted
+ *
+ * @event core.search_native_delete_index_before
+ * @var array sql_queries Array with queries for deleting the search index
+ * @var array stats Array with statistics of the current index (read only)
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'sql_queries',
+ 'stats',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_native_delete_index_before', compact($vars)));
+
+ foreach ($sql_queries as $sql_query)
+ {
+ $this->db->sql_query($sql_query);
+ }
}
/**
@@ -1689,7 +1760,7 @@ class fulltext_native extends \phpbb\search\base
*/
public function index_created()
{
- if (!sizeof($this->stats))
+ if (!count($this->stats))
{
$this->get_stats();
}
@@ -1702,7 +1773,7 @@ class fulltext_native extends \phpbb\search\base
*/
public function index_stats()
{
- if (!sizeof($this->stats))
+ if (!count($this->stats))
{
$this->get_stats();
}
@@ -1730,13 +1801,11 @@ class fulltext_native extends \phpbb\search\base
* @param string $allowed_chars String of special chars to allow
* @param string $encoding Text encoding
* @return string Cleaned up text, only alphanumeric chars are left
- *
- * @todo \normalizer::cleanup being able to be used?
*/
protected function cleanup($text, $allowed_chars = null, $encoding = 'utf-8')
{
static $conv = array(), $conv_loaded = array();
- $words = $allow = array();
+ $allow = array();
// Convert the text to UTF-8
$encoding = strtolower($encoding);
@@ -1758,12 +1827,9 @@ class fulltext_native extends \phpbb\search\base
$text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES);
/**
- * Load the UTF-8 normalizer
- *
- * If we use it more widely, an instance of that class should be held in a
- * a global variable instead
+ * Normalize to NFC
*/
- \utf_normalizer::nfc($text);
+ $text = \Normalizer::normalize($text);
/**
* The first thing we do is:
@@ -1856,9 +1922,9 @@ class fulltext_native extends \phpbb\search\base
$utf_char = substr($text, $pos, $utf_len);
$pos += $utf_len;
- if (($utf_char >= UTF8_HANGUL_FIRST && $utf_char <= UTF8_HANGUL_LAST)
- || ($utf_char >= UTF8_CJK_FIRST && $utf_char <= UTF8_CJK_LAST)
- || ($utf_char >= UTF8_CJK_B_FIRST && $utf_char <= UTF8_CJK_B_LAST))
+ if (($utf_char >= self::UTF8_HANGUL_FIRST && $utf_char <= self::UTF8_HANGUL_LAST)
+ || ($utf_char >= self::UTF8_CJK_FIRST && $utf_char <= self::UTF8_CJK_LAST)
+ || ($utf_char >= self::UTF8_CJK_B_FIRST && $utf_char <= self::UTF8_CJK_B_LAST))
{
/**
* All characters within these ranges are valid
diff --git a/phpBB/phpbb/search/fulltext_postgres.php b/phpBB/phpbb/search/fulltext_postgres.php
index 04441e6226..2f387e791e 100644
--- a/phpBB/phpbb/search/fulltext_postgres.php
+++ b/phpBB/phpbb/search/fulltext_postgres.php
@@ -294,7 +294,7 @@ class fulltext_postgres extends \phpbb\search\base
// remove too short or too long words
$text = array_values($text);
- for ($i = 0, $n = sizeof($text); $i < $n; $i++)
+ for ($i = 0, $n = count($text); $i < $n; $i++)
{
$text[$i] = trim($text[$i]);
if (utf8_strlen($text[$i]) < $this->config['fulltext_postgres_min_word_len'] || utf8_strlen($text[$i]) > $this->config['fulltext_postgres_max_word_len'])
@@ -498,17 +498,16 @@ class fulltext_postgres extends \phpbb\search\base
);
extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_keywords_main_query_before', compact($vars)));
- $sql_select = ($type == 'posts') ? 'p.post_id' : 'DISTINCT t.topic_id';
+ $sql_select = ($type == 'posts') ? 'p.post_id' : 'DISTINCT t.topic_id, ' . $sort_by_sql[$sort_key];
$sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : '';
$field = ($type == 'posts') ? 'post_id' : 'topic_id';
- $sql_author = (sizeof($author_ary) == 1) ? ' = ' . $author_ary[0] : 'IN (' . implode(', ', $author_ary) . ')';
- if (sizeof($author_ary) && $author_name)
+ if (count($author_ary) && $author_name)
{
// first one matches post of registered users, second one guests and deleted users
$sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')';
}
- else if (sizeof($author_ary))
+ else if (count($author_ary))
{
$sql_author = ' AND ' . $this->db->sql_in_set('p.poster_id', $author_ary);
}
@@ -520,13 +519,12 @@ class fulltext_postgres extends \phpbb\search\base
$sql_where_options = $sql_sort_join;
$sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : '';
$sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : '';
- $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
+ $sql_where_options .= (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
$sql_where_options .= ' AND ' . $post_visibility;
$sql_where_options .= $sql_author;
$sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
$sql_where_options .= $sql_match_where;
- $tmp_sql_match = array();
$sql_match = str_replace(',', " || ' ' ||", $sql_match);
$tmp_sql_match = "to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', " . $sql_match . ") @@ to_tsquery ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', '" . $this->db->sql_escape($this->tsearch_query) . "')";
@@ -611,7 +609,7 @@ class fulltext_postgres extends \phpbb\search\base
public function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page)
{
// No author? No posts
- if (!sizeof($author_ary))
+ if (!count($author_ary))
{
return 0;
}
@@ -688,7 +686,7 @@ class fulltext_postgres extends \phpbb\search\base
{
$sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
}
- $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
+ $sql_fora = (count($ex_fid_ary)) ? ' AND ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
$sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : '';
$sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
$sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : '';
@@ -838,7 +836,7 @@ class fulltext_postgres extends \phpbb\search\base
GROUP BY t.topic_id, $sort_by_sql[$sort_key]";
}
- $result = $this->db->sql_query($sql_count);
+ $this->db->sql_query($sql_count);
$result_count = (int) $this->db->sql_fetchfield('result_count');
if (!$result_count)
@@ -863,7 +861,7 @@ class fulltext_postgres extends \phpbb\search\base
$id_ary = array_unique($id_ary);
}
- if (sizeof($id_ary))
+ if (count($id_ary))
{
$this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir);
$id_ary = array_slice($id_ary, 0, $per_page);
@@ -891,6 +889,34 @@ class fulltext_postgres extends \phpbb\search\base
$words = array_unique(array_merge($split_text, $split_title));
+ /**
+ * Event to modify method arguments and words before the PostgreSQL search index is updated
+ *
+ * @event core.search_postgres_index_before
+ * @var string mode Contains the post mode: edit, post, reply, quote
+ * @var int post_id The id of the post which is modified/created
+ * @var string message New or updated post content
+ * @var string subject New or updated post subject
+ * @var int poster_id Post author's user id
+ * @var int forum_id The id of the forum in which the post is located
+ * @var array words Array of words added to the index
+ * @var array split_text Array of words from the message
+ * @var array split_title Array of words from the title
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'post_id',
+ 'message',
+ 'subject',
+ 'poster_id',
+ 'forum_id',
+ 'words',
+ 'split_text',
+ 'split_title',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_index_before', compact($vars)));
+
unset($split_text);
unset($split_title);
@@ -916,7 +942,7 @@ class fulltext_postgres extends \phpbb\search\base
// destroy too old cached search results
$this->destroy_cache(array());
- set_config('search_last_gc', time(), true);
+ $this->config->set('search_last_gc', time(), false);
}
/**
@@ -937,14 +963,37 @@ class fulltext_postgres extends \phpbb\search\base
$this->get_stats();
}
+ $sql_queries = [];
+
if (!isset($this->stats['post_subject']))
{
- $this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_subject ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_subject))");
+ $sql_queries[] = "CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_subject ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_subject))";
}
if (!isset($this->stats['post_content']))
{
- $this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_content ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_text || ' ' || post_subject))");
+ $sql_queries[] = "CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_content ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_text || ' ' || post_subject))";
+ }
+
+ $stats = $this->stats;
+
+ /**
+ * Event to modify SQL queries before the Postgres search index is created
+ *
+ * @event core.search_postgres_create_index_before
+ * @var array sql_queries Array with queries for creating the search index
+ * @var array stats Array with statistics of the current index (read only)
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'sql_queries',
+ 'stats',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_create_index_before', compact($vars)));
+
+ foreach ($sql_queries as $sql_query)
+ {
+ $this->db->sql_query($sql_query);
}
$this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
@@ -970,14 +1019,37 @@ class fulltext_postgres extends \phpbb\search\base
$this->get_stats();
}
+ $sql_queries = [];
+
if (isset($this->stats['post_subject']))
{
- $this->db->sql_query('DROP INDEX ' . $this->stats['post_subject']['relname']);
+ $sql_queries[] = 'DROP INDEX ' . $this->stats['post_subject']['relname'];
}
if (isset($this->stats['post_content']))
{
- $this->db->sql_query('DROP INDEX ' . $this->stats['post_content']['relname']);
+ $sql_queries[] = 'DROP INDEX ' . $this->stats['post_content']['relname'];
+ }
+
+ $stats = $this->stats;
+
+ /**
+ * Event to modify SQL queries before the Postgres search index is created
+ *
+ * @event core.search_postgres_delete_index_before
+ * @var array sql_queries Array with queries for deleting the search index
+ * @var array stats Array with statistics of the current index (read only)
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'sql_queries',
+ 'stats',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_postgres_delete_index_before', compact($vars)));
+
+ foreach ($sql_queries as $sql_query)
+ {
+ $this->db->sql_query($sql_query);
}
$this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
diff --git a/phpBB/phpbb/search/fulltext_sphinx.php b/phpBB/phpbb/search/fulltext_sphinx.php
index 0dbc6e33df..227fbd3fd6 100644
--- a/phpBB/phpbb/search/fulltext_sphinx.php
+++ b/phpBB/phpbb/search/fulltext_sphinx.php
@@ -85,7 +85,7 @@ class fulltext_sphinx
/**
* Database Tools object
- * @var \phpbb\db\tools
+ * @var \phpbb\db\tools\tools_interface
*/
protected $db_tools;
@@ -143,12 +143,13 @@ class fulltext_sphinx
$this->db = $db;
$this->auth = $auth;
- // Initialize \phpbb\db\tools object
- $this->db_tools = new \phpbb\db\tools($this->db);
+ // Initialize \phpbb\db\tools\tools object
+ global $phpbb_container; // TODO inject into object
+ $this->db_tools = $phpbb_container->get('dbal.tools');
if (!$this->config['fulltext_sphinx_id'])
{
- set_config('fulltext_sphinx_id', unique_id());
+ $this->config->set('fulltext_sphinx_id', unique_id());
}
$this->id = $this->config['fulltext_sphinx_id'];
$this->indexes = 'index_phpbb_' . $this->id . '_delta;index_phpbb_' . $this->id . '_main';
@@ -219,7 +220,7 @@ class fulltext_sphinx
}
// Move delta to main index each hour
- set_config('search_gc', 3600);
+ $this->config->set('search_gc', 3600);
return false;
}
@@ -291,7 +292,6 @@ class fulltext_sphinx
AND p.post_id >= $start AND p.post_id <= $end'),
array('sql_query_post', ''),
array('sql_query_post_index', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = $maxid WHERE counter_id = 1'),
- array('sql_query_info', 'SELECT * FROM ' . POSTS_TABLE . ' WHERE post_id = $id'),
array('sql_attr_uint', 'forum_id'),
array('sql_attr_uint', 'topic_id'),
array('sql_attr_uint', 'poster_id'),
@@ -303,7 +303,7 @@ class fulltext_sphinx
array('sql_attr_string', 'post_subject'),
),
'source source_phpbb_' . $this->id . '_delta : source_phpbb_' . $this->id . '_main' => array(
- array('sql_query_pre', ''),
+ array('sql_query_pre', 'SET NAMES \'utf8\''),
array('sql_query_range', ''),
array('sql_range_step', ''),
array('sql_query', 'SELECT
@@ -323,6 +323,7 @@ class fulltext_sphinx
WHERE
p.topic_id = t.topic_id
AND p.post_id >= ( SELECT max_doc_id FROM ' . SPHINX_TABLE . ' WHERE counter_id=1 )'),
+ array('sql_query_post_index', ''),
),
'index index_phpbb_' . $this->id . '_main' => array(
array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_main'),
@@ -331,10 +332,10 @@ class fulltext_sphinx
array('morphology', 'none'),
array('stopwords', ''),
array('min_word_len', '2'),
- array('charset_type', 'utf-8'),
array('charset_table', 'U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z, A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6, U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101, U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109, U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F, U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, U+0116->U+0117, U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D, U+011D, U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, U+0134->U+0135, U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, U+013C, U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, U+0143->U+0144, U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, U+014B, U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, U+0152->U+0153, U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159, U+0159, U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, U+0160->U+0161, U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, U+0167, U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, U+016E->U+016F, U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175, U+0175, U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, U+017B->U+017C, U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, U+0430..U+044F, U+4E00..U+9FFF'),
array('min_prefix_len', '0'),
array('min_infix_len', '0'),
+ array('html_strip', '1'),
),
'index index_phpbb_' . $this->id . '_delta : index_phpbb_' . $this->id . '_main' => array(
array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_delta'),
@@ -344,14 +345,12 @@ class fulltext_sphinx
array('mem_limit', $this->config['fulltext_sphinx_indexer_mem_limit'] . 'M'),
),
'searchd' => array(
- array('compat_sphinxql_magics' , '0'),
array('listen' , ($this->config['fulltext_sphinx_host'] ? $this->config['fulltext_sphinx_host'] : 'localhost') . ':' . ($this->config['fulltext_sphinx_port'] ? $this->config['fulltext_sphinx_port'] : '9312')),
array('log', $this->config['fulltext_sphinx_data_path'] . 'log/searchd.log'),
array('query_log', $this->config['fulltext_sphinx_data_path'] . 'log/sphinx-query.log'),
array('read_timeout', '5'),
array('max_children', '30'),
array('pid_file', $this->config['fulltext_sphinx_data_path'] . 'searchd.pid'),
- array('max_matches', (string) SPHINX_MAX_MATCHES),
array('binlog_path', $this->config['fulltext_sphinx_data_path']),
),
);
@@ -403,7 +402,7 @@ class fulltext_sphinx
$variable = $section->get_variable_by_name($key);
if (!$variable)
{
- $variable = $section->create_variable($key, $value);
+ $section->create_variable($key, $value);
}
else
{
@@ -412,7 +411,7 @@ class fulltext_sphinx
}
else
{
- $variable = $section->create_variable($key, $value);
+ $section->create_variable($key, $value);
}
}
}
@@ -436,7 +435,6 @@ class fulltext_sphinx
$match = array('#\sand\s#i', '#\sor\s#i', '#\snot\s#i', '#\+#', '#-#', '#\|#', '#@#');
$replace = array(' & ', ' | ', ' - ', ' +', ' -', ' |', '');
- $replacements = 0;
$keywords = preg_replace($match, $replace, $keywords);
$this->sphinx->SetMatchMode(SPH_MATCH_EXTENDED);
}
@@ -479,16 +477,16 @@ class fulltext_sphinx
*/
public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page)
{
+ global $user, $phpbb_log;
+
// No keywords? No posts.
- if (!strlen($this->search_query) && !sizeof($author_ary))
+ if (!strlen($this->search_query) && !count($author_ary))
{
return false;
}
$id_ary = array();
- $join_topic = ($type != 'posts');
-
// Sorting
if ($type == 'topics')
@@ -622,7 +620,7 @@ class fulltext_sphinx
break;
}
- if (sizeof($author_ary))
+ if (count($author_ary))
{
$this->sphinx->SetFilter('poster_id', $author_ary);
}
@@ -632,14 +630,14 @@ class fulltext_sphinx
// but at least it will also cause the same for normal users.
$this->sphinx->SetFilter('post_visibility', array(ITEM_APPROVED));
- if (sizeof($ex_fid_ary))
+ if (count($ex_fid_ary))
{
// All forums that a user is allowed to access
$fid_ary = array_unique(array_intersect(array_keys($this->auth->acl_getf('f_read', true)), array_keys($this->auth->acl_getf('f_search', true))));
// All forums that the user wants to and can search in
$search_forums = array_diff($fid_ary, $ex_fid_ary);
- if (sizeof($search_forums))
+ if (count($search_forums))
{
$this->sphinx->SetFilter('forum_id', $search_forums);
}
@@ -647,8 +645,8 @@ class fulltext_sphinx
$this->sphinx->SetFilter('deleted', array(0));
- $this->sphinx->SetLimits($start, (int) $per_page, SPHINX_MAX_MATCHES);
- $result = $this->sphinx->Query($search_query_prefix . str_replace('&quot;', '"', $this->search_query), $this->indexes);
+ $this->sphinx->SetLimits((int) $start, (int) $per_page, max(SPHINX_MAX_MATCHES, (int) $start + $per_page));
+ $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('&quot;', '"', $this->search_query)), $this->indexes);
// Could be connection to localhost:9312 failed (errno=111,
// msg=Connection refused) during rotate, retry if so
@@ -656,12 +654,12 @@ class fulltext_sphinx
while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--)
{
usleep(SPHINX_CONNECT_WAIT_TIME);
- $result = $this->sphinx->Query($search_query_prefix . str_replace('&quot;', '"', $this->search_query), $this->indexes);
+ $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('&quot;', '"', $this->search_query)), $this->indexes);
}
if ($this->sphinx->GetLastError())
{
- add_log('critical', 'LOG_SPHINX_ERROR', $this->sphinx->GetLastError());
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_SPHINX_ERROR', false, array($this->sphinx->GetLastError()));
if ($this->auth->acl_get('a_'))
{
trigger_error($this->user->lang('SPHINX_SEARCH_FAILED', $this->sphinx->GetLastError()));
@@ -678,8 +676,8 @@ class fulltext_sphinx
{
$start = floor(($result_count - 1) / $per_page) * $per_page;
- $this->sphinx->SetLimits((int) $start, (int) $per_page, SPHINX_MAX_MATCHES);
- $result = $this->sphinx->Query($search_query_prefix . str_replace('&quot;', '"', $this->search_query), $this->indexes);
+ $this->sphinx->SetLimits((int) $start, (int) $per_page, max(SPHINX_MAX_MATCHES, (int) $start + $per_page));
+ $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('&quot;', '"', $this->search_query)), $this->indexes);
// Could be connection to localhost:9312 failed (errno=111,
// msg=Connection refused) during rotate, retry if so
@@ -687,7 +685,7 @@ class fulltext_sphinx
while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--)
{
usleep(SPHINX_CONNECT_WAIT_TIME);
- $result = $this->sphinx->Query($search_query_prefix . str_replace('&quot;', '"', $this->search_query), $this->indexes);
+ $result = $this->sphinx->Query($search_query_prefix . $this->sphinx->EscapeString(str_replace('&quot;', '"', $this->search_query)), $this->indexes);
}
}
@@ -757,6 +755,28 @@ class fulltext_sphinx
*/
public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id)
{
+ /**
+ * Event to modify method arguments before the Sphinx search index is updated
+ *
+ * @event core.search_sphinx_index_before
+ * @var string mode Contains the post mode: edit, post, reply, quote
+ * @var int post_id The id of the post which is modified/created
+ * @var string message New or updated post content
+ * @var string subject New or updated post subject
+ * @var int poster_id Post author's user id
+ * @var int forum_id The id of the forum in which the post is located
+ * @since 3.2.3-RC1
+ */
+ $vars = array(
+ 'mode',
+ 'post_id',
+ 'message',
+ 'subject',
+ 'poster_id',
+ 'forum_id',
+ );
+ extract($this->phpbb_dispatcher->trigger_event('core.search_sphinx_index_before', compact($vars)));
+
if ($mode == 'edit')
{
$this->sphinx->UpdateAttributes($this->indexes, array('forum_id', 'poster_id'), array((int) $post_id => array((int) $forum_id, (int) $poster_id)));
@@ -789,7 +809,7 @@ class fulltext_sphinx
}
$this->db->sql_freeresult($result);
- if (sizeof($post_updates))
+ if (count($post_updates))
{
$this->sphinx->UpdateAttributes($this->indexes, array('topic_last_post_time'), $post_updates);
}
@@ -815,7 +835,7 @@ class fulltext_sphinx
*/
public function tidy($create = false)
{
- set_config('search_last_gc', time(), true);
+ $this->config->set('search_last_gc', time(), false);
}
/**
diff --git a/phpBB/phpbb/search/sphinx/config.php b/phpBB/phpbb/search/sphinx/config.php
index 675649b460..3205574b45 100644
--- a/phpBB/phpbb/search/sphinx/config.php
+++ b/phpBB/phpbb/search/sphinx/config.php
@@ -46,7 +46,7 @@ class config
*/
function get_section_by_name($name)
{
- for ($i = 0, $size = sizeof($this->sections); $i < $size; $i++)
+ for ($i = 0, $size = count($this->sections); $i < $size; $i++)
{
// Make sure this is really a section object and not a comment
if (($this->sections[$i] instanceof \phpbb\search\sphinx\config_section) && $this->sections[$i]->get_name() == $name)
@@ -67,7 +67,7 @@ class config
function add_section($name)
{
$this->sections[] = new \phpbb\search\sphinx\config_section($name, '');
- return $this->sections[sizeof($this->sections) - 1];
+ return $this->sections[count($this->sections) - 1];
}
/**
diff --git a/phpBB/phpbb/search/sphinx/config_section.php b/phpBB/phpbb/search/sphinx/config_section.php
index 14ab3a752c..2fc8b2da17 100644
--- a/phpBB/phpbb/search/sphinx/config_section.php
+++ b/phpBB/phpbb/search/sphinx/config_section.php
@@ -87,7 +87,7 @@ class config_section
*/
function get_variable_by_name($name)
{
- for ($i = 0, $size = sizeof($this->variables); $i < $size; $i++)
+ for ($i = 0, $size = count($this->variables); $i < $size; $i++)
{
// Make sure this is a variable object and not a comment
if (($this->variables[$i] instanceof \phpbb\search\sphinx\config_variable) && $this->variables[$i]->get_name() == $name)
@@ -106,7 +106,7 @@ class config_section
*/
function delete_variables_by_name($name)
{
- for ($i = 0, $size = sizeof($this->variables); $i < $size; $i++)
+ for ($i = 0, $size = count($this->variables); $i < $size; $i++)
{
// Make sure this is a variable object and not a comment
if (($this->variables[$i] instanceof \phpbb\search\sphinx\config_variable) && $this->variables[$i]->get_name() == $name)
@@ -129,7 +129,7 @@ class config_section
function create_variable($name, $value)
{
$this->variables[] = new \phpbb\search\sphinx\config_variable($name, $value, '');
- return $this->variables[sizeof($this->variables) - 1];
+ return $this->variables[count($this->variables) - 1];
}
/**
diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php
index 45e82df591..cc5a1b8f8f 100644
--- a/phpBB/phpbb/session.php
+++ b/phpBB/phpbb/session.php
@@ -91,15 +91,24 @@ class session
$page_name .= str_replace('%2F', '/', urlencode($symfony_request_path));
}
- // current directory within the phpBB root (for example: adm)
- $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path)));
- $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./')));
+ if (substr($root_path, 0, 2) === './' && strpos($root_path, '..') === false)
+ {
+ $root_dirs = explode('/', str_replace('\\', '/', rtrim($root_path, '/')));
+ $page_dirs = explode('/', str_replace('\\', '/', '.'));
+ }
+ else
+ {
+ // current directory within the phpBB root (for example: adm)
+ $root_dirs = explode('/', str_replace('\\', '/', $phpbb_filesystem->realpath($root_path)));
+ $page_dirs = explode('/', str_replace('\\', '/', $phpbb_filesystem->realpath('./')));
+ }
+
$intersection = array_intersect_assoc($root_dirs, $page_dirs);
$root_dirs = array_diff_assoc($root_dirs, $intersection);
$page_dirs = array_diff_assoc($page_dirs, $intersection);
- $page_dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
+ $page_dir = str_repeat('../', count($root_dirs)) . implode('/', $page_dirs);
if ($page_dir && substr($page_dir, -1, 1) == '/')
{
@@ -118,8 +127,8 @@ class session
// The script path from the webroot to the phpBB root (for example: /phpBB3/)
$script_dirs = explode('/', $script_path);
- array_splice($script_dirs, -sizeof($page_dirs));
- $root_script_path = implode('/', $script_dirs) . (sizeof($root_dirs) ? '/' . implode('/', $root_dirs) : '');
+ array_splice($script_dirs, -count($page_dirs));
+ $root_script_path = implode('/', $script_dirs) . (count($root_dirs) ? '/' . implode('/', $root_dirs) : '');
// We are on the base level (phpBB root == webroot), lets adjust the variables a bit...
if (!$root_script_path)
@@ -219,7 +228,7 @@ class session
function session_begin($update_session_page = true)
{
global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path;
- global $request, $phpbb_container, $phpbb_dispatcher;
+ global $request, $phpbb_container, $user, $phpbb_log, $phpbb_dispatcher;
// Give us some basic information
$this->time_now = time();
@@ -257,23 +266,23 @@ class session
if ($request->is_set($config['cookie_name'] . '_sid', \phpbb\request\request_interface::COOKIE) || $request->is_set($config['cookie_name'] . '_u', \phpbb\request\request_interface::COOKIE))
{
- $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
- $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
- $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true);
+ $this->cookie_data['u'] = $request->variable($config['cookie_name'] . '_u', 0, false, \phpbb\request\request_interface::COOKIE);
+ $this->cookie_data['k'] = $request->variable($config['cookie_name'] . '_k', '', false, \phpbb\request\request_interface::COOKIE);
+ $this->session_id = $request->variable($config['cookie_name'] . '_sid', '', false, \phpbb\request\request_interface::COOKIE);
$SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';
$_SID = (defined('NEED_SID')) ? $this->session_id : '';
if (empty($this->session_id))
{
- $this->session_id = $_SID = request_var('sid', '');
+ $this->session_id = $_SID = $request->variable('sid', '');
$SID = '?sid=' . $this->session_id;
$this->cookie_data = array('u' => 0, 'k' => '');
}
}
else
{
- $this->session_id = $_SID = request_var('sid', '');
+ $this->session_id = $_SID = $request->variable('sid', '');
$SID = '?sid=' . $this->session_id;
}
@@ -359,8 +368,8 @@ class session
}
else
{
- set_config('limit_load', '0');
- set_config('limit_search_load', '0');
+ $config->set('limit_load', '0');
+ $config->set('limit_search_load', '0');
}
}
@@ -423,6 +432,7 @@ class session
$session_expired = false;
// Check whether the session is still valid if we have one
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$provider = $provider_collection->get_provider();
@@ -473,11 +483,18 @@ class session
{
if ($referer_valid)
{
- add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for));
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_IP_BROWSER_FORWARDED_CHECK', false, array(
+ $u_ip,
+ $s_ip,
+ $u_browser,
+ $s_browser,
+ htmlspecialchars($u_forwarded_for),
+ htmlspecialchars($s_forwarded_for)
+ ));
}
else
{
- add_log('critical', 'LOG_REFERER_INVALID', $this->referer);
+ $phpbb_log->add('critical', $user->data['user_id'], $user->ip, 'LOG_REFERER_INVALID', false, array($this->referer));
}
}
}
@@ -499,7 +516,7 @@ class session
*/
function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true)
{
- global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
+ global $SID, $_SID, $db, $config, $cache, $phpbb_container, $phpbb_dispatcher;
$this->data = array();
@@ -562,16 +579,17 @@ class session
}
}
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$provider = $provider_collection->get_provider();
$this->data = $provider->autologin();
- if ($user_id !== false && sizeof($this->data) && $this->data['user_id'] != $user_id)
+ if ($user_id !== false && isset($this->data['user_id']) && $this->data['user_id'] != $user_id)
{
$this->data = array();
}
- if (sizeof($this->data))
+ if (isset($this->data['user_id']))
{
$this->cookie_data['k'] = '';
$this->cookie_data['u'] = $this->data['user_id'];
@@ -579,7 +597,7 @@ class session
// If we're presented with an autologin key we'll join against it.
// Else if we've been passed a user_id we'll grab data based on that
- if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data))
+ if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && empty($this->data))
{
$sql = 'SELECT u.*
FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k
@@ -599,7 +617,7 @@ class session
$db->sql_freeresult($result);
}
- if ($user_id !== false && !sizeof($this->data))
+ if ($user_id !== false && empty($this->data))
{
$this->cookie_data['k'] = '';
$this->cookie_data['u'] = $user_id;
@@ -627,7 +645,7 @@ class session
// User does not exist
// User is inactive
// User is bot
- if (!sizeof($this->data) || !is_array($this->data))
+ if (!is_array($this->data) || !count($this->data))
{
$this->cookie_data['k'] = '';
$this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS;
@@ -820,7 +838,7 @@ class session
$sql = 'SELECT COUNT(session_id) AS sessions
FROM ' . SESSIONS_TABLE . '
WHERE session_user_id = ' . (int) $this->data['user_id'] . '
- AND session_time >= ' . (int) ($this->time_now - (max($config['session_length'], $config['form_token_lifetime'])));
+ AND session_time >= ' . (int) ($this->time_now - (max((int) $config['session_length'], (int) $config['form_token_lifetime'])));
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -875,7 +893,7 @@ class session
*/
function session_kill($new_session = true)
{
- global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
+ global $SID, $_SID, $db, $phpbb_container, $phpbb_dispatcher;
$sql = 'DELETE FROM ' . SESSIONS_TABLE . "
WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
@@ -900,6 +918,7 @@ class session
unset($session_id);
// Allow connecting logout with external auth method logout
+ /* @var $provider_collection \phpbb\auth\provider_collection */
$provider_collection = $phpbb_container->get('auth.provider_collection');
$provider = $provider_collection->get_provider();
$provider->logout($this->data, $new_session);
@@ -966,7 +985,7 @@ class session
*/
function session_gc()
{
- global $db, $config, $phpbb_root_path, $phpEx, $phpbb_container, $phpbb_dispatcher;
+ global $db, $config, $phpbb_container, $phpbb_dispatcher;
$batch_size = 10;
@@ -1003,7 +1022,7 @@ class session
}
$db->sql_freeresult($result);
- if (sizeof($del_user_id))
+ if (count($del_user_id))
{
// Delete expired sessions
$sql = 'DELETE FROM ' . SESSIONS_TABLE . '
@@ -1016,7 +1035,7 @@ class session
{
// Less than 10 users, update gc timer ... else we want gc
// called again to delete other sessions
- set_config('session_last_gc', $this->time_now, true);
+ $config->set('session_last_gc', $this->time_now, false);
if ($config['max_autologin_time'])
{
@@ -1026,6 +1045,7 @@ class session
}
// only called from CRON; should be a safe workaround until the infrastructure gets going
+ /* @var $captcha_factory \phpbb\captcha\factory */
$captcha_factory = $phpbb_container->get('captcha.factory');
$captcha_factory->garbage_collect($config['captcha_plugin']);
@@ -1057,7 +1077,39 @@ class session
*/
function set_cookie($name, $cookiedata, $cookietime, $httponly = true)
{
- global $config;
+ global $config, $phpbb_dispatcher;
+
+ // If headers are already set, we just return
+ if (headers_sent())
+ {
+ return;
+ }
+
+ $disable_cookie = false;
+ /**
+ * Event to modify or disable setting cookies
+ *
+ * @event core.set_cookie
+ * @var bool disable_cookie Set to true to disable setting this cookie
+ * @var string name Name of the cookie
+ * @var string cookiedata The data to hold within the cookie
+ * @var int cookietime The expiration time as UNIX timestamp
+ * @var bool httponly Use HttpOnly?
+ * @since 3.2.9-RC1
+ */
+ $vars = array(
+ 'disable_cookie',
+ 'name',
+ 'cookiedata',
+ 'cookietime',
+ 'httponly',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.set_cookie', compact($vars)));
+
+ if ($disable_cookie)
+ {
+ return;
+ }
$name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
$expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
@@ -1130,7 +1182,7 @@ class session
$where_sql[] = $_sql;
}
- $sql .= (sizeof($where_sql)) ? implode(' AND ', $where_sql) : '';
+ $sql .= (count($where_sql)) ? implode(' AND ', $where_sql) : '';
$result = $db->sql_query($sql, $cache_ttl);
$ban_triggered_by = 'user';
@@ -1210,7 +1262,7 @@ class session
if ($banned && !$return)
{
- global $template, $phpbb_root_path, $phpEx;
+ global $phpbb_root_path, $phpEx;
// If the session is empty we need to create a valid one...
if (empty($this->session_id))
@@ -1273,7 +1325,12 @@ class session
trigger_error($message);
}
- return ($banned && $ban_row['ban_give_reason']) ? $ban_row['ban_give_reason'] : $banned;
+ if (!empty($ban_row))
+ {
+ $ban_row['ban_triggered_by'] = $ban_triggered_by;
+ }
+
+ return ($banned && $ban_row) ? $ban_row : $banned;
}
/**
@@ -1409,7 +1466,7 @@ class session
*/
function set_login_key($user_id = false, $key = false, $user_ip = false)
{
- global $config, $db;
+ global $db;
$user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
$user_ip = ($user_ip === false) ? $this->ip : $user_ip;
@@ -1419,7 +1476,7 @@ class session
$sql_ary = array(
'key_id' => (string) md5($key_id),
- 'last_ip' => (string) $this->ip,
+ 'last_ip' => (string) $user_ip,
'last_login' => (int) time()
);
@@ -1456,7 +1513,7 @@ class session
*/
function reset_login_keys($user_id = false)
{
- global $config, $db;
+ global $db;
$user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id;
@@ -1588,13 +1645,15 @@ class session
return;
}
+ // Do not update the session page for ajax requests, so the view online still works as intended
+ $page_changed = $this->update_session_page && $this->data['session_page'] != $this->page['page'] && !$request->is_ajax();
+
// Only update session DB a minute or so after last update or if page changes
- if ($this->time_now - ((isset($this->data['session_time'])) ? $this->data['session_time'] : 0) > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
+ if ($this->time_now - (isset($this->data['session_time']) ? $this->data['session_time'] : 0) > 60 || $page_changed)
{
$sql_ary = array('session_time' => $this->time_now);
- // Do not update the session page for ajax requests, so the view online still works as intended
- if ($this->update_session_page && !$request->is_ajax())
+ if ($page_changed)
{
$sql_ary['session_page'] = substr($this->page['page'], 0, 199);
$sql_ary['session_forum_id'] = $this->page['forum'];
diff --git a/phpBB/phpbb/template/asset.php b/phpBB/phpbb/template/asset.php
index ff9366af4a..cb00f16549 100644
--- a/phpBB/phpbb/template/asset.php
+++ b/phpBB/phpbb/template/asset.php
@@ -20,15 +20,20 @@ class asset
/** @var \phpbb\path_helper **/
protected $path_helper;
+ /** @var \phpbb\filesystem\filesystem */
+ protected $filesystem;
+
/**
* Constructor
*
* @param string $url URL
* @param \phpbb\path_helper $path_helper Path helper object
+ * @param \phpbb\filesystem\filesystem $filesystem
*/
- public function __construct($url, \phpbb\path_helper $path_helper)
+ public function __construct($url, \phpbb\path_helper $path_helper, \phpbb\filesystem\filesystem $filesystem)
{
$this->path_helper = $path_helper;
+ $this->filesystem = $filesystem;
$this->set_url($url);
}
@@ -152,18 +157,18 @@ class asset
*/
public function set_path($path, $urlencode = false)
{
- // Since 1.7.0 Twig returns the real path of the file. We need it to be relative to the working directory.
- $real_root_path = realpath($this->path_helper->get_phpbb_root_path()) . DIRECTORY_SEPARATOR;
+ // Since 1.7.0 Twig returns the real path of the file. We need it to be relative.
+ $real_root_path = $this->filesystem->realpath($this->path_helper->get_phpbb_root_path()) . DIRECTORY_SEPARATOR;
// If the asset is under the phpBB root path we need to remove its path and then prepend $phpbb_root_path
- if (substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path)
+ if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path)
{
$path = $this->path_helper->get_phpbb_root_path() . str_replace('\\', '/', substr($path, strlen($real_root_path)));
}
else
{
// Else we make the path relative to the current working directory
- $real_root_path = realpath('.') . DIRECTORY_SEPARATOR;
+ $real_root_path = $this->filesystem->realpath('.') . DIRECTORY_SEPARATOR;
if ($real_root_path && substr($path . DIRECTORY_SEPARATOR, 0, strlen($real_root_path)) === $real_root_path)
{
$path = str_replace('\\', '/', substr($path, strlen($real_root_path)));
diff --git a/phpBB/phpbb/template/assets_bag.php b/phpBB/phpbb/template/assets_bag.php
new file mode 100644
index 0000000000..067b0eb8f1
--- /dev/null
+++ b/phpBB/phpbb/template/assets_bag.php
@@ -0,0 +1,95 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\template;
+
+class assets_bag
+{
+ /** @var asset[] */
+ protected $stylesheets = [];
+
+ /** @var asset[] */
+ protected $scripts = [];
+
+ /**
+ * Add a css asset to the bag
+ *
+ * @param asset $asset
+ */
+ public function add_stylesheet(asset $asset)
+ {
+ $this->stylesheets[] = $asset;
+ }
+
+ /**
+ * Add a js script asset to the bag
+ *
+ * @param asset $asset
+ */
+ public function add_script(asset $asset)
+ {
+ $this->scripts[] = $asset;
+ }
+
+ /**
+ * Returns all css assets
+ *
+ * @return asset[]
+ */
+ public function get_stylesheets()
+ {
+ return $this->stylesheets;
+ }
+
+ /**
+ * Returns all js assets
+ *
+ * @return asset[]
+ */
+ public function get_scripts()
+ {
+ return $this->scripts;
+ }
+
+ /**
+ * Returns the HTML code to includes all css assets
+ *
+ * @return string
+ */
+ public function get_stylesheets_content()
+ {
+ $output = '';
+ foreach ($this->stylesheets as $stylesheet)
+ {
+ $output .= "<link href=\"{$stylesheet->get_url()}\" rel=\"stylesheet\" media=\"screen\" />\n";
+ }
+
+ return $output;
+ }
+
+ /**
+ * Returns the HTML code to includes all js assets
+ *
+ * @return string
+ */
+ public function get_scripts_content()
+ {
+ $output = '';
+ foreach ($this->scripts as $script)
+ {
+ $output .= "<script src=\"{$script->get_url()}\"></script>\n";
+ }
+
+ return $output;
+ }
+}
diff --git a/phpBB/phpbb/template/base.php b/phpBB/phpbb/template/base.php
index 41c0a01ba8..d502aceab8 100644
--- a/phpBB/phpbb/template/base.php
+++ b/phpBB/phpbb/template/base.php
@@ -107,6 +107,27 @@ abstract class base implements template
/**
* {@inheritdoc}
*/
+ public function retrieve_vars(array $vararray)
+ {
+ $result = array();
+ foreach ($vararray as $varname)
+ {
+ $result[$varname] = $this->retrieve_var($varname);
+ }
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function retrieve_var($varname)
+ {
+ return $this->context->retrieve_var($varname);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function assign_block_vars($blockname, array $vararray)
{
$this->context->assign_block_vars($blockname, $vararray);
@@ -127,6 +148,14 @@ abstract class base implements template
/**
* {@inheritdoc}
*/
+ public function retrieve_block_vars($blockname, array $vararray)
+ {
+ return $this->context->retrieve_block_vars($blockname, $vararray);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert')
{
return $this->context->alter_block_array($blockname, $vararray, $key, $mode);
diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php
index 5d04a09865..202e29ce00 100644
--- a/phpBB/phpbb/template/context.php
+++ b/phpBB/phpbb/template/context.php
@@ -87,6 +87,17 @@ class context
}
/**
+ * Retreive a single scalar value from a single key.
+ *
+ * @param string $varname Variable name
+ * @return mixed Variable value, or null if not set
+ */
+ public function retrieve_var($varname)
+ {
+ return isset($this->rootref[$varname]) ? $this->rootref[$varname] : null;
+ }
+
+ /**
* Returns a reference to template data array.
*
* This function is public so that template renderer may invoke it.
@@ -131,7 +142,7 @@ class context
*/
protected function set_num_rows(&$loop_data)
{
- $s_num_rows = sizeof($loop_data);
+ $s_num_rows = count($loop_data);
foreach ($loop_data as &$mod_block)
{
foreach ($mod_block as $sub_block_name => &$sub_block)
@@ -179,70 +190,51 @@ class context
public function assign_block_vars($blockname, array $vararray)
{
$this->num_rows_is_set = false;
- if (strpos($blockname, '.') !== false)
- {
- // Nested block.
- $blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
-
- $str = &$this->tpldata;
- for ($i = 0; $i < $blockcount; $i++)
- {
- $str = &$str[$blocks[$i]];
- $str = &$str[sizeof($str) - 1];
- }
- $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0;
- $vararray['S_ROW_COUNT'] = $vararray['S_ROW_NUM'] = $s_row_count;
+ // For nested block, $blockcount > 0, for top-level block, $blockcount == 0
+ $blocks = explode('.', $blockname);
+ $blockcount = count($blocks) - 1;
- // Assign S_FIRST_ROW
- if (!$s_row_count)
- {
- $vararray['S_FIRST_ROW'] = true;
- }
+ $block = &$this->tpldata;
+ for ($i = 0; $i < $blockcount; $i++)
+ {
+ $pos = strpos($blocks[$i], '[');
+ $name = ($pos !== false) ? substr($blocks[$i], 0, $pos) : $blocks[$i];
+ $block = &$block[$name];
+ $block_count = empty($block) ? 0 : count($block) - 1;
+ $index = (!$pos || strpos($blocks[$i], '[]') === $pos) ? $block_count : (min((int) substr($blocks[$i], $pos + 1, -1), $block_count));
+ $block = &$block[$index];
+ }
- // Assign S_BLOCK_NAME
- $vararray['S_BLOCK_NAME'] = $blocks[$blockcount];
+ // $block = &$block[$blocks[$i]]; // Do not traverse the last block as it might be empty
+ $name = $blocks[$i];
- // Now the tricky part, we always assign S_LAST_ROW and remove the entry before
- // This is much more clever than going through the complete template data on display (phew)
- $vararray['S_LAST_ROW'] = true;
- if ($s_row_count > 0)
- {
- unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']);
- }
+ // Assign S_ROW_COUNT and S_ROW_NUM
+ $s_row_count = isset($block[$name]) ? count($block[$name]) : 0;
+ $vararray['S_ROW_COUNT'] = $vararray['S_ROW_NUM'] = $s_row_count;
- // Now we add the block that we're actually assigning to.
- // We're adding a new iteration to this block with the given
- // variable assignments.
- $str[$blocks[$blockcount]][] = $vararray;
- }
- else
+ // Assign S_FIRST_ROW
+ if (!$s_row_count)
{
- // Top-level block.
- $s_row_count = (isset($this->tpldata[$blockname])) ? sizeof($this->tpldata[$blockname]) : 0;
- $vararray['S_ROW_COUNT'] = $vararray['S_ROW_NUM'] = $s_row_count;
-
- // Assign S_FIRST_ROW
- if (!$s_row_count)
- {
- $vararray['S_FIRST_ROW'] = true;
- }
+ $vararray['S_FIRST_ROW'] = true;
+ }
- // Assign S_BLOCK_NAME
- $vararray['S_BLOCK_NAME'] = $blockname;
+ // Assign S_BLOCK_NAME
+ $vararray['S_BLOCK_NAME'] = $name;
- // We always assign S_LAST_ROW and remove the entry before
- $vararray['S_LAST_ROW'] = true;
- if ($s_row_count > 0)
- {
- unset($this->tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']);
- }
-
- // Add a new iteration to this block with the variable assignments we were given.
- $this->tpldata[$blockname][] = $vararray;
+ // Now the tricky part, we always assign S_LAST_ROW and remove the entry before
+ // This is much more clever than going through the complete template data on display (phew)
+ $vararray['S_LAST_ROW'] = true;
+ if ($s_row_count > 0)
+ {
+ unset($block[$name][($s_row_count - 1)]['S_LAST_ROW']);
}
+ // Now we add the block that we're actually assigning to.
+ // We're adding a new iteration to this block with the given
+ // variable assignments.
+ $block[$name][] = $vararray;
+
return true;
}
@@ -264,57 +256,116 @@ class context
}
/**
- * Find the index for a specified key in the innermost specified block
- *
- * @param string $blockname the blockname, for example 'loop'
- * @param mixed $key Key to search for
- *
- * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
- *
- * int: Position [the position to search for]
+ * Retrieve key variable pairs from the specified block
*
- * If key is false the position is set to 0
- * If key is true the position is set to the last entry
- *
- * @return mixed false if not found, index position otherwise; be sure to test with ===
+ * @param string $blockname Name of block to retrieve $vararray from
+ * @param array $vararray An array of variable names, empty array retrieves all vars
+ * @return array of hashes with variable name as key and retrieved value or null as value
*/
- public function find_key_index($blockname, $key)
+ public function retrieve_block_vars($blockname, array $vararray)
{
// For nested block, $blockcount > 0, for top-level block, $blockcount == 0
$blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
+ $blockcount = count($blocks) - 1;
$block = $this->tpldata;
- for ($i = 0; $i < $blockcount; $i++)
+ for ($i = 0; $i <= $blockcount; $i++)
{
if (($pos = strpos($blocks[$i], '[')) !== false)
{
$name = substr($blocks[$i], 0, $pos);
+ if (empty($block[$name]))
+ {
+ return array();
+ }
+
if (strpos($blocks[$i], '[]') === $pos)
{
- $index = sizeof($block[$name]) - 1;
+ $index = count($block[$name]) - 1;
}
else
{
- $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1);
+ $index = min((int) substr($blocks[$i], $pos + 1, -1), count($block[$name]) - 1);
}
}
else
{
$name = $blocks[$i];
- $index = sizeof($block[$name]) - 1;
+ if (empty($block[$name]))
+ {
+ return array();
+ }
+
+ $index = count($block[$name]) - 1;
}
+ $block = $block[$name];
+ $block = $block[$index];
+ }
+
+ $result = array();
+ if ($vararray === array())
+ {
+ // The calculated vars that depend on the block position are excluded from the complete block returned results
+ $excluded_vars = array('S_FIRST_ROW', 'S_LAST_ROW', 'S_BLOCK_NAME', 'S_NUM_ROWS', 'S_ROW_COUNT', 'S_ROW_NUM');
+
+ foreach ($block as $varname => $varvalue)
+ {
+ if ($varname === strtoupper($varname) && !is_array($varvalue) && !in_array($varname, $excluded_vars))
+ {
+ $result[$varname] = $varvalue;
+ }
+ }
+ }
+ else
+ {
+ foreach ($vararray as $varname)
+ {
+ $result[$varname] = isset($block[$varname]) ? $block[$varname] : null;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Find the index for a specified key in the innermost specified block
+ *
+ * @param string $blockname the blockname, for example 'loop'
+ * @param mixed $key Key to search for
+ *
+ * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
+ *
+ * int: Position [the position to search for]
+ *
+ * If key is false the position is set to 0
+ * If key is true the position is set to the last entry
+ *
+ * @return mixed false if not found, index position otherwise; be sure to test with ===
+ */
+ public function find_key_index($blockname, $key)
+ {
+ // For nested block, $blockcount > 0, for top-level block, $blockcount == 0
+ $blocks = explode('.', $blockname);
+ $blockcount = count($blocks) - 1;
+
+ $block = $this->tpldata;
+ for ($i = 0; $i < $blockcount; $i++)
+ {
+ $pos = strpos($blocks[$i], '[');
+ $name = ($pos !== false) ? substr($blocks[$i], 0, $pos) : $blocks[$i];
+
if (!isset($block[$name]))
{
return false;
}
- $block = $block[$name];
- if (!isset($block[$index]))
+
+ $index = (!$pos || strpos($blocks[$i], '[]') === $pos) ? (count($block[$name]) - 1) : (min((int) substr($blocks[$i], $pos + 1, -1), count($block[$name]) - 1));
+
+ if (!isset($block[$name][$index]))
{
return false;
}
- $block = $block[$index];
+ $block = $block[$name][$index];
}
if (!isset($block[$blocks[$i]]))
@@ -324,9 +375,9 @@ class context
$block = $block[$blocks[$i]]; // Traverse the last block
// Change key to zero (change first position) if false and to last position if true
- if ($key === false || $key === true)
+ if (is_bool($key))
{
- return ($key === false) ? 0 : sizeof($block) - 1;
+ return (!$key) ? 0 : count($block) - 1;
}
// Get correct position if array given
@@ -343,7 +394,7 @@ class context
}
}
- return (is_int($key) && ((0 <= $key) && ($key < sizeof($block)))) ? $key : false;
+ return (is_int($key) && ((0 <= $key) && ($key < count($block)))) ? $key : false;
}
/**
@@ -363,10 +414,11 @@ class context
* If key is false the position is set to 0
* If key is true the position is set to the last entry
*
- * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
+ * @param string $mode Mode to execute (valid modes are 'insert', 'change' and 'delete')
*
* If insert, the vararray is inserted at the given position (position counting from zero).
* If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new \value).
+ * If delete, the vararray is ignored, and the block at the given position (counting from zero) is removed.
*
* Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
* and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
@@ -379,7 +431,7 @@ class context
// For nested block, $blockcount > 0, for top-level block, $blockcount == 0
$blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
+ $blockcount = count($blocks) - 1;
$block = &$this->tpldata;
for ($i = 0; $i < $blockcount; $i++)
@@ -390,17 +442,17 @@ class context
if (strpos($blocks[$i], '[]') === $pos)
{
- $index = sizeof($block[$name]) - 1;
+ $index = count($block[$name]) - 1;
}
else
{
- $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1);
+ $index = min((int) substr($blocks[$i], $pos + 1, -1), count($block[$name]) - 1);
}
}
else
{
$name = $blocks[$i];
- $index = sizeof($block[$name]) - 1;
+ $index = count($block[$name]) - 1;
}
$block = &$block[$name];
$block = &$block[$index];
@@ -422,7 +474,7 @@ class context
// Change key to zero (change first position) if false and to last position if true
if ($key === false || $key === true)
{
- $key = ($key === false) ? 0 : sizeof($block);
+ $key = ($key === false) ? 0 : count($block);
}
// Get correct position if array given
@@ -452,9 +504,9 @@ class context
if ($mode == 'insert')
{
// Make sure we are not exceeding the last iteration
- if ($key >= sizeof($block))
+ if ($key >= count($block))
{
- $key = sizeof($block);
+ $key = count($block);
unset($block[($key - 1)]['S_LAST_ROW']);
$vararray['S_LAST_ROW'] = true;
}
@@ -469,7 +521,7 @@ class context
$vararray['S_BLOCK_NAME'] = $name;
// Re-position template blocks
- for ($i = sizeof($block); $i > $key; $i--)
+ for ($i = count($block); $i > $key; $i--)
{
$block[$i] = $block[$i-1];
@@ -487,12 +539,12 @@ class context
if ($mode == 'change')
{
// If key is out of bounds, do not change anything
- if ($key > sizeof($block) || $key < 0)
+ if ($key > count($block) || $key < 0)
{
return false;
}
- if ($key == sizeof($block))
+ if ($key == count($block))
{
$key--;
}
@@ -502,6 +554,45 @@ class context
return true;
}
+ // Delete Block
+ if ($mode == 'delete')
+ {
+ // If we are exceeding last iteration, do not delete anything
+ if ($key > count($block) || $key < 0)
+ {
+ return false;
+ }
+
+ // If we are positioned at the end, we remove the last element
+ if ($key == count($block))
+ {
+ $key--;
+ }
+
+ // We are deleting the last element in the block, so remove the block
+ if (count($block) === 1)
+ {
+ $block = null; // unset($block); does not work on references
+ return true;
+ }
+
+ // Re-position template blocks
+ for ($i = $key; $i < count($block)-1; $i++)
+ {
+ $block[$i] = $block[$i+1];
+ $block[$i]['S_ROW_COUNT'] = $block[$i]['S_ROW_NUM'] = $i;
+ }
+
+ // Remove the last element
+ unset($block[$i]);
+
+ // Set first and last elements again, in case they were removed
+ $block[0]['S_FIRST_ROW'] = true;
+ $block[count($block)-1]['S_LAST_ROW'] = true;
+
+ return true;
+ }
+
return false;
}
@@ -518,13 +609,13 @@ class context
{
// Nested block.
$blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
+ $blockcount = count($blocks) - 1;
$str = &$this->tpldata;
for ($i = 0; $i < $blockcount; $i++)
{
$str = &$str[$blocks[$i]];
- $str = &$str[sizeof($str) - 1];
+ $str = &$str[count($str) - 1];
}
unset($str[$blocks[$blockcount]]);
diff --git a/phpBB/phpbb/template/exception/user_object_not_available.php b/phpBB/phpbb/template/exception/user_object_not_available.php
new file mode 100644
index 0000000000..62fd2743c1
--- /dev/null
+++ b/phpBB/phpbb/template/exception/user_object_not_available.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\template\exception;
+
+/**
+ * This exception is thrown when the user object was not set but it is required by the called method
+ */
+class user_object_not_available extends \phpbb\exception\runtime_exception
+{
+
+}
diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php
index 9e3d658ca8..df83d5bc43 100644
--- a/phpBB/phpbb/template/template.php
+++ b/phpBB/phpbb/template/template.php
@@ -128,6 +128,22 @@ interface template
public function append_var($varname, $varval);
/**
+ * Retrieve multiple template values
+ *
+ * @param array $vararray An array with variable names
+ * @return array A hash of variable name => value pairs (value is null if not set)
+ */
+ public function retrieve_vars(array $vararray);
+
+ /**
+ * Retreive a single scalar value from a single key.
+ *
+ * @param string $varname Variable name
+ * @return mixed Variable value, or null if not set
+ */
+ public function retrieve_var($varname);
+
+ /**
* Assign key variable pairs from an array to a specified block
* @param string $blockname Name of block to assign $vararray to
* @param array $vararray A hash of variable name => value pairs
@@ -144,6 +160,14 @@ interface template
public function assign_block_vars_array($blockname, array $block_vars_array);
/**
+ * Retrieve variable values from an specified block
+ * @param string $blockname Name of block to retrieve $vararray from
+ * @param array $vararray An array with variable names, empty array gets all vars
+ * @return array A hash of variable name => value pairs (value is null if not set)
+ */
+ public function retrieve_block_vars($blockname, array $vararray);
+
+ /**
* Change already assigned key variable pair (one-dimensional - single loop entry)
*
* An example of how to use this function:
@@ -160,10 +184,11 @@ interface template
* If key is false the position is set to 0
* If key is true the position is set to the last entry
*
- * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
+ * @param string $mode Mode to execute (valid modes are 'insert', 'change' and 'delete')
*
* If insert, the vararray is inserted at the given position (position counting from zero).
* If change, the current block gets merged with the vararray (resulting in new \key/value pairs be added and existing keys be replaced by the new \value).
+ * If delete, the vararray is ignored, and the block at the given position (counting from zero) is removed.
*
* Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
* and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
diff --git a/phpBB/phpbb/template/twig/environment.php b/phpBB/phpbb/template/twig/environment.php
index 476ffd935e..ac4b16e457 100644
--- a/phpBB/phpbb/template/twig/environment.php
+++ b/phpBB/phpbb/template/twig/environment.php
@@ -13,17 +13,28 @@
namespace phpbb\template\twig;
+use phpbb\template\assets_bag;
+
class environment extends \Twig_Environment
{
/** @var \phpbb\config\config */
protected $phpbb_config;
+ /** @var \phpbb\filesystem\filesystem */
+ protected $filesystem;
+
/** @var \phpbb\path_helper */
protected $phpbb_path_helper;
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
/** @var \phpbb\extension\manager */
protected $extension_manager;
+ /** @var \phpbb\event\dispatcher_interface */
+ protected $phpbb_dispatcher;
+
/** @var string */
protected $phpbb_root_path;
@@ -33,26 +44,43 @@ class environment extends \Twig_Environment
/** @var array **/
protected $namespace_look_up_order = array('__main__');
+ /** @var assets_bag */
+ protected $assets_bag;
+
/**
* Constructor
*
* @param \phpbb\config\config $phpbb_config The phpBB configuration
+ * @param \phpbb\filesystem\filesystem $filesystem
* @param \phpbb\path_helper $path_helper phpBB path helper
+ * @param string $cache_path The path to the cache directory
* @param \phpbb\extension\manager $extension_manager phpBB extension manager
* @param \Twig_LoaderInterface $loader Twig loader interface
+ * @param \phpbb\event\dispatcher_interface $phpbb_dispatcher Event dispatcher object
* @param array $options Array of options to pass to Twig
*/
- public function __construct($phpbb_config, \phpbb\path_helper $path_helper, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, $options = array())
+ public function __construct(\phpbb\config\config $phpbb_config, \phpbb\filesystem\filesystem $filesystem, \phpbb\path_helper $path_helper, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig_LoaderInterface $loader = null, \phpbb\event\dispatcher_interface $phpbb_dispatcher = null, $options = array())
{
$this->phpbb_config = $phpbb_config;
+ $this->filesystem = $filesystem;
$this->phpbb_path_helper = $path_helper;
$this->extension_manager = $extension_manager;
+ $this->phpbb_dispatcher = $phpbb_dispatcher;
$this->phpbb_root_path = $this->phpbb_path_helper->get_phpbb_root_path();
$this->web_root_path = $this->phpbb_path_helper->get_web_root_path();
- return parent::__construct($loader, $options);
+ $this->assets_bag = new assets_bag();
+
+ $options = array_merge(array(
+ 'cache' => (defined('IN_INSTALL')) ? false : $cache_path,
+ 'debug' => false,
+ 'auto_reload' => (bool) $this->phpbb_config['load_tplcompile'],
+ 'autoescape' => false,
+ ), $options);
+
+ parent::__construct($loader, $options);
}
/**
@@ -78,16 +106,26 @@ class environment extends \Twig_Environment
}
/**
- * Get the phpBB root path
- *
- * @return string
- */
+ * Get the phpBB root path
+ *
+ * @return string
+ */
public function get_phpbb_root_path()
{
return $this->phpbb_root_path;
}
/**
+ * Get the filesystem object
+ *
+ * @return \phpbb\filesystem\filesystem
+ */
+ public function get_filesystem()
+ {
+ return $this->filesystem;
+ }
+
+ /**
* Get the web root path
*
* @return string
@@ -108,6 +146,16 @@ class environment extends \Twig_Environment
}
/**
+ * Gets the assets bag
+ *
+ * @return assets_bag
+ */
+ public function get_assets_bag()
+ {
+ return $this->assets_bag;
+ }
+
+ /**
* Get the namespace look up order
*
* @return array
@@ -131,6 +179,84 @@ class environment extends \Twig_Environment
}
/**
+ * {@inheritdoc}
+ */
+ public function render($name, array $context = [])
+ {
+ return $this->display_with_assets($name, $context);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function display($name, array $context = [])
+ {
+ echo $this->display_with_assets($name, $context);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ private function display_with_assets($name, array $context = [])
+ {
+ $placeholder_salt = unique_id();
+
+ if (array_key_exists('definition', $context))
+ {
+ $context['definition']->set('SCRIPTS', '__SCRIPTS_' . $placeholder_salt . '__');
+ $context['definition']->set('STYLESHEETS', '__STYLESHEETS_' . $placeholder_salt . '__');
+ }
+
+ /**
+ * Allow changing the template output stream before rendering
+ *
+ * @event core.twig_environment_render_template_before
+ * @var array context Array with template variables
+ * @var string name The template name
+ * @since 3.2.1-RC1
+ */
+ if ($this->phpbb_dispatcher)
+ {
+ $vars = array('context', 'name');
+ extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_before', compact($vars)));
+ }
+
+ $output = parent::render($name, $context);
+
+ /**
+ * Allow changing the template output stream after rendering
+ *
+ * @event core.twig_environment_render_template_after
+ * @var array context Array with template variables
+ * @var string name The template name
+ * @var string output Rendered template output stream
+ * @since 3.2.1-RC1
+ */
+ if ($this->phpbb_dispatcher)
+ {
+ $vars = array('context', 'name', 'output');
+ extract($this->phpbb_dispatcher->trigger_event('core.twig_environment_render_template_after', compact($vars)));
+ }
+
+ return $this->inject_assets($output, $placeholder_salt);
+ }
+
+ /**
+ * Injects the assets (from INCLUDECSS/JS) in the output.
+ *
+ * @param string $output
+ *
+ * @return string
+ */
+ private function inject_assets($output, $placeholder_salt)
+ {
+ $output = str_replace('__STYLESHEETS_' . $placeholder_salt . '__', $this->assets_bag->get_stylesheets_content(), $output);
+ $output = str_replace('__SCRIPTS_' . $placeholder_salt . '__', $this->assets_bag->get_scripts_content(), $output);
+
+ return $output;
+ }
+
+ /**
* Loads a template by name.
*
* @param string $name The template name
diff --git a/phpBB/phpbb/template/twig/extension.php b/phpBB/phpbb/template/twig/extension.php
index d5b14129b5..f6f8e03ca2 100644
--- a/phpBB/phpbb/template/twig/extension.php
+++ b/phpBB/phpbb/template/twig/extension.php
@@ -18,20 +18,20 @@ class extension extends \Twig_Extension
/** @var \phpbb\template\context */
protected $context;
- /** @var \phpbb\user */
- protected $user;
+ /** @var \phpbb\language\language */
+ protected $language;
/**
* Constructor
*
* @param \phpbb\template\context $context
- * @param \phpbb\user $user
+ * @param \phpbb\language\language $language
* @return \phpbb\template\twig\extension
*/
- public function __construct(\phpbb\template\context $context, $user)
+ public function __construct(\phpbb\template\context $context, $language)
{
$this->context = $context;
- $this->user = $user;
+ $this->language = $language;
}
/**
@@ -71,6 +71,7 @@ class extension extends \Twig_Extension
{
return array(
new \Twig_SimpleFilter('subset', array($this, 'loop_subset'), array('needs_environment' => true)),
+ // @deprecated 3.2.0 Uses twig's JS escape method instead of addslashes
new \Twig_SimpleFilter('addslashes', 'addslashes'),
);
}
@@ -145,7 +146,7 @@ class extension extends \Twig_Extension
// of items to grab (length)
// Start must always be the actual starting number for this calculation (not negative)
- $start = ($start < 0) ? sizeof($item) + $start : $start;
+ $start = ($start < 0) ? count($item) + $start : $start;
$end = $end - $start;
}
@@ -171,14 +172,14 @@ class extension extends \Twig_Extension
$context_vars = $this->context->get_root_ref();
- if (isset($context_vars['L_' . $key]))
+ if (is_string($key) && isset($context_vars['L_' . $key]))
{
return $context_vars['L_' . $key];
}
- // LA_ is transformed into lang(\'$1\')|addslashes, so we should not
+ // LA_ is transformed into lang(\'$1\')|escape('js'), so we should not
// need to check for it
- return call_user_func_array(array($this->user, 'lang'), $args);
+ return call_user_func_array(array($this->language, 'lang'), $args);
}
}
diff --git a/phpBB/phpbb/template/twig/extension/routing.php b/phpBB/phpbb/template/twig/extension/routing.php
new file mode 100644
index 0000000000..829ce738eb
--- /dev/null
+++ b/phpBB/phpbb/template/twig/extension/routing.php
@@ -0,0 +1,43 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\template\twig\extension;
+
+use Symfony\Bridge\Twig\Extension\RoutingExtension;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+
+class routing extends RoutingExtension
+{
+ /** @var \phpbb\controller\helper */
+ protected $helper;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\routing\helper $helper
+ */
+ public function __construct(\phpbb\routing\helper $helper)
+ {
+ $this->helper = $helper;
+ }
+
+ public function getPath($name, $parameters = array(), $relative = false)
+ {
+ return $this->helper->route($name, $parameters, true, false, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH);
+ }
+
+ public function getUrl($name, $parameters = array(), $schemeRelative = false)
+ {
+ return $this->helper->route($name, $parameters, true, false, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL);
+ }
+}
diff --git a/phpBB/phpbb/template/twig/lexer.php b/phpBB/phpbb/template/twig/lexer.php
index c5dc7273ba..d0bcfa615e 100644
--- a/phpBB/phpbb/template/twig/lexer.php
+++ b/phpBB/phpbb/template/twig/lexer.php
@@ -15,8 +15,21 @@ namespace phpbb\template\twig;
class lexer extends \Twig_Lexer
{
+ public function set_environment(\Twig_Environment $env)
+ {
+ $this->env = $env;
+ }
+
public function tokenize($code, $filename = null)
{
+ // Handle \Twig_Source format input
+ if ($code instanceof \Twig_Source)
+ {
+ $source = $code;
+ $code = $source->getCode();
+ $filename = $source->getName();
+ }
+
// Our phpBB tags
// Commented out tokens are handled separately from the main replace
$phpbb_tags = array(
@@ -112,15 +125,16 @@ class lexer extends \Twig_Lexer
// Appends any filters after lang()
$code = preg_replace('#{L_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2 }}', $code);
- // Replace all of our escaped language variables, {LA_VARNAME}, with Twig style, {{ lang('NAME')|addslashes }}
- // Appends any filters after lang(), but before addslashes
- $code = preg_replace('#{LA_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2|addslashes }}', $code);
+ // Replace all of our escaped language variables, {LA_VARNAME}, with Twig style, {{ lang('NAME')|escape('js') }}
+ // Appends any filters after lang(), but before escape('js')
+ $code = preg_replace('#{LA_([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ lang(\'$1\')$2|escape(\'js\') }}', $code);
// Replace all of our variables, {VARNAME}, with Twig style, {{ VARNAME }}
// Appends any filters
$code = preg_replace('#{([a-zA-Z0-9_\.]+)(\|[^}]+?)?}#', '{{ $1$2 }}', $code);
- return parent::tokenize($code, $filename);
+ // Tokenize \Twig_Source instance
+ return parent::tokenize(new \Twig_Source($code, $filename));
}
/**
diff --git a/phpBB/phpbb/template/twig/loader.php b/phpBB/phpbb/template/twig/loader.php
index 139a413b70..c13e3ee298 100644
--- a/phpBB/phpbb/template/twig/loader.php
+++ b/phpBB/phpbb/template/twig/loader.php
@@ -21,6 +21,24 @@ class loader extends \Twig_Loader_Filesystem
protected $safe_directories = array();
/**
+ * @var \phpbb\filesystem\filesystem_interface
+ */
+ protected $filesystem;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\filesystem\filesystem_interface $filesystem
+ * @param string|array $paths
+ */
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem, $paths = array())
+ {
+ $this->filesystem = $filesystem;
+
+ parent::__construct($paths, $this->filesystem->realpath(dirname(__FILE__)));
+ }
+
+ /**
* Set safe directories
*
* @param array $directories Array of directories that are safe (empty to clear)
@@ -49,7 +67,7 @@ class loader extends \Twig_Loader_Filesystem
*/
public function addSafeDirectory($directory)
{
- $directory = phpbb_realpath($directory);
+ $directory = $this->filesystem->realpath($directory);
if ($directory !== false)
{
@@ -83,6 +101,16 @@ class loader extends \Twig_Loader_Filesystem
}
/**
+ * Adds a realpath call to fix a BC break in Twig 1.26 (https://github.com/twigphp/Twig/issues/2145)
+ *
+ * {@inheritdoc}
+ */
+ public function addPath($path, $namespace = self::MAIN_NAMESPACE)
+ {
+ return parent::addPath($this->filesystem->realpath($path), $namespace);
+ }
+
+ /**
* Find the template
*
* Override for Twig_Loader_Filesystem::findTemplate to add support
@@ -119,7 +147,7 @@ class loader extends \Twig_Loader_Filesystem
// can now check if we're within a "safe" directory
// Find the real path of the directory the file is in
- $directory = phpbb_realpath(dirname($file));
+ $directory = $this->filesystem->realpath(dirname($file));
if ($directory === false)
{
diff --git a/phpBB/phpbb/template/twig/node/event.php b/phpBB/phpbb/template/twig/node/event.php
index b765bde98d..11fdb75247 100644
--- a/phpBB/phpbb/template/twig/node/event.php
+++ b/phpBB/phpbb/template/twig/node/event.php
@@ -46,7 +46,7 @@ class event extends \Twig_Node
{
$ext_namespace = str_replace('/', '_', $ext_namespace);
- if (defined('DEBUG'))
+ if ($this->environment->isDebug())
{
// If debug mode is enabled, lets check for new/removed EVENT
// templates on page load rather than at compile. This is
@@ -58,7 +58,7 @@ class event extends \Twig_Node
;
}
- if (defined('DEBUG') || $this->environment->getLoader()->exists('@' . $ext_namespace . '/' . $location . '.html'))
+ if ($this->environment->isDebug() || $this->environment->getLoader()->exists('@' . $ext_namespace . '/' . $location . '.html'))
{
$compiler
->write("\$previous_look_up_order = \$this->env->getNamespaceLookUpOrder();\n")
@@ -70,7 +70,7 @@ class event extends \Twig_Node
;
}
- if (defined('DEBUG'))
+ if ($this->environment->isDebug())
{
$compiler
->outdent()
diff --git a/phpBB/phpbb/template/twig/node/includeasset.php b/phpBB/phpbb/template/twig/node/includeasset.php
index 15195a226b..12034b7820 100644
--- a/phpBB/phpbb/template/twig/node/includeasset.php
+++ b/phpBB/phpbb/template/twig/node/includeasset.php
@@ -39,7 +39,7 @@ abstract class includeasset extends \Twig_Node
->write("\$asset_file = ")
->subcompile($this->getNode('expr'))
->raw(";\n")
- ->write("\$asset = new \phpbb\\template\\asset(\$asset_file, \$this->getEnvironment()->get_path_helper());\n")
+ ->write("\$asset = new \phpbb\\template\\asset(\$asset_file, \$this->getEnvironment()->get_path_helper(), \$this->getEnvironment()->get_filesystem());\n")
->write("if (substr(\$asset_file, 0, 2) !== './' && \$asset->is_relative()) {\n")
->indent()
->write("\$asset_path = \$asset->get_path();")
@@ -49,33 +49,23 @@ abstract class includeasset extends \Twig_Node
->write("\$local_file = \$this->getEnvironment()->findTemplate(\$asset_path);\n")
->write("\$asset->set_path(\$local_file, true);\n")
->outdent()
- ->write("\$asset->add_assets_version('{$config['assets_version']}');\n")
- ->write("\$asset_file = \$asset->get_url();\n")
->write("}\n")
->outdent()
->write("}\n")
- ->write("\$context['definition']->append('{$this->get_definition_name()}', '")
- ;
-
- $this->append_asset($compiler);
-
- $compiler
- ->raw("\n');\n")
+ ->write("\n")
+ ->write("if (\$asset->is_relative()) {\n")
+ ->indent()
+ ->write("\$asset->add_assets_version('{$config['assets_version']}');\n")
+ ->outdent()
+ ->write("}\n")
+ ->write("\$this->getEnvironment()->get_assets_bag()->add_{$this->get_setters_name()}(\$asset);")
;
}
/**
- * Get the definition name
- *
- * @return string (e.g. 'SCRIPTS')
- */
- abstract public function get_definition_name();
-
- /**
- * Append the output code for the asset
+ * Get the name of the assets bag setter
*
- * @param \Twig_Compiler A Twig_Compiler instance
- * @return null
+ * @return string (e.g. 'script')
*/
- abstract protected function append_asset(\Twig_Compiler $compiler);
+ abstract public function get_setters_name();
}
diff --git a/phpBB/phpbb/template/twig/node/includecss.php b/phpBB/phpbb/template/twig/node/includecss.php
index 2dac154036..2e97d4972d 100644
--- a/phpBB/phpbb/template/twig/node/includecss.php
+++ b/phpBB/phpbb/template/twig/node/includecss.php
@@ -18,20 +18,8 @@ class includecss extends \phpbb\template\twig\node\includeasset
/**
* {@inheritdoc}
*/
- public function get_definition_name()
+ public function get_setters_name()
{
- return 'STYLESHEETS';
- }
-
- /**
- * {@inheritdoc}
- */
- public function append_asset(\Twig_Compiler $compiler)
- {
- $compiler
- ->raw("<link href=\"' . ")
- ->raw("\$asset_file . '\"")
- ->raw(' rel="stylesheet" type="text/css" media="screen" />')
- ;
+ return 'stylesheet';
}
}
diff --git a/phpBB/phpbb/template/twig/node/includejs.php b/phpBB/phpbb/template/twig/node/includejs.php
index 0f67f9ff60..505b49757b 100644
--- a/phpBB/phpbb/template/twig/node/includejs.php
+++ b/phpBB/phpbb/template/twig/node/includejs.php
@@ -18,22 +18,8 @@ class includejs extends \phpbb\template\twig\node\includeasset
/**
* {@inheritdoc}
*/
- public function get_definition_name()
+ public function get_setters_name()
{
- return 'SCRIPTS';
- }
-
- /**
- * {@inheritdoc}
- */
- protected function append_asset(\Twig_Compiler $compiler)
- {
- $config = $this->environment->get_phpbb_config();
-
- $compiler
- ->raw("<script type=\"text/javascript\" src=\"' . ")
- ->raw("\$asset_file")
- ->raw(". '\"></script>\n")
- ;
+ return 'script';
}
}
diff --git a/phpBB/phpbb/template/twig/twig.php b/phpBB/phpbb/template/twig/twig.php
index d1bbb2b55a..f322778eda 100644
--- a/phpBB/phpbb/template/twig/twig.php
+++ b/phpBB/phpbb/template/twig/twig.php
@@ -13,6 +13,8 @@
namespace phpbb\template\twig;
+use phpbb\template\exception\user_object_not_available;
+
/**
* Twig Template class.
*/
@@ -76,11 +78,14 @@ class twig extends \phpbb\template\base
*
* @param \phpbb\path_helper $path_helper
* @param \phpbb\config\config $config
- * @param \phpbb\user $user
* @param \phpbb\template\context $context template context
+ * @param \phpbb\template\twig\environment $twig_environment
+ * @param string $cache_path
+ * @param \phpbb\user|null $user
+ * @param array|\ArrayAccess $extensions
* @param \phpbb\extension\manager $extension_manager extension manager, if null then template events will not be invoked
*/
- public function __construct(\phpbb\path_helper $path_helper, $config, $user, \phpbb\template\context $context, \phpbb\extension\manager $extension_manager = null)
+ public function __construct(\phpbb\path_helper $path_helper, $config, \phpbb\template\context $context, \phpbb\template\twig\environment $twig_environment, $cache_path, \phpbb\user $user = null, $extensions = array(), \phpbb\extension\manager $extension_manager = null)
{
$this->path_helper = $path_helper;
$this->phpbb_root_path = $path_helper->get_phpbb_root_path();
@@ -89,41 +94,14 @@ class twig extends \phpbb\template\base
$this->user = $user;
$this->context = $context;
$this->extension_manager = $extension_manager;
+ $this->cachepath = $cache_path;
+ $this->twig = $twig_environment;
- $this->cachepath = $this->phpbb_root_path . 'cache/twig/';
-
- // Initiate the loader, __main__ namespace paths will be setup later in set_style_names()
- $loader = new \phpbb\template\twig\loader('');
-
- $this->twig = new \phpbb\template\twig\environment(
- $this->config,
- $this->path_helper,
- $this->extension_manager,
- $loader,
- array(
- 'cache' => (defined('IN_INSTALL')) ? false : $this->cachepath,
- 'debug' => defined('DEBUG'),
- 'auto_reload' => (bool) $this->config['load_tplcompile'],
- 'autoescape' => false,
- )
- );
-
- $this->twig->addExtension(
- new \phpbb\template\twig\extension(
- $this->context,
- $this->user
- )
- );
-
- if (defined('DEBUG'))
+ foreach ($extensions as $extension)
{
- $this->twig->addExtension(new \Twig_Extension_Debug());
+ $this->twig->addExtension($extension);
}
- $lexer = new \phpbb\template\twig\lexer($this->twig);
-
- $this->twig->setLexer($lexer);
-
// Add admin namespace
if ($this->path_helper->get_adm_relative_path() !== null && is_dir($this->phpbb_root_path . $this->path_helper->get_adm_relative_path() . 'style/'))
{
@@ -150,9 +128,16 @@ class twig extends \phpbb\template\base
* Get the style tree of the style preferred by the current user
*
* @return array Style tree, most specific first
+ *
+ * @throws \phpbb\template\exception\user_object_not_available When user service was not set
*/
public function get_user_style()
{
+ if ($this->user === null)
+ {
+ throw new user_object_not_available();
+ }
+
$style_list = array(
$this->user->style['style_path'],
);
@@ -368,14 +353,24 @@ class twig extends \phpbb\template\base
$context_vars['.'][0], // To get normal vars
array(
'definition' => new \phpbb\template\twig\definition(),
- 'user' => $this->user,
'loops' => $context_vars, // To get loops
)
);
+ if ($this->user instanceof \phpbb\user)
+ {
+ $vars['user'] = $this->user;
+ }
+
// cleanup
unset($vars['loops']['.']);
+ // Inject in the main context the value added by assign_block_vars() to be able to use directly the Twig loops.
+ foreach ($vars['loops'] as $key => &$value)
+ {
+ $vars[$key] = $value;
+ }
+
return $vars;
}
diff --git a/phpBB/phpbb/textformatter/cache_interface.php b/phpBB/phpbb/textformatter/cache_interface.php
new file mode 100644
index 0000000000..f6b5f195c7
--- /dev/null
+++ b/phpBB/phpbb/textformatter/cache_interface.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter;
+
+/**
+* Currently only used to signal that something that could effect the rendering has changed.
+* BBCodes, smilies, censored words, templates, etc...
+*/
+interface cache_interface
+{
+ /**
+ * Invalidate and/or regenerate this text formatter's cache(s)
+ */
+ public function invalidate();
+
+ /**
+ * Tidy/prune this text formatter's cache(s)
+ */
+ public function tidy();
+}
diff --git a/phpBB/phpbb/textformatter/data_access.php b/phpBB/phpbb/textformatter/data_access.php
new file mode 100644
index 0000000000..0d37e62c87
--- /dev/null
+++ b/phpBB/phpbb/textformatter/data_access.php
@@ -0,0 +1,252 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter;
+
+/**
+* Data access layer that fetchs BBCodes, smilies and censored words from the database.
+* To be extended to include insert/update/delete operations.
+*
+* Also used to get templates.
+*/
+class data_access
+{
+ /**
+ * @var string Name of the BBCodes table
+ */
+ protected $bbcodes_table;
+
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var string Name of the smilies table
+ */
+ protected $smilies_table;
+
+ /**
+ * @var string Name of the styles table
+ */
+ protected $styles_table;
+
+ /**
+ * @var string Path to the styles dir
+ */
+ protected $styles_path;
+
+ /**
+ * @var string Name of the words table
+ */
+ protected $words_table;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param string $bbcodes_table Name of the BBCodes table
+ * @param string $smilies_table Name of the smilies table
+ * @param string $styles_table Name of the styles table
+ * @param string $words_table Name of the words table
+ * @param string $styles_path Path to the styles dir
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, $bbcodes_table, $smilies_table, $styles_table, $words_table, $styles_path)
+ {
+ $this->db = $db;
+
+ $this->bbcodes_table = $bbcodes_table;
+ $this->smilies_table = $smilies_table;
+ $this->styles_table = $styles_table;
+ $this->words_table = $words_table;
+
+ $this->styles_path = $styles_path;
+ }
+
+ /**
+ * Return the list of custom BBCodes
+ *
+ * @return array
+ */
+ public function get_bbcodes()
+ {
+ $sql = 'SELECT bbcode_match, bbcode_tpl FROM ' . $this->bbcodes_table;
+
+ return $this->fetch_decoded_rowset($sql, ['bbcode_match']);
+ }
+
+ /**
+ * Return the list of smilies
+ *
+ * @return array
+ */
+ public function get_smilies()
+ {
+ // NOTE: smilies that are displayed on the posting page are processed first because they're
+ // typically the most used smilies and it ends up producing a slightly more efficient
+ // renderer
+ $sql = 'SELECT code, emotion, smiley_url, smiley_width, smiley_height
+ FROM ' . $this->smilies_table . '
+ ORDER BY display_on_posting DESC';
+
+ return $this->fetch_decoded_rowset($sql, ['code', 'emotion', 'smiley_url']);
+ }
+
+ /**
+ * Return the list of installed styles
+ *
+ * @return array
+ */
+ protected function get_styles()
+ {
+ $sql = 'SELECT style_id, style_path, style_parent_id, bbcode_bitfield FROM ' . $this->styles_table;
+
+ return $this->fetch_decoded_rowset($sql);
+ }
+
+ /**
+ * Return the bbcode.html template for every installed style
+ *
+ * @return array 2D array. style_id as keys, each element is an array with a "template" element that contains the style's bbcode.html and a "bbcodes" element that contains the name of each BBCode that is to be stylised
+ */
+ public function get_styles_templates()
+ {
+ $templates = array();
+
+ $bbcode_ids = array(
+ 'quote' => 0,
+ 'b' => 1,
+ 'i' => 2,
+ 'url' => 3,
+ 'img' => 4,
+ 'size' => 5,
+ 'color' => 6,
+ 'u' => 7,
+ 'code' => 8,
+ 'list' => 9,
+ '*' => 9,
+ 'email' => 10,
+ 'flash' => 11,
+ 'attachment' => 12,
+ );
+
+ $styles = array();
+ foreach ($this->get_styles() as $row)
+ {
+ $styles[$row['style_id']] = $row;
+ }
+
+ foreach ($styles as $style_id => $style)
+ {
+ $bbcodes = array();
+
+ // Collect the name of the BBCodes whose bit is set in the style's bbcode_bitfield
+ $template_bitfield = new \bitfield($style['bbcode_bitfield']);
+ foreach ($bbcode_ids as $bbcode_name => $bit)
+ {
+ if ($template_bitfield->get($bit))
+ {
+ $bbcodes[] = $bbcode_name;
+ }
+ }
+
+ $filename = $this->resolve_style_filename($styles, $style);
+ if ($filename === false)
+ {
+ // Ignore this style, it will use the default templates
+ continue;
+ }
+
+ $templates[$style_id] = array(
+ 'bbcodes' => $bbcodes,
+ 'template' => file_get_contents($filename),
+ );
+ }
+
+ return $templates;
+ }
+
+ /**
+ * Resolve inheritance for given style and return the path to their bbcode.html file
+ *
+ * @param array $styles Associative array of [style_id => style] containing all styles
+ * @param array $style Style for which we resolve
+ * @return string|bool Path to this style's bbcode.html, or FALSE
+ */
+ protected function resolve_style_filename(array $styles, array $style)
+ {
+ // Look for a bbcode.html in this style's dir
+ $filename = $this->styles_path . $style['style_path'] . '/template/bbcode.html';
+ if (file_exists($filename))
+ {
+ return $filename;
+ }
+
+ // Resolve using this style's parent
+ $parent_id = $style['style_parent_id'];
+ if ($parent_id && !empty($styles[$parent_id]))
+ {
+ return $this->resolve_style_filename($styles, $styles[$parent_id]);
+ }
+
+ return false;
+ }
+
+ /**
+ * Return the list of censored words
+ *
+ * @return array
+ */
+ public function get_censored_words()
+ {
+ $sql = 'SELECT word, replacement FROM ' . $this->words_table;
+
+ return $this->fetch_decoded_rowset($sql, ['word', 'replacement']);
+ }
+
+ /**
+ * Decode HTML special chars in given rowset
+ *
+ * @param array $rows Original rowset
+ * @param array $columns List of columns to decode
+ * @return array Decoded rowset
+ */
+ protected function decode_rowset(array $rows, array $columns)
+ {
+ foreach ($rows as &$row)
+ {
+ foreach ($columns as $column)
+ {
+ $row[$column] = htmlspecialchars_decode($row[$column]);
+ }
+ }
+
+ return $rows;
+ }
+
+ /**
+ * Fetch all rows for given query and decode plain text columns
+ *
+ * @param string $sql SELECT query
+ * @param array $columns List of columns to decode
+ * @return array
+ */
+ protected function fetch_decoded_rowset($sql, array $columns = [])
+ {
+ $result = $this->db->sql_query($sql);
+ $rows = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ return $this->decode_rowset($rows, $columns);
+ }
+}
diff --git a/phpBB/phpbb/textformatter/parser_interface.php b/phpBB/phpbb/textformatter/parser_interface.php
new file mode 100644
index 0000000000..ad611fb5b4
--- /dev/null
+++ b/phpBB/phpbb/textformatter/parser_interface.php
@@ -0,0 +1,112 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter;
+
+interface parser_interface
+{
+ /**
+ * Parse given text
+ *
+ * @param string $text
+ * @return string
+ */
+ public function parse($text);
+
+ /**
+ * Disable a specific BBCode
+ *
+ * @param string $name BBCode name
+ * @return null
+ */
+ public function disable_bbcode($name);
+
+ /**
+ * Disable BBCodes in general
+ */
+ public function disable_bbcodes();
+
+ /**
+ * Disable the censor
+ */
+ public function disable_censor();
+
+ /**
+ * Disable magic URLs
+ */
+ public function disable_magic_url();
+
+ /**
+ * Disable smilies
+ */
+ public function disable_smilies();
+
+ /**
+ * Enable a specific BBCode
+ *
+ * @param string $name BBCode name
+ * @return null
+ */
+ public function enable_bbcode($name);
+
+ /**
+ * Enable BBCodes in general
+ */
+ public function enable_bbcodes();
+
+ /**
+ * Enable the censor
+ */
+ public function enable_censor();
+
+ /**
+ * Enable magic URLs
+ */
+ public function enable_magic_url();
+
+ /**
+ * Enable smilies
+ */
+ public function enable_smilies();
+
+ /**
+ * Get the list of errors that were generated during last parsing
+ *
+ * @return array[] Array of arrays. Each array contains a lang string at index 0 plus any number
+ * of optional parameters
+ */
+ public function get_errors();
+
+ /**
+ * Set a variable to be used by the parser
+ *
+ * - max_font_size
+ * - max_img_height
+ * - max_img_width
+ * - max_smilies
+ * - max_urls
+ *
+ * @param string $name
+ * @param mixed $value
+ * @return null
+ */
+ public function set_var($name, $value);
+
+ /**
+ * Set multiple variables to be used by the parser
+ *
+ * @param array $vars Associative array of [name => value]
+ * @return null
+ */
+ public function set_vars(array $vars);
+}
diff --git a/phpBB/phpbb/textformatter/renderer_interface.php b/phpBB/phpbb/textformatter/renderer_interface.php
new file mode 100644
index 0000000000..609b0bb642
--- /dev/null
+++ b/phpBB/phpbb/textformatter/renderer_interface.php
@@ -0,0 +1,92 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter;
+
+interface renderer_interface
+{
+ /**
+ * Render given text
+ *
+ * @param string $text Text, as parsed by something that implements \phpbb\textformatter\parser
+ * @return string
+ */
+ public function render($text);
+
+ /**
+ * Set the smilies' path
+ *
+ * @return null
+ */
+ public function set_smilies_path($path);
+
+ /**
+ * Return the value of the "viewcensors" option
+ *
+ * @return bool Option's value
+ */
+ public function get_viewcensors();
+
+ /**
+ * Return the value of the "viewflash" option
+ *
+ * @return bool Option's value
+ */
+ public function get_viewflash();
+
+ /**
+ * Return the value of the "viewimg" option
+ *
+ * @return bool Option's value
+ */
+ public function get_viewimg();
+
+ /**
+ * Return the value of the "viewsmilies" option
+ *
+ * @return bool Option's value
+ */
+ public function get_viewsmilies();
+
+ /**
+ * Set the "viewcensors" option
+ *
+ * @param bool $value Option's value
+ * @return null
+ */
+ public function set_viewcensors($value);
+
+ /**
+ * Set the "viewflash" option
+ *
+ * @param bool $value Option's value
+ * @return null
+ */
+ public function set_viewflash($value);
+
+ /**
+ * Set the "viewimg" option
+ *
+ * @param bool $value Option's value
+ * @return null
+ */
+ public function set_viewimg($value);
+
+ /**
+ * Set the "viewsmilies" option
+ *
+ * @param bool $value Option's value
+ * @return null
+ */
+ public function set_viewsmilies($value);
+}
diff --git a/phpBB/phpbb/textformatter/s9e/bbcode_merger.php b/phpBB/phpbb/textformatter/s9e/bbcode_merger.php
new file mode 100644
index 0000000000..264eb93782
--- /dev/null
+++ b/phpBB/phpbb/textformatter/s9e/bbcode_merger.php
@@ -0,0 +1,199 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter\s9e;
+
+use phpbb\textformatter\s9e\factory;
+use s9e\TextFormatter\Configurator\Helpers\TemplateHelper;
+use s9e\TextFormatter\Configurator\Items\UnsafeTemplate;
+
+class bbcode_merger
+{
+ /**
+ * @var \s9e\TextFormatter\Configurator $configurator Configurator instance used to inspect BBCodes
+ */
+ protected $configurator;
+
+ /**
+ * @param \phpbb\textformatter\s9e\factory $factory
+ */
+ public function __construct(factory $factory)
+ {
+ $this->configurator = $factory->get_configurator();
+ }
+
+ /**
+ * Merge two BBCode definitions
+ *
+ * All of the arrays contain a "usage" element and a "template" element
+ *
+ * @throws InvalidArgumentException if a definition cannot be interpreted
+ * @throws RuntimeException if something unexpected occurs
+ *
+ * @param array $without BBCode definition without an attribute
+ * @param array $with BBCode definition with an attribute
+ * @return array Merged definition
+ */
+ public function merge_bbcodes(array $without, array $with)
+ {
+ $without = $this->create_bbcode($without);
+ $with = $this->create_bbcode($with);
+
+ // Select the appropriate strategy for merging this BBCode
+ if (!$this->is_optional_bbcode($without, $with) && $this->is_content_bbcode($without, $with))
+ {
+ $merged = $this->merge_content_bbcode($without, $with);
+ }
+ else
+ {
+ $merged = $this->merge_optional_bbcode($without, $with);
+ }
+
+ $merged['template'] = $this->normalize_template($merged['template']);
+
+ return $merged;
+ }
+
+ /**
+ * Create a custom BBCode for inspection
+ *
+ * @param array $definition Original BBCode definition
+ * @return array Updated definition containing a BBCode object and a Tag
+ */
+ protected function create_bbcode(array $definition)
+ {
+ $bbcode = $this->configurator->BBCodes->addCustom(
+ $definition['usage'],
+ new UnsafeTemplate($definition['template'])
+ );
+
+ $definition['bbcode'] = $bbcode;
+ $definition['tag'] = $this->configurator->tags[$bbcode->tagName];
+
+ return $definition;
+ }
+
+ /**
+ * Indent given template for readability
+ *
+ * @param string $template
+ * @return string
+ */
+ protected function indent_template($template)
+ {
+ $dom = TemplateHelper::loadTemplate($template);
+ $dom->formatOutput = true;
+ $template = TemplateHelper::saveTemplate($dom);
+
+ // Remove the first level of indentation if the template starts with whitespace
+ if (preg_match('(^\\n +)', $template, $m))
+ {
+ $template = str_replace($m[0], "\n", $template);
+ }
+
+ return trim($template);
+ }
+
+ /**
+ * Test whether the two definitions form a "content"-style BBCode
+ *
+ * Such BBCodes include the [url] BBCode, which uses its text content as
+ * attribute if none is provided
+ *
+ * @param array $without BBCode definition without an attribute
+ * @param array $with BBCode definition with an attribute
+ * @return bool
+ */
+ protected function is_content_bbcode(array $without, array $with)
+ {
+ // Test whether we find the same non-TEXT token between "]" and "[" in the usage
+ // as between ">" and "<" in the template
+ return (preg_match('(\\]\\s*(\\{(?!TEXT)[^}]+\\})\\s*\\[)', $without['usage'], $m)
+ && preg_match('(>[^<]*?' . preg_quote($m[1]) . '[^>]*?<)s', $without['template']));
+ }
+
+ /**
+ * Test whether the two definitions form BBCode with an optional attribute
+ *
+ * @param array $without BBCode definition without an attribute
+ * @param array $with BBCode definition with an attribute
+ * @return bool
+ */
+ protected function is_optional_bbcode(array $without, array $with)
+ {
+ // Remove the default attribute from the definition
+ $with['usage'] = preg_replace('(=[^\\]]++)', '', $with['usage']);
+
+ // Test whether both definitions are the same, regardless of case
+ return strcasecmp($without['usage'], $with['usage']) === 0;
+ }
+
+ /**
+ * Merge the two BBCode definitions of a "content"-style BBCode
+ *
+ * @param array $without BBCode definition without an attribute
+ * @param array $with BBCode definition with an attribute
+ * @return array Merged definition
+ */
+ protected function merge_content_bbcode(array $without, array $with)
+ {
+ // Convert [x={X}] into [x={X;useContent}]
+ $usage = preg_replace('(\\})', ';useContent}', $with['usage'], 1);
+
+ // Use the template from the definition that uses an attribute
+ $template = $with['tag']->template;
+
+ return ['usage' => $usage, 'template' => $template];
+ }
+
+ /**
+ * Merge the two BBCode definitions of a BBCode with an optional argument
+ *
+ * Such BBCodes include the [quote] BBCode, which takes an optional argument
+ * but otherwise does not behave differently
+ *
+ * @param array $without BBCode definition without an attribute
+ * @param array $with BBCode definition with an attribute
+ * @return array Merged definition
+ */
+ protected function merge_optional_bbcode(array $without, array $with)
+ {
+ // Convert [X={X}] into [X={X?}]
+ $usage = preg_replace('(\\})', '?}', $with['usage'], 1);
+
+ // Build a template for both versions
+ $template = '<xsl:choose><xsl:when test="@' . $with['bbcode']->defaultAttribute . '">' . $with['tag']->template . '</xsl:when><xsl:otherwise>' . $without['tag']->template . '</xsl:otherwise></xsl:choose>';
+
+ return ['usage' => $usage, 'template' => $template];
+ }
+
+ /**
+ * Normalize a template
+ *
+ * @param string $template
+ * @return string
+ */
+ protected function normalize_template($template)
+ {
+ // Normalize the template to simplify it
+ $template = $this->configurator->templateNormalizer->normalizeTemplate($template);
+
+ // Convert xsl:value-of elements back to {L_} tokens where applicable
+ $template = preg_replace('(<xsl:value-of select="\\$(L_\\w+)"/>)', '{$1}', $template);
+
+ // Beautify the template
+ $template = $this->indent_template($template);
+
+ return $template;
+ }
+}
diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php
new file mode 100644
index 0000000000..f82c7b0771
--- /dev/null
+++ b/phpBB/phpbb/textformatter/s9e/factory.php
@@ -0,0 +1,678 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter\s9e;
+
+use s9e\TextFormatter\Configurator;
+use s9e\TextFormatter\Configurator\Items\AttributeFilters\RegexpFilter;
+use s9e\TextFormatter\Configurator\Items\UnsafeTemplate;
+
+/**
+* Creates s9e\TextFormatter objects
+*/
+class factory implements \phpbb\textformatter\cache_interface
+{
+ /**
+ * @var \phpbb\textformatter\s9e\link_helper
+ */
+ protected $link_helper;
+
+ /**
+ * @var \phpbb\cache\driver\driver_interface
+ */
+ protected $cache;
+
+ /**
+ * @var string Path to the cache dir
+ */
+ protected $cache_dir;
+
+ /**
+ * @var string Cache key used for the parser
+ */
+ protected $cache_key_parser;
+
+ /**
+ * @var string Cache key used for the renderer
+ */
+ protected $cache_key_renderer;
+
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var array Custom tokens used in bbcode.html and their corresponding token from the definition
+ */
+ protected $custom_tokens = array(
+ 'email' => array('{DESCRIPTION}' => '{TEXT}'),
+ 'flash' => array('{WIDTH}' => '{NUMBER1}', '{HEIGHT}' => '{NUMBER2}'),
+ 'img' => array('{URL}' => '{IMAGEURL}'),
+ 'list' => array('{LIST_TYPE}' => '{HASHMAP}'),
+ 'quote' => array('{USERNAME}' => '{TEXT1}'),
+ 'size' => array('{SIZE}' => '{FONTSIZE}'),
+ 'url' => array('{DESCRIPTION}' => '{TEXT}'),
+ );
+
+ /**
+ * @var \phpbb\textformatter\data_access
+ */
+ protected $data_access;
+
+ /**
+ * @var array Default BBCode definitions
+ */
+ protected $default_definitions = array(
+ 'attachment' => '[ATTACHMENT index={NUMBER} filename={TEXT;useContent}]',
+ 'b' => '[B]{TEXT}[/B]',
+ 'code' => '[CODE lang={IDENTIFIER;optional}]{TEXT}[/CODE]',
+ 'color' => '[COLOR={COLOR}]{TEXT}[/COLOR]',
+ 'email' => '[EMAIL={EMAIL;useContent} subject={TEXT1;optional;postFilter=rawurlencode} body={TEXT2;optional;postFilter=rawurlencode}]{TEXT}[/EMAIL]',
+ 'flash' => '[FLASH={NUMBER1},{NUMBER2} width={NUMBER1;postFilter=#flashwidth} height={NUMBER2;postFilter=#flashheight} url={URL;useContent} /]',
+ 'i' => '[I]{TEXT}[/I]',
+ 'img' => '[IMG src={IMAGEURL;useContent}]',
+ 'list' => '[LIST type={HASHMAP=1:decimal,a:lower-alpha,A:upper-alpha,i:lower-roman,I:upper-roman;optional;postFilter=#simpletext} #createChild=LI]{TEXT}[/LIST]',
+ 'li' => '[* $tagName=LI]{TEXT}[/*]',
+ 'quote' =>
+ "[QUOTE
+ author={TEXT1;optional}
+ post_id={UINT;optional}
+ post_url={URL;optional;postFilter=#false}
+ msg_id={UINT;optional}
+ msg_url={URL;optional;postFilter=#false}
+ profile_url={URL;optional;postFilter=#false}
+ time={UINT;optional}
+ url={URL;optional}
+ user_id={UINT;optional}
+ author={PARSE=/^\\[url=(?'url'.*?)](?'author'.*)\\[\\/url]$/i}
+ author={PARSE=/^\\[url](?'author'(?'url'.*?))\\[\\/url]$/i}
+ author={PARSE=/(?'url'https?:\\/\\/[^[\\]]+)/i}
+ ]{TEXT2}[/QUOTE]",
+ 'size' => '[SIZE={FONTSIZE}]{TEXT}[/SIZE]',
+ 'u' => '[U]{TEXT}[/U]',
+ 'url' => '[URL={URL;useContent} $forceLookahead=true]{TEXT}[/URL]',
+ );
+
+ /**
+ * @var array Default templates, taken from bbcode::bbcode_tpl()
+ */
+ protected $default_templates = array(
+ 'b' => '<span style="font-weight: bold"><xsl:apply-templates/></span>',
+ 'i' => '<span style="font-style: italic"><xsl:apply-templates/></span>',
+ 'u' => '<span style="text-decoration: underline"><xsl:apply-templates/></span>',
+ 'img' => '<img src="{IMAGEURL}" class="postimage" alt="{L_IMAGE}"/>',
+ 'size' => '<span><xsl:attribute name="style"><xsl:text>font-size: </xsl:text><xsl:value-of select="substring(@size, 1, 4)"/><xsl:text>%; line-height: normal</xsl:text></xsl:attribute><xsl:apply-templates/></span>',
+ 'color' => '<span style="color: {COLOR}"><xsl:apply-templates/></span>',
+ 'email' => '<a>
+ <xsl:attribute name="href">
+ <xsl:text>mailto:</xsl:text>
+ <xsl:value-of select="@email"/>
+ <xsl:if test="@subject or @body">
+ <xsl:text>?</xsl:text>
+ <xsl:if test="@subject">subject=<xsl:value-of select="@subject"/></xsl:if>
+ <xsl:if test="@body"><xsl:if test="@subject">&amp;</xsl:if>body=<xsl:value-of select="@body"/></xsl:if>
+ </xsl:if>
+ </xsl:attribute>
+ <xsl:apply-templates/>
+ </a>',
+ );
+
+ /**
+ * @var \phpbb\event\dispatcher_interface
+ */
+ protected $dispatcher;
+
+ /**
+ * @var \phpbb\log\log_interface
+ */
+ protected $log;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\textformatter\data_access $data_access
+ * @param \phpbb\cache\driver\driver_interface $cache
+ * @param \phpbb\event\dispatcher_interface $dispatcher
+ * @param \phpbb\config\config $config
+ * @param \phpbb\textformatter\s9e\link_helper $link_helper
+ * @param \phpbb\log\log_interface $log
+ * @param string $cache_dir Path to the cache dir
+ * @param string $cache_key_parser Cache key used for the parser
+ * @param string $cache_key_renderer Cache key used for the renderer
+ */
+ public function __construct(\phpbb\textformatter\data_access $data_access, \phpbb\cache\driver\driver_interface $cache, \phpbb\event\dispatcher_interface $dispatcher, \phpbb\config\config $config, \phpbb\textformatter\s9e\link_helper $link_helper, \phpbb\log\log_interface $log, $cache_dir, $cache_key_parser, $cache_key_renderer)
+ {
+ $this->link_helper = $link_helper;
+ $this->cache = $cache;
+ $this->cache_dir = $cache_dir;
+ $this->cache_key_parser = $cache_key_parser;
+ $this->cache_key_renderer = $cache_key_renderer;
+ $this->config = $config;
+ $this->data_access = $data_access;
+ $this->dispatcher = $dispatcher;
+ $this->log = $log;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function invalidate()
+ {
+ $this->regenerate();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Will remove old renderers from the cache dir but won't touch the current renderer
+ */
+ public function tidy()
+ {
+ // Get the name of current renderer
+ $renderer_data = $this->cache->get($this->cache_key_renderer);
+ $renderer_file = ($renderer_data) ? $renderer_data['class'] . '.php' : null;
+
+ foreach (glob($this->cache_dir . 's9e_*') as $filename)
+ {
+ // Only remove the file if it's not the current renderer
+ if (!$renderer_file || substr($filename, -strlen($renderer_file)) !== $renderer_file)
+ {
+ unlink($filename);
+ }
+ }
+ }
+
+ /**
+ * Generate and return a new configured instance of s9e\TextFormatter\Configurator
+ *
+ * @return Configurator
+ */
+ public function get_configurator()
+ {
+ // Create a new Configurator
+ $configurator = new Configurator;
+
+ /**
+ * Modify the s9e\TextFormatter configurator before the default settings are set
+ *
+ * @event core.text_formatter_s9e_configure_before
+ * @var \s9e\TextFormatter\Configurator configurator Configurator instance
+ * @since 3.2.0-a1
+ */
+ $vars = array('configurator');
+ extract($this->dispatcher->trigger_event('core.text_formatter_s9e_configure_before', compact($vars)));
+
+ // Reset the list of allowed schemes
+ foreach ($configurator->urlConfig->getAllowedSchemes() as $scheme)
+ {
+ $configurator->urlConfig->disallowScheme($scheme);
+ }
+ foreach (explode(',', $this->config['allowed_schemes_links']) as $scheme)
+ {
+ $configurator->urlConfig->allowScheme(trim($scheme));
+ }
+
+ // Convert newlines to br elements by default
+ $configurator->rootRules->enableAutoLineBreaks();
+
+ // Don't automatically ignore text in places where text is not allowed
+ $configurator->rulesGenerator->remove('IgnoreTextIfDisallowed');
+
+ // Don't remove comments and instead convert them to xsl:comment elements
+ $configurator->templateNormalizer->remove('RemoveComments');
+ $configurator->templateNormalizer->add('TransposeComments');
+
+ // Set the rendering engine and configure it to save to the cache dir
+ $configurator->rendering->engine = 'PHP';
+ $configurator->rendering->engine->cacheDir = $this->cache_dir;
+ $configurator->rendering->engine->defaultClassPrefix = 's9e_renderer_';
+ $configurator->rendering->engine->enableQuickRenderer = true;
+
+ // Create custom filters for BBCode tokens that are supported in phpBB but not in
+ // s9e\TextFormatter
+ $filter = new RegexpFilter('#^' . get_preg_expression('relative_url') . '$#Du');
+ $configurator->attributeFilters->add('#local_url', $filter);
+ $configurator->attributeFilters->add('#relative_url', $filter);
+
+ // INTTEXT regexp from acp_bbcodes
+ $filter = new RegexpFilter('!^([\p{L}\p{N}\-+,_. ]+)$!Du');
+ $configurator->attributeFilters->add('#inttext', $filter);
+
+ // Create custom filters for Flash restrictions, which use the same values as the image
+ // restrictions but have their own error message
+ $configurator->attributeFilters
+ ->add('#flashheight', __NAMESPACE__ . '\\parser::filter_flash_height')
+ ->addParameterByName('max_img_height')
+ ->addParameterByName('logger');
+
+ $configurator->attributeFilters
+ ->add('#flashwidth', __NAMESPACE__ . '\\parser::filter_flash_width')
+ ->addParameterByName('max_img_width')
+ ->addParameterByName('logger');
+
+ // Create a custom filter for phpBB's per-mode font size limits
+ $configurator->attributeFilters
+ ->add('#fontsize', __NAMESPACE__ . '\\parser::filter_font_size')
+ ->addParameterByName('max_font_size')
+ ->addParameterByName('logger')
+ ->markAsSafeInCSS();
+
+ // Create a custom filter for image URLs
+ $configurator->attributeFilters
+ ->add('#imageurl', __NAMESPACE__ . '\\parser::filter_img_url')
+ ->addParameterByName('urlConfig')
+ ->addParameterByName('logger')
+ ->addParameterByName('max_img_height')
+ ->addParameterByName('max_img_width')
+ ->markAsSafeAsURL()
+ ->setJS('UrlFilter.filter');
+
+ // Add default BBCodes
+ foreach ($this->get_default_bbcodes($configurator) as $bbcode)
+ {
+ $this->add_bbcode($configurator, $bbcode['usage'], $bbcode['template']);
+ }
+ if (isset($configurator->tags['QUOTE']))
+ {
+ // Remove the nesting limit and let other services remove quotes at parsing time
+ $configurator->tags['QUOTE']->nestingLimit = PHP_INT_MAX;
+ }
+
+ // Modify the template to disable images/flash depending on user's settings
+ foreach (array('FLASH', 'IMG') as $name)
+ {
+ $tag = $configurator->tags[$name];
+ $tag->template = '<xsl:choose><xsl:when test="$S_VIEW' . $name . '">' . $tag->template . '</xsl:when><xsl:otherwise><xsl:apply-templates/></xsl:otherwise></xsl:choose>';
+ }
+
+ // Load custom BBCodes
+ foreach ($this->data_access->get_bbcodes() as $row)
+ {
+ // Insert the board's URL before {LOCAL_URL} tokens
+ $tpl = preg_replace_callback(
+ '#\\{LOCAL_URL\\d*\\}#',
+ function ($m)
+ {
+ return generate_board_url() . '/' . $m[0];
+ },
+ $row['bbcode_tpl']
+ );
+ $this->add_bbcode($configurator, $row['bbcode_match'], $tpl);
+ }
+
+ // Load smilies
+ foreach ($this->data_access->get_smilies() as $row)
+ {
+ $configurator->Emoticons->set(
+ $row['code'],
+ '<img class="smilies" src="{$T_SMILIES_PATH}/' . $this->escape_html_attribute($row['smiley_url']) . '" width="' . $row['smiley_width'] . '" height="' . $row['smiley_height'] . '" alt="{.}" title="' . $this->escape_html_attribute($row['emotion']) . '"/>'
+ );
+ }
+
+ if (isset($configurator->Emoticons))
+ {
+ // Force emoticons to be rendered as text if $S_VIEWSMILIES is not set
+ $configurator->Emoticons->notIfCondition = 'not($S_VIEWSMILIES)';
+
+ // Only parse emoticons at the beginning of the text or if they're preceded by any
+ // one of: a new line, a space, a dot, or a right square bracket
+ $configurator->Emoticons->notAfter = '[^\\n .\\]]';
+
+ // Ignore emoticons that are immediately followed by a "word" character
+ $configurator->Emoticons->notBefore = '\\w';
+ }
+
+ // Load the censored words
+ $censor = $this->data_access->get_censored_words();
+ if (!empty($censor))
+ {
+ // Use a namespaced tag to avoid collisions
+ $configurator->plugins->load('Censor', array('tagName' => 'censor:tag'));
+ foreach ($censor as $row)
+ {
+ $configurator->Censor->add($row['word'], $row['replacement']);
+ }
+ }
+
+ // Load the magic links plugins. We do that after BBCodes so that they use the same tags
+ $this->configure_autolink($configurator);
+
+ // Register some vars with a default value. Those should be set at runtime by whatever calls
+ // the parser
+ $configurator->registeredVars['max_font_size'] = 0;
+ $configurator->registeredVars['max_img_height'] = 0;
+ $configurator->registeredVars['max_img_width'] = 0;
+
+ // Load the Emoji plugin and modify its tag's template to obey viewsmilies
+ $tag = $configurator->Emoji->getTag();
+ $tag->template = '<xsl:choose>
+ <xsl:when test="@tseq">
+ <img alt="{.}" class="emoji" draggable="false" src="//twemoji.maxcdn.com/2/svg/{@tseq}.svg"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <img alt="{.}" class="emoji" draggable="false" src="https://cdn.jsdelivr.net/gh/s9e/emoji-assets-twemoji@11.2/dist/svgz/{@seq}.svgz"/>
+ </xsl:otherwise>
+ </xsl:choose>';
+ $tag->template = '<xsl:choose><xsl:when test="$S_VIEWSMILIES">' . str_replace('class="emoji"', 'class="emoji smilies"', $tag->template) . '</xsl:when><xsl:otherwise><xsl:value-of select="."/></xsl:otherwise></xsl:choose>';
+
+ /**
+ * Modify the s9e\TextFormatter configurator after the default settings are set
+ *
+ * @event core.text_formatter_s9e_configure_after
+ * @var \s9e\TextFormatter\Configurator configurator Configurator instance
+ * @since 3.2.0-a1
+ */
+ $vars = array('configurator');
+ extract($this->dispatcher->trigger_event('core.text_formatter_s9e_configure_after', compact($vars)));
+
+ return $configurator;
+ }
+
+ /**
+ * Regenerate and cache a new parser and renderer
+ *
+ * @return array Associative array with at least two elements: "parser" and "renderer"
+ */
+ public function regenerate()
+ {
+ $configurator = $this->get_configurator();
+
+ // Get the censor helper and remove the Censor plugin if applicable
+ if (isset($configurator->Censor))
+ {
+ $censor = $configurator->Censor->getHelper();
+ unset($configurator->Censor);
+ unset($configurator->tags['censor:tag']);
+ }
+
+ $objects = $configurator->finalize();
+
+ /**
+ * Access the objects returned by finalize() before they are saved to cache
+ *
+ * @event core.text_formatter_s9e_configure_finalize
+ * @var array objects Array containing a "parser" object, a "renderer" object and optionally a "js" string
+ * @since 3.2.2-RC1
+ */
+ $vars = array('objects');
+ extract($this->dispatcher->trigger_event('core.text_formatter_s9e_configure_finalize', compact($vars)));
+
+ $parser = $objects['parser'];
+ $renderer = $objects['renderer'];
+
+ // Cache the parser as-is
+ $this->cache->put($this->cache_key_parser, $parser);
+
+ // We need to cache the name of the renderer's generated class
+ $renderer_data = array('class' => get_class($renderer));
+ if (isset($censor))
+ {
+ $renderer_data['censor'] = $censor;
+ }
+ $this->cache->put($this->cache_key_renderer, $renderer_data);
+
+ return array('parser' => $parser, 'renderer' => $renderer);
+ }
+
+ /**
+ * Add a BBCode to given configurator
+ *
+ * @param Configurator $configurator
+ * @param string $usage
+ * @param string $template
+ * @return void
+ */
+ protected function add_bbcode(Configurator $configurator, $usage, $template)
+ {
+ try
+ {
+ $configurator->BBCodes->addCustom($usage, new UnsafeTemplate($template));
+ }
+ catch (\Exception $e)
+ {
+ $this->log->add('critical', null, null, 'LOG_BBCODE_CONFIGURATION_ERROR', false, [$usage, $e->getMessage()]);
+ }
+ }
+
+ /**
+ * Configure the Autolink / Autoemail plugins used to linkify text
+ *
+ * @param \s9e\TextFormatter\Configurator $configurator
+ * @return void
+ */
+ protected function configure_autolink(Configurator $configurator)
+ {
+ $configurator->plugins->load('Autoemail');
+ $configurator->plugins->load('Autolink', array('matchWww' => true));
+
+ // Add a tag filter that creates a tag that stores and replace the
+ // content of a link created by the Autolink plugin
+ $configurator->Autolink->getTag()->filterChain
+ ->add(array($this->link_helper, 'generate_link_text_tag'))
+ ->resetParameters()
+ ->addParameterByName('tag')
+ ->addParameterByName('parser');
+
+ // Create a tag that will be used to display the truncated text by
+ // replacing the original content with the content of the @text attribute
+ $tag = $configurator->tags->add('LINK_TEXT');
+ $tag->attributes->add('text');
+ $tag->template = '<xsl:value-of select="@text"/>';
+
+ $tag->filterChain
+ ->add(array($this->link_helper, 'truncate_local_url'))
+ ->resetParameters()
+ ->addParameterByName('tag')
+ ->addParameterByValue(generate_board_url() . '/');
+ $tag->filterChain
+ ->add(array($this->link_helper, 'truncate_text'))
+ ->resetParameters()
+ ->addParameterByName('tag');
+ $tag->filterChain
+ ->add(array($this->link_helper, 'cleanup_tag'))
+ ->resetParameters()
+ ->addParameterByName('tag')
+ ->addParameterByName('parser');
+ }
+
+ /**
+ * Escape a literal to be used in an HTML attribute in an XSL template
+ *
+ * Escapes "HTML special chars" for obvious reasons and curly braces to avoid them
+ * being interpreted as an attribute value template
+ *
+ * @param string $value Original string
+ * @return string Escaped string
+ */
+ protected function escape_html_attribute($value)
+ {
+ return htmlspecialchars(strtr($value, ['{' => '{{', '}' => '}}']), ENT_COMPAT | ENT_XML1, 'UTF-8');
+ }
+
+ /**
+ * Return the default BBCodes configuration
+ *
+ * @return array 2D array. Each element has a 'usage' key, a 'template' key, and an optional 'options' key
+ */
+ protected function get_default_bbcodes($configurator)
+ {
+ // For each BBCode, build an associative array matching style_ids to their template
+ $templates = array();
+ foreach ($this->data_access->get_styles_templates() as $style_id => $data)
+ {
+ foreach ($this->extract_templates($data['template']) as $bbcode_name => $template)
+ {
+ $templates[$bbcode_name][$style_id] = $template;
+ }
+
+ // Add default templates wherever missing, or for BBCodes that were not specified in
+ // this template's bitfield. For instance, prosilver has a custom template for b but its
+ // bitfield does not enable it so the default template is used instead
+ foreach ($this->default_templates as $bbcode_name => $template)
+ {
+ if (!isset($templates[$bbcode_name][$style_id]) || !in_array($bbcode_name, $data['bbcodes'], true))
+ {
+ $templates[$bbcode_name][$style_id] = $template;
+ }
+ }
+ }
+
+ // Replace custom tokens and normalize templates
+ foreach ($templates as $bbcode_name => $style_templates)
+ {
+ foreach ($style_templates as $i => $template)
+ {
+ if (isset($this->custom_tokens[$bbcode_name]))
+ {
+ $template = strtr($template, $this->custom_tokens[$bbcode_name]);
+ }
+
+ $templates[$bbcode_name][$i] = $configurator->templateNormalizer->normalizeTemplate($template);
+ }
+ }
+
+ $bbcodes = array();
+ foreach ($this->default_definitions as $bbcode_name => $usage)
+ {
+ $bbcodes[$bbcode_name] = array(
+ 'usage' => $usage,
+ 'template' => $this->merge_templates($templates[$bbcode_name]),
+ );
+ }
+
+ return $bbcodes;
+ }
+
+ /**
+ * Extract and recompose individual BBCode templates from a style's template file
+ *
+ * @param string $template Style template (bbcode.html)
+ * @return array Associative array matching BBCode names to their template
+ */
+ protected function extract_templates($template)
+ {
+ // Capture the template fragments
+ // Allow either phpBB template or the Twig syntax
+ preg_match_all('#<!-- BEGIN (.*?) -->(.*?)<!-- END .*? -->#s', $template, $matches, PREG_SET_ORDER) ?:
+ preg_match_all('#{% for (.*?) in .*? %}(.*?){% endfor %}#s', $template, $matches, PREG_SET_ORDER);
+
+ $fragments = array();
+ foreach ($matches as $match)
+ {
+ // Normalize the whitespace
+ $fragment = preg_replace('#>\\n\\t*<#', '><', trim($match[2]));
+
+ $fragments[$match[1]] = $fragment;
+ }
+
+ // Automatically recompose templates split between *_open and *_close
+ foreach ($fragments as $fragment_name => $fragment)
+ {
+ if (preg_match('#^(\\w+)_close$#', $fragment_name, $match))
+ {
+ $bbcode_name = $match[1];
+
+ if (isset($fragments[$bbcode_name . '_open']))
+ {
+ $templates[$bbcode_name] = $fragments[$bbcode_name . '_open'] . '<xsl:apply-templates/>' . $fragment;
+ }
+ }
+ }
+
+ // Manually recompose and overwrite irregular templates
+ $templates['list'] =
+ '<xsl:choose>
+ <xsl:when test="not(@type)">
+ ' . $fragments['ulist_open_default'] . '<xsl:apply-templates/>' . $fragments['ulist_close'] . '
+ </xsl:when>
+ <xsl:when test="contains(\'upperlowerdecim\',substring(@type,1,5))">
+ ' . $fragments['olist_open'] . '<xsl:apply-templates/>' . $fragments['olist_close'] . '
+ </xsl:when>
+ <xsl:otherwise>
+ ' . $fragments['ulist_open'] . '<xsl:apply-templates/>' . $fragments['ulist_close'] . '
+ </xsl:otherwise>
+ </xsl:choose>';
+
+ $templates['li'] = $fragments['listitem'] . '<xsl:apply-templates/>' . $fragments['listitem_close'];
+
+ // Replace the regular quote template with the extended quote template if available
+ if (isset($fragments['quote_extended']))
+ {
+ $templates['quote'] = $fragments['quote_extended'];
+ }
+
+ // The [attachment] BBCode uses the inline_attachment template to output a comment that
+ // is post-processed by parse_attachments()
+ $templates['attachment'] = $fragments['inline_attachment_open'] . '<xsl:comment> ia<xsl:value-of select="@index"/> </xsl:comment><xsl:value-of select="@filename"/><xsl:comment> ia<xsl:value-of select="@index"/> </xsl:comment>' . $fragments['inline_attachment_close'];
+
+ // Add fragments as templates
+ foreach ($fragments as $fragment_name => $fragment)
+ {
+ if (preg_match('#^\\w+$#', $fragment_name))
+ {
+ $templates[$fragment_name] = $fragment;
+ }
+ }
+
+ // Keep only templates that are named after an existing BBCode
+ $templates = array_intersect_key($templates, $this->default_definitions);
+
+ return $templates;
+ }
+
+ /**
+ * Merge the templates from any number of styles into one BBCode template
+ *
+ * When multiple templates are available for the same BBCode (because of multiple styles) we
+ * merge them into a single template that uses an xsl:choose construct that determines which
+ * style to use at rendering time.
+ *
+ * @param array $style_templates Associative array matching style_ids to their template
+ * @return string
+ */
+ protected function merge_templates(array $style_templates)
+ {
+ // Return the template as-is if there's only one style or all styles share the same template
+ if (count(array_unique($style_templates)) === 1)
+ {
+ return end($style_templates);
+ }
+
+ // Group identical templates together
+ $grouped_templates = array();
+ foreach ($style_templates as $style_id => $style_template)
+ {
+ $grouped_templates[$style_template][] = '$STYLE_ID=' . $style_id;
+ }
+
+ // Sort templates by frequency descending
+ $templates_cnt = array_map('sizeof', $grouped_templates);
+ array_multisort($grouped_templates, $templates_cnt);
+
+ // Remove the most frequent template from the list; It becomes the default
+ reset($grouped_templates);
+ $default_template = key($grouped_templates);
+ unset($grouped_templates[$default_template]);
+
+ // Build an xsl:choose switch
+ $template = '<xsl:choose>';
+ foreach ($grouped_templates as $style_template => $exprs)
+ {
+ $template .= '<xsl:when test="' . implode(' or ', $exprs) . '">' . $style_template . '</xsl:when>';
+ }
+ $template .= '<xsl:otherwise>' . $default_template . '</xsl:otherwise></xsl:choose>';
+
+ return $template;
+ }
+}
diff --git a/phpBB/phpbb/textformatter/s9e/link_helper.php b/phpBB/phpbb/textformatter/s9e/link_helper.php
new file mode 100644
index 0000000000..1cd5dd2fa7
--- /dev/null
+++ b/phpBB/phpbb/textformatter/s9e/link_helper.php
@@ -0,0 +1,115 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter\s9e;
+
+class link_helper
+{
+ /**
+ * Clean up and invalidate a LINK_TEXT tag if applicable
+ *
+ * Will invalidate the tag if its replacement text is the same as the original
+ * text and would have no visible effect
+ *
+ * @param \s9e\TextFormatter\Parser\Tag $tag LINK_TEXT tag
+ * @param \s9e\TextFormatter\Parser $parser Parser
+ * @return void
+ */
+ public function cleanup_tag(\s9e\TextFormatter\Parser\Tag $tag, \s9e\TextFormatter\Parser $parser)
+ {
+ // Invalidate if the content of the tag matches the text attribute
+ $text = substr($parser->getText(), $tag->getPos(), $tag->getLen());
+ if ($text === $tag->getAttribute('text'))
+ {
+ $tag->invalidate();
+ }
+ }
+
+ /**
+ * Create a LINK_TEXT tag inside of a link
+ *
+ * Meant to only apply to linkified URLs and [url] BBCodes without a parameter
+ *
+ * @param \s9e\TextFormatter\Parser\Tag $tag URL tag (start tag)
+ * @param \s9e\TextFormatter\Parser $parser Parser
+ * @return void
+ */
+ public function generate_link_text_tag(\s9e\TextFormatter\Parser\Tag $tag, \s9e\TextFormatter\Parser $parser)
+ {
+ // Only create a LINK_TEXT tag if the start tag is paired with an end
+ // tag, which is the case with tags from the Autolink plugins and with
+ // the [url] BBCode when its content is used for the URL
+ if (!$tag->getEndTag() || !$this->should_shorten($tag, $parser->getText()))
+ {
+ return;
+ }
+
+ // Capture the text between the start tag and its end tag
+ $start = $tag->getPos() + $tag->getLen();
+ $end = $tag->getEndTag()->getPos();
+ $length = $end - $start;
+ $text = substr($parser->getText(), $start, $length);
+
+ // Create a tag that consumes the link's text and make it depends on this tag
+ $link_text_tag = $parser->addSelfClosingTag('LINK_TEXT', $start, $length, 10);
+ $link_text_tag->setAttribute('text', $text);
+ $tag->cascadeInvalidationTo($link_text_tag);
+ }
+
+ /**
+ * Test whether we should shorten this tag's text
+ *
+ * Will test whether the tag either does not use any markup or uses a single
+ * [url] BBCode
+ *
+ * @param \s9e\TextFormatter\Parser\Tag $tag URL tag
+ * @param string $text Original text
+ * @return bool
+ */
+ protected function should_shorten(\s9e\TextFormatter\Parser\Tag $tag, $text)
+ {
+ return ($tag->getLen() === 0 || strtolower(substr($text, $tag->getPos(), $tag->getLen())) === '[url]');
+ }
+
+ /**
+ * Remove the board's root URL from a the start of a string
+ *
+ * @param \s9e\TextFormatter\Parser\Tag $tag LINK_TEXT tag
+ * @param string $board_url Forum's root URL (with trailing slash)
+ * @return void
+ */
+ public function truncate_local_url(\s9e\TextFormatter\Parser\Tag $tag, $board_url)
+ {
+ $text = $tag->getAttribute('text');
+ if (stripos($text, $board_url) === 0 && strlen($text) > strlen($board_url))
+ {
+ $tag->setAttribute('text', substr($text, strlen($board_url)));
+ }
+ }
+
+ /**
+ * Truncate the replacement text set in a LINK_TEXT tag
+ *
+ * @param \s9e\TextFormatter\Parser\Tag $tag LINK_TEXT tag
+ * @return void
+ */
+ public function truncate_text(\s9e\TextFormatter\Parser\Tag $tag)
+ {
+ $text = $tag->getAttribute('text');
+ if (utf8_strlen($text) > 55)
+ {
+ $text = utf8_substr($text, 0, 39) . ' ... ' . utf8_substr($text, -10);
+ $tag->setAttribute('text', $text);
+ }
+ }
+}
diff --git a/phpBB/phpbb/textformatter/s9e/parser.php b/phpBB/phpbb/textformatter/s9e/parser.php
new file mode 100644
index 0000000000..f7e4668980
--- /dev/null
+++ b/phpBB/phpbb/textformatter/s9e/parser.php
@@ -0,0 +1,417 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter\s9e;
+
+use s9e\TextFormatter\Parser\AttributeFilters\UrlFilter;
+use s9e\TextFormatter\Parser\Logger;
+use s9e\TextFormatter\Parser\Tag;
+
+/**
+* s9e\TextFormatter\Parser adapter
+*/
+class parser implements \phpbb\textformatter\parser_interface
+{
+ /**
+ * @var \phpbb\event\dispatcher_interface
+ */
+ protected $dispatcher;
+
+ /**
+ * @var \s9e\TextFormatter\Parser
+ */
+ protected $parser;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\cache\driver_interface $cache
+ * @param string $key Cache key
+ * @param factory $factory
+ * @param \phpbb\event\dispatcher_interface $dispatcher
+ */
+ public function __construct(\phpbb\cache\driver\driver_interface $cache, $key, factory $factory, \phpbb\event\dispatcher_interface $dispatcher)
+ {
+ $parser = $cache->get($key);
+ if (!$parser)
+ {
+ $objects = $factory->regenerate();
+ $parser = $objects['parser'];
+ }
+
+ $this->dispatcher = $dispatcher;
+ $this->parser = $parser;
+
+ $parser = $this;
+
+ /**
+ * Configure the parser service
+ *
+ * Can be used to:
+ * - toggle features or BBCodes
+ * - register variables or custom parsers in the s9e\TextFormatter parser
+ * - configure the s9e\TextFormatter parser's runtime settings
+ *
+ * @event core.text_formatter_s9e_parser_setup
+ * @var \phpbb\textformatter\s9e\parser parser This parser service
+ * @since 3.2.0-a1
+ */
+ $vars = array('parser');
+ extract($dispatcher->trigger_event('core.text_formatter_s9e_parser_setup', compact($vars)));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function parse($text)
+ {
+ $parser = $this;
+
+ /**
+ * Modify a text before it is parsed
+ *
+ * @event core.text_formatter_s9e_parse_before
+ * @var \phpbb\textformatter\s9e\parser parser This parser service
+ * @var string text The original text
+ * @since 3.2.0-a1
+ */
+ $vars = array('parser', 'text');
+ extract($this->dispatcher->trigger_event('core.text_formatter_s9e_parse_before', compact($vars)));
+
+ $xml = $this->parser->parse($text);
+
+ /**
+ * Modify a parsed text in its XML form
+ *
+ * @event core.text_formatter_s9e_parse_after
+ * @var \phpbb\textformatter\s9e\parser parser This parser service
+ * @var string xml The parsed text, in XML
+ * @since 3.2.0-a1
+ */
+ $vars = array('parser', 'xml');
+ extract($this->dispatcher->trigger_event('core.text_formatter_s9e_parse_after', compact($vars)));
+
+ return $xml;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disable_bbcode($name)
+ {
+ $this->parser->disableTag(strtoupper($name));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disable_bbcodes()
+ {
+ $this->parser->disablePlugin('BBCodes');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disable_censor()
+ {
+ $this->parser->disablePlugin('Censor');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disable_magic_url()
+ {
+ $this->parser->disablePlugin('Autoemail');
+ $this->parser->disablePlugin('Autolink');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function disable_smilies()
+ {
+ $this->parser->disablePlugin('Emoticons');
+ $this->parser->disablePlugin('Emoji');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function enable_bbcode($name)
+ {
+ $this->parser->enableTag(strtoupper($name));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function enable_bbcodes()
+ {
+ $this->parser->enablePlugin('BBCodes');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function enable_censor()
+ {
+ $this->parser->enablePlugin('Censor');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function enable_magic_url()
+ {
+ $this->parser->enablePlugin('Autoemail');
+ $this->parser->enablePlugin('Autolink');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function enable_smilies()
+ {
+ $this->parser->enablePlugin('Emoticons');
+ $this->parser->enablePlugin('Emoji');
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * This will convert the log entries found in s9e\TextFormatter's logger into phpBB error
+ * messages
+ */
+ public function get_errors()
+ {
+ $errors = array();
+ foreach ($this->parser->getLogger()->getLogs() as $entry)
+ {
+ list(, $msg, $context) = $entry;
+
+ if ($msg === 'Tag limit exceeded')
+ {
+ if ($context['tagName'] === 'E')
+ {
+ $errors[] = array('TOO_MANY_SMILIES', $context['tagLimit']);
+ }
+ else if ($context['tagName'] === 'URL')
+ {
+ $errors[] = array('TOO_MANY_URLS', $context['tagLimit']);
+ }
+ }
+ else if ($msg === 'MAX_FONT_SIZE_EXCEEDED')
+ {
+ $errors[] = array($msg, $context['max_size']);
+ }
+ else if (preg_match('/^MAX_(?:FLASH|IMG)_(HEIGHT|WIDTH)_EXCEEDED$/D', $msg, $m))
+ {
+ $errors[] = array($msg, $context['max_' . strtolower($m[1])]);
+ }
+ else if ($msg === 'Tag is disabled' && $this->is_a_bbcode($context['tag']))
+ {
+ $name = strtolower($context['tag']->getName());
+ $errors[] = array('UNAUTHORISED_BBCODE', '[' . $name . ']');
+ }
+ else if ($msg === 'UNABLE_GET_IMAGE_SIZE')
+ {
+ $errors[] = array($msg);
+ }
+ }
+
+ // Deduplicate error messages. array_unique() only works on strings so we have to serialize
+ if (!empty($errors))
+ {
+ $errors = array_map('unserialize', array_unique(array_map('serialize', $errors)));
+ }
+
+ return $errors;
+ }
+
+ /**
+ * Return the instance of s9e\TextFormatter\Parser used by this object
+ *
+ * @return \s9e\TextFormatter\Parser
+ */
+ public function get_parser()
+ {
+ return $this->parser;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_var($name, $value)
+ {
+ if ($name === 'max_smilies')
+ {
+ $this->parser->setTagLimit('E', $value ?: PHP_INT_MAX);
+ }
+ else if ($name === 'max_urls')
+ {
+ $this->parser->setTagLimit('URL', $value ?: PHP_INT_MAX);
+ }
+ else
+ {
+ $this->parser->registeredVars[$name] = $value;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_vars(array $vars)
+ {
+ foreach ($vars as $name => $value)
+ {
+ $this->set_var($name, $value);
+ }
+ }
+
+ /**
+ * Filter a flash object's height
+ *
+ * @see bbcode_firstpass::bbcode_flash()
+ *
+ * @param string $height
+ * @param integer $max_height
+ * @param Logger $logger
+ * @return mixed Original value if valid, FALSE otherwise
+ */
+ static public function filter_flash_height($height, $max_height, Logger $logger)
+ {
+ if ($max_height && $height > $max_height)
+ {
+ $logger->err('MAX_FLASH_HEIGHT_EXCEEDED', array('max_height' => $max_height));
+
+ return false;
+ }
+
+ return $height;
+ }
+
+ /**
+ * Filter a flash object's width
+ *
+ * @see bbcode_firstpass::bbcode_flash()
+ *
+ * @param string $width
+ * @param integer $max_width
+ * @param Logger $logger
+ * @return mixed Original value if valid, FALSE otherwise
+ */
+ static public function filter_flash_width($width, $max_width, Logger $logger)
+ {
+ if ($max_width && $width > $max_width)
+ {
+ $logger->err('MAX_FLASH_WIDTH_EXCEEDED', array('max_width' => $max_width));
+
+ return false;
+ }
+
+ return $width;
+ }
+
+ /**
+ * Filter the value used in a [size] BBCode
+ *
+ * @see bbcode_firstpass::bbcode_size()
+ *
+ * @param string $size Original size
+ * @param integer $max_size Maximum allowed size
+ * @param Logger $logger
+ * @return mixed Original value if valid, FALSE otherwise
+ */
+ static public function filter_font_size($size, $max_size, Logger $logger)
+ {
+ if ($max_size && $size > $max_size)
+ {
+ $logger->err('MAX_FONT_SIZE_EXCEEDED', array('max_size' => $max_size));
+
+ return false;
+ }
+
+ if ($size < 1 || !is_numeric($size))
+ {
+ return false;
+ }
+
+ return $size;
+ }
+
+ /**
+ * Filter an image's URL to enforce restrictions on its dimensions
+ *
+ * @see bbcode_firstpass::bbcode_img()
+ *
+ * @param string $url Original URL
+ * @param array $url_config Config used by the URL filter
+ * @param Logger $logger
+ * @param integer $max_height Maximum height allowed
+ * @param integer $max_width Maximum width allowed
+ * @return string|bool Original value if valid, FALSE otherwise
+ */
+ static public function filter_img_url($url, array $url_config, Logger $logger, $max_height, $max_width)
+ {
+ // Validate the URL
+ $url = UrlFilter::filter($url, $url_config, $logger);
+ if ($url === false)
+ {
+ return false;
+ }
+
+ if ($max_height || $max_width)
+ {
+ $imagesize = new \FastImageSize\FastImageSize();
+ $size_info = $imagesize->getImageSize($url);
+ if ($size_info === false)
+ {
+ $logger->err('UNABLE_GET_IMAGE_SIZE');
+ return false;
+ }
+
+ if ($max_height && $max_height < $size_info['height'])
+ {
+ $logger->err('MAX_IMG_HEIGHT_EXCEEDED', array('max_height' => $max_height));
+ return false;
+ }
+
+ if ($max_width && $max_width < $size_info['width'])
+ {
+ $logger->err('MAX_IMG_WIDTH_EXCEEDED', array('max_width' => $max_width));
+ return false;
+ }
+ }
+
+ return $url;
+ }
+
+ /**
+ * Test whether given tag consumes text that looks like BBCode-styled markup
+ *
+ * @param Tag $tag Original tag
+ * @return bool
+ */
+ protected function is_a_bbcode(Tag $tag)
+ {
+ if ($tag->getLen() < 3)
+ {
+ return false;
+ }
+ $markup = substr($this->parser->getText(), $tag->getPos(), $tag->getLen());
+
+ return (bool) preg_match('(^\\[\\w++.*?\\]$)s', $markup);
+ }
+}
diff --git a/phpBB/phpbb/textformatter/s9e/quote_helper.php b/phpBB/phpbb/textformatter/s9e/quote_helper.php
new file mode 100644
index 0000000000..3011ec88dc
--- /dev/null
+++ b/phpBB/phpbb/textformatter/s9e/quote_helper.php
@@ -0,0 +1,87 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter\s9e;
+
+class quote_helper
+{
+ /**
+ * @var string Base URL for a post link, uses {POST_ID} as placeholder
+ */
+ protected $post_url;
+
+ /**
+ * @var string Base URL for a private message link, uses {MSG_ID} as placeholder
+ */
+ protected $msg_url;
+
+ /**
+ * @var string Base URL for a profile link, uses {USER_ID} as placeholder
+ */
+ protected $profile_url;
+
+ /**
+ * @var \phpbb\user
+ */
+ protected $user;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\user $user
+ * @param string $root_path
+ * @param string $php_ext
+ */
+ public function __construct(\phpbb\user $user, $root_path, $php_ext)
+ {
+ $this->post_url = append_sid($root_path . 'viewtopic.' . $php_ext, 'p={POST_ID}#p{POST_ID}', false);
+ $this->msg_url = append_sid($root_path . 'ucp.' . $php_ext, 'i=pm&mode=view&p={MSG_ID}', false);
+ $this->profile_url = append_sid($root_path . 'memberlist.' . $php_ext, 'mode=viewprofile&u={USER_ID}', false);
+ $this->user = $user;
+ }
+
+ /**
+ * Inject dynamic metadata into QUOTE tags in given XML
+ *
+ * @param string $xml Original XML
+ * @return string Modified XML
+ */
+ public function inject_metadata($xml)
+ {
+ return \s9e\TextFormatter\Utils::replaceAttributes(
+ $xml,
+ 'QUOTE',
+ function ($attributes)
+ {
+ if (isset($attributes['post_id']))
+ {
+ $attributes['post_url'] = str_replace('{POST_ID}', $attributes['post_id'], $this->post_url);
+ }
+ if (isset($attributes['msg_id']))
+ {
+ $attributes['msg_url'] = str_replace('{MSG_ID}', $attributes['msg_id'], $this->msg_url);
+ }
+ if (isset($attributes['time']))
+ {
+ $attributes['date'] = $this->user->format_date($attributes['time']);
+ }
+ if (isset($attributes['user_id']))
+ {
+ $attributes['profile_url'] = str_replace('{USER_ID}', $attributes['user_id'], $this->profile_url);
+ }
+
+ return $attributes;
+ }
+ );
+ }
+}
diff --git a/phpBB/phpbb/textformatter/s9e/renderer.php b/phpBB/phpbb/textformatter/s9e/renderer.php
new file mode 100644
index 0000000000..6fcd2b0a98
--- /dev/null
+++ b/phpBB/phpbb/textformatter/s9e/renderer.php
@@ -0,0 +1,313 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter\s9e;
+
+/**
+* s9e\TextFormatter\Renderer adapter
+*/
+class renderer implements \phpbb\textformatter\renderer_interface
+{
+ /**
+ * @var \s9e\TextFormatter\Plugins\Censor\Helper
+ */
+ protected $censor;
+
+ /**
+ * @var \phpbb\event\dispatcher_interface
+ */
+ protected $dispatcher;
+
+ /**
+ * @var quote_helper
+ */
+ protected $quote_helper;
+
+ /**
+ * @var \s9e\TextFormatter\Renderer
+ */
+ protected $renderer;
+
+ /**
+ * @var bool Status of the viewcensors option
+ */
+ protected $viewcensors = false;
+
+ /**
+ * @var bool Status of the viewflash option
+ */
+ protected $viewflash = false;
+
+ /**
+ * @var bool Status of the viewimg option
+ */
+ protected $viewimg = false;
+
+ /**
+ * @var bool Status of the viewsmilies option
+ */
+ protected $viewsmilies = false;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\cache\driver\driver_interface $cache
+ * @param string $cache_dir Path to the cache dir
+ * @param string $key Cache key
+ * @param factory $factory
+ * @param \phpbb\event\dispatcher_interface $dispatcher
+ */
+ public function __construct(\phpbb\cache\driver\driver_interface $cache, $cache_dir, $key, factory $factory, \phpbb\event\dispatcher_interface $dispatcher)
+ {
+ $renderer_data = $cache->get($key);
+ if ($renderer_data)
+ {
+ $class = $renderer_data['class'];
+ if (!class_exists($class, false))
+ {
+ // Try to load the renderer class from its cache file
+ $cache_file = $cache_dir . $class . '.php';
+
+ if (file_exists($cache_file))
+ {
+ include($cache_file);
+ }
+ }
+ if (class_exists($class, false))
+ {
+ $renderer = new $class;
+ }
+ if (isset($renderer_data['censor']))
+ {
+ $censor = $renderer_data['censor'];
+ }
+ }
+ if (!isset($renderer))
+ {
+ $objects = $factory->regenerate();
+ $renderer = $objects['renderer'];
+ }
+
+ if (isset($censor))
+ {
+ $this->censor = $censor;
+ }
+ $this->dispatcher = $dispatcher;
+ $this->renderer = $renderer;
+ $renderer = $this;
+
+ /**
+ * Configure the renderer service
+ *
+ * @event core.text_formatter_s9e_renderer_setup
+ * @var \phpbb\textformatter\s9e\renderer renderer This renderer service
+ * @since 3.2.0-a1
+ */
+ $vars = array('renderer');
+ extract($dispatcher->trigger_event('core.text_formatter_s9e_renderer_setup', compact($vars)));
+ }
+
+ /**
+ * Configure the quote_helper object used to display extended information in quotes
+ *
+ * @param quote_helper $quote_helper
+ */
+ public function configure_quote_helper(quote_helper $quote_helper)
+ {
+ $this->quote_helper = $quote_helper;
+ }
+
+ /**
+ * Automatically set the smilies path based on config
+ *
+ * @param \phpbb\config\config $config
+ * @param \phpbb\path_helper $path_helper
+ * @return null
+ */
+ public function configure_smilies_path(\phpbb\config\config $config, \phpbb\path_helper $path_helper)
+ {
+ /**
+ * @see smiley_text()
+ */
+ $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $path_helper->get_web_root_path();
+
+ $this->set_smilies_path($root_path . $config['smilies_path']);
+ }
+
+ /**
+ * Configure this renderer as per the user's settings
+ *
+ * Should set the locale as well as the viewcensor/viewflash/viewimg/viewsmilies options.
+ *
+ * @param \phpbb\user $user
+ * @param \phpbb\config\config $config
+ * @param \phpbb\auth\auth $auth
+ * @return null
+ */
+ public function configure_user(\phpbb\user $user, \phpbb\config\config $config, \phpbb\auth\auth $auth)
+ {
+ $censor = $user->optionget('viewcensors') || !$config['allow_nocensors'] || !$auth->acl_get('u_chgcensors');
+
+ $this->set_viewcensors($censor);
+ $this->set_viewflash($user->optionget('viewflash'));
+ $this->set_viewimg($user->optionget('viewimg'));
+ $this->set_viewsmilies($user->optionget('viewsmilies'));
+
+ // Set the stylesheet parameters
+ foreach (array_keys($this->renderer->getParameters()) as $param_name)
+ {
+ if (strpos($param_name, 'L_') === 0)
+ {
+ // L_FOO is set to $user->lang('FOO')
+ $this->renderer->setParameter($param_name, $user->lang(substr($param_name, 2)));
+ }
+ }
+
+ // Set this user's style id and other parameters
+ $this->renderer->setParameters(array(
+ 'S_IS_BOT' => $user->data['is_bot'],
+ 'S_REGISTERED_USER' => $user->data['is_registered'],
+ 'S_USER_LOGGED_IN' => ($user->data['user_id'] != ANONYMOUS),
+ 'STYLE_ID' => $user->style['style_id'],
+ ));
+ }
+
+ /**
+ * Return the instance of s9e\TextFormatter\Renderer used by this object
+ *
+ * @return \s9e\TextFormatter\Renderer
+ */
+ public function get_renderer()
+ {
+ return $this->renderer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_viewcensors()
+ {
+ return $this->viewcensors;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_viewflash()
+ {
+ return $this->viewflash;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_viewimg()
+ {
+ return $this->viewimg;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_viewsmilies()
+ {
+ return $this->viewsmilies;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render($xml)
+ {
+ if (isset($this->quote_helper))
+ {
+ $xml = $this->quote_helper->inject_metadata($xml);
+ }
+
+ $renderer = $this;
+
+ /**
+ * Modify a parsed text before it is rendered
+ *
+ * @event core.text_formatter_s9e_render_before
+ * @var \phpbb\textformatter\s9e\renderer renderer This renderer service
+ * @var string xml The parsed text, in its XML form
+ * @since 3.2.0-a1
+ */
+ $vars = array('renderer', 'xml');
+ extract($this->dispatcher->trigger_event('core.text_formatter_s9e_render_before', compact($vars)));
+
+ $html = $this->renderer->render($xml);
+ if (isset($this->censor) && $this->viewcensors)
+ {
+ $html = $this->censor->censorHtml($html, true);
+ }
+
+ /**
+ * Modify a rendered text
+ *
+ * @event core.text_formatter_s9e_render_after
+ * @var string html The rendered text's HTML
+ * @var \phpbb\textformatter\s9e\renderer renderer This renderer service
+ * @since 3.2.0-a1
+ */
+ $vars = array('html', 'renderer');
+ extract($this->dispatcher->trigger_event('core.text_formatter_s9e_render_after', compact($vars)));
+
+ return $html;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_smilies_path($path)
+ {
+ $this->renderer->setParameter('T_SMILIES_PATH', $path);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_viewcensors($value)
+ {
+ $this->viewcensors = $value;
+ $this->renderer->setParameter('S_VIEWCENSORS', $value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_viewflash($value)
+ {
+ $this->viewflash = $value;
+ $this->renderer->setParameter('S_VIEWFLASH', $value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_viewimg($value)
+ {
+ $this->viewimg = $value;
+ $this->renderer->setParameter('S_VIEWIMG', $value);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set_viewsmilies($value)
+ {
+ $this->viewsmilies = $value;
+ $this->renderer->setParameter('S_VIEWSMILIES', $value);
+ }
+}
diff --git a/phpBB/phpbb/textformatter/s9e/utils.php b/phpBB/phpbb/textformatter/s9e/utils.php
new file mode 100644
index 0000000000..a9a6d4b892
--- /dev/null
+++ b/phpBB/phpbb/textformatter/s9e/utils.php
@@ -0,0 +1,152 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter\s9e;
+
+/**
+* Text manipulation utilities
+*/
+class utils implements \phpbb\textformatter\utils_interface
+{
+ /**
+ * Replace BBCodes and other formatting elements with whitespace
+ *
+ * NOTE: preserves smilies as text
+ *
+ * @param string $xml Parsed text
+ * @return string Plain text
+ */
+ public function clean_formatting($xml)
+ {
+ // Insert a space before <s> and <e> then remove formatting
+ $xml = preg_replace('#<[es]>#', ' $0', $xml);
+
+ return \s9e\TextFormatter\Utils::removeFormatting($xml);
+ }
+
+ /**
+ * Format given string to be used as an attribute value
+ *
+ * Will return the string as-is if it can be used in a BBCode without quotes. Otherwise,
+ * it will use either single- or double- quotes depending on whichever requires less escaping.
+ * Quotes and backslashes are escaped with backslashes where necessary
+ *
+ * @param string $str Original string
+ * @return string Same string if possible, escaped string within quotes otherwise
+ */
+ protected function format_attribute_value($str)
+ {
+ if (!preg_match('/[ "\'\\\\\\]]/', $str))
+ {
+ // Return as-is if it contains none of: space, ' " \ or ]
+ return $str;
+ }
+ $singleQuoted = "'" . addcslashes($str, "\\'") . "'";
+ $doubleQuoted = '"' . addcslashes($str, '\\"') . '"';
+
+ return (strlen($singleQuoted) < strlen($doubleQuoted)) ? $singleQuoted : $doubleQuoted;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function generate_quote($text, array $attributes = array())
+ {
+ $text = trim($text);
+ $quote = '[quote';
+ if (isset($attributes['author']))
+ {
+ // Add the author as the BBCode's default attribute
+ $quote .= '=' . $this->format_attribute_value($attributes['author']);
+ unset($attributes['author']);
+ }
+
+ if (isset($attributes['user_id']) && $attributes['user_id'] == ANONYMOUS)
+ {
+ unset($attributes['user_id']);
+ }
+
+ ksort($attributes);
+ foreach ($attributes as $name => $value)
+ {
+ $quote .= ' ' . $name . '=' . $this->format_attribute_value($value);
+ }
+ $quote .= ']';
+ $newline = (strlen($quote . $text . '[/quote]') > 80 || strpos($text, "\n") !== false) ? "\n" : '';
+ $quote .= $newline . $text . $newline . '[/quote]';
+
+ return $quote;
+ }
+
+ /**
+ * Get a list of quote authors, limited to the outermost quotes
+ *
+ * @param string $xml Parsed text
+ * @return string[] List of authors
+ */
+ public function get_outermost_quote_authors($xml)
+ {
+ $authors = array();
+ if (strpos($xml, '<QUOTE ') === false)
+ {
+ return $authors;
+ }
+
+ $dom = new \DOMDocument;
+ $dom->loadXML($xml);
+ $xpath = new \DOMXPath($dom);
+ foreach ($xpath->query('//QUOTE[not(ancestor::QUOTE)]/@author') as $author)
+ {
+ $authors[] = $author->textContent;
+ }
+
+ return $authors;
+ }
+
+ /**
+ * Remove given BBCode and its content, at given nesting depth
+ *
+ * @param string $xml Parsed text
+ * @param string $bbcode_name BBCode's name
+ * @param integer $depth Minimum nesting depth (number of parents of the same name)
+ * @return string Parsed text
+ */
+ public function remove_bbcode($xml, $bbcode_name, $depth = 0)
+ {
+ return \s9e\TextFormatter\Utils::removeTag($xml, strtoupper($bbcode_name), $depth);
+ }
+
+ /**
+ * Return a parsed text to its original form
+ *
+ * @param string $xml Parsed text
+ * @return string Original plain text
+ */
+ public function unparse($xml)
+ {
+ return \s9e\TextFormatter\Unparser::unparse($xml);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function is_empty($text)
+ {
+ if ($text === null || $text === '')
+ {
+ return true;
+ }
+
+ return trim($this->unparse($text)) === '';
+ }
+}
diff --git a/phpBB/phpbb/textformatter/utils_interface.php b/phpBB/phpbb/textformatter/utils_interface.php
new file mode 100644
index 0000000000..4b7392976a
--- /dev/null
+++ b/phpBB/phpbb/textformatter/utils_interface.php
@@ -0,0 +1,79 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textformatter;
+
+/**
+* Used to manipulate a parsed text
+*/
+interface utils_interface
+{
+ /**
+ * Replace BBCodes and other formatting elements with whitespace
+ *
+ * NOTE: preserves smilies as text
+ *
+ * @param string $text Parsed text
+ * @return string Plain text
+ */
+ public function clean_formatting($text);
+
+ /**
+ * Create a quote block for given text
+ *
+ * Possible attributes:
+ * - author: author's name (usually a username)
+ * - post_id: post_id of the post being quoted
+ * - user_id: user_id of the user being quoted
+ * - time: timestamp of the original message
+ *
+ * @param string $text Quote's text
+ * @param array $attributes Quote's attributes
+ * @return string Quote block to be used in a new post/text
+ */
+ public function generate_quote($text, array $attributes = array());
+
+ /**
+ * Get a list of quote authors, limited to the outermost quotes
+ *
+ * @param string $text Parsed text
+ * @return string[] List of authors
+ */
+ public function get_outermost_quote_authors($text);
+
+ /**
+ * Remove given BBCode and its content, at given nesting depth
+ *
+ * @param string $text Parsed text
+ * @param string $bbcode_name BBCode's name
+ * @param integer $depth Minimum nesting depth (number of parents of the same name)
+ * @return string Parsed text
+ */
+ public function remove_bbcode($text, $bbcode_name, $depth = 0);
+
+ /**
+ * Return a parsed text to its original form
+ *
+ * @param string $text Parsed text
+ * @return string Original plain text
+ */
+ public function unparse($text);
+
+ /**
+ * Return whether or not a parsed text represent an empty text.
+ *
+ * @param string $text Parsed text
+ * @return bool Tue if the original text is empty
+ */
+ public function is_empty($text);
+}
diff --git a/phpBB/phpbb/textreparser/base.php b/phpBB/phpbb/textreparser/base.php
new file mode 100644
index 0000000000..2ee6ea2cb3
--- /dev/null
+++ b/phpBB/phpbb/textreparser/base.php
@@ -0,0 +1,269 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser;
+
+abstract class base implements reparser_interface
+{
+ /**
+ * @var string The reparser name
+ */
+ protected $name;
+
+ /**
+ * @var bool Whether to save changes to the database
+ */
+ protected $save_changes = true;
+
+ /**
+ * {@inheritdoc}
+ */
+ abstract public function get_max_id();
+
+ /**
+ * Return all records in given range
+ *
+ * @param integer $min_id Lower bound
+ * @param integer $max_id Upper bound
+ * @return array Array of records
+ */
+ abstract protected function get_records_by_range($min_id, $max_id);
+
+ /**
+ * {@inheritdoc}
+ */
+ abstract protected function save_record(array $record);
+
+ /**
+ * Add fields to given record, if applicable
+ *
+ * The enable_* fields are not always saved to the database. Sometimes we need to guess their
+ * original value based on the text content or possibly other fields
+ *
+ * @param array $record Original record
+ * @return array Complete record
+ */
+ protected function add_missing_fields(array $record)
+ {
+ if (!isset($record['enable_bbcode'], $record['enable_smilies'], $record['enable_magic_url']))
+ {
+ if (isset($record['options']))
+ {
+ $record += array(
+ 'enable_bbcode' => (bool) ($record['options'] & OPTION_FLAG_BBCODE),
+ 'enable_smilies' => (bool) ($record['options'] & OPTION_FLAG_SMILIES),
+ 'enable_magic_url' => (bool) ($record['options'] & OPTION_FLAG_LINKS),
+ );
+ }
+ else
+ {
+ $record += array(
+ 'enable_bbcode' => $this->guess_bbcodes($record),
+ 'enable_smilies' => $this->guess_smilies($record),
+ 'enable_magic_url' => $this->guess_magic_url($record),
+ );
+ }
+ }
+
+ // Those BBCodes are disabled based on context and user permissions and that value is never
+ // stored in the database. Here we test whether they were used in the original text.
+ $bbcodes = array('flash', 'img', 'quote', 'url');
+ foreach ($bbcodes as $bbcode)
+ {
+ $field_name = 'enable_' . $bbcode . '_bbcode';
+ $record[$field_name] = $this->guess_bbcode($record, $bbcode);
+ }
+
+ // Magic URLs are tied to the URL BBCode, that's why if magic URLs are enabled we make sure
+ // that the URL BBCode is also enabled
+ if ($record['enable_magic_url'])
+ {
+ $record['enable_url_bbcode'] = true;
+ }
+
+ return $record;
+ }
+
+ /**
+ * Returns the name of the reparser
+ *
+ * @return string Name of reparser
+ */
+ public function get_name()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Sets the name of the reparser
+ *
+ * @param string $name The reparser name
+ */
+ public function set_name($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Disable saving changes to the database
+ */
+ public function disable_save()
+ {
+ $this->save_changes = false;
+ }
+
+ /**
+ * Enable saving changes to the database
+ */
+ public function enable_save()
+ {
+ $this->save_changes = true;
+ }
+
+ /**
+ * Guess whether given BBCode is in use in given record
+ *
+ * @param array $record
+ * @param string $bbcode
+ * @return bool
+ */
+ protected function guess_bbcode(array $record, $bbcode)
+ {
+ if (!empty($record['bbcode_uid']))
+ {
+ // Look for the closing tag, e.g. [/url]
+ $match = '[/' . $bbcode . ':' . $record['bbcode_uid'];
+ if (strpos($record['text'], $match) !== false)
+ {
+ return true;
+ }
+ }
+
+ if (substr($record['text'], 0, 2) === '<r')
+ {
+ // Look for the closing tag inside of a e element, in an element of the same name, e.g.
+ // <e>[/url]</e></URL>
+ $match = '<e>[/' . $bbcode . ']</e></' . $bbcode . '>';
+ if (stripos($record['text'], $match) !== false)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Guess whether any BBCode is in use in given record
+ *
+ * @param array $record
+ * @return bool
+ */
+ protected function guess_bbcodes(array $record)
+ {
+ if (!empty($record['bbcode_uid']))
+ {
+ // Test whether the bbcode_uid is in use
+ $match = ':' . $record['bbcode_uid'];
+ if (strpos($record['text'], $match) !== false)
+ {
+ return true;
+ }
+ }
+
+ if (substr($record['text'], 0, 2) === '<r')
+ {
+ // Look for a closing tag inside of an e element
+ return (bool) preg_match('(<e>\\[/\\w+\\]</e>)', $match);
+ }
+
+ return false;
+ }
+
+ /**
+ * Guess whether magic URLs are in use in given record
+ *
+ * @param array $record
+ * @return bool
+ */
+ protected function guess_magic_url(array $record)
+ {
+ // Look for <!-- m --> or for a URL tag that's not immediately followed by <s>
+ return (strpos($record['text'], '<!-- m -->') !== false || preg_match('(<URL [^>]++>(?!<s>))', $record['text']));
+ }
+
+ /**
+ * Guess whether smilies are in use in given record
+ *
+ * @param array $record
+ * @return bool
+ */
+ protected function guess_smilies(array $record)
+ {
+ return (strpos($record['text'], '<!-- s') !== false || strpos($record['text'], '<E>') !== false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reparse_range($min_id, $max_id)
+ {
+ foreach ($this->get_records_by_range($min_id, $max_id) as $record)
+ {
+ $this->reparse_record($record);
+ }
+ }
+
+ /**
+ * Reparse given record
+ *
+ * @param array $record Associative array containing the record's data
+ */
+ protected function reparse_record(array $record)
+ {
+ $record = $this->add_missing_fields($record);
+ $flags = ($record['enable_bbcode']) ? OPTION_FLAG_BBCODE : 0;
+ $flags |= ($record['enable_smilies']) ? OPTION_FLAG_SMILIES : 0;
+ $flags |= ($record['enable_magic_url']) ? OPTION_FLAG_LINKS : 0;
+ $unparsed = array_merge(
+ $record,
+ generate_text_for_edit($record['text'], $record['bbcode_uid'], $flags)
+ );
+
+ // generate_text_for_edit() and decode_message() actually return the text as HTML. It has to
+ // be decoded to plain text before it can be reparsed
+ $text = html_entity_decode($unparsed['text'], ENT_QUOTES, 'UTF-8');
+ $bitfield = $flags = null;
+ generate_text_for_storage(
+ $text,
+ $unparsed['bbcode_uid'],
+ $bitfield,
+ $flags,
+ $unparsed['enable_bbcode'],
+ $unparsed['enable_magic_url'],
+ $unparsed['enable_smilies'],
+ $unparsed['enable_img_bbcode'],
+ $unparsed['enable_flash_bbcode'],
+ $unparsed['enable_quote_bbcode'],
+ $unparsed['enable_url_bbcode'],
+ 'text_reparser.' . $this->get_name()
+ );
+
+ // Save the new text if it has changed and it's not a dry run
+ if ($text !== $record['text'] && $this->save_changes)
+ {
+ $record['text'] = $text;
+ $this->save_record($record);
+ }
+ }
+}
diff --git a/phpBB/phpbb/textreparser/manager.php b/phpBB/phpbb/textreparser/manager.php
new file mode 100644
index 0000000000..7ca65d708d
--- /dev/null
+++ b/phpBB/phpbb/textreparser/manager.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\textreparser;
+
+class manager
+{
+ /**
+ * @var \phpbb\config\config
+ */
+ protected $config;
+
+ /**
+ * @var \phpbb\config\db_text
+ */
+ protected $config_text;
+
+ /**
+ * @var \phpbb\di\service_collection
+ */
+ protected $reparsers;
+
+ /**
+ * @var array
+ */
+ protected $resume_data;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\config\config $config
+ * @param \phpbb\config\db_text $config_text
+ * @param \phpbb\di\service_collection $reparsers
+ */
+ public function __construct(\phpbb\config\config $config, \phpbb\config\db_text $config_text, \phpbb\di\service_collection $reparsers)
+ {
+ $this->config = $config;
+ $this->config_text = $config_text;
+ $this->reparsers = $reparsers;
+ }
+
+ /**
+ * Loads resume data from the database
+ *
+ * @param string $name Name of the reparser to which the resume data belongs
+ *
+ * @return array
+ */
+ public function get_resume_data($name)
+ {
+ if ($this->resume_data === null)
+ {
+ $resume_data = $this->config_text->get('reparser_resume');
+ $this->resume_data = !empty($resume_data) ? unserialize($resume_data) : array();
+ }
+
+ return isset($this->resume_data[$name]) ? $this->resume_data[$name] : array();
+ }
+
+ /**
+ * Updates the resume data in the database
+ *
+ * @param string $name Name of the reparser to which the resume data belongs
+ * @param int $min Lowest record ID
+ * @param int $current Current record ID
+ * @param int $size Number of records to process at a time
+ * @param bool $update_db True if the resume data should be written to the database, false if not. (default: true)
+ */
+ public function update_resume_data($name, $min, $current, $size, $update_db = true)
+ {
+ // Prevent overwriting the old, stored array
+ if ($this->resume_data === null)
+ {
+ $this->get_resume_data('');
+ }
+
+ $this->resume_data[$name] = array(
+ 'range-min' => $min,
+ 'range-max' => $current,
+ 'range-size' => $size,
+ );
+
+ if ($update_db)
+ {
+ $this->config_text->set('reparser_resume', serialize($this->resume_data));
+ }
+ }
+
+ /**
+ * Sets the interval for a text_reparser cron task
+ *
+ * @param string $name Name of the reparser to schedule
+ * @param int $interval Interval in seconds, 0 to disable the cron task
+ */
+ public function schedule($name, $interval)
+ {
+ if (isset($this->reparsers[$name]) && isset($this->config[$name . '_cron_interval']))
+ {
+ $this->config->set($name . '_cron_interval', $interval);
+ }
+ }
+
+ /**
+ * Sets the interval for all text_reparser cron tasks
+ *
+ * @param int $interval Interval in seconds, 0 to disable the cron task
+ */
+ public function schedule_all($interval)
+ {
+ // This way we don't construct every registered reparser
+ $reparser_array = array_keys($this->reparsers->getArrayCopy());
+
+ foreach ($reparser_array as $reparser)
+ {
+ $this->schedule($reparser, $interval);
+ }
+ }
+
+ /**
+ * Finds a reparser by name.
+ *
+ * If there is no reparser with the specified name, null is returned.
+ *
+ * @param string $name Name of the reparser to look up.
+ * @return string A reparser service name, or null.
+ */
+ public function find_reparser($name)
+ {
+ foreach ($this->reparsers as $service => $reparser)
+ {
+ if ($reparser->get_name() == $name)
+ {
+ return $service;
+ }
+ }
+ return null;
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/contact_admin_info.php b/phpBB/phpbb/textreparser/plugins/contact_admin_info.php
new file mode 100644
index 0000000000..8910f2256b
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/contact_admin_info.php
@@ -0,0 +1,69 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class contact_admin_info extends \phpbb\textreparser\base
+{
+ /**
+ * @var \phpbb\config\db_text
+ */
+ protected $config_text;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\config\db_text $config_text
+ */
+ public function __construct(\phpbb\config\db_text $config_text)
+ {
+ $this->config_text = $config_text;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_max_id()
+ {
+ return 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_records_by_range($min_id, $max_id)
+ {
+ $values = $this->config_text->get_array(array(
+ 'contact_admin_info',
+ 'contact_admin_info_uid',
+ 'contact_admin_info_flags',
+ ));
+
+ return array(array(
+ 'id' => 1,
+ 'text' => $values['contact_admin_info'],
+ 'bbcode_uid' => $values['contact_admin_info_uid'],
+ 'enable_bbcode' => $values['contact_admin_info_flags'] & OPTION_FLAG_BBCODE,
+ 'enable_magic_url' => $values['contact_admin_info_flags'] & OPTION_FLAG_LINKS,
+ 'enable_smilies' => $values['contact_admin_info_flags'] & OPTION_FLAG_SMILIES,
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function save_record(array $record)
+ {
+ $this->config_text->set('contact_admin_info', $record['text']);
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/forum_description.php b/phpBB/phpbb/textreparser/plugins/forum_description.php
new file mode 100644
index 0000000000..b0f5a42452
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/forum_description.php
@@ -0,0 +1,30 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class forum_description extends \phpbb\textreparser\row_based_plugin
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_columns()
+ {
+ return array(
+ 'id' => 'forum_id',
+ 'text' => 'forum_desc',
+ 'bbcode_uid' => 'forum_desc_uid',
+ 'options' => 'forum_desc_options',
+ );
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/forum_rules.php b/phpBB/phpbb/textreparser/plugins/forum_rules.php
new file mode 100644
index 0000000000..d131d00707
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/forum_rules.php
@@ -0,0 +1,30 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class forum_rules extends \phpbb\textreparser\row_based_plugin
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_columns()
+ {
+ return array(
+ 'id' => 'forum_id',
+ 'text' => 'forum_rules',
+ 'bbcode_uid' => 'forum_rules_uid',
+ 'options' => 'forum_rules_options',
+ );
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/group_description.php b/phpBB/phpbb/textreparser/plugins/group_description.php
new file mode 100644
index 0000000000..2c45c00474
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/group_description.php
@@ -0,0 +1,30 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class group_description extends \phpbb\textreparser\row_based_plugin
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_columns()
+ {
+ return array(
+ 'id' => 'group_id',
+ 'text' => 'group_desc',
+ 'bbcode_uid' => 'group_desc_uid',
+ 'options' => 'group_desc_options',
+ );
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/pm_text.php b/phpBB/phpbb/textreparser/plugins/pm_text.php
new file mode 100644
index 0000000000..867da624ee
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/pm_text.php
@@ -0,0 +1,32 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class pm_text extends \phpbb\textreparser\row_based_plugin
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_columns()
+ {
+ return array(
+ 'id' => 'msg_id',
+ 'enable_bbcode' => 'enable_bbcode',
+ 'enable_smilies' => 'enable_smilies',
+ 'enable_magic_url' => 'enable_magic_url',
+ 'text' => 'message_text',
+ 'bbcode_uid' => 'bbcode_uid',
+ );
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/poll_option.php b/phpBB/phpbb/textreparser/plugins/poll_option.php
new file mode 100644
index 0000000000..44cacfae62
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/poll_option.php
@@ -0,0 +1,74 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class poll_option extends \phpbb\textreparser\base
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db)
+ {
+ $this->db = $db;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_max_id()
+ {
+ $sql = 'SELECT MAX(topic_id) AS max_id FROM ' . POLL_OPTIONS_TABLE;
+ $result = $this->db->sql_query($sql);
+ $max_id = (int) $this->db->sql_fetchfield('max_id');
+ $this->db->sql_freeresult($result);
+
+ return $max_id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_records_by_range($min_id, $max_id)
+ {
+ $sql = 'SELECT o.topic_id, o.poll_option_id, o.poll_option_text AS text, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.bbcode_uid
+ FROM ' . POLL_OPTIONS_TABLE . ' o, ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
+ WHERE o.topic_id BETWEEN ' . $min_id . ' AND ' . $max_id .'
+ AND t.topic_id = o.topic_id
+ AND p.post_id = t.topic_first_post_id';
+ $result = $this->db->sql_query($sql);
+ $records = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ return $records;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function save_record(array $record)
+ {
+ $sql = 'UPDATE ' . POLL_OPTIONS_TABLE . "
+ SET poll_option_text = '" . $this->db->sql_escape($record['text']) . "'
+ WHERE topic_id = " . $record['topic_id'] . '
+ AND poll_option_id = ' . $record['poll_option_id'];
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/poll_title.php b/phpBB/phpbb/textreparser/plugins/poll_title.php
new file mode 100644
index 0000000000..5ca8bb063b
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/poll_title.php
@@ -0,0 +1,42 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class poll_title extends \phpbb\textreparser\row_based_plugin
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_columns()
+ {
+ return array(
+ 'id' => 'topic_id',
+ 'text' => 'poll_title',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_records_by_range_query($min_id, $max_id)
+ {
+ $sql = 'SELECT t.topic_id AS id, t.poll_title AS text, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, p.bbcode_uid
+ FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
+ WHERE t.topic_id BETWEEN ' . $min_id . ' AND ' . $max_id .'
+ AND t.poll_start > 0
+ AND p.post_id = t.topic_first_post_id';
+
+ return $sql;
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/post_text.php b/phpBB/phpbb/textreparser/plugins/post_text.php
new file mode 100644
index 0000000000..1c98e86067
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/post_text.php
@@ -0,0 +1,32 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class post_text extends \phpbb\textreparser\row_based_plugin
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function get_columns()
+ {
+ return array(
+ 'id' => 'post_id',
+ 'enable_bbcode' => 'enable_bbcode',
+ 'enable_smilies' => 'enable_smilies',
+ 'enable_magic_url' => 'enable_magic_url',
+ 'text' => 'post_text',
+ 'bbcode_uid' => 'bbcode_uid',
+ );
+ }
+}
diff --git a/phpBB/phpbb/textreparser/plugins/user_signature.php b/phpBB/phpbb/textreparser/plugins/user_signature.php
new file mode 100644
index 0000000000..647d3a7b14
--- /dev/null
+++ b/phpBB/phpbb/textreparser/plugins/user_signature.php
@@ -0,0 +1,65 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser\plugins;
+
+class user_signature extends \phpbb\textreparser\row_based_plugin
+{
+ /**
+ * @var array Bit numbers used for user options
+ * @see \phpbb\user
+ */
+ protected $keyoptions;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function add_missing_fields(array $row)
+ {
+ if (!isset($this->keyoptions))
+ {
+ $this->save_keyoptions();
+ }
+
+ $options = $row['user_options'];
+ $row += array(
+ 'enable_bbcode' => phpbb_optionget($this->keyoptions['sig_bbcode'], $options),
+ 'enable_smilies' => phpbb_optionget($this->keyoptions['sig_smilies'], $options),
+ 'enable_magic_url' => phpbb_optionget($this->keyoptions['sig_links'], $options),
+ );
+
+ return parent::add_missing_fields($row);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_columns()
+ {
+ return array(
+ 'id' => 'user_id',
+ 'text' => 'user_sig',
+ 'bbcode_uid' => 'user_sig_bbcode_uid',
+ 'user_options' => 'user_options',
+ );
+ }
+
+ /**
+ * Save the keyoptions var from \phpbb\user
+ */
+ protected function save_keyoptions()
+ {
+ $class_vars = get_class_vars('phpbb\\user');
+ $this->keyoptions = $class_vars['keyoptions'];
+ }
+}
diff --git a/phpBB/phpbb/textreparser/reparser_interface.php b/phpBB/phpbb/textreparser/reparser_interface.php
new file mode 100644
index 0000000000..912de10058
--- /dev/null
+++ b/phpBB/phpbb/textreparser/reparser_interface.php
@@ -0,0 +1,46 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser;
+
+interface reparser_interface
+{
+ /**
+ * Return the highest ID for all existing records
+ *
+ * @return integer
+ */
+ public function get_max_id();
+
+ /**
+ * Returns the name of the reparser
+ *
+ * @return string Name of reparser
+ */
+ public function get_name();
+
+ /**
+ * Sets the name of the reparser
+ *
+ * @param string $name The reparser name
+ */
+ public function set_name($name);
+
+ /**
+ * Reparse all records in given range
+ *
+ * @param integer $min_id Lower bound
+ * @param integer $max_id Upper bound
+ */
+ public function reparse_range($min_id, $max_id);
+}
diff --git a/phpBB/phpbb/textreparser/row_based_plugin.php b/phpBB/phpbb/textreparser/row_based_plugin.php
new file mode 100644
index 0000000000..2d32104493
--- /dev/null
+++ b/phpBB/phpbb/textreparser/row_based_plugin.php
@@ -0,0 +1,117 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace phpbb\textreparser;
+
+abstract class row_based_plugin extends base
+{
+ /**
+ * @var \phpbb\db\driver\driver_interface
+ */
+ protected $db;
+
+ /**
+ * @var string
+ */
+ protected $table;
+
+ /**
+ * Constructor
+ *
+ * @param \phpbb\db\driver\driver_interface $db Database connection
+ * @param string $table
+ */
+ public function __construct(\phpbb\db\driver\driver_interface $db, $table)
+ {
+ $this->db = $db;
+ $this->table = $table;
+ }
+
+ /**
+ * Return the name of the column that correspond to each field
+ *
+ * @return array
+ */
+ abstract public function get_columns();
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get_max_id()
+ {
+ $columns = $this->get_columns();
+
+ $sql = 'SELECT MAX(' . $columns['id'] . ') AS max_id FROM ' . $this->table;
+ $result = $this->db->sql_query($sql);
+ $max_id = (int) $this->db->sql_fetchfield('max_id');
+ $this->db->sql_freeresult($result);
+
+ return $max_id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function get_records_by_range($min_id, $max_id)
+ {
+ $sql = $this->get_records_by_range_query($min_id, $max_id);
+ $result = $this->db->sql_query($sql);
+ $records = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ return $records;
+ }
+
+ /**
+ * Generate the query that retrieves all records for given range
+ *
+ * @param integer $min_id Lower bound
+ * @param integer $max_id Upper bound
+ * @return string SQL query
+ */
+ protected function get_records_by_range_query($min_id, $max_id)
+ {
+ $columns = $this->get_columns();
+ $fields = array();
+ foreach ($columns as $field_name => $column_name)
+ {
+ if ($column_name === $field_name)
+ {
+ $fields[] = $column_name;
+ }
+ else
+ {
+ $fields[] = $column_name . ' AS ' . $field_name;
+ }
+ }
+
+ $sql = 'SELECT ' . implode(', ', $fields) . '
+ FROM ' . $this->table . '
+ WHERE ' . $columns['id'] . ' BETWEEN ' . $min_id . ' AND ' . $max_id;
+
+ return $sql;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function save_record(array $record)
+ {
+ $columns = $this->get_columns();
+
+ $sql = 'UPDATE ' . $this->table . '
+ SET ' . $columns['text'] . " = '" . $this->db->sql_escape($record['text']) . "'
+ WHERE " . $columns['id'] . ' = ' . $record['id'];
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/phpbb/tree/nestedset.php b/phpBB/phpbb/tree/nestedset.php
index 8490c7c299..eadd2b3273 100644
--- a/phpBB/phpbb/tree/nestedset.php
+++ b/phpBB/phpbb/tree/nestedset.php
@@ -391,7 +391,6 @@ abstract class nestedset implements \phpbb\tree\tree_interface
throw new \OutOfBoundsException($this->message_prefix . 'INVALID_PARENT');
}
- $diff = sizeof($move_items) * 2;
$sql_exclude_moved_items = $this->db->sql_in_set($this->column_item_id, $move_items, true);
$this->db->sql_transaction('begin');
@@ -490,7 +489,6 @@ abstract class nestedset implements \phpbb\tree\tree_interface
throw new \OutOfBoundsException($this->message_prefix . 'INVALID_PARENT');
}
- $diff = sizeof($move_items) * 2;
$sql_exclude_moved_items = $this->db->sql_in_set($this->column_item_id, $move_items, true);
$this->db->sql_transaction('begin');
@@ -535,7 +533,7 @@ abstract class nestedset implements \phpbb\tree\tree_interface
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
- $diff = ' + ' . ($row[$this->column_right_id] - (int) $item[$this->column_left_id] + 1);
+ $diff = ' + ' . ((int) $row[$this->column_right_id] - (int) $item[$this->column_left_id] + 1);
}
$sql = 'UPDATE ' . $this->table_name . '
@@ -708,7 +706,7 @@ abstract class nestedset implements \phpbb\tree\tree_interface
{
$acquired_new_lock = $this->acquire_lock();
- $diff = sizeof($subset_items) * 2;
+ $diff = count($subset_items) * 2;
$sql_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items);
$sql_not_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items, true);
@@ -748,7 +746,7 @@ abstract class nestedset implements \phpbb\tree\tree_interface
*/
protected function prepare_adding_subset(array $subset_items, array $new_parent)
{
- $diff = sizeof($subset_items) * 2;
+ $diff = count($subset_items) * 2;
$sql_not_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items, true);
$set_left_id = $this->db->sql_case($this->column_left_id . ' > ' . (int) $new_parent[$this->column_right_id], $this->column_left_id . ' + ' . $diff, $this->column_left_id);
diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php
index faedd79703..9817e40edb 100644
--- a/phpBB/phpbb/user.php
+++ b/phpBB/phpbb/user.php
@@ -21,8 +21,11 @@ namespace phpbb;
*/
class user extends \phpbb\session
{
- var $lang = array();
- var $help = array();
+ /**
+ * @var \phpbb\language\language
+ */
+ protected $language;
+
var $style = array();
var $date_format;
@@ -42,35 +45,63 @@ class user extends \phpbb\session
var $img_lang;
var $img_array = array();
+ /** @var bool */
+ protected $is_setup_flag;
+
// Able to add new options (up to id 31)
var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'sig_bbcode' => 15, 'sig_smilies' => 16, 'sig_links' => 17);
/**
* Constructor to set the lang path
- * @param string $datetime_class Class name of datetime class
+ *
+ * @param \phpbb\language\language $lang phpBB's Language loader
+ * @param string $datetime_class Class name of datetime class
*/
- function __construct($datetime_class)
+ function __construct(\phpbb\language\language $lang, $datetime_class)
{
global $phpbb_root_path;
$this->lang_path = $phpbb_root_path . 'language/';
+ $this->language = $lang;
$this->datetime = $datetime_class;
+
+ $this->is_setup_flag = false;
}
/**
- * Function to set custom language path (able to use directory outside of phpBB)
- *
- * @param string $lang_path New language path used.
- * @access public
- */
- function set_custom_lang_path($lang_path)
+ * Returns whether user::setup was called
+ *
+ * @return bool
+ */
+ public function is_setup()
{
- $this->lang_path = $lang_path;
+ return $this->is_setup_flag;
+ }
- if (substr($this->lang_path, -1) != '/')
+ /**
+ * Magic getter for BC compatibility
+ *
+ * Implement array access for user::lang.
+ *
+ * @param string $param_name Name of the BC component the user want to access
+ *
+ * @return array The appropriate array
+ *
+ * @deprecated 3.2.0-dev (To be removed: 4.0.0)
+ */
+ public function __get($param_name)
+ {
+ if ($param_name === 'lang')
{
- $this->lang_path .= '/';
+ return $this->language->get_lang_array();
}
+ else if ($param_name === 'help')
+ {
+ $help_array = $this->language->get_lang_array();
+ return $help_array['__help'];
+ }
+
+ return array();
}
/**
@@ -81,6 +112,8 @@ class user extends \phpbb\session
global $db, $request, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
global $phpbb_dispatcher;
+ $this->language->set_default_language($config['default_lang']);
+
if ($this->data['user_id'] != ANONYMOUS)
{
$user_lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
@@ -98,6 +131,7 @@ class user extends \phpbb\session
{
$lang_override = $request->variable($config['cookie_name'] . '_lang', '', true, \phpbb\request\request_interface::COOKIE);
}
+
if ($lang_override)
{
$use_lang = basename($lang_override);
@@ -108,6 +142,7 @@ class user extends \phpbb\session
{
$user_lang_name = basename($config['default_lang']);
}
+
$user_date_format = $config['default_dateformat'];
$user_timezone = $config['board_timezone'];
@@ -154,6 +189,9 @@ class user extends \phpbb\session
/**
* Event to load language files and modify user data on every page
*
+ * Note: To load language file with this event, see description
+ * of lang_set_ext variable.
+ *
* @event core.user_setup
* @var array user_data Array with user's data row
* @var string user_lang_name Basename of the user's langauge
@@ -187,6 +225,8 @@ class user extends \phpbb\session
$this->lang_name = $user_lang_name;
$this->date_format = $user_date_format;
+ $this->language->set_user_language($user_lang_name);
+
try
{
$this->timezone = new \DateTimeZone($user_timezone);
@@ -197,17 +237,6 @@ class user extends \phpbb\session
$this->timezone = new \DateTimeZone('UTC');
}
- // We include common language file here to not load it every time a custom language file is included
- $lang = &$this->lang;
-
- // Do not suppress error if in DEBUG mode
- $include_result = (defined('DEBUG')) ? (include $this->lang_path . $this->lang_name . "/common.$phpEx") : (@include $this->lang_path . $this->lang_name . "/common.$phpEx");
-
- if ($include_result === false)
- {
- die('Language file ' . $this->lang_path . $this->lang_name . "/common.$phpEx" . " couldn't be opened.");
- }
-
$this->add_lang($lang_set);
unset($lang_set);
@@ -252,27 +281,43 @@ class user extends \phpbb\session
$db->sql_freeresult($result);
}
- // User has wrong style
- if (!$this->style && $style_id == $this->data['user_style'])
+ // Fallback to board's default style
+ if (!$this->style)
{
- $style_id = $this->data['user_style'] = $config['default_style'];
-
- $sql = 'UPDATE ' . USERS_TABLE . "
- SET user_style = $style_id
- WHERE user_id = {$this->data['user_id']}";
- $db->sql_query($sql);
-
- $sql = 'SELECT *
- FROM ' . STYLES_TABLE . " s
- WHERE s.style_id = $style_id";
- $result = $db->sql_query($sql, 3600);
- $this->style = $db->sql_fetchrow($result);
+ // Verify default style exists in the database
+ $sql = 'SELECT style_id
+ FROM ' . STYLES_TABLE . '
+ WHERE style_id = ' . (int) $config['default_style'];
+ $result = $db->sql_query($sql);
+ $style_id = (int) $db->sql_fetchfield('style_id');
$db->sql_freeresult($result);
+
+ if ($style_id > 0)
+ {
+ $db->sql_transaction('begin');
+
+ // Update $user row
+ $sql = 'SELECT *
+ FROM ' . STYLES_TABLE . '
+ WHERE style_id = ' . (int) $config['default_style'];
+ $result = $db->sql_query($sql);
+ $this->style = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ // Update user style preference
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET user_style = ' . (int) $style_id . '
+ WHERE user_id = ' . (int) $this->data['user_id'];
+ $db->sql_query($sql);
+
+ $db->sql_transaction('commit');
+ }
}
+ // This should never happen
if (!$this->style)
{
- trigger_error('NO_STYLE_DATA', E_USER_ERROR);
+ trigger_error($this->language->lang('NO_STYLE_DATA', $this->data['user_style'], $this->data['user_id']), E_USER_ERROR);
}
// Now parse the cfg file and cache it
@@ -332,7 +377,7 @@ class user extends \phpbb\session
}
// Is board disabled and user not an admin or moderator?
- if ($config['board_disable'] && !defined('IN_LOGIN') && !defined('SKIP_CHECK_DISABLED') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
+ if ($config['board_disable'] && !defined('IN_INSTALL') && !defined('IN_LOGIN') && !defined('SKIP_CHECK_DISABLED') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
{
if ($this->data['is_bot'])
{
@@ -401,6 +446,8 @@ class user extends \phpbb\session
}
}
+ $this->is_setup_flag = true;
+
return;
}
@@ -414,103 +461,13 @@ class user extends \phpbb\session
*
* If the first parameter is an array, the elements are used as keys and subkeys to get the language entry:
* Example: <samp>$user->lang(array('datetime', 'AGO'), 1)</samp> uses $user->lang['datetime']['AGO'] as language entry.
+ *
+ * @deprecated 3.2.0-dev (To be removed 4.0.0)
*/
function lang()
{
$args = func_get_args();
- $key = $args[0];
-
- if (is_array($key))
- {
- $lang = &$this->lang[array_shift($key)];
-
- foreach ($key as $_key)
- {
- $lang = &$lang[$_key];
- }
- }
- else
- {
- $lang = &$this->lang[$key];
- }
-
- // Return if language string does not exist
- if (!isset($lang) || (!is_string($lang) && !is_array($lang)))
- {
- return $key;
- }
-
- // If the language entry is a string, we simply mimic sprintf() behaviour
- if (is_string($lang))
- {
- if (sizeof($args) == 1)
- {
- return $lang;
- }
-
- // Replace key with language entry and simply pass along...
- $args[0] = $lang;
- return call_user_func_array('sprintf', $args);
- }
- else if (sizeof($lang) == 0)
- {
- // If the language entry is an empty array, we just return the language key
- return $args[0];
- }
-
- // It is an array... now handle different nullar/singular/plural forms
- $key_found = false;
-
- // We now get the first number passed and will select the key based upon this number
- for ($i = 1, $num_args = sizeof($args); $i < $num_args; $i++)
- {
- if (is_int($args[$i]) || is_float($args[$i]))
- {
- if ($args[$i] == 0 && isset($lang[0]))
- {
- // We allow each translation using plural forms to specify a version for the case of 0 things,
- // so that "0 users" may be displayed as "No users".
- $key_found = 0;
- break;
- }
- else
- {
- $use_plural_form = $this->get_plural_form($args[$i]);
- if (isset($lang[$use_plural_form]))
- {
- // The key we should use exists, so we use it.
- $key_found = $use_plural_form;
- }
- else
- {
- // If the key we need to use does not exist, we fall back to the previous one.
- $numbers = array_keys($lang);
-
- foreach ($numbers as $num)
- {
- if ($num > $use_plural_form)
- {
- break;
- }
-
- $key_found = $num;
- }
- }
- break;
- }
- }
- }
-
- // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form)
- if ($key_found === false)
- {
- $numbers = array_keys($lang);
- $key_found = end($numbers);
- }
-
- // Use the language string we determined and pass it to sprintf()
- $args[0] = $lang[$key_found];
- return call_user_func_array('sprintf', $args);
+ return call_user_func_array(array($this->language, 'lang'), $args);
}
/**
@@ -520,24 +477,22 @@ class user extends \phpbb\session
* @param $number int|float The number we want to get the plural case for. Float numbers are floored.
* @param $force_rule mixed False to use the plural rule of the language package
* or an integer to force a certain plural rule
- * @return int The plural-case we need to use for the number plural-rule combination
+ * @return int|bool The plural-case we need to use for the number plural-rule combination, false if $force_rule
+ * was invalid.
+ *
+ * @deprecated: 3.2.0-dev (To be removed: 3.3.0)
*/
function get_plural_form($number, $force_rule = false)
{
- $number = (int) $number;
-
- // Default to English system
- $plural_rule = ($force_rule !== false) ? $force_rule : ((isset($this->lang['PLURAL_RULE'])) ? $this->lang['PLURAL_RULE'] : 1);
-
- return phpbb_get_plural_form($plural_rule, $number);
+ return $this->language->get_plural_form($number, $force_rule);
}
/**
* Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
*
* @param mixed $lang_set specifies the language entries to include
- * @param bool $use_db internal variable for recursion, do not use
- * @param bool $use_help internal variable for recursion, do not use
+ * @param bool $use_db internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 3.3.0)
+ * @param bool $use_help internal variable for recursion, do not use @deprecated 3.2.0-dev (To be removed: 3.3.0)
* @param string $ext_name The extension to load language from, or empty for core files
*
* Examples:
@@ -548,11 +503,14 @@ class user extends \phpbb\session
* $lang_set = 'posting'
* $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
* </code>
+ *
+ * Note: $use_db and $use_help should be removed. The old function was kept for BC purposes,
+ * so the BC logic is handled here.
+ *
+ * @deprecated: 3.2.0-dev (To be removed: 3.3.0)
*/
function add_lang($lang_set, $use_db = false, $use_help = false, $ext_name = '')
{
- global $phpEx;
-
if (is_array($lang_set))
{
foreach ($lang_set as $key => $lang_file)
@@ -563,6 +521,7 @@ class user extends \phpbb\session
if ($key == 'db')
{
+ // This is never used
$this->add_lang($lang_file, true, $use_help, $ext_name);
}
else if ($key == 'help')
@@ -571,7 +530,7 @@ class user extends \phpbb\session
}
else if (!is_array($lang_file))
{
- $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help, $ext_name);
+ $this->set_lang($lang_file, $use_help, $ext_name);
}
else
{
@@ -582,8 +541,37 @@ class user extends \phpbb\session
}
else if ($lang_set)
{
- $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help, $ext_name);
+ $this->set_lang($lang_set, $use_help, $ext_name);
+ }
+ }
+
+ /**
+ * BC function for loading language files
+ *
+ * @deprecated 3.2.0-dev (To be removed: 3.3.0)
+ */
+ private function set_lang($lang_set, $use_help, $ext_name)
+ {
+ if (empty($ext_name))
+ {
+ $ext_name = null;
+ }
+
+ if ($use_help && strpos($lang_set, '/') !== false)
+ {
+ $component = dirname($lang_set) . '/help_' . basename($lang_set);
+
+ if ($component[0] === '/')
+ {
+ $component = substr($component, 1);
+ }
}
+ else
+ {
+ $component = (($use_help) ? 'help_' : '') . $lang_set;
+ }
+
+ $this->language->add_lang($component, $ext_name);
}
/**
@@ -593,6 +581,10 @@ class user extends \phpbb\session
* @param mixed $lang_set specifies the language entries to include
* @param bool $use_db internal variable for recursion, do not use
* @param bool $use_help internal variable for recursion, do not use
+ *
+ * Note: $use_db and $use_help should be removed. Kept for BC purposes.
+ *
+ * @deprecated: 3.2.0-dev (To be removed: 3.3.0)
*/
function add_lang_ext($ext_name, $lang_set, $use_db = false, $use_help = false)
{
@@ -605,109 +597,6 @@ class user extends \phpbb\session
}
/**
- * Set language entry (called by add_lang)
- * @access private
- */
- function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false, $ext_name = '')
- {
- global $phpbb_root_path, $phpEx;
-
- // Make sure the language name is set (if the user setup did not happen it is not set)
- if (!$this->lang_name)
- {
- global $config;
- $this->lang_name = basename($config['default_lang']);
- }
-
- // $lang == $this->lang
- // $help == $this->help
- // - add appropriate variables here, name them as they are used within the language file...
- if (!$use_db)
- {
- if ($use_help && strpos($lang_file, '/') !== false)
- {
- $filename = dirname($lang_file) . '/help_' . basename($lang_file);
- }
- else
- {
- $filename = (($use_help) ? 'help_' : '') . $lang_file;
- }
-
- if ($ext_name)
- {
- global $phpbb_extension_manager;
- $ext_path = $phpbb_extension_manager->get_extension_path($ext_name, true);
-
- $lang_path = $ext_path . 'language/';
- }
- else
- {
- $lang_path = $this->lang_path;
- }
-
- if (strpos($phpbb_root_path . $filename, $lang_path) === 0)
- {
- $language_filename = $phpbb_root_path . $filename;
- }
- else
- {
- $language_filename = $lang_path . $this->lang_name . '/' . $filename . '.' . $phpEx;
- }
-
- // If we are in install, try to use the updated version, when available
- $install_language_filename = str_replace('language/', 'install/update/new/language/', $language_filename);
- if (defined('IN_INSTALL') && file_exists($install_language_filename))
- {
- $language_filename = $install_language_filename;
- }
-
- if (!file_exists($language_filename))
- {
- global $config;
-
- if ($this->lang_name == 'en')
- {
- // The user's selected language is missing the file, the board default's language is missing the file, and the file doesn't exist in /en.
- $language_filename = str_replace($lang_path . 'en', $lang_path . $this->data['user_lang'], $language_filename);
- trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR);
- }
- else if ($this->lang_name == basename($config['default_lang']))
- {
- // Fall back to the English Language
- $reset_lang_name = $this->lang_name;
- $this->lang_name = 'en';
- $this->set_lang($lang, $help, $lang_file, $use_db, $use_help, $ext_name);
- $this->lang_name = $reset_lang_name;
- }
- else if ($this->lang_name == $this->data['user_lang'])
- {
- // Fall back to the board default language
- $reset_lang_name = $this->lang_name;
- $this->lang_name = basename($config['default_lang']);
- $this->set_lang($lang, $help, $lang_file, $use_db, $use_help, $ext_name);
- $this->lang_name = $reset_lang_name;
- }
-
- return;
- }
-
- // Do not suppress error if in DEBUG mode
- $include_result = (defined('DEBUG')) ? (include $language_filename) : (@include $language_filename);
-
- if ($include_result === false)
- {
- trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR);
- }
- }
- else if ($use_db)
- {
- // Get Database Language Strings
- // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed
- // For example: help:faq, posting
- }
- }
-
- /**
* Format user date
*
* @param int $gmepoch unix timestamp
@@ -718,6 +607,7 @@ class user extends \phpbb\session
*/
function format_date($gmepoch, $format = false, $forcedate = false)
{
+ global $phpbb_dispatcher;
static $utc;
if (!isset($utc))
@@ -725,10 +615,34 @@ class user extends \phpbb\session
$utc = new \DateTimeZone('UTC');
}
- $time = new $this->datetime($this, '@' . (int) $gmepoch, $utc);
- $time->setTimezone($this->timezone);
+ $format_date_override = false;
+ $function_arguments = func_get_args();
+ /**
+ * Execute code and/or override format_date()
+ *
+ * To override the format_date() function generated value
+ * set $format_date_override to new return value
+ *
+ * @event core.user_format_date_override
+ * @var DateTimeZone utc Is DateTimeZone in UTC
+ * @var array function_arguments is array comprising a function's argument list
+ * @var string format_date_override Shall we return custom format (string) or not (false)
+ * @since 3.2.1-RC1
+ */
+ $vars = array('utc', 'function_arguments', 'format_date_override');
+ extract($phpbb_dispatcher->trigger_event('core.user_format_date_override', compact($vars)));
- return $time->format($format, $forcedate);
+ if (!$format_date_override)
+ {
+ $time = new $this->datetime($this, '@' . (int) $gmepoch, $utc);
+ $time->setTimezone($this->timezone);
+
+ return $time->format($format, $forcedate);
+ }
+ else
+ {
+ return $format_date_override;
+ }
}
/**
@@ -816,7 +730,7 @@ class user extends \phpbb\session
if ($alt)
{
- $alt = $this->lang($alt);
+ $alt = $this->language->lang($alt);
$title = ' title="' . $alt . '"';
}
return '<span class="imageset ' . $img . '"' . $title . '>' . $alt . '</span>';
@@ -877,8 +791,6 @@ class user extends \phpbb\session
*/
function leave_newly_registered()
{
- global $db;
-
if (empty($this->data['user_new']))
{
return false;
diff --git a/phpBB/phpbb/user_loader.php b/phpBB/phpbb/user_loader.php
index 967d96d73a..9297450f3e 100644
--- a/phpBB/phpbb/user_loader.php
+++ b/phpBB/phpbb/user_loader.php
@@ -64,8 +64,9 @@ class user_loader
* Load user helper
*
* @param array $user_ids
+ * @param array $ignore_types user types to ignore
*/
- public function load_users(array $user_ids)
+ public function load_users(array $user_ids, array $ignore_types = array())
{
$user_ids[] = ANONYMOUS;
@@ -75,11 +76,12 @@ class user_loader
// Do not load users we already have in $this->users
$user_ids = array_diff($user_ids, array_keys($this->users));
- if (sizeof($user_ids))
+ if (count($user_ids))
{
$sql = 'SELECT *
FROM ' . $this->users_table . '
- WHERE ' . $this->db->sql_in_set('user_id', $user_ids);
+ WHERE ' . $this->db->sql_in_set('user_id', $user_ids) . '
+ AND ' . $this->db->sql_in_set('user_type', $ignore_types, true, true);
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
@@ -175,7 +177,7 @@ class user_loader
/**
* Get avatar
*
- * @param int $user_id User ID of the user you want to retreive the avatar for
+ * @param int $user_id User ID of the user you want to retrieve the avatar for
* @param bool $query Should we query the database if this user has not yet been loaded?
* Typically this should be left as false and you should make sure
* you load users ahead of time with load_users()
@@ -189,7 +191,14 @@ class user_loader
return '';
}
- return phpbb_get_avatar(\phpbb\avatar\manager::clean_row($user, 'user'), 'USER_AVATAR', false, $lazy);
+ $row = array(
+ 'avatar' => $user['user_avatar'],
+ 'avatar_type' => $user['user_avatar_type'],
+ 'avatar_width' => $user['user_avatar_width'],
+ 'avatar_height' => $user['user_avatar_height'],
+ );
+
+ return phpbb_get_avatar($row, 'USER_AVATAR', false, $lazy);
}
/**
diff --git a/phpBB/phpbb/version_helper.php b/phpBB/phpbb/version_helper.php
index 7e5edbf522..a73fbfbfbe 100644
--- a/phpBB/phpbb/version_helper.php
+++ b/phpBB/phpbb/version_helper.php
@@ -13,6 +13,8 @@
namespace phpbb;
+use phpbb\exception\version_check_exception;
+
/**
* Class to handle version checking and comparison
*/
@@ -58,9 +60,6 @@ class version_helper
/** @var \phpbb\file_downloader */
protected $file_downloader;
- /** @var \phpbb\user */
- protected $user;
-
protected $version_schema = array(
'stable' => array(
'current' => 'version',
@@ -84,14 +83,12 @@ class version_helper
* @param \phpbb\cache\service $cache
* @param \phpbb\config\config $config
* @param \phpbb\file_downloader $file_downloader
- * @param \phpbb\user $user
*/
- public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader, \phpbb\user $user)
+ public function __construct(\phpbb\cache\service $cache, \phpbb\config\config $config, \phpbb\file_downloader $file_downloader)
{
$this->cache = $cache;
$this->config = $config;
$this->file_downloader = $file_downloader;
- $this->user = $user;
if (defined('PHPBB_QA'))
{
@@ -192,7 +189,7 @@ class version_helper
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
* @return string
- * @throws \RuntimeException
+ * @throws version_check_exception
*/
public function get_latest_on_current_branch($force_update = false, $force_cache = false)
{
@@ -329,7 +326,7 @@ class version_helper
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
* @return array
- * @throws \RuntimeException
+ * @throws version_check_exception
*/
public function get_suggested_updates($force_update = false, $force_cache = false)
{
@@ -350,7 +347,7 @@ class version_helper
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
* @return array Version info
- * @throws \RuntimeException
+ * @throws version_check_exception
*/
public function get_versions_matching_stability($force_update = false, $force_cache = false)
{
@@ -370,7 +367,7 @@ class version_helper
* @param bool $force_update Ignores cached data. Defaults to false.
* @param bool $force_cache Force the use of the cache. Override $force_update.
* @return array Version info, includes stable and unstable data
- * @throws \RuntimeException
+ * @throws version_check_exception
*/
public function get_versions($force_update = false, $force_cache = false)
{
@@ -380,23 +377,16 @@ class version_helper
if ($info === false && $force_cache)
{
- throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL'));
+ throw new version_check_exception('VERSIONCHECK_FAIL');
}
else if ($info === false || $force_update)
{
- try {
- $info = $this->file_downloader->get($this->host, $this->path, $this->file, $this->use_ssl ? 443 : 80);
- }
- catch (\phpbb\exception\runtime_exception $exception)
- {
- $prepare_parameters = array_merge(array($exception->getMessage()), $exception->get_parameters());
- throw new \RuntimeException(call_user_func_array(array($this->user, 'lang'), $prepare_parameters));
- }
+ $info = $this->file_downloader->get($this->host, $this->path, $this->file, $this->use_ssl ? 443 : 80);
$error_string = $this->file_downloader->get_error_string();
if (!empty($error_string))
{
- throw new \RuntimeException($error_string);
+ throw new version_check_exception($error_string);
}
$info = json_decode($info, true);
@@ -413,9 +403,7 @@ class version_helper
if (empty($info['stable']) && empty($info['unstable']))
{
- $this->user->add_lang('acp/common');
-
- throw new \RuntimeException($this->user->lang('VERSIONCHECK_FAIL'));
+ throw new version_check_exception('VERSIONCHECK_FAIL');
}
$info['stable'] = (empty($info['stable'])) ? array() : $info['stable'];
@@ -436,6 +424,7 @@ class version_helper
* and cleaned by this method
*
* @return array Versions info array
+ * @throws version_check_exception
*/
public function validate_versions($versions_info)
{
@@ -483,7 +472,7 @@ class version_helper
if (!isset($this->version_schema[$stability_type][$key]))
{
unset($version_data[$key]);
- throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_ENTRY'));
+ throw new version_check_exception('VERSIONCHECK_INVALID_ENTRY');
}
switch ($this->version_schema[$stability_type][$key])
@@ -496,20 +485,20 @@ class version_helper
if (!empty($value) && !preg_match('#^' . get_preg_expression('url') . '$#iu', $value) &&
!preg_match('#^' . get_preg_expression('www_url') . '$#iu', $value))
{
- throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_URL'));
+ throw new version_check_exception('VERSIONCHECK_INVALID_URL');
}
break;
case 'version':
if (!empty($value) && !preg_match(get_preg_expression('semantic_version'), $value))
{
- throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_VERSION'));
+ throw new version_check_exception('VERSIONCHECK_INVALID_VERSION');
}
break;
default:
// Shouldn't be possible to trigger this
- throw new \RuntimeException($this->user->lang('VERSIONCHECK_INVALID_ENTRY'));
+ throw new version_check_exception('VERSIONCHECK_INVALID_ENTRY');
}
}
}
diff --git a/phpBB/phpbb/viewonline_helper.php b/phpBB/phpbb/viewonline_helper.php
index b722f9d911..89915f2228 100644
--- a/phpBB/phpbb/viewonline_helper.php
+++ b/phpBB/phpbb/viewonline_helper.php
@@ -18,13 +18,13 @@ namespace phpbb;
*/
class viewonline_helper
{
- /** @var \phpbb\filesystem */
+ /** @var \phpbb\filesystem\filesystem_interface */
protected $filesystem;
/**
- * @param \phpbb\filesystem $filesystem
+ * @param \phpbb\filesystem\filesystem_interface $filesystem phpBB's filesystem service
*/
- public function __construct(\phpbb\filesystem $filesystem)
+ public function __construct(\phpbb\filesystem\filesystem_interface $filesystem)
{
$this->filesystem = $filesystem;
}
diff --git a/phpBB/posting.php b/phpBB/posting.php
index 35c1f84fa3..57b52320a3 100644
--- a/phpBB/posting.php
+++ b/phpBB/posting.php
@@ -29,11 +29,10 @@ $auth->acl($user->data);
// Grab only parameters needed here
-$post_id = request_var('p', 0);
-$topic_id = request_var('t', 0);
-$forum_id = request_var('f', 0);
-$draft_id = request_var('d', 0);
-$lastclick = request_var('lastclick', 0);
+$post_id = $request->variable('p', 0);
+$topic_id = $request->variable('t', 0);
+$forum_id = $request->variable('f', 0);
+$draft_id = $request->variable('d', 0);
$preview = (isset($_POST['preview'])) ? true : false;
$save = (isset($_POST['save'])) ? true : false;
@@ -43,7 +42,7 @@ $cancel = (isset($_POST['cancel']) && !isset($_POST['save'])) ? true : false;
$refresh = (isset($_POST['add_file']) || isset($_POST['delete_file']) || isset($_POST['cancel_unglobalise']) || $save || $load || $preview);
$submit = $request->is_set_post('post') && !$refresh && !$preview;
-$mode = request_var('mode', '');
+$mode = $request->variable('mode', '');
// If the user is not allowed to delete the post, we try to soft delete it, so we overwrite the mode here.
if ($mode == 'delete' && (($confirm && !$request->is_set_post('delete_permanent')) || !$auth->acl_gets('f_delete', 'm_delete', $forum_id)))
@@ -68,7 +67,6 @@ $current_time = time();
* @var int topic_id ID of the topic
* @var int forum_id ID of the forum
* @var int draft_id ID of the draft
-* @var int lastclick Timestamp of when the form was last loaded
* @var bool submit Whether or not the form has been submitted
* @var bool preview Whether or not the post is being previewed
* @var bool save Whether or not a draft is being saved
@@ -85,13 +83,13 @@ $current_time = time();
* language keys.
* @since 3.1.0-a1
* @changed 3.1.2-RC1 Removed 'delete' var as it does not exist
+* @changed 3.2.4-RC1 Remove unused 'lastclick' var
*/
$vars = array(
'post_id',
'topic_id',
'forum_id',
'draft_id',
- 'lastclick',
'submit',
'preview',
'save',
@@ -104,7 +102,7 @@ $vars = array(
extract($phpbb_dispatcher->trigger_event('core.modify_posting_parameters', compact($vars)));
// Was cancel pressed? If so then redirect to the appropriate page
-if ($cancel || ($current_time - $lastclick < 2 && $submit))
+if ($cancel)
{
$f = ($forum_id) ? 'f=' . $forum_id . '&amp;' : '';
$redirect = ($post_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $f . 'p=' . $post_id) . '#p' . $post_id : (($topic_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $f . 't=' . $topic_id) : (($forum_id) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) : append_sid("{$phpbb_root_path}index.$phpEx")));
@@ -116,6 +114,7 @@ if (in_array($mode, array('post', 'reply', 'quote', 'edit', 'delete')) && !$foru
trigger_error('NO_FORUM');
}
+/* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
// We need to know some basic information in all cases before we do anything.
@@ -223,6 +222,25 @@ if (!$post_data)
trigger_error(($mode == 'post' || $mode == 'bump' || $mode == 'reply') ? 'NO_TOPIC' : 'NO_POST');
}
+/**
+* This event allows you to bypass reply/quote test of an unapproved post.
+*
+* @event core.posting_modify_row_data
+* @var array post_data All post data from database
+* @var string mode What action to take if the form has been submitted
+* post|reply|quote|edit|delete|bump|smilies|popup
+* @var int topic_id ID of the topic
+* @var int forum_id ID of the forum
+* @since 3.2.8-RC1
+*/
+$vars = array(
+ 'post_data',
+ 'mode',
+ 'topic_id',
+ 'forum_id',
+);
+extract($phpbb_dispatcher->trigger_event('core.posting_modify_row_data', compact($vars)));
+
// Not able to reply to unapproved posts/topics
// TODO: add more descriptive language key
if ($auth->acl_get('m_approve', $forum_id) && ((($mode == 'reply' || $mode == 'bump') && $post_data['topic_visibility'] != ITEM_APPROVED) || ($mode == 'quote' && $post_data['post_visibility'] != ITEM_APPROVED)))
@@ -238,12 +256,6 @@ if ($mode == 'popup')
$user->setup(array('posting', 'mcp', 'viewtopic'), $post_data['forum_style']);
-if ($config['enable_post_confirm'] && !$user->data['is_registered'])
-{
- $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']);
- $captcha->init(CONFIRM_POST);
-}
-
// Use post_row values in favor of submitted ones...
$forum_id = (!empty($post_data['forum_id'])) ? (int) $post_data['forum_id'] : (int) $forum_id;
$topic_id = (!empty($post_data['topic_id'])) ? (int) $post_data['topic_id'] : (int) $topic_id;
@@ -353,7 +365,6 @@ switch ($mode)
* @var int topic_id ID of the topic
* @var int forum_id ID of the forum
* @var int draft_id ID of the draft
-* @var int lastclick Timestamp of when the form was last loaded
* @var bool submit Whether or not the form has been submitted
* @var bool preview Whether or not the post is being previewed
* @var bool save Whether or not a draft is being saved
@@ -369,13 +380,13 @@ switch ($mode)
* @var array post_data All post data from database
* @since 3.1.3-RC1
* @changed 3.1.10-RC1 Added post_data
+* @changed 3.2.4-RC1 Remove unused 'lastclick' var
*/
$vars = array(
'post_id',
'topic_id',
'forum_id',
'draft_id',
- 'lastclick',
'submit',
'preview',
'save',
@@ -410,6 +421,12 @@ if (!$is_authed || !empty($error))
login_box('', $message);
}
+if ($config['enable_post_confirm'] && !$user->data['is_registered'])
+{
+ $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']);
+ $captcha->init(CONFIRM_POST);
+}
+
// Is the user able to post within this forum?
if ($post_data['forum_type'] != FORUM_POST && in_array($mode, array('post', 'bump', 'quote', 'reply')))
{
@@ -487,7 +504,7 @@ if ($mode == 'delete' || $mode == 'soft_delete')
if ($mode == 'bump')
{
if ($bump_time = bump_topic_allowed($forum_id, $post_data['topic_bumped'], $post_data['topic_last_post_time'], $post_data['topic_poster'], $post_data['topic_last_poster_id'])
- && check_link_hash(request_var('hash', ''), "topic_{$post_data['topic_id']}"))
+ && check_link_hash($request->variable('hash', ''), "topic_{$post_data['topic_id']}"))
{
$meta_url = phpbb_bump_topic($forum_id, $topic_id, $post_data, $current_time);
meta_refresh(3, $meta_url);
@@ -546,6 +563,27 @@ if ($post_data['poll_start'])
$db->sql_freeresult($result);
}
+/**
+* This event allows you to modify the post data before parsing
+*
+* @event core.posting_modify_post_data
+* @var int forum_id ID of the forum
+* @var string mode What action to take if the form has been submitted
+* post|reply|quote|edit|delete|bump|smilies|popup
+* @var array post_data Array with post data
+* @var int post_id ID of the post
+* @var int topic_id ID of the topic
+* @since 3.2.2-RC1
+*/
+$vars = array(
+ 'forum_id',
+ 'mode',
+ 'post_data',
+ 'post_id',
+ 'topic_id',
+);
+extract($phpbb_dispatcher->trigger_event('core.posting_modify_post_data', compact($vars)));
+
if ($mode == 'edit')
{
$original_poll_data = array(
@@ -559,13 +597,15 @@ if ($mode == 'edit')
);
}
-$orig_poll_options_size = sizeof($post_data['poll_options']);
+$orig_poll_options_size = count($post_data['poll_options']);
$message_parser = new parse_message();
+/* @var $plupload \phpbb\plupload\plupload */
$plupload = $phpbb_container->get('plupload');
+
+/* @var $mimetype_guesser \phpbb\mimetype\guesser */
$mimetype_guesser = $phpbb_container->get('mimetype.guesser');
$message_parser->set_plupload($plupload);
-$message_parser->set_mimetype_guesser($mimetype_guesser);
if (isset($post_data['post_text']))
{
@@ -576,6 +616,20 @@ if (isset($post_data['post_text']))
// Set some default variables
$uninit = array('post_attachment' => 0, 'poster_id' => $user->data['user_id'], 'enable_magic_url' => 0, 'topic_status' => 0, 'topic_type' => POST_NORMAL, 'post_subject' => '', 'topic_title' => '', 'post_time' => 0, 'post_edit_reason' => '', 'notify_set' => 0);
+/**
+* This event allows you to modify the default variables for post_data, and unset them in post_data if needed
+*
+* @event core.posting_modify_default_variables
+* @var array post_data Array with post data
+* @var array uninit Array with default vars to put into post_data, if they aren't there
+* @since 3.2.5-RC1
+*/
+$vars = array(
+ 'post_data',
+ 'uninit',
+);
+extract($phpbb_dispatcher->trigger_event('core.posting_modify_default_variables', compact($vars)));
+
foreach ($uninit as $var_name => $default_value)
{
if (!isset($post_data[$var_name]))
@@ -678,21 +732,24 @@ $quote_status = true;
// Save Draft
if ($save && $user->data['is_registered'] && $auth->acl_get('u_savedrafts') && ($mode == 'reply' || $mode == 'post' || $mode == 'quote'))
{
- $subject = utf8_normalize_nfc(request_var('subject', '', true));
+ $subject = $request->variable('subject', '', true);
$subject = (!$subject && $mode != 'post') ? $post_data['topic_title'] : $subject;
- $message = utf8_normalize_nfc(request_var('message', '', true));
+ $message = $request->variable('message', '', true);
if ($subject && $message)
{
if (confirm_box(true))
{
+ $message_parser->message = $message;
+ $message_parser->parse($post_data['enable_bbcode'], ($config['allow_post_links']) ? $post_data['enable_urls'] : false, $post_data['enable_smilies'], $img_status, $flash_status, $quote_status, $config['allow_post_links']);
+
$sql = 'INSERT INTO ' . DRAFTS_TABLE . ' ' . $db->sql_build_array('INSERT', array(
'user_id' => (int) $user->data['user_id'],
'topic_id' => (int) $topic_id,
'forum_id' => (int) $forum_id,
'save_time' => (int) $current_time,
'draft_subject' => (string) $subject,
- 'draft_message' => (string) $message)
+ 'draft_message' => (string) $message_parser->message)
);
$db->sql_query($sql);
@@ -750,11 +807,11 @@ if ($save && $user->data['is_registered'] && $auth->acl_get('u_savedrafts') && (
if (is_bool($default))
{
// Use the string representation
- $hidden_fields[$name] = request_var($name, '');
+ $hidden_fields[$name] = $request->variable($name, '');
}
else
{
- $hidden_fields[$name] = request_var($name, $default);
+ $hidden_fields[$name] = $request->variable($name, $default);
}
}
@@ -808,23 +865,25 @@ if ($load && ($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_
load_drafts($topic_id, $forum_id);
}
+/** @var \phpbb\textformatter\utils_interface $bbcode_utils */
+$bbcode_utils = $phpbb_container->get('text_formatter.utils');
if ($submit || $preview || $refresh)
{
- $post_data['topic_cur_post_id'] = request_var('topic_cur_post_id', 0);
- $post_data['post_subject'] = utf8_normalize_nfc(request_var('subject', '', true));
- $message_parser->message = utf8_normalize_nfc(request_var('message', '', true));
+ $post_data['topic_cur_post_id'] = $request->variable('topic_cur_post_id', 0);
+ $post_data['post_subject'] = $request->variable('subject', '', true);
+ $message_parser->message = $request->variable('message', '', true);
- $post_data['username'] = utf8_normalize_nfc(request_var('username', $post_data['username'], true));
- $post_data['post_edit_reason'] = ($request->variable('edit_reason', false, false, \phpbb\request\request_interface::POST) && $mode == 'edit' && $auth->acl_get('m_edit', $forum_id)) ? utf8_normalize_nfc(request_var('edit_reason', '', true)) : '';
+ $post_data['username'] = $request->variable('username', $post_data['username'], true);
+ $post_data['post_edit_reason'] = ($request->variable('edit_reason', false, false, \phpbb\request\request_interface::POST) && $mode == 'edit' && $auth->acl_get('m_edit', $forum_id)) ? $request->variable('edit_reason', '', true) : '';
$post_data['orig_topic_type'] = $post_data['topic_type'];
- $post_data['topic_type'] = request_var('topic_type', (($mode != 'post') ? (int) $post_data['topic_type'] : POST_NORMAL));
- $post_data['topic_time_limit'] = request_var('topic_time_limit', (($mode != 'post') ? (int) $post_data['topic_time_limit'] : 0));
+ $post_data['topic_type'] = $request->variable('topic_type', (($mode != 'post') ? (int) $post_data['topic_type'] : POST_NORMAL));
+ $post_data['topic_time_limit'] = $request->variable('topic_time_limit', (($mode != 'post') ? (int) $post_data['topic_time_limit'] : 0));
if ($post_data['enable_icons'] && $auth->acl_get('f_icons', $forum_id))
{
- $post_data['icon_id'] = request_var('icon', (int) $post_data['icon_id']);
+ $post_data['icon_id'] = $request->variable('icon', (int) $post_data['icon_id']);
}
$post_data['enable_bbcode'] = (!$bbcode_status || isset($_POST['disable_bbcode'])) ? false : true;
@@ -856,7 +915,7 @@ if ($submit || $preview || $refresh)
}
// Delete Poll
- if ($poll_delete && $mode == 'edit' && sizeof($post_data['poll_options']) &&
+ if ($poll_delete && $mode == 'edit' && count($post_data['poll_options']) &&
((!$post_data['poll_last_vote'] && $post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)) || $auth->acl_get('m_delete', $forum_id)))
{
if ($submit && check_form_key('posting'))
@@ -889,10 +948,10 @@ if ($submit || $preview || $refresh)
}
else
{
- $post_data['poll_title'] = utf8_normalize_nfc(request_var('poll_title', '', true));
- $post_data['poll_length'] = request_var('poll_length', 0);
- $post_data['poll_option_text'] = utf8_normalize_nfc(request_var('poll_option_text', '', true));
- $post_data['poll_max_options'] = request_var('poll_max_options', 1);
+ $post_data['poll_title'] = $request->variable('poll_title', '', true);
+ $post_data['poll_length'] = $request->variable('poll_length', 0);
+ $post_data['poll_option_text'] = $request->variable('poll_option_text', '', true);
+ $post_data['poll_max_options'] = $request->variable('poll_max_options', 1);
$post_data['poll_vote_change'] = ($auth->acl_get('f_votechg', $forum_id) && $auth->acl_get('f_vote', $forum_id) && isset($_POST['poll_vote_change'])) ? 1 : 0;
}
@@ -915,7 +974,10 @@ if ($submit || $preview || $refresh)
}
// Parse Attachments - before checksum is calculated
- $message_parser->parse_attachments('fileupload', $mode, $forum_id, $submit, $preview, $refresh);
+ if ($message_parser->check_attachment_form_token($language, $request, 'posting'))
+ {
+ $message_parser->parse_attachments('fileupload', $mode, $forum_id, $submit, $preview, $refresh);
+ }
/**
* This event allows you to modify message text before parsing
@@ -964,8 +1026,8 @@ if ($submit || $preview || $refresh)
// Notify and show user the changed post
if ($mode == 'edit' && $post_data['forum_flags'] & FORUM_FLAG_POST_REVIEW)
{
- $edit_post_message_checksum = request_var('edit_post_message_checksum', '');
- $edit_post_subject_checksum = request_var('edit_post_subject_checksum', '');
+ $edit_post_message_checksum = $request->variable('edit_post_message_checksum', '');
+ $edit_post_subject_checksum = $request->variable('edit_post_subject_checksum', '');
// $post_data['post_checksum'] is the checksum of the post submitted in the meantime
// $message_md5 is the checksum of the post we're about to submit
@@ -1006,7 +1068,7 @@ if ($submit || $preview || $refresh)
// Parse message
if ($update_message)
{
- if (sizeof($message_parser->warn_msg))
+ if (count($message_parser->warn_msg))
{
$error[] = implode('<br />', $message_parser->warn_msg);
$message_parser->warn_msg = array();
@@ -1018,7 +1080,7 @@ if ($submit || $preview || $refresh)
}
// On a refresh we do not care about message parsing errors
- if (sizeof($message_parser->warn_msg) && $refresh && !$preview)
+ if (count($message_parser->warn_msg) && $refresh && !$preview)
{
$message_parser->warn_msg = array();
}
@@ -1083,9 +1145,9 @@ if ($submit || $preview || $refresh)
if ($config['enable_post_confirm'] && !$user->data['is_registered'] && in_array($mode, array('quote', 'post', 'reply')))
{
$captcha_data = array(
- 'message' => utf8_normalize_nfc(request_var('message', '', true)),
- 'subject' => utf8_normalize_nfc(request_var('subject', '', true)),
- 'username' => utf8_normalize_nfc(request_var('username', '', true)),
+ 'message' => $request->variable('message', '', true),
+ 'subject' => $request->variable('subject', '', true),
+ 'username' => $request->variable('username', '', true),
);
$vc_response = $captcha->validate($captcha_data);
if ($vc_response)
@@ -1119,12 +1181,27 @@ if ($submit || $preview || $refresh)
$error[] = $user->lang['EMPTY_SUBJECT'];
}
- // Check for out-of-bounds characters that are currently
- // not supported by utf8_bin in MySQL
- if (preg_match_all('/[\x{10000}-\x{10FFFF}]/u', $post_data['post_subject'], $matches))
+ /**
+ * Replace Emojis and other 4bit UTF-8 chars not allowed by MySQL to UCR/NCR.
+ * Using their Numeric Character Reference's Hexadecimal notation.
+ * Check the permissions for posting Emojis first.
+ */
+ if ($auth->acl_get('u_emoji'))
{
- $character_list = implode('<br />', $matches[0]);
- $error[] = $user->lang('UNSUPPORTED_CHARACTERS_SUBJECT', $character_list);
+ $post_data['post_subject'] = utf8_encode_ucr($post_data['post_subject']);
+ }
+ else
+ {
+ /**
+ * Check for out-of-bounds characters that are currently
+ * not supported by utf8_bin in MySQL
+ */
+ if (preg_match_all('/[\x{10000}-\x{10FFFF}]/u', $post_data['post_subject'], $matches))
+ {
+ $character_list = implode('<br>', $matches[0]);
+
+ $error[] = $user->lang('UNSUPPORTED_CHARACTERS_SUBJECT', $character_list);
+ }
}
$post_data['poll_last_vote'] = (isset($post_data['poll_last_vote'])) ? $post_data['poll_last_vote'] : 0;
@@ -1176,10 +1253,15 @@ if ($submit || $preview || $refresh)
$post_data['poll_title'] = '';
$post_data['poll_start'] = $post_data['poll_length'] = $post_data['poll_max_options'] = $post_data['poll_last_vote'] = $post_data['poll_vote_change'] = 0;
}
- else if (!$auth->acl_get('f_poll', $forum_id) && ($mode == 'edit') && ($post_id == $post_data['topic_first_post_id']) && ($original_poll_data['poll_title'] != ''))
+ else if (!$auth->acl_get('f_poll', $forum_id) && ($mode == 'edit') && ($post_id == $post_data['topic_first_post_id']) && !$bbcode_utils->is_empty($original_poll_data['poll_title']))
{
// We have a poll but the editing user is not permitted to create/edit it.
// So we just keep the original poll-data.
+ // Decode the poll title and options text fisrt.
+ $original_poll_data['poll_title'] = $bbcode_utils->unparse($original_poll_data['poll_title']);
+ $original_poll_data['poll_option_text'] = $bbcode_utils->unparse($original_poll_data['poll_option_text']);
+ $original_poll_data['poll_options'] = explode("\n", $original_poll_data['poll_option_text']);
+
$poll = array_merge($original_poll_data, array(
'enable_bbcode' => $post_data['enable_bbcode'],
'enable_urls' => $post_data['enable_urls'],
@@ -1203,6 +1285,9 @@ if ($submit || $preview || $refresh)
switch ($post_data['topic_type'])
{
case POST_GLOBAL:
+ $auth_option = 'f_announce_global';
+ break;
+
case POST_ANNOUNCE:
$auth_option = 'f_announce';
break;
@@ -1232,7 +1317,7 @@ if ($submit || $preview || $refresh)
}
}
- if (sizeof($message_parser->warn_msg))
+ if (count($message_parser->warn_msg))
{
$error[] = implode('<br />', $message_parser->warn_msg);
}
@@ -1254,7 +1339,6 @@ if ($submit || $preview || $refresh)
* @var array poll Array with poll data from post (must be used instead of the post_data equivalent)
* @var string mode What action to take if the form is submitted
* post|reply|quote|edit|delete|bump|smilies|popup
- * @var string page_title Title of the mode page
* @var int post_id ID of the post
* @var int topic_id ID of the topic
* @var int forum_id ID of the forum
@@ -1263,12 +1347,12 @@ if ($submit || $preview || $refresh)
* NOTE: Should be actual language strings, NOT language keys.
* @since 3.1.0-RC5
* @changed 3.1.5-RC1 Added poll array to the event
+ * @changed 3.2.0-a1 Removed undefined page_title
*/
$vars = array(
'post_data',
'poll',
'mode',
- 'page_title',
'post_id',
'topic_id',
'forum_id',
@@ -1278,7 +1362,7 @@ if ($submit || $preview || $refresh)
extract($phpbb_dispatcher->trigger_event('core.posting_modify_submission_errors', compact($vars)));
// Store message, sync counters
- if (!sizeof($error) && $submit)
+ if (!count($error) && $submit)
{
if ($submit)
{
@@ -1305,7 +1389,11 @@ if ($submit || $preview || $refresh)
$user_lock = ($auth->acl_get('f_user_lock', $forum_id) && $user->data['is_registered'] && $user->data['user_id'] == $post_data['topic_poster']) ? 'USER_' : '';
- add_log('mod', $forum_id, $topic_id, 'LOG_' . $user_lock . (($change_topic_status == ITEM_LOCKED) ? 'LOCK' : 'UNLOCK'), $post_data['topic_title']);
+ $phpbb_log->add('mod', $user->data['user_id'], $user->ip, 'LOG_' . $user_lock . (($change_topic_status == ITEM_LOCKED) ? 'LOCK' : 'UNLOCK'), false, array(
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ $post_data['topic_title']
+ ));
}
// Lock/Unlock Post Edit
@@ -1377,7 +1465,6 @@ if ($submit || $preview || $refresh)
* @var array data Array with post data going to be stored in the database
* @var string mode What action to take if the form is submitted
* post|reply|quote|edit|delete
- * @var string page_title Title of the mode page
* @var int post_id ID of the post
* @var int topic_id ID of the topic
* @var int forum_id ID of the forum
@@ -1387,13 +1474,13 @@ if ($submit || $preview || $refresh)
* NOTE: Should be actual language strings, NOT language keys.
* @since 3.1.0-RC5
* @changed 3.1.6-RC1 remove submit and error from event Submit and Error are checked previously prior to running event
+ * @change 3.2.0-a1 Removed undefined page_title
*/
$vars = array(
'post_data',
'poll',
'data',
'mode',
- 'page_title',
'post_id',
'topic_id',
'forum_id',
@@ -1415,7 +1502,6 @@ if ($submit || $preview || $refresh)
* @var array data Array with post data going to be stored in the database
* @var string mode What action to take if the form is submitted
* post|reply|quote|edit|delete
- * @var string page_title Title of the mode page
* @var int post_id ID of the post
* @var int topic_id ID of the topic
* @var int forum_id ID of the forum
@@ -1426,13 +1512,13 @@ if ($submit || $preview || $refresh)
* NOTE: Should be actual language strings, NOT language keys.
* @since 3.1.0-RC5
* @changed 3.1.6-RC1 remove submit and error from event Submit and Error are checked previously prior to running event
+ * @change 3.2.0-a1 Removed undefined page_title
*/
$vars = array(
'post_data',
'poll',
'data',
'mode',
- 'page_title',
'post_id',
'topic_id',
'forum_id',
@@ -1473,7 +1559,7 @@ if ($submit || $preview || $refresh)
}
// Preview
-if (!sizeof($error) && $preview)
+if (!count($error) && $preview)
{
$post_data['post_time'] = ($mode == 'edit') ? $post_data['post_time'] : $current_time;
@@ -1486,14 +1572,11 @@ if (!sizeof($error) && $preview)
// Signature
if ($post_data['enable_sig'] && $config['allow_sig'] && $preview_signature && $auth->acl_get('f_sigs', $forum_id))
{
- $parse_sig = new parse_message($preview_signature);
- $parse_sig->bbcode_uid = $preview_signature_uid;
- $parse_sig->bbcode_bitfield = $preview_signature_bitfield;
-
- // Not sure about parameters for bbcode/smilies/urls... in signatures
- $parse_sig->format_display($config['allow_sig_bbcode'], $config['allow_sig_links'], $config['allow_sig_smilies']);
- $preview_signature = $parse_sig->message;
- unset($parse_sig);
+ $flags = ($config['allow_sig_bbcode']) ? OPTION_FLAG_BBCODE : 0;
+ $flags |= ($config['allow_sig_links']) ? OPTION_FLAG_LINKS : 0;
+ $flags |= ($config['allow_sig_smilies']) ? OPTION_FLAG_SMILIES : 0;
+
+ $preview_signature = generate_text_for_display($preview_signature, $preview_signature_uid, $preview_signature_bitfield, $flags, false);
}
else
{
@@ -1518,7 +1601,7 @@ if (!sizeof($error) && $preview)
}
$template->assign_vars(array(
- 'S_HAS_POLL_OPTIONS' => (sizeof($post_data['poll_options'])),
+ 'S_HAS_POLL_OPTIONS' => (count($post_data['poll_options'])),
'S_IS_MULTI_CHOICE' => ($post_data['poll_max_options'] > 1) ? true : false,
'POLL_QUESTION' => $parse_poll->message,
@@ -1547,7 +1630,7 @@ if (!sizeof($error) && $preview)
}
// Attachment Preview
- if (sizeof($message_parser->attachment_data))
+ if (count($message_parser->attachment_data))
{
$template->assign_var('S_HAS_ATTACHMENTS', true);
@@ -1565,7 +1648,7 @@ if (!sizeof($error) && $preview)
unset($attachment_data);
}
- if (!sizeof($error))
+ if (!count($error))
{
$template->assign_vars(array(
'PREVIEW_SUBJECT' => $preview_subject,
@@ -1588,7 +1671,7 @@ if ($generate_quote && $config['max_quote_depth'] > 0)
}
// Decode text for message display
-$post_data['bbcode_uid'] = ($mode == 'quote' && !$preview && !$refresh && !sizeof($error)) ? $post_data['bbcode_uid'] : $message_parser->bbcode_uid;
+$post_data['bbcode_uid'] = ($mode == 'quote' && !$preview && !$refresh && !count($error)) ? $post_data['bbcode_uid'] : $message_parser->bbcode_uid;
$message_parser->decode_message($post_data['bbcode_uid']);
if ($generate_quote)
@@ -1596,38 +1679,56 @@ if ($generate_quote)
// Remove attachment bbcode tags from the quoted message to avoid mixing with the new post attachments if any
$message_parser->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#uis', '\\2', $message_parser->message);
- if ($config['allow_bbcode'])
- {
- $message_parser->message = '[quote=&quot;' . $post_data['quote_username'] . '&quot;]' . censor_text(trim($message_parser->message)) . "[/quote]\n";
- }
- else
- {
- $offset = 0;
- $quote_string = "&gt; ";
- $message = censor_text(trim($message_parser->message));
- // see if we are nesting. It's easily tricked but should work for one level of nesting
- if (strpos($message, "&gt;") !== false)
- {
- $offset = 10;
- }
- $message = utf8_wordwrap($message, 75 + $offset, "\n");
+ $quote_attributes = array(
+ 'author' => $post_data['quote_username'],
+ 'post_id' => $post_data['post_id'],
+ 'time' => $post_data['post_time'],
+ 'user_id' => $post_data['poster_id'],
+ );
- $message = $quote_string . $message;
- $message = str_replace("\n", "\n" . $quote_string, $message);
- $message_parser->message = $post_data['quote_username'] . " " . $user->lang['WROTE'] . ":\n" . $message . "\n";
- }
+ /**
+ * This event allows you to modify the quote attributes of the post being quoted
+ *
+ * @event core.posting_modify_quote_attributes
+ * @var array quote_attributes Array with quote attributes
+ * @var array post_data Array with post data
+ * @since 3.2.6-RC1
+ */
+ $vars = array(
+ 'quote_attributes',
+ 'post_data',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.posting_modify_quote_attributes', compact($vars)));
+
+ /** @var \phpbb\language\language $language */
+ $language = $phpbb_container->get('language');
+ phpbb_format_quote($language, $message_parser, $bbcode_utils, $bbcode_status, $quote_attributes);
}
if (($mode == 'reply' || $mode == 'quote') && !$submit && !$preview && !$refresh)
{
$post_data['post_subject'] = ((strpos($post_data['post_subject'], 'Re: ') !== 0) ? 'Re: ' : '') . censor_text($post_data['post_subject']);
+
+ $post_subject = $post_data['post_subject'];
+
+ /**
+ * This event allows you to modify the post subject of the post being quoted
+ *
+ * @event core.posting_modify_post_subject
+ * @var string post_subject String with the post subject already censored.
+ * @since 3.2.8-RC1
+ */
+ $vars = array('post_subject');
+ extract($phpbb_dispatcher->trigger_event('core.posting_modify_post_subject', compact($vars)));
+
+ $post_data['post_subject'] = $post_subject;
}
$attachment_data = $message_parser->attachment_data;
$filename_data = $message_parser->filename_data;
$post_data['post_text'] = $message_parser->message;
-if (sizeof($post_data['poll_options']) || !empty($post_data['poll_title']))
+if (count($post_data['poll_options']) || (isset($post_data['poll_title']) && !$bbcode_utils->is_empty($post_data['poll_title'])))
{
$message_parser->message = $post_data['poll_title'];
$message_parser->bbcode_uid = $post_data['bbcode_uid'];
@@ -1719,8 +1820,7 @@ if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($c
}
$s_hidden_fields = ($mode == 'reply' || $mode == 'quote') ? '<input type="hidden" name="topic_cur_post_id" value="' . $post_data['topic_last_post_id'] . '" />' : '';
-$s_hidden_fields .= '<input type="hidden" name="lastclick" value="' . $current_time . '" />';
-$s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '<input type="hidden" name="draft_loaded" value="' . request_var('draft_loaded', $draft_id) . '" />' : '';
+$s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '<input type="hidden" name="draft_loaded" value="' . $request->variable('draft_loaded', $draft_id) . '" />' : '';
if ($mode == 'edit')
{
@@ -1739,6 +1839,8 @@ if (isset($captcha) && $captcha->is_solved() !== false)
$form_enctype = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !$config['allow_attachments'] || !$auth->acl_get('u_attach') || !$auth->acl_get('f_attach', $forum_id)) ? '' : ' enctype="multipart/form-data"';
add_form_key('posting');
+/** @var \phpbb\controller\helper $controller_helper */
+$controller_helper = $phpbb_container->get('controller.helper');
// Build array of variables for main posting page
$page_data = array(
@@ -1750,11 +1852,11 @@ $page_data = array(
'FORUM_NAME' => $post_data['forum_name'],
'FORUM_DESC' => ($post_data['forum_desc']) ? generate_text_for_display($post_data['forum_desc'], $post_data['forum_desc_uid'], $post_data['forum_desc_bitfield'], $post_data['forum_desc_options']) : '',
'TOPIC_TITLE' => censor_text($post_data['topic_title']),
- 'MODERATORS' => (sizeof($moderators)) ? implode($user->lang['COMMA_SEPARATOR'], $moderators[$forum_id]) : '',
+ 'MODERATORS' => (count($moderators)) ? implode($user->lang['COMMA_SEPARATOR'], $moderators[$forum_id]) : '',
'USERNAME' => ((!$preview && $mode != 'quote') || $preview) ? $post_data['username'] : '',
'SUBJECT' => $post_data['post_subject'],
'MESSAGE' => $post_data['post_text'],
- 'BBCODE_STATUS' => ($bbcode_status) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'),
+ 'BBCODE_STATUS' => $user->lang(($bbcode_status ? 'BBCODE_IS_ON' : 'BBCODE_IS_OFF'), '<a href="' . $controller_helper->route('phpbb_help_bbcode_controller') . '">', '</a>'),
'IMG_STATUS' => ($img_status) ? $user->lang['IMAGES_ARE_ON'] : $user->lang['IMAGES_ARE_OFF'],
'FLASH_STATUS' => ($flash_status) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'],
'SMILIES_STATUS' => ($smilies_status) ? $user->lang['SMILIES_ARE_ON'] : $user->lang['SMILIES_ARE_OFF'],
@@ -1762,7 +1864,7 @@ $page_data = array(
'MAX_FONT_SIZE' => (int) $config['max_post_font_size'],
'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']),
'POST_DATE' => ($post_data['post_time']) ? $user->format_date($post_data['post_time']) : '',
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
+ 'ERROR' => (count($error)) ? implode('<br />', $error) : '',
'TOPIC_TIME_LIMIT' => (int) $post_data['topic_time_limit'],
'EDIT_REASON' => $request->variable('edit_reason', '', true),
'SHOW_PANEL' => $request->variable('show_panel', ''),
@@ -1822,7 +1924,7 @@ if (($mode == 'post' || ($mode == 'edit' && $post_id == $post_data['topic_first_
$page_data = array_merge($page_data, array(
'S_SHOW_POLL_BOX' => true,
'S_POLL_VOTE_CHANGE' => ($auth->acl_get('f_votechg', $forum_id) && $auth->acl_get('f_vote', $forum_id)),
- 'S_POLL_DELETE' => ($mode == 'edit' && sizeof($post_data['poll_options']) && ((!$post_data['poll_last_vote'] && $post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)) || $auth->acl_get('m_delete', $forum_id))),
+ 'S_POLL_DELETE' => ($mode == 'edit' && count($post_data['poll_options']) && ((!$post_data['poll_last_vote'] && $post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id)) || $auth->acl_get('m_delete', $forum_id))),
'S_POLL_DELETE_CHECKED' => (!empty($poll_delete)) ? true : false,
'L_POLL_OPTIONS_EXPLAIN' => $user->lang('POLL_OPTIONS_' . (($mode == 'edit') ? 'EDIT_' : '') . 'EXPLAIN', (int) $config['max_poll_options']),
diff --git a/phpBB/report.php b/phpBB/report.php
index 3ea6bb40c5..bb26b972aa 100644
--- a/phpBB/report.php
+++ b/phpBB/report.php
@@ -11,6 +11,8 @@
*
*/
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
/**
* @ignore
*/
@@ -18,321 +20,22 @@ define('IN_PHPBB', true);
$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
include($phpbb_root_path . 'common.' . $phpEx);
-include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
// Start session management
$user->session_begin();
$auth->acl($user->data);
-$user->setup('mcp');
-
-$forum_id = request_var('f', 0);
-$post_id = request_var('p', 0);
-$pm_id = request_var('pm', 0);
-$reason_id = request_var('reason_id', 0);
-$report_text = utf8_normalize_nfc(request_var('report_text', '', true));
-$user_notify = ($user->data['is_registered']) ? request_var('notify', 0) : false;
-
-$submit = (isset($_POST['submit'])) ? true : false;
-
-if (!$post_id && (!$pm_id || !$config['allow_pm_report']))
-{
- trigger_error('NO_POST_SELECTED');
-}
-
-if ($post_id)
-{
- $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;p=$post_id") . "#p$post_id";
- $return_forum_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id");
- $pm_id = 0;
-}
-else
-{
- $redirect_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&p=$pm_id");
- $return_forum_url = '';
- $post_id = 0;
- $forum_id = 0;
-}
-
-// Has the report been cancelled?
-if (isset($_POST['cancel']))
-{
- redirect($redirect_url);
-}
-
-if ($post_id)
-{
- // Grab all relevant data
- $sql = 'SELECT t.*, p.*
- FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t
- WHERE p.post_id = $post_id
- AND p.topic_id = t.topic_id";
- $result = $db->sql_query($sql);
- $report_data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$report_data)
- {
- trigger_error('POST_NOT_EXIST');
- }
-
- $forum_id = (int) $report_data['forum_id'];
- $topic_id = (int) $report_data['topic_id'];
- $reported_post_text = $report_data['post_text'];
- $reported_post_bitfield = $report_data['bbcode_bitfield'];
- $reported_post_uid = $report_data['bbcode_uid'];
- $reported_post_enable_bbcode = $report_data['enable_bbcode'];
- $reported_post_enable_smilies = $report_data['enable_smilies'];
- $reported_post_enable_magic_url = $report_data['enable_magic_url'];
-
- $sql = 'SELECT *
- FROM ' . FORUMS_TABLE . '
- WHERE forum_id = ' . $forum_id;
- $result = $db->sql_query($sql);
- $forum_data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$forum_data)
- {
- trigger_error('FORUM_NOT_EXIST');
- }
-
- // Check required permissions
- $acl_check_ary = array('f_list' => 'POST_NOT_EXIST', 'f_read' => 'USER_CANNOT_READ', 'f_report' => 'USER_CANNOT_REPORT');
-
- /**
- * This event allows you to do extra auth checks and verify if the user
- * has the required permissions
- *
- * @event core.report_post_auth
- * @var array forum_data All data available from the forums table on this post's forum
- * @var array report_data All data available from the topics and the posts tables on this post (and its topic)
- * @var array acl_check_ary An array with the ACL to be tested. The evaluation is made in the same order as the array is sorted
- * The key is the ACL name and the value is the language key for the error message.
- * @since 3.1.3-RC1
- */
- $vars = array(
- 'forum_data',
- 'report_data',
- 'acl_check_ary',
- );
- extract($phpbb_dispatcher->trigger_event('core.report_post_auth', compact($vars)));
-
- foreach ($acl_check_ary as $acl => $error)
- {
- if (!$auth->acl_get($acl, $forum_id))
- {
- trigger_error($error);
- }
- }
- unset($acl_check_ary);
-
- if ($report_data['post_reported'])
- {
- $message = $user->lang['ALREADY_REPORTED'];
- $message .= '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $redirect_url . '">', '</a>');
- $message .= '<br /><br />' . sprintf($user->lang['RETURN_FORUM'], '<a href="' . $return_forum_url . '">', '</a>');
- trigger_error($message);
- }
-}
-else
-{
- // Grab all relevant data
- $sql = 'SELECT p.*, pt.*
- FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . " pt
- WHERE p.msg_id = $pm_id
- AND p.msg_id = pt.msg_id
- AND (p.author_id = " . $user->data['user_id'] . " OR pt.user_id = " . $user->data['user_id'] . ")";
- $result = $db->sql_query($sql);
- $report_data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$report_data)
- {
- $user->add_lang('ucp');
- trigger_error('NO_MESSAGE');
- }
-
- if ($report_data['message_reported'])
- {
- $message = $user->lang['ALREADY_REPORTED_PM'];
- $message .= '<br /><br />' . sprintf($user->lang['RETURN_PM'], '<a href="' . $redirect_url . '">', '</a>');
- trigger_error($message);
- }
-
- $reported_post_text = $report_data['message_text'];
- $reported_post_bitfield = $report_data['bbcode_bitfield'];
- $reported_post_uid = $report_data['bbcode_uid'];
- $reported_post_enable_bbcode = $report_data['enable_bbcode'];
- $reported_post_enable_smilies = $report_data['enable_smilies'];
- $reported_post_enable_magic_url = $report_data['enable_magic_url'];
-}
-
-if ($config['enable_post_confirm'] && !$user->data['is_registered'])
-{
- $captcha = $phpbb_container->get('captcha.factory')->get_instance($config['captcha_plugin']);
- $captcha->init(CONFIRM_REPORT);
-}
-
-$error = array();
-$s_hidden_fields = '';
-
-// Submit report?
-if ($submit && $reason_id)
-{
- if (isset($captcha))
- {
- $visual_confirmation_response = $captcha->validate();
- if ($visual_confirmation_response)
- {
- $error[] = $visual_confirmation_response;
- }
- }
-
- $sql = 'SELECT *
- FROM ' . REPORTS_REASONS_TABLE . "
- WHERE reason_id = $reason_id";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- if (!$row || (!$report_text && strtolower($row['reason_title']) == 'other'))
- {
- $error[] = $user->lang('EMPTY_REPORT');
- }
+$post_id = $request->variable('p', 0);
+$pm_id = $request->variable('pm', 0);
- if (!sizeof($error))
- {
- if (isset($captcha))
- {
- $captcha->reset();
- }
+$redirect_route_name = ($pm_id === 0) ? 'phpbb_report_post_controller' : 'phpbb_report_pm_controller';
- $sql_ary = array(
- 'reason_id' => (int) $reason_id,
- 'post_id' => $post_id,
- 'pm_id' => $pm_id,
- 'user_id' => (int) $user->data['user_id'],
- 'user_notify' => (int) $user_notify,
- 'report_closed' => 0,
- 'report_time' => (int) time(),
- 'report_text' => (string) $report_text,
- 'reported_post_text' => $reported_post_text,
- 'reported_post_uid' => $reported_post_uid,
- 'reported_post_bitfield' => $reported_post_bitfield,
- 'reported_post_enable_bbcode' => $reported_post_enable_bbcode,
- 'reported_post_enable_smilies' => $reported_post_enable_smilies,
- 'reported_post_enable_magic_url' => $reported_post_enable_magic_url,
- );
-
- $sql = 'INSERT INTO ' . REPORTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
- $db->sql_query($sql);
- $report_id = $db->sql_nextid();
-
- $phpbb_notifications = $phpbb_container->get('notification_manager');
-
- if ($post_id)
- {
- $sql = 'UPDATE ' . POSTS_TABLE . '
- SET post_reported = 1
- WHERE post_id = ' . $post_id;
- $db->sql_query($sql);
-
- if (!$report_data['topic_reported'])
- {
- $sql = 'UPDATE ' . TOPICS_TABLE . '
- SET topic_reported = 1
- WHERE topic_id = ' . $report_data['topic_id'] . '
- OR topic_moved_id = ' . $report_data['topic_id'];
- $db->sql_query($sql);
- }
-
- $lang_return = $user->lang['RETURN_TOPIC'];
- $lang_success = $user->lang['POST_REPORTED_SUCCESS'];
-
- $phpbb_notifications->add_notifications('notification.type.report_post', array_merge($report_data, $row, $forum_data, array(
- 'report_text' => $report_text,
- )));
- }
- else
- {
- $sql = 'UPDATE ' . PRIVMSGS_TABLE . '
- SET message_reported = 1
- WHERE msg_id = ' . $pm_id;
- $db->sql_query($sql);
-
- $sql_ary = array(
- 'msg_id' => $pm_id,
- 'user_id' => ANONYMOUS,
- 'author_id' => (int) $report_data['author_id'],
- 'pm_deleted' => 0,
- 'pm_new' => 0,
- 'pm_unread' => 0,
- 'pm_replied' => 0,
- 'pm_marked' => 0,
- 'pm_forwarded' => 0,
- 'folder_id' => PRIVMSGS_INBOX,
- );
-
- $sql = 'INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
- $db->sql_query($sql);
-
- $lang_return = $user->lang['RETURN_PM'];
- $lang_success = $user->lang['PM_REPORTED_SUCCESS'];
-
- $phpbb_notifications->add_notifications('notification.type.report_pm', array_merge($report_data, $row, array(
- 'report_text' => $report_text,
- 'from_user_id' => $report_data['author_id'],
- 'report_id' => $report_id,
- )));
- }
-
- meta_refresh(3, $redirect_url);
-
- $message = $lang_success . '<br /><br />' . sprintf($lang_return, '<a href="' . $redirect_url . '">', '</a>');
- if ($return_forum_url)
- {
- $message .= '<br /><br />' . sprintf($user->lang['RETURN_FORUM'], '<a href="' . $return_forum_url . '">', '</a>');
- }
- trigger_error($message);
- }
- else if (isset($captcha) && $captcha->is_solved() !== false)
- {
- $s_hidden_fields .= build_hidden_fields($captcha->get_hidden_fields());
- }
-}
-
-// Generate the reasons
-display_reasons($reason_id);
-
-$page_title = ($pm_id) ? $user->lang['REPORT_MESSAGE'] : $user->lang['REPORT_POST'];
-
-if (isset($captcha) && $captcha->is_solved() === false)
-{
- $template->assign_vars(array(
- 'S_CONFIRM_CODE' => true,
- 'CAPTCHA_TEMPLATE' => $captcha->get_template(),
- ));
-}
-
-$template->assign_vars(array(
- 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
- 'S_REPORT_POST' => ($pm_id) ? false : true,
- 'REPORT_TEXT' => $report_text,
- 'S_REPORT_ACTION' => append_sid("{$phpbb_root_path}report.$phpEx", 'f=' . $forum_id . '&amp;p=' . $post_id . '&amp;pm=' . $pm_id),
- 'S_HIDDEN_FIELDS' => (sizeof($s_hidden_fields)) ? $s_hidden_fields : null,
-
- 'S_NOTIFY' => $user_notify,
- 'S_CAN_NOTIFY' => ($user->data['is_registered']) ? true : false,
- 'S_IN_REPORT' => true,
-));
-
-generate_forum_nav($forum_data);
-
-// Start output of page
-page_header($page_title);
-
-$template->set_filenames(array(
- 'body' => 'report_body.html')
+/** @var \phpbb\controller\helper $controller_helper */
+$controller_helper = $phpbb_container->get('controller.helper');
+$response = new RedirectResponse(
+ $controller_helper->route($redirect_route_name, array(
+ 'id' => ($pm_id === 0) ? $post_id : $pm_id,
+ )),
+ 301
);
-
-page_footer();
+$response->send();
diff --git a/phpBB/search.php b/phpBB/search.php
index 27ec8e4dab..64f6041371 100644
--- a/phpBB/search.php
+++ b/phpBB/search.php
@@ -25,30 +25,30 @@ $auth->acl($user->data);
$user->setup('search');
// Define initial vars
-$mode = request_var('mode', '');
-$search_id = request_var('search_id', '');
-$start = max(request_var('start', 0), 0);
-$post_id = request_var('p', 0);
-$topic_id = request_var('t', 0);
-$view = request_var('view', '');
-
-$submit = request_var('submit', false);
-$keywords = utf8_normalize_nfc(request_var('keywords', '', true));
-$add_keywords = utf8_normalize_nfc(request_var('add_keywords', '', true));
-$author = request_var('author', '', true);
-$author_id = request_var('author_id', 0);
-$show_results = ($topic_id) ? 'posts' : request_var('sr', 'posts');
+$mode = $request->variable('mode', '');
+$search_id = $request->variable('search_id', '');
+$start = max($request->variable('start', 0), 0);
+$post_id = $request->variable('p', 0);
+$topic_id = $request->variable('t', 0);
+$view = $request->variable('view', '');
+
+$submit = $request->variable('submit', false);
+$keywords = $request->variable('keywords', '', true);
+$add_keywords = $request->variable('add_keywords', '', true);
+$author = $request->variable('author', '', true);
+$author_id = $request->variable('author_id', 0);
+$show_results = ($topic_id) ? 'posts' : $request->variable('sr', 'posts');
$show_results = ($show_results == 'posts') ? 'posts' : 'topics';
-$search_terms = request_var('terms', 'all');
-$search_fields = request_var('sf', 'all');
-$search_child = request_var('sc', true);
+$search_terms = $request->variable('terms', 'all');
+$search_fields = $request->variable('sf', 'all');
+$search_child = $request->variable('sc', true);
-$sort_days = request_var('st', 0);
-$sort_key = request_var('sk', 't');
-$sort_dir = request_var('sd', 'd');
+$sort_days = $request->variable('st', 0);
+$sort_key = $request->variable('sk', 't');
+$sort_dir = $request->variable('sd', 'd');
-$return_chars = request_var('ch', ($topic_id) ? -1 : 300);
-$search_forum = request_var('fid', array(0));
+$return_chars = $request->variable('ch', ($topic_id) ? -1 : 300);
+$search_forum = $request->variable('fid', array(0));
// We put login boxes for the case if search_id is newposts, egosearch or unreadposts
// because a guest should be able to log in even if guests search is not permitted
@@ -123,7 +123,10 @@ $sort_by_text = array('a' => $user->lang['SORT_AUTHOR'], 't' => $user->lang['SOR
$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
+/* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
+/* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
/**
@@ -195,7 +198,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$sql_author_match = (strpos($author, '*') !== false) ? ' ' . $db->sql_like_expression(str_replace('*', $db->get_any_char(), utf8_clean_string($author))) : " = '" . $db->sql_escape(utf8_clean_string($author)) . "'";
}
- if (!sizeof($author_id_ary))
+ if (!count($author_id_ary))
{
trigger_error('NO_SEARCH_RESULTS');
}
@@ -217,7 +220,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
}
// Which forums should not be searched? Author searches are also carried out in unindexed forums
- if (empty($keywords) && sizeof($author_id_ary))
+ if (empty($keywords) && count($author_id_ary))
{
$ex_fid_ary = array_keys($auth->acl_getf('!f_read', true));
}
@@ -226,7 +229,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$ex_fid_ary = array_unique(array_merge(array_keys($auth->acl_getf('!f_read', true)), array_keys($auth->acl_getf('!f_search', true))));
}
- $not_in_fid = (sizeof($ex_fid_ary)) ? 'WHERE ' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . " OR (f.forum_password <> '' AND fa.user_id <> " . (int) $user->data['user_id'] . ')' : "";
+ $not_in_fid = (count($ex_fid_ary)) ? 'WHERE ' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . " OR (f.forum_password <> '' AND fa.user_id <> " . (int) $user->data['user_id'] . ')' : "";
$sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.right_id, f.forum_password, f.forum_flags, fa.user_id
FROM ' . FORUMS_TABLE . ' f
@@ -253,7 +256,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
continue;
}
- if (sizeof($search_forum))
+ if (count($search_forum))
{
if ($search_child)
{
@@ -306,9 +309,9 @@ if ($keywords || $author || $author_id || $search_id || $submit)
{
$correct_query = $search->split_keywords($keywords, $search_terms);
$common_words = $search->get_common_words();
- if (!$correct_query || (!$search->get_search_query() && !sizeof($author_id_ary) && !$search_id))
+ if (!$correct_query || (!$search->get_search_query() && !count($author_id_ary) && !$search_id))
{
- $ignored = (sizeof($common_words)) ? sprintf($user->lang['IGNORED_TERMS_EXPLAIN'], implode(' ', $common_words)) . '<br />' : '';
+ $ignored = (count($common_words)) ? sprintf($user->lang['IGNORED_TERMS_EXPLAIN'], implode(' ', $common_words)) . '<br />' : '';
$word_length = $search->get_word_length();
if ($word_length)
{
@@ -321,10 +324,10 @@ if ($keywords || $author || $author_id || $search_id || $submit)
}
}
- if (!$keywords && sizeof($author_id_ary))
+ if (!$keywords && count($author_id_ary))
{
// if it is an author search we want to show topics by default
- $show_results = ($topic_id) ? 'posts' : request_var('sr', ($search_id == 'egosearch') ? 'topics' : 'posts');
+ $show_results = ($topic_id) ? 'posts' : $request->variable('sr', ($search_id == 'egosearch') ? 'topics' : 'posts');
$show_results = ($show_results == 'posts') ? 'posts' : 'topics';
}
@@ -368,7 +371,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$show_results = 'topics';
$sort_key = 't';
$sort_dir = 'd';
- $sort_days = request_var('st', 7);
+ $sort_days = $request->variable('st', 7);
$sort_by_sql['t'] = 't.topic_last_post_time';
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
@@ -381,14 +384,14 @@ if ($keywords || $author || $author_id || $search_id || $submit)
WHERE t.topic_moved_id = 0
$last_post_time_sql
AND " . $m_approve_topics_fid_sql . '
- ' . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . '
+ ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . '
ORDER BY t.topic_last_post_time DESC';
$field = 'topic_id';
break;
case 'unanswered':
$l_search_title = $user->lang['SEARCH_UNANSWERED'];
- $show_results = request_var('sr', 'topics');
+ $show_results = $request->variable('sr', 'topics');
$show_results = ($show_results == 'posts') ? 'posts' : 'topics';
$sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time';
$sort_by_sql['s'] = ($show_results == 'posts') ? 'p.post_subject' : 't.topic_title';
@@ -419,7 +422,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
AND p.topic_id = t.topic_id
$last_post_time
AND $m_approve_posts_fid_sql
- " . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
+ " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
$sql_sort";
$field = 'post_id';
}
@@ -432,7 +435,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
AND p.topic_id = t.topic_id
$last_post_time
AND $m_approve_topics_fid_sql
- " . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
+ " . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
$sql_sort";
$field = 'topic_id';
}
@@ -448,7 +451,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$sql_where = 'AND t.topic_moved_id = 0
AND ' . $m_approve_topics_fid_sql . '
- ' . ((sizeof($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '');
+ ' . ((count($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '');
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
$s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = '';
@@ -459,7 +462,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
case 'newposts':
$l_search_title = $user->lang['SEARCH_NEW'];
// force sorting
- $show_results = (request_var('sr', 'topics') == 'posts') ? 'posts' : 'topics';
+ $show_results = ($request->variable('sr', 'topics') == 'posts') ? 'posts' : 'topics';
$sort_key = 't';
$sort_dir = 'd';
$sort_by_sql['t'] = ($show_results == 'posts') ? 'p.post_time' : 't.topic_last_post_time';
@@ -474,7 +477,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
FROM ' . POSTS_TABLE . ' p
WHERE p.post_time > ' . $user->data['user_lastvisit'] . '
AND ' . $m_approve_posts_fid_sql . '
- ' . ((sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
+ ' . ((count($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '') . "
$sql_sort";
$field = 'post_id';
}
@@ -485,7 +488,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
WHERE t.topic_last_post_time > ' . $user->data['user_lastvisit'] . '
AND t.topic_moved_id = 0
AND ' . $m_approve_topics_fid_sql . '
- ' . ((sizeof($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . "
+ ' . ((count($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : '') . "
$sql_sort";
/*
[Fix] queued replies missing from "view new posts" (Bug #42705 - Patch by Paul)
@@ -559,7 +562,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$search_id = '';
}
- $total_match_count = sizeof($id_ary);
+ $total_match_count = count($id_ary);
if ($total_match_count)
{
// Limit the number to $total_matches_limit for pre-made searches
@@ -589,7 +592,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
{
$total_match_count = $search->keyword_search($show_results, $search_fields, $search_terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page);
}
- else if (sizeof($author_id_ary))
+ else if (count($author_id_ary))
{
$firstpost_only = ($search_fields === 'firstpost' || $search_fields == 'titleonly') ? true : false;
$total_match_count = $search->author_search($show_results, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_posts_fid_sql, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page);
@@ -639,10 +642,10 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$sql_where = '';
- if (sizeof($id_ary))
+ if (count($id_ary))
{
$sql_where .= $db->sql_in_set(($show_results == 'posts') ? 'p.post_id' : 't.topic_id', $id_ary);
- $sql_where .= (sizeof($ex_fid_ary)) ? ' AND (' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . ' OR f.forum_id IS NULL)' : '';
+ $sql_where .= (count($ex_fid_ary)) ? ' AND (' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . ' OR f.forum_id IS NULL)' : '';
$sql_where .= ' AND ' . (($show_results == 'posts') ? $m_approve_posts_fid_sql : $m_approve_topics_fid_sql);
}
@@ -853,7 +856,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$result = $db->sql_query($sql);
$result_topic_id = 0;
- $rowset = array();
+ $rowset = $attachments = $topic_tracking_info = array();
if ($show_results == 'topics')
{
@@ -880,7 +883,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
$db->sql_freeresult($result);
// If we have some shadow topics, update the rowset to reflect their topic information
- if (sizeof($shadow_topic_list))
+ if (count($shadow_topic_list))
{
$sql = 'SELECT *
FROM ' . TOPICS_TABLE . '
@@ -929,6 +932,26 @@ if ($keywords || $author || $author_id || $search_id || $submit)
while ($row = $db->sql_fetchrow($result))
{
+ /**
+ * Modify the row of a post result before the post_text is trimmed
+ *
+ * @event core.search_modify_post_row
+ * @var string hilit String to highlight
+ * @var array row Array with the post data
+ * @var string u_hilit Highlight string to be injected into URL
+ * @var string view Search results view mode
+ * @var array zebra Array with zebra data for the current user
+ * @since 3.2.2-RC1
+ */
+ $vars = array(
+ 'hilit',
+ 'row',
+ 'u_hilit',
+ 'view',
+ 'zebra',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.search_modify_post_row', compact($vars)));
+
// We pre-process some variables here for later usage
$row['post_text'] = censor_text($row['post_text']);
@@ -964,7 +987,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
unset($text_only_message);
// Pull attachment data
- if (sizeof($attach_list))
+ if (count($attach_list))
{
$use_attach_list = $attach_list;
$attach_list = array();
@@ -978,7 +1001,7 @@ if ($keywords || $author || $author_id || $search_id || $submit)
}
}
- if (sizeof($attach_list))
+ if (count($attach_list))
{
$sql = 'SELECT *
FROM ' . ATTACHMENTS_TABLE . '
@@ -1070,9 +1093,12 @@ if ($keywords || $author || $author_id || $search_id || $submit)
'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
'TOPIC_AUTHOR_FULL' => get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
'FIRST_POST_TIME' => $user->format_date($row['topic_time']),
+ 'FIRST_POST_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_time']),
'LAST_POST_SUBJECT' => $row['topic_last_post_subject'],
'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']),
+ 'LAST_POST_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_last_post_time']),
'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']),
+ 'LAST_VIEW_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_last_view_time']),
'LAST_POST_AUTHOR' => get_username_string('username', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
'LAST_POST_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
'LAST_POST_AUTHOR_FULL' => get_username_string('full', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
@@ -1487,7 +1513,6 @@ if ($auth->acl_get('a_search'))
ORDER BY search_time DESC';
break;
- case 'mssql':
case 'mssql_odbc':
case 'mssqlnative':
$sql = 'SELECT search_time, search_keywords
diff --git a/phpBB/styles/all/template/feed.xml.twig b/phpBB/styles/all/template/feed.xml.twig
new file mode 100644
index 0000000000..91467c62cd
--- /dev/null
+++ b/phpBB/styles/all/template/feed.xml.twig
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{{ FEED_LANG }}">
+ <link rel="self" type="application/atom+xml" href="{{ SELF_LINK }}" />
+
+ {% if not FEED_TITLE is empty %}<title>{{ FEED_TITLE }}</title>{% endif %}
+
+ {% if not FEED_SUBTITLE is empty %}<subtitle>{{ FEED_SUBTITLE }}</subtitle>{% endif %}
+
+ {% if not FEED_LINK is empty %}<link href="{{ FEED_LINK }}" />{% endif %}
+
+ <updated>{{ FEED_UPDATED }}</updated>
+
+ <author><name><![CDATA[{{ FEED_AUTHOR }}]]></name></author>
+ <id>{{ SELF_LINK }}</id>
+
+ {% for row in FEED_ROWS %}
+ <entry>
+ {% if not row.author is empty %}<author><name><![CDATA[{{ row.author }}]]></name></author>{% endif %}
+
+ <updated>{% if not row.updated is empty %}{{ row.updated }} {% else %}{{ row.published }}{% endif %}</updated>
+
+ {% if not row.published is empty %}<published>{{ row.published }}</published>{% endif %}
+
+ <id>{{ row.link }}</id>
+ <link href="{{ row.link }}"/>
+ <title type="html"><![CDATA[{{ row.title }}]]></title>
+
+ {% if not row.category is empty and row.category_name is defined and row.category_name != '' %}
+ <category term="{{ row.category_name }}" scheme="{{ row.category }}" label="{{ row.category_name }}"/>
+ {% endif %}
+
+ <content type="html" xml:base="{{ row.link }}"><![CDATA[
+{{ row.description }}{% if not row.statistics is empty %}<p>{{ lang('STATISTICS') }}: {{ row.statistics }}</p>{% endif %}<hr />
+]]></content>
+ </entry>
+ {% endfor %}
+</feed>
diff --git a/phpBB/styles/prosilver/style.cfg b/phpBB/styles/prosilver/style.cfg
index 019db11bc7..697bcee97d 100644
--- a/phpBB/styles/prosilver/style.cfg
+++ b/phpBB/styles/prosilver/style.cfg
@@ -21,11 +21,11 @@
# General Information about this style
name = prosilver
copyright = © phpBB Limited, 2007
-style_version = 3.1.11
-phpbb_version = 3.1.11
+style_version = 3.2.9
+phpbb_version = 3.2.9
# Defining a different template bitfield
-# template_bitfield = lNg=
+# template_bitfield = //g=
# Parent style
# Set value to empty or to this style's name if this style does not have a parent style
diff --git a/phpBB/styles/prosilver/template/ajax.js b/phpBB/styles/prosilver/template/ajax.js
index ec9b53328f..5e66e5cda1 100644
--- a/phpBB/styles/prosilver/template/ajax.js
+++ b/phpBB/styles/prosilver/template/ajax.js
@@ -26,7 +26,7 @@ phpbb.addAjaxCallback('mark_forums_read', function(res) {
});
// Mark subforums read
- $('a.subforum[class*="unread"]').removeClass('unread').addClass('read');
+ $('a.subforum[class*="unread"]').removeClass('unread').addClass('read').children('.icon.icon-red').removeClass('icon-red').addClass('icon-blue');
// Mark topics read if we are watching a category and showing active topics
if ($('#active_topics').length) {
@@ -87,7 +87,7 @@ phpbb.addAjaxCallback('mark_topics_read', function(res, updateTopicLinks) {
});
// Remove link to first unread post
- $('a').has('span.icon_topic_newest').remove();
+ $('a.unread').has('.icon-red').remove();
// Update mark topics read links
if (updateTopicLinks) {
@@ -199,7 +199,7 @@ phpbb.addAjaxCallback('zebra', function(res) {
*/
phpbb.addAjaxCallback('vote_poll', function(res) {
if (typeof res.success !== 'undefined') {
- var poll = $('.topic_poll');
+ var poll = $(this).closest('.topic_poll');
var panel = poll.find('.panel');
var resultsVisible = poll.find('dl:first-child .resultbar').is(':visible');
var mostVotes = 0;
diff --git a/phpBB/styles/prosilver/template/attachment.html b/phpBB/styles/prosilver/template/attachment.html
index 4546f53d6c..615717e026 100644
--- a/phpBB/styles/prosilver/template/attachment.html
+++ b/phpBB/styles/prosilver/template/attachment.html
@@ -8,14 +8,14 @@
<!-- IF _file.S_THUMBNAIL -->
<dl class="thumbnail">
- <dt><a href="{_file.U_DOWNLOAD_LINK}"><img src="{_file.THUMB_IMAGE}" class="postimage" alt="{_file.DOWNLOAD_NAME}" title="{_file.DOWNLOAD_NAME} ({_file.FILESIZE} {_file.SIZE_LANG}) {_file.L_DOWNLOAD_COUNT}" /></a></dt>
+ <dt><a href="{_file.U_DOWNLOAD_LINK}"><img src="{_file.THUMB_IMAGE}" class="postimage" alt="{% if _file.COMMENT %}{{ _file.COMMENT|e('html') }}{% else %}{{ _file.DOWNLOAD_NAME }}{% endif %}" title="{_file.DOWNLOAD_NAME} ({_file.FILESIZE} {_file.SIZE_LANG}) {_file.L_DOWNLOAD_COUNT}" /></a></dt>
<!-- IF _file.COMMENT --><dd> {_file.COMMENT}</dd><!-- ENDIF -->
</dl>
<!-- ENDIF -->
<!-- IF _file.S_IMAGE -->
<dl class="file">
- <dt class="attach-image"><img src="{_file.U_INLINE_LINK}" class="postimage" alt="{_file.DOWNLOAD_NAME}" onclick="viewableArea(this);" /></dt>
+ <dt class="attach-image"><img src="{_file.U_INLINE_LINK}" class="postimage" alt="{% if _file.COMMENT %}{{ _file.COMMENT|e('html') }}{% else %}{{ _file.DOWNLOAD_NAME }}{% endif %}" onclick="viewableArea(this);" /></dt>
<!-- IF _file.COMMENT --><dd><em>{_file.COMMENT}</em></dd><!-- ENDIF -->
<dd>{_file.DOWNLOAD_NAME} ({_file.FILESIZE} {_file.SIZE_LANG}) {_file.L_DOWNLOAD_COUNT}</dd>
</dl>
@@ -29,36 +29,7 @@
</dl>
<!-- ENDIF -->
- <!-- IF _file.S_WM_FILE -->
- <!-- method used here from http://alistapart.com/articles/byebyeembed / autosizing seems to not work always, this will not fix -->
- <object width="320" height="285" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" id="wmstream_{_file.ATTACH_ID}">
- <param name="url" value="{_file.U_DOWNLOAD_LINK}" />
- <param name="showcontrols" value="1" />
- <param name="showdisplay" value="0" />
- <param name="showstatusbar" value="0" />
- <param name="autosize" value="1" />
- <param name="autostart" value="0" />
- <param name="visible" value="1" />
- <param name="animationstart" value="0" />
- <param name="loop" value="0" />
- <param name="src" value="{_file.U_DOWNLOAD_LINK}" />
- <!--[if !IE]>-->
- <object width="320" height="285" type="video/x-ms-wmv" data="{_file.U_DOWNLOAD_LINK}">
- <param name="src" value="{_file.U_DOWNLOAD_LINK}" />
- <param name="controller" value="1" />
- <param name="showcontrols" value="1" />
- <param name="showdisplay" value="0" />
- <param name="showstatusbar" value="0" />
- <param name="autosize" value="1" />
- <param name="autostart" value="0" />
- <param name="visible" value="1" />
- <param name="animationstart" value="0" />
- <param name="loop" value="0" />
- </object>
- <!--<![endif]-->
- </object>
-
- <!-- ELSEIF _file.S_FLASH_FILE -->
+ <!-- IF _file.S_FLASH_FILE -->
<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{_file.WIDTH}" height="{_file.HEIGHT}">
<param name="movie" value="{_file.U_VIEW_LINK}" />
<param name="play" value="true" />
@@ -68,53 +39,7 @@
<param name="allowNetworking" value="internal" />
<embed src="{_file.U_VIEW_LINK}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{_file.WIDTH}" height="{_file.HEIGHT}" play="true" loop="true" quality="high" allowscriptaccess="never" allownetworking="internal"></embed>
</object>
- <!-- ELSEIF _file.S_QUICKTIME_FILE -->
- <object id="qtstream_{_file.ATTACH_ID}" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0" width="320" height="285">
- <param name="src" value="{_file.U_DOWNLOAD_LINK}" />
- <param name="controller" value="true" />
- <param name="autoplay" value="false" />
- <param name="type" value="video/quicktime" />
- <embed name="qtstream_{_file.ATTACH_ID}" src="{_file.U_DOWNLOAD_LINK}" pluginspage="http://www.apple.com/quicktime/download/" enablejavascript="true" controller="true" width="320" height="285" type="video/quicktime" autoplay="false"></embed>
- </object>
- <!-- ELSEIF _file.S_RM_FILE -->
- <object id="rmstream_{_file.ATTACH_ID}" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" width="200" height="50">
- <param name="src" value="{_file.U_DOWNLOAD_LINK}" />
- <param name="autostart" value="false" />
- <param name="controls" value="ImageWindow" />
- <param name="console" value="ctrls_{_file.ATTACH_ID}" />
- <param name="prefetch" value="false" />
- <embed name="rmstream_{_file.ATTACH_ID}" type="audio/x-pn-realaudio-plugin" src="{_file.U_DOWNLOAD_LINK}" width="0" height="0" autostart="false" controls="ImageWindow" console="ctrls_{_file.ATTACH_ID}" prefetch="false"></embed>
- </object>
- <br />
- <object id="ctrls_{_file.ATTACH_ID}" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" width="0" height="36">
- <param name="controls" value="ControlPanel" />
- <param name="console" value="ctrls_{_file.ATTACH_ID}" />
- <embed name="ctrls_{_file.ATTACH_ID}" type="audio/x-pn-realaudio-plugin" width="200" height="36" controls="ControlPanel" console="ctrls_{_file.ATTACH_ID}"></embed>
- </object>
-
- <script type="text/javascript">
- // <![CDATA[
- if (document.rmstream_{_file.ATTACH_ID}.GetClipWidth)
- {
- while (!document.rmstream_{_file.ATTACH_ID}.GetClipWidth())
- {
- }
-
- var width = document.rmstream_{_file.ATTACH_ID}.GetClipWidth();
- var height = document.rmstream_{_file.ATTACH_ID}.GetClipHeight();
-
- document.rmstream_{_file.ATTACH_ID}.width = width;
- document.rmstream_{_file.ATTACH_ID}.height = height;
- document.ctrls_{_file.ATTACH_ID}.width = width;
- }
- // ]]>
- </script>
- <!-- ENDIF -->
-
- <!-- IF _file.S_WM_FILE or _file.S_RM_FILE or _file.S_FLASH_FILE or _file.S_QUICKTIME_FILE -->
- <p>
- <!-- IF _file.S_QUICKTIME_FILE --><a href="#" onclick="play_qt_file(document.qtstream_{_file.ATTACH_ID}); return false;">[ {L_PLAY_QUICKTIME_FILE} ]</a> <!-- ENDIF -->
- <a href="{_file.U_DOWNLOAD_LINK}">{_file.DOWNLOAD_NAME}</a> [ {_file.FILESIZE} {_file.SIZE_LANG} | {_file.L_DOWNLOAD_COUNT} ]</p>
+ <p><a href="{_file.U_DOWNLOAD_LINK}">{_file.DOWNLOAD_NAME}</a> [ {_file.FILESIZE} {_file.SIZE_LANG} | {_file.L_DOWNLOAD_COUNT} ]</p>
<!-- ENDIF -->
<!-- EVENT attachment_file_append -->
diff --git a/phpBB/styles/prosilver/template/bbcode.html b/phpBB/styles/prosilver/template/bbcode.html
index 49bcd56945..b37ba238d2 100644
--- a/phpBB/styles/prosilver/template/bbcode.html
+++ b/phpBB/styles/prosilver/template/bbcode.html
@@ -11,9 +11,48 @@
<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open -->
<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open -->
<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close -->
+<!-- BEGIN quote_extended -->
+<blockquote>
+ <xsl:if test="not(@author)">
+ <xsl:attribute name="class">uncited</xsl:attribute>
+ </xsl:if>
+ <div>
+ <xsl:if test="@author">
+ <cite>
+ <xsl:choose>
+ <xsl:when test="@url">
+ <a href="{@url}" class="postlink"><xsl:value-of select="@author"/></a>
+ </xsl:when>
+ <xsl:when test="@profile_url">
+ <a href="{@profile_url}"><xsl:value-of select="@author"/></a>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@author"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="$L_WROTE"/>
+ <xsl:value-of select="$L_COLON"/>
+ <xsl:if test="@post_url">
+ <xsl:text> </xsl:text>
+ <a href="{@post_url}" data-post-id="{@post_id}" onclick="if(document.getElementById(hash.substr(1)))href=hash">&#8593;</a>
+ </xsl:if>
+ <xsl:if test="@msg_url">
+ <xsl:text> </xsl:text>
+ <a href="{@msg_url}" data-msg-id="{@msg_id}">&#8593;</a>
+ </xsl:if>
+ <xsl:if test="@date">
+ <div class="responsive-hide"><xsl:value-of select="@date"/></div>
+ </xsl:if>
+ </cite>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </div>
+</blockquote>
+<!-- END quote_extended -->
-<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open -->
-<!-- BEGIN code_close --></code></div><!-- END code_close -->
+<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><pre><code><!-- END code_open -->
+<!-- BEGIN code_close --></code></pre></div><!-- END code_close -->
<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open -->
<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close -->
diff --git a/phpBB/styles/prosilver/template/captcha_recaptcha.html b/phpBB/styles/prosilver/template/captcha_recaptcha.html
index fee0f7423e..a123f543a8 100644
--- a/phpBB/styles/prosilver/template/captcha_recaptcha.html
+++ b/phpBB/styles/prosilver/template/captcha_recaptcha.html
@@ -12,24 +12,11 @@
<dl>
<dt><label>{L_CONFIRM_CODE}{L_COLON}</label><br /><span>{L_RECAPTCHA_EXPLAIN}</span></dt>
<dd class="captcha">
- <script>
- var RecaptchaOptions = {
- lang : '{LA_RECAPTCHA_LANG}',
- theme : 'clean',
- tabindex : <!-- IF $CAPTCHA_TAB_INDEX -->{$CAPTCHA_TAB_INDEX}<!-- ELSE -->10<!-- ENDIF -->
- };
- </script>
- <script src="{RECAPTCHA_SERVER}/challenge?k={RECAPTCHA_PUBKEY}{RECAPTCHA_ERRORGET}"></script>
-
<noscript>
- <div>
- <object data="{RECAPTCHA_SERVER}/noscript?k={RECAPTCHA_PUBKEY}{RECAPTCHA_ERRORGET}" type="text/html" height="300" width="500"></object><br />
- <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
- <input type="hidden" name="recaptcha_response_field" value="manual_challenge" />
- </div>
+ <div>{L_RECAPTCHA_NOSCRIPT}</div>
</noscript>
-
- <a href="http://www.google.com/intl/{LA_RECAPTCHA_LANG}/policies/" target="_blank" class="recaptcha-responsive" style="display: none"><img alt="" width="71" height="36" src="{RECAPTCHA_SERVER}/img/clean/logo.png"></a>
+ <script src="{RECAPTCHA_SERVER}.js?hl={LA_RECAPTCHA_LANG}" async defer></script>
+ <div class="g-recaptcha" data-sitekey="{RECAPTCHA_PUBKEY}" data-tabindex="<!-- IF $CAPTCHA_TAB_INDEX -->{$CAPTCHA_TAB_INDEX}<!-- ELSE -->10<!-- ENDIF -->"></div>
</dd>
</dl>
<!-- ELSE -->
diff --git a/phpBB/styles/prosilver/template/confirm_delete_body.html b/phpBB/styles/prosilver/template/confirm_delete_body.html
index fbd881a940..637830a5bc 100644
--- a/phpBB/styles/prosilver/template/confirm_delete_body.html
+++ b/phpBB/styles/prosilver/template/confirm_delete_body.html
@@ -49,6 +49,8 @@
</dl>
<!-- ENDIF -->
+ {% EVENT confirm_delete_body_delete_reason_before %}
+
<dl>
<dt><label for="delete_reason">{L_DELETE_REASON}{L_COLON}</label><br /><span>{L_DELETE_REASON_EXPLAIN}</span></dt>
<dd><input type="text" name="delete_reason" id="delete_reason" value="" class="inputbox autowidth" maxlength="120" size="45" /></dd>
@@ -58,7 +60,7 @@
<fieldset class="submit-buttons">
{S_HIDDEN_FIELDS}
- <input type="submit" name="confirm" value="{L_YES}" class="button1" />&nbsp;
+ <input type="submit" name="confirm" value="{L_YES}" class="button1" />&nbsp;
<input type="submit" name="cancel" value="{L_NO}" class="button2" />
</fieldset>
diff --git a/phpBB/styles/prosilver/template/display_options.html b/phpBB/styles/prosilver/template/display_options.html
new file mode 100644
index 0000000000..a426d08845
--- /dev/null
+++ b/phpBB/styles/prosilver/template/display_options.html
@@ -0,0 +1,27 @@
+<div class="dropdown-container dropdown-container-left dropdown-button-control sort-tools">
+ <span title="{L_SORT_OPTIONS}" class="button button-secondary dropdown-trigger dropdown-select">
+ <i class="icon fa-sort-amount-asc fa-fw" aria-hidden="true"></i>
+ <span class="caret"><i class="icon fa-sort-down fa-fw" aria-hidden="true"></i></span>
+ </span>
+ <div class="dropdown hidden">
+ <div class="pointer"><div class="pointer-inner"></div></div>
+ <div class="dropdown-contents">
+ <fieldset class="display-options">
+ <!-- IF S_SORT_OPTIONS -->
+ <label>{L_SORT_BY}{L_COLON} <select name="sk" id="sk">{S_SORT_OPTIONS}</select></label>
+ <label>{L_SORT_DIRECTION}{L_COLON} <select name="sd" id="sd">{S_ORDER_SELECT}</select></label>
+ <hr class="dashed" />
+ <input type="submit" class="button2" name="sort" value="{L_SORT}" />
+ <!-- ELSE -->
+ <label>{L_DISPLAY}{L_COLON} {S_SELECT_SORT_DAYS}</label>
+ <!-- IF S_SELECT_SORT_KEY -->
+ <label>{L_SORT_BY}{L_COLON} {S_SELECT_SORT_KEY}</label>
+ <label>{L_SORT_DIRECTION}{L_COLON} {S_SELECT_SORT_DIR}</label>
+ <!-- ENDIF -->
+ <hr class="dashed" />
+ <input type="submit" class="button2" name="sort" value="{L_GO}" />
+ <!-- ENDIF -->
+ </fieldset>
+ </div>
+ </div>
+</div>
diff --git a/phpBB/styles/prosilver/template/faq_body.html b/phpBB/styles/prosilver/template/faq_body.html
index 53205d14e9..e55c12ac48 100644
--- a/phpBB/styles/prosilver/template/faq_body.html
+++ b/phpBB/styles/prosilver/template/faq_body.html
@@ -34,8 +34,10 @@
<dl class="faq">
<dt id="f{faq_block.S_ROW_COUNT}r{faq_block.faq_row.S_ROW_COUNT}"><strong>{faq_block.faq_row.FAQ_QUESTION}</strong></dt>
<dd>{faq_block.faq_row.FAQ_ANSWER}</dd>
- <dd><a href="#faqlinks" class="top2">{L_BACK_TO_TOP}</a></dd>
</dl>
+ <a href="#faqlinks" class="top">
+ <i class="icon fa-chevron-circle-up fa-fw icon-gray" aria-hidden="true"></i><span>{L_BACK_TO_TOP}</span>
+ </a>
<!-- IF not faq_block.faq_row.S_LAST_ROW --><hr class="dashed" /><!-- ENDIF -->
<!-- END faq_row -->
</div>
diff --git a/phpBB/styles/prosilver/template/forum_fn.js b/phpBB/styles/prosilver/template/forum_fn.js
index d779008f80..3f28f8a326 100644
--- a/phpBB/styles/prosilver/template/forum_fn.js
+++ b/phpBB/styles/prosilver/template/forum_fn.js
@@ -194,37 +194,6 @@ function selectCode(a) {
}
}
-/**
-* Play quicktime file by determining it's width/height
-* from the displayed rectangle area
-*/
-function play_qt_file(obj) {
- 'use strict';
-
- var rectangle = obj.GetRectangle();
- var width, height;
-
- if (rectangle) {
- rectangle = rectangle.split(',');
- var x1 = parseInt(rectangle[0], 10);
- var x2 = parseInt(rectangle[2], 10);
- var y1 = parseInt(rectangle[1], 10);
- var y2 = parseInt(rectangle[3], 10);
-
- width = (x1 < 0) ? (x1 * -1) + x2 : x2 - x1;
- height = (y1 < 0) ? (y1 * -1) + y2 : y2 - y1;
- } else {
- width = 200;
- height = 0;
- }
-
- obj.width = width;
- obj.height = height + 16;
-
- obj.SetControllerVisible(true);
- obj.Play();
-}
-
var inAutocomplete = false;
var lastKeyEntered = '';
@@ -304,11 +273,9 @@ function insertUser(formId, value) {
function insert_marked_users(formId, users) {
'use strict';
- for (var i = 0; i < users.length; i++) {
- if (users[i].checked) {
- insertUser(formId, users[i].value);
- }
- }
+ $(users).filter(':checked').each(function() {
+ insertUser(formId, this.value);
+ });
window.close();
}
@@ -365,13 +332,13 @@ function parseDocument($container) {
/**
* Adjust HTML code for IE8 and older versions
*/
- if (oldBrowser) {
- // Fix .linklist.bulletin lists
- $container
- .find('ul.linklist.bulletin > li')
- .filter(':first-child, .rightside:last-child')
- .addClass('no-bulletin');
- }
+ // if (oldBrowser) {
+ // // Fix .linklist.bulletin lists
+ // $container
+ // .find('ul.linklist.bulletin > li')
+ // .filter(':first-child, .rightside:last-child')
+ // .addClass('no-bulletin');
+ // }
/**
* Resize navigation (breadcrumbs) block to keep all links on same line
@@ -492,7 +459,7 @@ function parseDocument($container) {
$linksFirst = $linksNotSkip.not(filterLast), // The items that will be hidden first
$linksLast = $linksNotSkip.filter(filterLast), // The items that will be hidden last
persistent = $this.attr('id') === 'nav-main', // Does this list already have a menu (such as quick-links)?
- html = '<li class="responsive-menu hidden"><a href="javascript:void(0);" class="responsive-menu-link">&nbsp;</a><div class="dropdown hidden"><div class="pointer"><div class="pointer-inner" /></div><ul class="dropdown-contents" /></div></li>',
+ html = '<li class="responsive-menu hidden"><a href="javascript:void(0);" class="js-responsive-menu-link responsive-menu-link"><i class="icon fa-bars fa-fw" aria-hidden="true"></i></a><div class="dropdown"><div class="pointer"><div class="pointer-inner" /></div><ul class="dropdown-contents" /></div></li>',
slack = 3; // Vertical slack space (in pixels). Determines how sensitive the script is in determining whether a line-break has occured.
// Add a hidden drop-down menu to each links list (except those that already have one)
@@ -581,8 +548,10 @@ function parseDocument($container) {
$menuContents.prepend($clones1.addClass('clone clone-first').removeClass('leftside rightside'));
if ($this.hasClass('post-buttons')) {
- $('.button', $menuContents).removeClass('button icon-button');
- $('.responsive-menu-link', $menu).addClass('button icon-button').prepend('<span></span>');
+ $('.button', $menuContents).removeClass('button');
+ $('.sr-only', $menuContents).removeClass('sr-only');
+ $('.js-responsive-menu-link').addClass('button').addClass('button-icon-only');
+ $('.js-responsive-menu-link .icon').removeClass('fa-bars').addClass('fa-ellipsis-h');
}
copied1 = true;
}
@@ -636,12 +605,12 @@ function parseDocument($container) {
}
if (!persistent) {
- phpbb.registerDropdown($menu.find('a.responsive-menu-link'), $menu.find('.dropdown'), false);
+ phpbb.registerDropdown($menu.find('a.js-responsive-menu-link'), $menu.find('.dropdown'), false);
}
// If there are any images in the links list, run the check again after they have loaded
$linksAll.find('img').each(function() {
- $(this).load(function() {
+ $(this).on('load', function() {
check();
});
});
diff --git a/phpBB/styles/prosilver/template/forumlist_body.html b/phpBB/styles/prosilver/template/forumlist_body.html
index a197545b90..4932860f8c 100644
--- a/phpBB/styles/prosilver/template/forumlist_body.html
+++ b/phpBB/styles/prosilver/template/forumlist_body.html
@@ -14,7 +14,7 @@
<ul class="topiclist">
<li class="header">
<!-- EVENT forumlist_body_category_header_row_prepend -->
- <dl class="icon">
+ <dl class="row-item">
<dt><div class="list-inner"><!-- IF forumrow.S_IS_CAT --><a href="{forumrow.U_VIEWFORUM}">{forumrow.FORUM_NAME}</a><!-- ELSE -->{L_FORUM}<!-- ENDIF --></div></dt>
<dd class="topics">{L_TOPICS}</dd>
<dd class="posts">{L_POSTS}</dd>
@@ -31,13 +31,22 @@
<!-- EVENT forumlist_body_forum_row_before -->
<li class="row">
<!-- EVENT forumlist_body_forum_row_prepend -->
- <dl class="icon {forumrow.FORUM_IMG_STYLE}">
+ <dl class="row-item {forumrow.FORUM_IMG_STYLE}">
<dt title="{forumrow.FORUM_FOLDER_IMG_ALT}">
- <!-- IF forumrow.S_UNREAD_FORUM --><a href="{forumrow.U_VIEWFORUM}" class="icon-link"></a><!-- ENDIF -->
+ <!-- IF forumrow.S_UNREAD_FORUM --><a href="{forumrow.U_VIEWFORUM}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
- <!-- IF S_ENABLE_FEEDS and forumrow.S_FEED_ENABLED --><!-- <a class="feed-icon-forum" title="{L_FEED} - {forumrow.FORUM_NAME}" href="{U_FEED}?f={forumrow.FORUM_ID}"><img src="{T_THEME_PATH}/images/feed.gif" alt="{L_FEED} - {forumrow.FORUM_NAME}" /></a> --><!-- ENDIF -->
-
- <!-- IF forumrow.FORUM_IMAGE --><span class="forum-image">{forumrow.FORUM_IMAGE}</span><!-- ENDIF -->
+ <!-- IF S_ENABLE_FEEDS and forumrow.S_FEED_ENABLED -->
+ <!--
+ <a class="feed-icon-forum" title="{L_FEED} - {forumrow.FORUM_NAME}" href="{U_FEED}?f={forumrow.FORUM_ID}">
+ <i class="icon fa-rss-square fa-fw icon-orange" aria-hidden="true"></i><span class="sr-only">{L_FEED} - {forumrow.FORUM_NAME}</span>
+ </a>
+ -->
+ <!-- ENDIF -->
+ <!-- IF forumrow.FORUM_IMAGE -->
+ <!-- EVENT forumlist_body_forum_image_before -->
+ <span class="forum-image"><!-- EVENT forumlist_body_forum_image_prepend -->{forumrow.FORUM_IMAGE}<!-- EVENT forumlist_body_forum_image_append --></span>
+ <!-- EVENT forumlist_body_forum_image_after -->
+ <!-- ENDIF -->
<a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a>
<!-- IF forumrow.FORUM_DESC --><br />{forumrow.FORUM_DESC}<!-- ENDIF -->
<!-- IF forumrow.MODERATORS -->
@@ -47,7 +56,8 @@
<!-- EVENT forumlist_body_subforums_before -->
<br /><strong>{forumrow.L_SUBFORUM_STR}{L_COLON}</strong>
<!-- BEGIN subforum -->
- <!-- EVENT forumlist_body_subforum_link_prepend --><a href="{forumrow.subforum.U_SUBFORUM}" class="subforum<!-- IF forumrow.subforum.S_UNREAD --> unread<!-- ELSE --> read<!-- ENDIF -->" title="<!-- IF forumrow.subforum.S_UNREAD -->{L_UNREAD_POSTS}<!-- ELSE -->{L_NO_UNREAD_POSTS}<!-- ENDIF -->">{forumrow.subforum.SUBFORUM_NAME}</a><!-- IF not forumrow.subforum.S_LAST_ROW -->{L_COMMA_SEPARATOR}<!-- ENDIF --><!-- EVENT forumlist_body_subforum_link_append -->
+ <!-- EVENT forumlist_body_subforum_link_prepend --><a href="{forumrow.subforum.U_SUBFORUM}" class="subforum<!-- IF forumrow.subforum.S_UNREAD --> unread<!-- ELSE --> read<!-- ENDIF -->" title="<!-- IF forumrow.subforum.S_UNREAD -->{L_UNREAD_POSTS}<!-- ELSE -->{L_NO_UNREAD_POSTS}<!-- ENDIF -->">
+ <i class="icon <!-- IF forumrow.subforum.IS_LINK -->fa-external-link<!-- ELSE -->fa-file-o<!-- ENDIF --> fa-fw <!-- IF forumrow.subforum.S_UNREAD --> icon-red<!-- ELSE --> icon-blue<!-- ENDIF --> icon-md" aria-hidden="true"></i>{forumrow.subforum.SUBFORUM_NAME}</a><!-- IF not forumrow.subforum.S_LAST_ROW -->{L_COMMA_SEPARATOR}<!-- ENDIF --><!-- EVENT forumlist_body_subforum_link_append -->
<!-- END subforum -->
<!-- EVENT forumlist_body_subforums_after -->
<!-- ENDIF -->
@@ -68,19 +78,38 @@
<!-- ELSEIF not forumrow.S_IS_LINK -->
<dd class="topics">{forumrow.TOPICS} <dfn>{L_TOPICS}</dfn></dd>
<dd class="posts">{forumrow.POSTS} <dfn>{L_POSTS}</dfn></dd>
- <dd class="lastpost"><span>
- <!-- IF forumrow.U_UNAPPROVED_TOPICS -->
- <a href="{forumrow.U_UNAPPROVED_TOPICS}">{UNAPPROVED_IMG}</a>
- <!-- ELSEIF forumrow.U_UNAPPROVED_POSTS -->
- <a href="{forumrow.U_UNAPPROVED_POSTS}">{UNAPPROVED_POST_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}
- <!-- IF not S_IS_BOT --><a href="{forumrow.U_LAST_POST}">{LAST_POST_IMG}</a> <!-- ENDIF --><br />{forumrow.LAST_POST_TIME}<!-- ELSE -->{L_NO_POSTS}<br />&nbsp;<!-- ENDIF --></span>
+ <dd class="lastpost">
+ <span>
+ <!-- IF forumrow.U_UNAPPROVED_TOPICS -->
+ <a href="{forumrow.U_UNAPPROVED_TOPICS}" title="{L_TOPICS_UNAPPROVED}">
+ <i class="icon fa-question fa-fw icon-blue" aria-hidden="true"></i><span class="sr-only">{L_TOPICS_UNAPPROVED}</span>
+ </a>
+ <!-- ELSEIF forumrow.U_UNAPPROVED_POSTS -->
+ <a href="{forumrow.U_UNAPPROVED_POSTS}" title="{L_POSTS_UNAPPROVED_FORUM}">
+ <i class="icon fa-question fa-fw icon-blue" aria-hidden="true"></i><span class="sr-only">{L_POSTS_UNAPPROVED_FORUM}</span>
+ </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} <!-- EVENT forumlist_body_last_poster_username_prepend -->{forumrow.LAST_POSTER_FULL}<!-- EVENT forumlist_body_last_poster_username_append -->
+ <!-- IF not S_IS_BOT -->
+ <a href="{forumrow.U_LAST_POST}" title="{L_VIEW_LATEST_POST}">
+ <i class="icon fa-external-link-square fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{L_VIEW_LATEST_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ <br /><time datetime="{forumrow.LAST_POST_TIME_RFC3339}">{forumrow.LAST_POST_TIME}</time>
+ <!-- ELSE -->
+ {% if forumrow.U_UNAPPROVED_TOPICS %}
+ {{ lang('TOPIC_UNAPPROVED_FORUM', forumrow.TOPICS) }}
+ {% else %}
+ {{ lang('NO_POSTS') }}
+ {% endif %}
+ <!-- ENDIF -->
+ </span>
</dd>
<!-- ELSE -->
<dd>&nbsp;</dd>
diff --git a/phpBB/styles/prosilver/template/index_body.html b/phpBB/styles/prosilver/template/index_body.html
index b292c40eb2..239a91c580 100644
--- a/phpBB/styles/prosilver/template/index_body.html
+++ b/phpBB/styles/prosilver/template/index_body.html
@@ -29,6 +29,7 @@
<!-- ENDIF -->
<input type="submit" tabindex="5" name="login" value="{L_LOGIN}" class="button2" />
{S_LOGIN_REDIRECT}
+ {S_FORM_TOKEN_LOGIN}
</fieldset>
</form>
<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/jumpbox.html b/phpBB/styles/prosilver/template/jumpbox.html
index fcd8ddbc1e..070efc0cb9 100644
--- a/phpBB/styles/prosilver/template/jumpbox.html
+++ b/phpBB/styles/prosilver/template/jumpbox.html
@@ -1,34 +1,50 @@
<div class="action-bar actions-jump">
<!-- IF S_VIEWTOPIC -->
- <p class="jumpbox-return"><a href="{U_VIEW_FORUM}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" accesskey="r">{L_RETURN_TO_FORUM}</a></p>
+ <p class="jumpbox-return">
+ <a href="{U_VIEW_FORUM}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" accesskey="r">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_RETURN_TO_FORUM}</span>
+ </a>
+ </p>
<!-- ELSEIF S_VIEWFORUM -->
- <p class="jumpbox-return"><a href="{U_INDEX}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" accesskey="r">{L_RETURN_TO_INDEX}</a></p>
+ <p class="jumpbox-return">
+ <a href="{U_INDEX}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" accesskey="r">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_RETURN_TO_INDEX}</span>
+ </a>
+ </p>
<!-- ELSEIF SEARCH_TOPIC -->
- <p class="jumpbox-return"><a class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH_TOPIC}" accesskey="r">{L_RETURN_TO_TOPIC}</a></p>
+ <p class="jumpbox-return">
+ <a class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH_TOPIC}" accesskey="r">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_RETURN_TO_TOPIC}</span>
+ </a>
+ </p>
<!-- ELSEIF S_SEARCH_ACTION -->
- <p class="jumpbox-return"><a class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH}" title="{L_SEARCH_ADV}" accesskey="r">{L_GO_TO_SEARCH_ADV}</a></p>
+ <p class="jumpbox-return">
+ <a class="left-box arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH}" title="{L_SEARCH_ADV}" accesskey="r">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_GO_TO_SEARCH_ADV}</span>
+ </a>
+ </p>
<!-- ENDIF -->
<!-- IF S_DISPLAY_JUMPBOX -->
-
- <div class="dropdown-container dropdown-container-{S_CONTENT_FLOW_END}<!-- IF not S_IN_MCP --> dropdown-up<!-- ENDIF --> dropdown-{S_CONTENT_FLOW_BEGIN} dropdown-button-control" id="jumpbox">
- <span title="<!-- IF S_IN_MCP and S_MERGE_SELECT -->{L_SELECT_TOPICS_FROM}<!-- ELSEIF S_IN_MCP -->{L_MODERATE_FORUM}<!-- ELSE -->{L_JUMP_TO}<!-- ENDIF -->" class="dropdown-trigger button dropdown-select">
- <!-- IF S_IN_MCP and S_MERGE_SELECT -->{L_SELECT_TOPICS_FROM}<!-- ELSEIF S_IN_MCP -->{L_MODERATE_FORUM}<!-- ELSE -->{L_JUMP_TO}<!-- ENDIF -->
+ <div class="jumpbox dropdown-container dropdown-container-right<!-- IF not S_IN_MCP --> dropdown-up<!-- ENDIF --> dropdown-{S_CONTENT_FLOW_BEGIN} dropdown-button-control" id="jumpbox">
+ <span title="<!-- IF S_IN_MCP and S_MERGE_SELECT -->{L_SELECT_TOPICS_FROM}<!-- ELSEIF S_IN_MCP -->{L_MODERATE_FORUM}<!-- ELSE -->{L_JUMP_TO}<!-- ENDIF -->" class="button button-secondary dropdown-trigger dropdown-select">
+ <span><!-- IF S_IN_MCP and S_MERGE_SELECT -->{L_SELECT_TOPICS_FROM}<!-- ELSEIF S_IN_MCP -->{L_MODERATE_FORUM}<!-- ELSE -->{L_JUMP_TO}<!-- ENDIF --></span>
+ <span class="caret"><i class="icon fa-sort-down fa-fw" aria-hidden="true"></i></span>
</span>
- <div class="dropdown hidden">
- <div class="pointer"><div class="pointer-inner"></div></div>
- <ul class="dropdown-contents">
+ <div class="dropdown">
+ <div class="pointer"><div class="pointer-inner"></div></div>
+ <ul class="dropdown-contents">
<!-- BEGIN jumpbox_forums -->
- <!-- IF jumpbox_forums.FORUM_ID neq -1 -->
- <li><!-- BEGIN level -->&nbsp; &nbsp;<!-- END level --><a href="{jumpbox_forums.LINK}">{jumpbox_forums.FORUM_NAME}</a></li>
- <!-- ENDIF -->
+ <!-- IF jumpbox_forums.FORUM_ID neq -1 -->
+ <li><a href="{jumpbox_forums.LINK}" class="<!-- IF jumpbox_forums.level -->jumpbox-sub-link<!-- ELSEIF jumpbox_forums.S_IS_CAT -->jumpbox-cat-link<!-- ELSE -->jumpbox-forum-link<!-- ENDIF -->"><!-- BEGIN level --><span class="spacer"></span><!-- END level --> <span><!-- IF jumpbox_forums.level --><!-- IF S_CONTENT_DIRECTION eq 'rtl' -->&#8626;<!-- ELSE -->&#8627;<!-- ENDIF --> &nbsp;<!-- ENDIF --> {jumpbox_forums.FORUM_NAME}</span></a></li>
+ <!-- ENDIF -->
<!-- END jumpbox_forums -->
- </ul>
- </div>
+ </ul>
</div>
+ </div>
<!-- ELSE -->
- </br></br>
+ <br /><br />
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/login_body.html b/phpBB/styles/prosilver/template/login_body.html
index ef08035717..dc597af51d 100644
--- a/phpBB/styles/prosilver/template/login_body.html
+++ b/phpBB/styles/prosilver/template/login_body.html
@@ -33,6 +33,7 @@
<!-- ENDIF -->
{S_LOGIN_REDIRECT}
+ {S_FORM_TOKEN_LOGIN}
<dl>
<dt>&nbsp;</dt>
<dd>{S_HIDDEN_FIELDS}<input type="submit" name="login" tabindex="6" value="{L_LOGIN}" class="button1" /></dd>
diff --git a/phpBB/styles/prosilver/template/login_body_oauth.html b/phpBB/styles/prosilver/template/login_body_oauth.html
index 156485d211..1364d01ccb 100644
--- a/phpBB/styles/prosilver/template/login_body_oauth.html
+++ b/phpBB/styles/prosilver/template/login_body_oauth.html
@@ -1,8 +1,6 @@
+<br>
<div class="content">
- <!-- BEGIN oauth -->
- <dl>
- <dt>&nbsp;</dt>
- <dd><a href="{oauth.REDIRECT_URL}" class="button2">{oauth.SERVICE_NAME}</a></dd>
- </dl>
- <!-- END oauth -->
+ {% for oauth in oauth %}
+ <a href="{{ oauth.REDIRECT_URL }}" class="button2">{{ oauth.SERVICE_NAME }}</a>
+ {% endfor %}
</div>
diff --git a/phpBB/styles/prosilver/template/login_forum.html b/phpBB/styles/prosilver/template/login_forum.html
index 7fa9736a96..c5c36d4564 100644
--- a/phpBB/styles/prosilver/template/login_forum.html
+++ b/phpBB/styles/prosilver/template/login_forum.html
@@ -25,6 +25,7 @@
<dd><input type="password" tabindex="1" id="password" name="password" size="25" class="inputbox narrow" autocomplete="off" /></dd>
</dl>
{S_LOGIN_REDIRECT}
+ {S_FORM_TOKEN_LOGIN}
<dl>
<dt>&nbsp;</dt>
<dd>{S_HIDDEN_FIELDS}<input type="submit" name="login" id="login" class="button1" value="{L_LOGIN}" tabindex="2" /></dd>
diff --git a/phpBB/styles/prosilver/template/mcp_approve.html b/phpBB/styles/prosilver/template/mcp_approve.html
index 14472bcf4f..f7874ab90b 100644
--- a/phpBB/styles/prosilver/template/mcp_approve.html
+++ b/phpBB/styles/prosilver/template/mcp_approve.html
@@ -39,7 +39,7 @@
<fieldset>
<!-- IF S_NOTIFY_POSTER -->
- <dl class="panel">
+ <dl class="fields2 nobg">
<dt>&nbsp;</dt>
<dd><label><input type="checkbox" name="notify_poster" checked="checked" /> <!-- IF S_APPROVE -->{L_NOTIFY_POSTER_APPROVAL}<!-- ELSE -->{L_NOTIFY_POSTER_DISAPPROVAL}<!-- ENDIF --></label></dd>
</dl>
@@ -66,7 +66,7 @@
</fieldset>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="button1" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="button1" />&nbsp;
<input type="submit" name="cancel" value="{L_NO}" class="button2" />
</fieldset>
diff --git a/phpBB/styles/prosilver/template/mcp_ban.html b/phpBB/styles/prosilver/template/mcp_ban.html
index 5a7eaa7840..86a322435d 100644
--- a/phpBB/styles/prosilver/template/mcp_ban.html
+++ b/phpBB/styles/prosilver/template/mcp_ban.html
@@ -1,8 +1,6 @@
<!-- INCLUDE mcp_header.html -->
-<script type="text/javascript">
-// <![CDATA[
-
+<script>
var ban_length = new Array();
ban_length[-1] = '';
var ban_reason = new Array();
@@ -11,12 +9,12 @@
ban_give_reason[-1] = '';
<!-- BEGIN bans -->
- ban_length['{bans.BAN_ID}'] = '{bans.A_LENGTH}';
+ ban_length['{bans.BAN_ID}'] = '{{ bans.A_LENGTH }}';
<!-- IF bans.A_REASON -->
- ban_reason['{bans.BAN_ID}'] = '{bans.A_REASON}';
+ ban_reason['{bans.BAN_ID}'] = '{{ bans.REASON | e('js') }}';
<!-- ENDIF -->
<!-- IF bans.A_GIVE_REASON -->
- ban_give_reason['{bans.BAN_ID}'] = '{bans.A_GIVE_REASON}';
+ ban_give_reason['{bans.BAN_ID}'] = '{{ bans.GIVE_REASON | e('js') }}';
<!-- ENDIF -->
<!-- END bans -->
@@ -34,8 +32,6 @@
document.getElementById('unbangivereason').innerHTML = '';
}
}
-
-// ]]>
</script>
<form id="mcp_ban" method="post" action="{U_ACTION}">
@@ -74,7 +70,7 @@
<dl>
<dt><label for="banexclude0">{L_BAN_EXCLUDE}{L_COLON}</label><br /><span>{L_BAN_EXCLUDE_EXPLAIN}</span></dt>
<dd>
- <label for="banexclude1"><input type="radio" name="banexclude" id="banexclude1" value="1" /> {L_YES}</label>
+ <label for="banexclude1"><input type="radio" name="banexclude" id="banexclude1" value="1" /> {L_YES}</label>
<label for="banexclude0"><input type="radio" name="banexclude" id="banexclude0" value="0" checked="checked" /> {L_NO}</label>
</dd>
</dl>
@@ -85,7 +81,7 @@
</div>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="bansubmit" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
@@ -122,7 +118,7 @@
</div>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="unbansubmit" value="{L_SUBMIT}" class="button1" />
</fieldset>
diff --git a/phpBB/styles/prosilver/template/mcp_forum.html b/phpBB/styles/prosilver/template/mcp_forum.html
index 4c037f56ae..82df5d5dbe 100644
--- a/phpBB/styles/prosilver/template/mcp_forum.html
+++ b/phpBB/styles/prosilver/template/mcp_forum.html
@@ -10,7 +10,7 @@
<div class="panel">
<div class="inner">
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<div class="pagination">
{TOTAL_TOPICS}
<!-- IF .pagination -->
@@ -24,7 +24,7 @@
<!-- IF .topicrow -->
<ul class="topiclist<!-- IF S_MERGE_SELECT --> missing-column<!-- ENDIF -->">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt><div class="list-inner">{L_TOPICS}</div></dt>
<dd class="posts">{L_REPLIES}</dd>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
@@ -36,23 +36,35 @@
<!-- BEGIN topicrow -->
<li class="row<!-- IF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->">
- <dl class="icon {topicrow.TOPIC_IMG_STYLE}">
+ <dl class="row-item {topicrow.TOPIC_IMG_STYLE}">
<dt <!-- IF topicrow.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->>
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="icon-link"></a><!-- ENDIF -->
+ <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
<!-- EVENT topiclist_row_prepend -->
<!-- IF topicrow.S_SELECT_TOPIC --><a href="{topicrow.U_SELECT_TOPIC}" class="topictitle">[ {L_SELECT_MERGE} ]</a>&nbsp;&nbsp; <!-- ENDIF -->
<!-- EVENT mcp_forum_topic_title_before -->
<a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
<!-- EVENT mcp_forum_topic_title_after -->
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_DELETED or topicrow.S_POSTS_DELETED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.DELETED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED -->
+ <a href="{topicrow.U_MCP_QUEUE}" title="{L_TOPIC_UNAPPROVED}">
+ <i class="icon fa-question fa-fw icon-blue" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_UNAPPROVED}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_DELETED or topicrow.S_POSTS_DELETED -->
+ <a href="{topicrow.U_MCP_QUEUE}" title="{L_TOPIC_DELETED}">
+ <i class="icon fa-recycle fa-fw icon-green" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_DELETED}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_REPORTED -->
+ <a href="{topicrow.U_MCP_REPORT}" title="{L_TOPIC_REPORTED}">
+ <i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_REPORTED}</span>
+ </a>
+ <!-- ENDIF -->
<!-- IF topicrow.S_MOVED_TOPIC and S_CAN_DELETE -->&nbsp;<a href="{topicrow.U_DELETE_TOPIC}" class="topictitle">[ {L_DELETE_SHADOW_TOPIC} ]</a><!-- ENDIF -->
<br />
<!-- EVENT topiclist_row_topic_title_after -->
<div class="responsive-show" style="display: none;">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL} &laquo; {topicrow.LAST_POST_TIME}<br />
</div>
<span class="responsive-show left-box" style="display: none;">{L_REPLIES}{L_COLON} <strong>{topicrow.REPLIES}</strong></span>
@@ -73,15 +85,16 @@
<!-- ENDIF -->
<div class="responsive-hide">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
+ {% EVENT topiclist_row_topic_by_author_before %}
{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
+ {% EVENT topiclist_row_topic_by_author_after %}
</div>
<!-- EVENT topiclist_row_append -->
</div>
</dt>
<dd class="posts">{topicrow.REPLIES} <dfn>{L_REPLIES}</dfn></dd>
- <dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}<br />{topicrow.LAST_POST_TIME}</span>
- </dd>
+ <dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}<br />{topicrow.LAST_POST_TIME}</span></dd>
<!-- IF not S_MERGE_SELECT -->
<dd class="mark">
<!-- IF not topicrow.S_MOVED_TOPIC --><input type="checkbox" name="topic_id_list[]" value="{topicrow.TOPIC_ID}"<!-- IF topicrow.S_TOPIC_CHECKED --> checked="checked"<!-- ENDIF --> /><!-- ELSE -->&nbsp;<!-- ENDIF -->
@@ -97,16 +110,9 @@
</ul>
<!-- ENDIF -->
- <fieldset class="display-options">
- <label>{L_DISPLAY_TOPICS}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label>
- <label>{S_SELECT_SORT_DIR}</label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- </fieldset>
-
- <hr />
-
<div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
+
<div class="pagination">
{TOTAL_TOPICS}
<!-- IF .pagination -->
@@ -134,10 +140,8 @@
<!-- IF S_CAN_SYNC --><option value="resync">{L_RESYNC}</option><!-- ENDIF -->
<!-- IF S_CAN_MAKE_NORMAL --><option value="make_normal">{L_MAKE_NORMAL}</option><!-- ENDIF -->
<!-- IF S_CAN_MAKE_STICKY --><option value="make_sticky">{L_MAKE_STICKY}</option><!-- ENDIF -->
- <!-- IF S_CAN_MAKE_ANNOUNCE -->
- <option value="make_announce">{L_MAKE_ANNOUNCE}</option>
- <option value="make_global">{L_MAKE_GLOBAL}</option>
- <!-- ENDIF -->
+ <!-- IF S_CAN_MAKE_ANNOUNCE --><option value="make_announce">{L_MAKE_ANNOUNCE}</option><!-- ENDIF -->
+ <!-- IF S_CAN_MAKE_ANNOUNCE_GLOBAL --><option value="make_global">{L_MAKE_GLOBAL}</option><!-- ENDIF -->
<!-- EVENT mcp_forum_actions_append -->
</select>
<input class="button2" type="submit" value="{L_SUBMIT}" />
diff --git a/phpBB/styles/prosilver/template/mcp_front.html b/phpBB/styles/prosilver/template/mcp_front.html
index 8fe7dfdf65..90793d072b 100644
--- a/phpBB/styles/prosilver/template/mcp_front.html
+++ b/phpBB/styles/prosilver/template/mcp_front.html
@@ -30,7 +30,7 @@
<dl>
<dt>
<div class="list-inner">
- <a href="{unapproved.U_POST_DETAILS}" class="topictitle">{unapproved.SUBJECT}</a> {unapproved.ATTACH_ICON_IMG}<br />
+ <a href="{unapproved.U_POST_DETAILS}" class="topictitle">{unapproved.SUBJECT}</a> <!-- IF unapproved.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i><!-- ENDIF --> <br />
{L_POSTED} {L_POST_BY_AUTHOR} {unapproved.AUTHOR_FULL} &raquo; {unapproved.POST_TIME}
</div>
</dt>
@@ -86,12 +86,12 @@
<dl>
<dt>
<div class="list-inner">
- <a href="{report.U_POST_DETAILS}#reports" class="topictitle">{report.SUBJECT}</a> {report.ATTACH_ICON_IMG}<br />
+ <a href="{report.U_POST_DETAILS}#reports" class="topictitle">{report.SUBJECT}</a> <!-- IF report.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i><!-- ENDIF --> <br />
<span>{L_POSTED} {L_POST_BY_AUTHOR} {report.AUTHOR_FULL} &raquo; {report.POST_TIME}</span>
</div>
</dt>
<dd class="moderation">
- <span>{L_REPORTED} {L_POST_BY_AUTHOR} {report.REPORTER_FULL} {L_REPORTED_ON_DATE} {report.REPORT_TIME}<br />
+ <span>{L_REPORTED} {L_POST_BY_AUTHOR} {report.REPORTER_FULL} {L_REPORTED_ON_DATE} <br />
{L_FORUM}{L_COLON} <a href="{report.U_FORUM}">{report.FORUM_NAME}</a></span>
</dd>
</dl>
@@ -129,7 +129,7 @@
<dl>
<dt>
<div class="list-inner">
- <a href="{pm_report.U_PM_DETAILS}" class="topictitle">{pm_report.PM_SUBJECT}</a> {pm_report.ATTACH_ICON_IMG}<br />
+ <a href="{pm_report.U_PM_DETAILS}" class="topictitle">{pm_report.PM_SUBJECT}</a> <!-- IF pm_report.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i><!-- ENDIF --> <br />
<span>{L_MESSAGE_BY_AUTHOR} {pm_report.PM_AUTHOR_FULL} &raquo; {pm_report.PM_TIME}</span><br />
<span>{L_MESSAGE_TO} {pm_report.RECIPIENTS}</span>
</div>
diff --git a/phpBB/styles/prosilver/template/mcp_header.html b/phpBB/styles/prosilver/template/mcp_header.html
index 69239887e3..5841c1bbd2 100644
--- a/phpBB/styles/prosilver/template/mcp_header.html
+++ b/phpBB/styles/prosilver/template/mcp_header.html
@@ -8,7 +8,7 @@
</p>
<!-- ENDIF -->
-<div id="tabs">
+<div id="tabs" class="tabs">
<ul>
<!-- BEGIN l_block1 -->
<li class="tab<!-- IF l_block1.S_SELECTED --> activetab<!-- ENDIF -->"><a href="{l_block1.U_TITLE}">{l_block1.L_TITLE}</a></li>
@@ -21,14 +21,14 @@
<div style="width: 100%;">
- <div id="cp-menu">
- <div id="navigation" role="navigation">
+ <div id="cp-menu" class="cp-menu">
+ <div id="navigation" class="navigation" role="navigation">
<ul>
<!-- BEGIN l_block1 -->
<!-- IF l_block1.S_SELECTED -->
<!-- BEGIN l_block2 -->
<!-- IF l_block1.l_block2.S_SELECTED -->
- <li id="active-subsection"><a href="{l_block1.l_block2.U_TITLE}"><span>{l_block1.l_block2.L_TITLE}<!-- IF l_block1.l_block2.ADD_ITEM --> ({l_block1.l_block2.ADD_ITEM})<!-- ENDIF --></span></a></li>
+ <li id="active-subsection" class="active-subsection"><a href="{l_block1.l_block2.U_TITLE}"><span>{l_block1.l_block2.L_TITLE}<!-- IF l_block1.l_block2.ADD_ITEM --> ({l_block1.l_block2.ADD_ITEM})<!-- ENDIF --></span></a></li>
<!-- ELSE -->
<li><a href="{l_block1.l_block2.U_TITLE}"><span>{l_block1.l_block2.L_TITLE}<!-- IF l_block1.l_block2.ADD_ITEM --> ({l_block1.l_block2.ADD_ITEM})<!-- ENDIF --></span></a></li>
<!-- ENDIF -->
@@ -39,7 +39,7 @@
</div>
</div>
- <div id="cp-main" class="mcp-main panel-container">
+ <div id="cp-main" class="cp-main mcp-main panel-container">
<!-- IF MESSAGE -->
<div class="content">
<h2 class="message-title">{L_MESSAGE}</h2>
diff --git a/phpBB/styles/prosilver/template/mcp_logs.html b/phpBB/styles/prosilver/template/mcp_logs.html
index 4f74085968..03216b4f38 100644
--- a/phpBB/styles/prosilver/template/mcp_logs.html
+++ b/phpBB/styles/prosilver/template/mcp_logs.html
@@ -7,13 +7,13 @@
<div class="panel">
<div class="inner">
- <div class="action-bar top">
+ <div class="action-bar bar-top">
{L_SEARCH_KEYWORDS}{L_COLON} <input type="search" class="inputbox autowidth" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="button2" name="filter" value="{L_SEARCH}" />
<div class="pagination">
{TOTAL}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -51,21 +51,14 @@
</table>
<!-- IF .log -->
- <fieldset class="display-options">
- <label>{L_DISPLAY_POSTS}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label>
- <label>{S_SELECT_SORT_DIR}</label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- </fieldset>
-
- <hr />
-
<div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
+
<div class="pagination">
{TOTAL}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/mcp_move.html b/phpBB/styles/prosilver/template/mcp_move.html
index 45a9ae83bc..63197ef274 100644
--- a/phpBB/styles/prosilver/template/mcp_move.html
+++ b/phpBB/styles/prosilver/template/mcp_move.html
@@ -43,12 +43,14 @@
<!-- IF ADDITIONAL_MSG --><p>{ADDITIONAL_MSG}</p><!-- ENDIF -->
<fieldset>
+ {% EVENT mcp_move_destination_forum_before %}
<dl class="fields2">
<dt><label>{L_SELECT_DESTINATION_FORUM}{L_COLON}</label></dt>
<dd><select name="to_forum_id">{S_FORUM_SELECT}</select></dd>
<!-- IF S_CAN_LEAVE_SHADOW --><dd><label for="move_leave_shadow"><input type="checkbox" name="move_leave_shadow" id="move_leave_shadow" />{L_LEAVE_SHADOW}</label></dd><!-- ENDIF -->
<!-- IF S_CAN_LOCK_TOPIC --><dd><label for="move_lock_topics"><input type="checkbox" name="move_lock_topics" id="move_lock_topics" />{L_LOCK_TOPIC}</label></dd><!-- ENDIF -->
</dl>
+ {% EVENT mcp_move_destination_forum_after %}
<dl class="fields2">
<dt>&nbsp;</dt>
<dd><strong>{MESSAGE_TEXT}</strong></dd>
diff --git a/phpBB/styles/prosilver/template/mcp_notes_front.html b/phpBB/styles/prosilver/template/mcp_notes_front.html
index db10284bce..11f362376d 100644
--- a/phpBB/styles/prosilver/template/mcp_notes_front.html
+++ b/phpBB/styles/prosilver/template/mcp_notes_front.html
@@ -19,7 +19,7 @@
</div>
<fieldset class="submit-buttons">
- <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="submituser" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/mcp_notes_user.html b/phpBB/styles/prosilver/template/mcp_notes_user.html
index 3e8d47eb9d..62d0562a46 100644
--- a/phpBB/styles/prosilver/template/mcp_notes_user.html
+++ b/phpBB/styles/prosilver/template/mcp_notes_user.html
@@ -50,13 +50,13 @@
<div class="panel">
<div class="inner">
- <div class="action-bar top">
+ <div class="action-bar bar-top">
{L_SEARCH_KEYWORDS}{L_COLON} <input type="search" class="inputbox autowidth" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="button2" name="filter" value="{L_SEARCH}" />
<div class="pagination">
{TOTAL_REPORTS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -90,22 +90,14 @@
</tbody>
</table>
- <hr />
-
- <fieldset class="display-options">
- <label>{L_DISPLAY_LOG}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label><label>{S_SELECT_SORT_DIR}</label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- </fieldset>
-
- <hr />
-
<div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
+
<div class="pagination">
{TOTAL_REPORTS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/mcp_post.html b/phpBB/styles/prosilver/template/mcp_post.html
index 5acdcef859..c2297a8053 100644
--- a/phpBB/styles/prosilver/template/mcp_post.html
+++ b/phpBB/styles/prosilver/template/mcp_post.html
@@ -14,7 +14,7 @@
<h3>{L_REPORT_REASON}{L_COLON} {REPORT_REASON_TITLE}</h3>
<p class="author">{L_REPORTED} {L_POST_BY_AUTHOR} {REPORTER_FULL} &laquo; {REPORT_DATE}</p>
<!-- IF S_REPORT_CLOSED -->
- <p class="post-notice reported">{L_REPORT_CLOSED}</p>
+ <p class="post-notice reported"><i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i>{L_REPORT_CLOSED}</p>
<!-- ENDIF -->
<div class="content">
<!-- IF REPORT_TEXT -->
@@ -31,10 +31,12 @@
<form method="post" id="mcp_report" action="{S_CLOSE_ACTION}">
<fieldset class="submit-buttons">
+ {% EVENT mcp_post_report_buttons_top_before %}
<!-- IF not S_REPORT_CLOSED -->
<input class="button1" type="submit" value="{L_CLOSE_REPORT}" name="action[close]" /> &nbsp;
<!-- ENDIF -->
<input class="button2" type="submit" value="{L_DELETE_REPORT}" name="action[delete]" />
+ {% EVENT mcp_post_report_buttons_top_after %}
<input type="hidden" name="report_id_list[]" value="{REPORT_ID}" />
{S_FORM_TOKEN}
</fieldset>
@@ -58,8 +60,8 @@
</li>
<!-- IF U_EDIT -->
<li>
- <a href="{U_EDIT}" title="{L_EDIT_POST}" class="button icon-button edit-icon">
- <span>{L_EDIT_POST}</span>
+ <a href="{U_EDIT}" title="{L_EDIT_POST}" class="button">
+ <i class="icon fa-pencil fa-fw" aria-hidden="true"></i><span class="sr-only">{L_EDIT_POST}</span>
</a>
</li>
<!-- ENDIF -->
@@ -69,11 +71,11 @@
<p class="author">
<strong>{L_SENT_AT}{L_COLON}</strong> {POST_DATE}
<br /><strong>{L_PM_FROM}{L_COLON}</strong> {POST_AUTHOR_FULL}
- <!-- IF S_TO_RECIPIENT --><br /><strong>{L_TO}{L_COLON}</strong> <!-- BEGIN to_recipient --><!-- IF to_recipient.NAME_FULL -->{to_recipient.NAME_FULL}<!-- ELSE --><a href="{to_recipient.U_VIEW}" style="color:<!-- IF to_recipient.COLOUR -->{to_recipient.COLOUR}<!-- ELSEIF to_recipient.IS_GROUP -->#0000FF<!-- ENDIF -->;">{to_recipient.NAME}</a><!-- ENDIF -->&nbsp;<!-- END to_recipient --><!-- ENDIF -->
- <!-- IF S_BCC_RECIPIENT --><br /><strong>{L_BCC}{L_COLON}</strong> <!-- BEGIN bcc_recipient --><!-- IF bcc_recipient.NAME_FULL -->{bcc_recipient.NAME_FULL}<!-- ELSE --><a href="{bcc_recipient.U_VIEW}" style="color:<!-- IF bcc_recipient.COLOUR -->{bcc_recipient.COLOUR}<!-- ELSEIF bcc_recipient.IS_GROUP -->#0000FF<!-- ENDIF -->;">{bcc_recipient.NAME}</a><!-- ENDIF -->&nbsp;<!-- END bcc_recipient --><!-- ENDIF -->
+ <!-- IF S_TO_RECIPIENT --><br /><strong>{L_TO}{L_COLON}</strong> <!-- BEGIN to_recipient --><!-- IF to_recipient.NAME_FULL -->{to_recipient.NAME_FULL}<!-- ELSE --><a href="{to_recipient.U_VIEW}"<!-- IF to_recipient.COLOUR --> style="color:{to_recipient.COLOUR};"<!-- ENDIF -->><strong>{to_recipient.NAME}</strong></a><!-- ENDIF -->&nbsp;<!-- END to_recipient --><!-- ENDIF -->
+ <!-- IF S_BCC_RECIPIENT --><br /><strong>{L_BCC}{L_COLON}</strong> <!-- BEGIN bcc_recipient --><!-- IF bcc_recipient.NAME_FULL -->{bcc_recipient.NAME_FULL}<!-- ELSE --><a href="{bcc_recipient.U_VIEW}"<!-- IF bcc_recipient.COLOUR --> style="color:{bcc_recipient.COLOUR};"<!-- ENDIF -->><strong>{bcc_recipient.NAME}</strong></a><!-- ENDIF -->&nbsp;<!-- END bcc_recipient --><!-- ENDIF -->
</p>
<!-- ELSE -->
- <p class="author">{MINI_POST_IMG} {L_POSTED} {L_POST_BY_AUTHOR} {POST_AUTHOR_FULL} &raquo; {POST_DATE}</p>
+ <p class="author"><span><i class="icon fa-file fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{MINI_POST_IMG}</span></span> {L_POSTED} {L_POST_BY_AUTHOR} {POST_AUTHOR_FULL} &raquo; {POST_DATE}</p>
<!-- ENDIF -->
<!-- IF S_POST_UNAPPROVED -->
@@ -102,14 +104,18 @@
<!-- IF S_MESSAGE_REPORTED -->
<p class="post-notice reported">
- {REPORTED_IMG} <a href="{U_MCP_REPORT}"><strong>{L_MESSAGE_REPORTED}</strong></a>
+ <i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_REPORTED}</span> <a href="{U_MCP_REPORT}"><strong>{L_MESSAGE_REPORTED}</strong></a>
</p>
<!-- ENDIF -->
- <div class="content" id="post_details">
+ {% EVENT mcp_post_text_before %}
+
+ <div id="post_details" class="content post_details">
{POST_PREVIEW}
</div>
+ {% EVENT mcp_post_text_after %}
+
<!-- IF S_HAS_ATTACHMENTS -->
<dl class="attachbox">
<dt>{L_ATTACHMENTS}</dt>
@@ -331,15 +337,15 @@
<ul>
<!-- BEGIN pagination_ips -->
<!-- IF pagination_ips.S_IS_PREV -->
- <li class="previous"><a href="{pagination_ips.PAGE_URL}" rel="prev" role="button">{L_PREVIOUS}</a></li>
+ <li class="arrow previous"><a class="button button-icon-only" href="{pagination_ips.PAGE_URL}" rel="prev" role="button"><i class="icon fa-chevron-{S_CONTENT_FLOW_BEGIN} fa-fw" aria-hidden="true"></i><span class="sr-only">{L_PREVIOUS}</span></a></li>
<!-- ELSEIF pagination_ips.S_IS_CURRENT -->
- <li class="active"><span>{pagination_ips.PAGE_NUMBER}</span></li>
+ <li class="active"><span>{pagination_ips.PAGE_NUMBER}</span></li>
<!-- ELSEIF pagination_ips.S_IS_ELLIPSIS -->
- <li class="ellipsis" role="separator"><span>{L_ELLIPSIS}</span></li>
+ <li class="ellipsis" role="separator"><span>{L_ELLIPSIS}</span></li>
<!-- ELSEIF pagination_ips.S_IS_NEXT -->
- <li class="next"><a href="{pagination_ips.PAGE_URL}" rel="next" role="button">{L_NEXT}</a></li>
+ <li class="arrow next"><a class="button button-icon-only" href="{pagination_ips.PAGE_URL}" rel="next" role="button"><i class="icon fa-chevron-{S_CONTENT_FLOW_END} fa-fw" aria-hidden="true"></i><span class="sr-only">{L_NEXT}</span></a></li>
<!-- ELSE -->
- <li><a href="{pagination_ips.PAGE_URL}" role="button">{pagination_ips.PAGE_NUMBER}</a></li>
+ <li><a class="button" href="{pagination_ips.PAGE_URL}" role="button">{pagination_ips.PAGE_NUMBER}</a></li>
<!-- ENDIF -->
<!-- END pagination_ips -->
</ul>
diff --git a/phpBB/styles/prosilver/template/mcp_queue.html b/phpBB/styles/prosilver/template/mcp_queue.html
index 864b231142..ee69bf448d 100644
--- a/phpBB/styles/prosilver/template/mcp_queue.html
+++ b/phpBB/styles/prosilver/template/mcp_queue.html
@@ -16,12 +16,12 @@
<p>{L_EXPLAIN}</p>
<!-- IF .postrow -->
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<div class="pagination">
{TOTAL}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -48,7 +48,7 @@
<dl>
<dt>
<div class="list-inner">
- <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
+ <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a><!-- IF postrow.S_HAS_ATTACHMENTS --> <i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF --><br />
<span>{L_POSTED} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} &raquo; {postrow.POST_TIME}</span>
</div>
</dt>
@@ -73,21 +73,15 @@
<!-- END postrow -->
</ul>
- <fieldset class="display-options">
- <label>{L_DISPLAY_POSTS}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label><label>{S_SELECT_SORT_DIR}</label>
- <!-- IF TOPIC_ID --><label><input type="checkbox" class="radio" name="t" value="{TOPIC_ID}" checked="checked" />&nbsp; <strong>{L_ONLY_TOPIC}</strong></label><!-- ENDIF -->
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- </fieldset>
-
- <hr />
-
<div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
+ <!-- IF TOPIC_ID --><label><input type="checkbox" class="radio" name="t" value="{TOPIC_ID}" checked="checked" onClick="document.getElementById('mcp').submit()" /> <strong>{L_ONLY_TOPIC}</strong></label><!-- ENDIF -->
+
<div class="pagination">
{TOTAL}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/mcp_reports.html b/phpBB/styles/prosilver/template/mcp_reports.html
index 24c0479f63..e7e0a5c9ba 100644
--- a/phpBB/styles/prosilver/template/mcp_reports.html
+++ b/phpBB/styles/prosilver/template/mcp_reports.html
@@ -18,12 +18,12 @@
<p>{L_EXPLAIN}</p>
<!-- IF .postrow -->
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<div class="pagination">
{TOTAL_REPORTS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -46,7 +46,7 @@
<!-- IF S_PM -->
<dt>
<div class="list-inner">
- <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.PM_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
+ <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.PM_SUBJECT}</a> <i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <br />
<span>{L_MESSAGE_BY_AUTHOR} {postrow.PM_AUTHOR_FULL} &raquo; {postrow.PM_TIME}</span><br />
<span>{L_MESSAGE_TO} {postrow.RECIPIENTS}</span>
<div class="responsive-show" style="display: none;">
@@ -60,7 +60,7 @@
<!-- ELSE -->
<dt>
<div class="list-inner">
- <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
+ <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <br />
<span>{L_POSTED} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} &raquo; {postrow.POST_TIME}</span>
<div class="responsive-show" style="display: none;">
{L_REPORTER}{L_COLON} {postrow.REPORTER_FULL} &laquo; {postrow.REPORT_TIME}<br />
@@ -79,21 +79,15 @@
<!-- END postrow -->
</ul>
- <fieldset class="display-options">
- <label>{L_DISPLAY_POSTS}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label><label>{S_SELECT_SORT_DIR}</label>
- <!-- IF TOPIC_ID --><label><input type="checkbox" class="radio" name="t" value="{TOPIC_ID}" checked="checked" />&nbsp; <strong>{L_ONLY_TOPIC}</strong></label><!-- ENDIF -->
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- </fieldset>
-
- <hr />
-
<div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
+ <!-- IF TOPIC_ID --><label><input type="checkbox" class="radio" name="t" value="{TOPIC_ID}" checked="checked" onClick="document.getElementById('mcp').submit()" /> <strong>{L_ONLY_TOPIC}</strong></label><!-- ENDIF -->
+
<div class="pagination">
{TOTAL_REPORTS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/mcp_topic.html b/phpBB/styles/prosilver/template/mcp_topic.html
index af4b63265f..889cab8b83 100644
--- a/phpBB/styles/prosilver/template/mcp_topic.html
+++ b/phpBB/styles/prosilver/template/mcp_topic.html
@@ -11,7 +11,7 @@
<!-- DEFINE $SHOW_PANEL = 'display-panel' -->
<!-- ENDIF -->
-<div id="minitabs" class="sub-panels" data-show-panel="{$SHOW_PANEL}" role="tablist">
+<div id="minitabs" class="minitabs sub-panels" data-show-panel="{$SHOW_PANEL}" role="tablist">
<ul>
<li id="display-panel-tab" class="tab<!-- IF not S_MERGE_VIEW --> activetab<!-- ENDIF -->">
<a href="#minitabs" data-subpanel="display-panel" role="tab" aria-controls="display-panel">{L_DISPLAY_OPTIONS}</a>
@@ -87,21 +87,22 @@
<div class="panel">
<div class="inner">
- <h3 id="review">
+ <h3 id="review" class="review">
<span class="right-box"><a href="#review" onclick="viewableArea(getElementById('topicreview'), true); var rev_text = getElementById('review').getElementsByTagName('a').item(0).firstChild; if (rev_text.data == '{LA_EXPAND_VIEW}'){rev_text.data = '{LA_COLLAPSE_VIEW}'; } else if (rev_text.data == '{LA_COLLAPSE_VIEW}'){rev_text.data = '{LA_EXPAND_VIEW}'};">{L_EXPAND_VIEW}</a></span>
{L_TOPIC_REVIEW}{L_COLON} <!-- EVENT mcp_topic_topic_title_before -->{TOPIC_TITLE}<!-- EVENT mcp_topic_topic_title_after -->
</h3>
- <div id="topicreview">
+ <div id="topicreview" class="topicreview">
<!-- BEGIN postrow -->
+ <!-- EVENT mcp_topic_postrow_post_before -->
<div class="post <!-- IF postrow.S_ROW_COUNT is odd -->bg1<!-- ELSE -->bg2<!-- ENDIF -->">
<div class="inner">
<div class="postbody" id="pr{postrow.POST_ID}">
<ul class="post-buttons">
<li>
- <a href="{postrow.U_POST_DETAILS}" title="{L_POST_DETAILS}" class="button icon-button info-icon">
- <span>{L_POST_DETAILS}</span>
+ <a href="{postrow.U_POST_DETAILS}" title="{L_POST_DETAILS}" class="button button-icon-only">
+ <i class="icon fa-info fa-fw" aria-hidden="true"></i><span class="sr-only">{L_POST_DETAILS}</span>
</a>
</li>
<li>
@@ -116,12 +117,16 @@
<!-- EVENT mcp_topic_postrow_post_subject_after -->
<!-- EVENT mcp_topic_postrow_post_details_before -->
- <p class="author"><a href="#pr{postrow.POST_ID}">{postrow.MINI_POST_IMG}</a> {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} <strong>{postrow.POST_AUTHOR_FULL}</strong><!-- IF postrow.U_MCP_DETAILS --> [ <a href="{postrow.U_MCP_DETAILS}">{L_POST_DETAILS}</a> ]<!-- ENDIF --></p>
+ <p class="author">
+ <a href="{postrow.U_MINI_POST}" title="{postrow.MINI_POST}">
+ <i class="icon fa-file fa-fw icon-lightgray icon-tiny" aria-hidden="true"></i><span class="sr-only">{postrow.MINI_POST}</span>
+ </a> {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} {% EVENT mcp_topic_post_author_full_prepend %}<strong>{postrow.POST_AUTHOR_FULL}</strong>{% EVENT mcp_topic_post_author_full_append %}<!-- IF postrow.U_MCP_DETAILS --> [ <a href="{postrow.U_MCP_DETAILS}">{L_POST_DETAILS}</a> ]<!-- ENDIF -->
+ </p>
<!-- EVENT mcp_topic_postrow_post_details_after -->
<!-- IF postrow.S_POST_UNAPPROVED -->
<p class="post-notice unapproved">
- <a href="{postrow.U_MCP_APPROVE}"><strong>{L_POST_UNAPPROVED}</strong></a>
+ <a href="{postrow.U_MCP_APPROVE}"><i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><strong>{L_POST_UNAPPROVED}</strong></a>
</p>
<!-- ENDIF -->
@@ -133,12 +138,14 @@
<!-- IF postrow.S_POST_REPORTED -->
<p class="post-notice reported">
- <a href="{postrow.U_MCP_REPORT}"><strong>{L_POST_REPORTED}</strong></a>
+ <a href="{postrow.U_MCP_REPORT}"><i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><strong>{L_POST_REPORTED}</strong></a>
</p>
<!-- ENDIF -->
<div class="content" id="message_{postrow.POST_ID}">{postrow.MESSAGE}</div>
+ <!-- EVENT mcp_topic_postrow_attachments_before -->
+
<!-- IF postrow.S_HAS_ATTACHMENTS -->
<dl class="attachbox">
<dt>{L_ATTACHMENTS}</dt>
@@ -148,6 +155,8 @@
</dl>
<!-- ENDIF -->
+ <!-- EVENT mcp_topic_postrow_attachments_after -->
+
</div>
</div>
@@ -157,7 +166,7 @@
<hr />
- <div class="action-bar bottom">
+ <div class="action-bar bar-bottom">
<div class="pagination">
{TOTAL_POSTS}
<!-- IF .pagination -->
diff --git a/phpBB/styles/prosilver/template/mcp_warn_front.html b/phpBB/styles/prosilver/template/mcp_warn_front.html
index 668a0d81a8..9b188b52ac 100644
--- a/phpBB/styles/prosilver/template/mcp_warn_front.html
+++ b/phpBB/styles/prosilver/template/mcp_warn_front.html
@@ -21,7 +21,7 @@
</div>
<fieldset class="submit-buttons">
- <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="submituser" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/mcp_warn_list.html b/phpBB/styles/prosilver/template/mcp_warn_list.html
index d0e80a1479..29a2d29e8f 100644
--- a/phpBB/styles/prosilver/template/mcp_warn_list.html
+++ b/phpBB/styles/prosilver/template/mcp_warn_list.html
@@ -10,12 +10,12 @@
<p>{L_WARNED_USERS_EXPLAIN}</p>
<!-- IF .user -->
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<div class="pagination">
{TOTAL_USERS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -43,20 +43,14 @@
</tbody>
</table>
- <fieldset class="display-options">
- <label>{L_DISPLAY_POSTS}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label><label>{S_SELECT_SORT_DIR}</label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- </fieldset>
-
- <hr />
-
<div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
+
<div class="pagination">
{TOTAL_USERS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/mcp_warn_post.html b/phpBB/styles/prosilver/template/mcp_warn_post.html
index 59c7d0d495..5e39480658 100644
--- a/phpBB/styles/prosilver/template/mcp_warn_post.html
+++ b/phpBB/styles/prosilver/template/mcp_warn_post.html
@@ -69,7 +69,7 @@
<!-- EVENT mcp_warn_post_add_warning_field_after -->
<fieldset class="submit-buttons">
- <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="action[add_warning]" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/mcp_warn_user.html b/phpBB/styles/prosilver/template/mcp_warn_user.html
index 1ad6df7ade..f4dbf2819e 100644
--- a/phpBB/styles/prosilver/template/mcp_warn_user.html
+++ b/phpBB/styles/prosilver/template/mcp_warn_user.html
@@ -53,7 +53,7 @@
<!-- EVENT mcp_warn_user_add_warning_field_after -->
<fieldset class="submit-buttons">
- <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="action[add_warning]" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/mcp_whois.html b/phpBB/styles/prosilver/template/mcp_whois.html
index 41a825458d..1d08a4627e 100644
--- a/phpBB/styles/prosilver/template/mcp_whois.html
+++ b/phpBB/styles/prosilver/template/mcp_whois.html
@@ -3,13 +3,19 @@
<div class="panel">
<div class="inner">
-
- <p><a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_RETURN_POST}">{L_RETURN_POST}</a></p>
+ <p>
+ <a href="{U_RETURN_POST}" class="arrow-{S_CONTENT_FLOW_BEGIN}" accesskey="r">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_RETURN_POST}</span>
+ </a>
+ </p>
<div class="postbody"><div class="content">
<pre>{WHOIS}</pre>
</div></div>
- <p><a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_RETURN_POST}">{L_RETURN_POST}</a></p>
-
+ <p>
+ <a href="{U_RETURN_POST}" class="arrow-{S_CONTENT_FLOW_BEGIN}" accesskey="r">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_RETURN_POST}</span>
+ </a>
+ </p>
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/memberlist_body.html b/phpBB/styles/prosilver/template/memberlist_body.html
index 5fba59159c..b8ff092372 100644
--- a/phpBB/styles/prosilver/template/memberlist_body.html
+++ b/phpBB/styles/prosilver/template/memberlist_body.html
@@ -12,36 +12,50 @@
<!-- ENDIF -->
+{% EVENT memberlist_body_page_header_after %}
+
<!-- IF S_SHOW_GROUP -->
+ {% EVENT memberlist_body_group_name_before %}
<h2 class="group-title"<!-- IF GROUP_COLOR --> style="color:#{GROUP_COLOR};"<!-- ENDIF -->>{GROUP_NAME}</h2>
+ {% EVENT memberlist_body_group_name_after %}
<!-- IF U_MANAGE -->
<p class="right responsive-center manage rightside"><a href="{U_MANAGE}">{L_MANAGE_GROUP}</a></p>
<!-- ENDIF -->
<p>{GROUP_DESC} {GROUP_TYPE}</p>
+ {% EVENT memberlist_body_group_desc_after %}
+
<p>
<!-- IF AVATAR_IMG -->{AVATAR_IMG}<!-- ENDIF -->
- <!-- IF RANK_IMG -->{RANK_IMG}<!-- ENDIF -->
- <!-- IF GROUP_RANK -->{GROUP_RANK}<!-- ENDIF -->
+ {% EVENT memberlist_body_group_rank_before %}
+ {% if RANK_IMG %}{{ RANK_IMG }}{% endif %}
+ {% if GROUP_RANK %}
+ {% if not RANK_IMG %}
+ {{ lang('GROUP_RANK') ~ lang('COLON') }}
+ {% endif %}
+ {{ GROUP_RANK }}
+ {% endif %}
+ {% EVENT memberlist_body_group_rank_after %}
</p>
<!-- ELSE -->
+ {% EVENT memberlist_body_page_title_before %}
<h2 class="solo">{PAGE_TITLE}<!-- IF SEARCH_WORDS -->{L_COLON} <a href="{U_SEARCH_WORDS}">{SEARCH_WORDS}</a><!-- ENDIF --></h2>
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<div class="member-search panel">
- <!-- IF U_FIND_MEMBER and not S_SEARCH_USER --><a href="{U_FIND_MEMBER}" id="member_search" data-alt-text="{LA_HIDE_MEMBER_SEARCH}">{L_FIND_USERNAME}</a> &bull; <!-- ELSEIF S_SEARCH_USER and U_HIDE_FIND_MEMBER and not S_IN_SEARCH_POPUP --><a href="{U_HIDE_FIND_MEMBER}" id="member_search" data-alt-text="{LA_FIND_USERNAME}">{L_HIDE_MEMBER_SEARCH}</a> &bull; <!-- ENDIF -->
+ <!-- IF U_FIND_MEMBER and not S_SEARCH_USER --><a href="{U_FIND_MEMBER}" id="member_search" data-alt-text="{L_HIDE_MEMBER_SEARCH}">{L_FIND_USERNAME}</a> &bull; <!-- ELSEIF S_SEARCH_USER and U_HIDE_FIND_MEMBER and not S_IN_SEARCH_POPUP --><a href="{U_HIDE_FIND_MEMBER}" id="member_search" data-alt-text="{L_FIND_USERNAME}">{L_HIDE_MEMBER_SEARCH}</a> &bull; <!-- ENDIF -->
<strong>
<!-- BEGIN first_char -->
<a href="{first_char.U_SORT}">{first_char.DESC}</a>&nbsp;
<!-- END first_char -->
</strong>
</div>
-
+
<div class="pagination">
{TOTAL_USERS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -52,7 +66,7 @@
<div class="forumbg forumbg-table">
<div class="inner">
- <table class="table1" id="memberlist">
+ <table class="table1 memberlist" id="memberlist">
<thead>
<tr>
<th class="name" data-dfn="{L_RANK}{L_COMMA_SEPARATOR}<!-- IF S_SHOW_GROUP and .memberrow -->{L_GROUP_LEADER}<!-- ELSE -->{L_USERNAME}<!-- ENDIF -->"><span class="rank-img"><a href="{U_SORT_RANK}">{L_RANK}</a></span><a href="{U_SORT_USERNAME}"><!-- IF S_SHOW_GROUP and .memberrow -->{L_GROUP_LEADER}<!-- ELSE -->{L_USERNAME}<!-- ENDIF --></a></th>
@@ -60,6 +74,7 @@
<th class="info"><!-- BEGIN custom_fields --><!-- IF not custom_fields.S_FIRST_ROW -->{L_COMMA_SEPARATOR} <!-- ENDIF -->{custom_fields.PROFILE_FIELD_NAME}<!-- END custom_fields --></th>
<th class="joined"><a href="{U_SORT_JOINED}#memberlist">{L_JOINED}</a></th>
<!-- IF U_SORT_ACTIVE --><th class="active"><a href="{U_SORT_ACTIVE}#memberlist">{L_LAST_ACTIVE}</a></th><!-- ENDIF -->
+ {% EVENT memberlist_body_memberlist_after %}
</tr>
</thead>
<tbody>
@@ -88,15 +103,17 @@
<!-- IF not S_LEADERS_SET -->
<th class="name" data-dfn="{L_RANK}{L_COMMA_SEPARATOR}{L_USERNAME}"><span class="rank-img"><a href="{U_SORT_RANK}">{L_RANK}</a></span><a href="{U_SORT_USERNAME}"><!-- IF S_SHOW_GROUP -->{L_GROUP_MEMBERS}<!-- ELSE -->{L_USERNAME}<!-- ENDIF --></a></th>
<th class="posts"><a href="{U_SORT_POSTS}#memberlist">{L_POSTS}</a></th>
- <th class="info"><!-- BEGIN custom_fields --><!-- IF not custom_fields.S_FIRST_ROW -->{L_COMMA_SEPARATOR} <!-- ENDIF -->{custom_fields.PROFILE_FIELD_NAME}<!-- END custom_fields --></th>
+ <th class="info">{% for field in custom_fields %}{% if not loop.first %}{L_COMMA_SEPARATOR} {% endif %}{{ field.PROFILE_FIELD_NAME }}{% endfor %}</th>
<th class="joined"><a href="{U_SORT_JOINED}#memberlist">{L_JOINED}</a></th>
<!-- IF U_SORT_ACTIVE --><th class="active"><a href="{U_SORT_ACTIVE}#memberlist">{L_LAST_ACTIVE}</a></th><!-- ENDIF -->
+ {% EVENT memberlist_body_leaders_set_after %}
<!-- ELSEIF S_SHOW_GROUP -->
<th class="name">{L_GROUP_MEMBERS}</th>
<th class="posts">{L_POSTS}</th>
<th class="info"><!-- BEGIN custom_fields --><!-- IF not custom_fields.S_FIRST_ROW -->{L_COMMA_SEPARATOR} <!-- ENDIF -->{custom_fields.PROFILE_FIELD_NAME}<!-- END custom_fields --></th>
<th class="joined">{L_JOINED}</th>
<!-- IF U_SORT_ACTIVE --><th class="active">{L_LAST_ACTIVE}</th><!-- ENDIF -->
+ {% EVENT memberlist_body_show_group_after %}
<!-- ENDIF -->
</tr>
</thead>
@@ -108,9 +125,16 @@
<tr class="<!-- IF memberrow.S_ROW_COUNT is even -->bg1<!-- ELSE -->bg2<!-- ENDIF --><!-- IF memberrow.S_INACTIVE --> inactive<!-- ENDIF -->">
<td><span class="rank-img"><!-- EVENT memberlist_body_rank_prepend --><!-- IF memberrow.RANK_IMG -->{memberrow.RANK_IMG}<!-- ELSE -->{memberrow.RANK_TITLE}<!-- ENDIF --><!-- EVENT memberlist_body_rank_append --></span><!-- IF S_IN_SEARCH_POPUP and not S_SELECT_SINGLE --><input type="checkbox" name="user" value="{memberrow.USERNAME}" /> <!-- ENDIF --><!-- EVENT memberlist_body_username_prepend -->{memberrow.USERNAME_FULL}<!-- IF memberrow.S_INACTIVE --> ({L_INACTIVE})<!-- ENDIF --><!-- EVENT memberlist_body_username_append --><!-- IF S_IN_SEARCH_POPUP --><br />[&nbsp;<a href="#" onclick="insert_single_user('#results', '{memberrow.A_USERNAME}'); return false;">{L_SELECT}</a>&nbsp;]<!-- ENDIF --></td>
<td class="posts"><!-- IF memberrow.POSTS and S_DISPLAY_SEARCH --><a href="{memberrow.U_SEARCH_USER}" title="{L_SEARCH_USER_POSTS}">{memberrow.POSTS}</a><!-- ELSE -->{memberrow.POSTS}<!-- ENDIF --></td>
- <td class="info"><!-- BEGIN custom_fields --><div>{memberrow.custom_fields.PROFILE_FIELD_VALUE}</div><!-- BEGINELSE -->&nbsp;<!-- END custom_fields --></td>
+ <td class="info">
+ {%- for field in memberrow.custom_fields -%}
+ <div>{% if field.S_PROFILE_CONTACT %}<a href="{{ field.PROFILE_FIELD_CONTACT }}">{% endif %}{{ field.PROFILE_FIELD_VALUE }}{% if field.S_PROFILE_CONTACT %}</a>{% endif %}</div>
+ {%- else -%}
+ &nbsp;
+ {%- endfor -%}
+ </td>
<td>{memberrow.JOINED}</td>
<!-- IF S_VIEWONLINE --><td>{memberrow.LAST_ACTIVE}&nbsp;</td><!-- ENDIF -->
+ {% EVENT memberlist_body_memberrow_after %}
</tr>
<!-- BEGINELSE -->
<tr class="bg1">
@@ -145,17 +169,19 @@
</form>
-<div class="action-bar bottom">
+<div class="action-bar bar-bottom">
<div class="pagination">
{TOTAL_USERS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
</div>
+{% EVENT memberlist_body_page_footer_before %}
+
<!-- IF S_IN_SEARCH_POPUP -->
<!-- INCLUDE simple_footer.html -->
<!-- ELSE -->
diff --git a/phpBB/styles/prosilver/template/memberlist_team.html b/phpBB/styles/prosilver/template/memberlist_team.html
index 327dde412e..59041fbac0 100644
--- a/phpBB/styles/prosilver/template/memberlist_team.html
+++ b/phpBB/styles/prosilver/template/memberlist_team.html
@@ -36,7 +36,7 @@
<!-- END user -->
</tbody>
</table>
-
+
</div>
</div>
<!-- END group -->
diff --git a/phpBB/styles/prosilver/template/memberlist_view.html b/phpBB/styles/prosilver/template/memberlist_view.html
index a7439bc759..debf64cba2 100644
--- a/phpBB/styles/prosilver/template/memberlist_view.html
+++ b/phpBB/styles/prosilver/template/memberlist_view.html
@@ -21,7 +21,7 @@
<dl class="left-box details profile-details">
<dt>{L_USERNAME}{L_COLON}</dt>
<dd>
- <!-- IF USER_COLOR --><span style="color: {USER_COLOR}; font-weight: bold;"><!-- ELSE --><span><!-- ENDIF -->{USERNAME}</span>
+ <!-- EVENT memberlist_view_username_prepend --><!-- IF USER_COLOR --><span style="color: {USER_COLOR}; font-weight: bold;"><!-- ELSE --><span><!-- ENDIF -->{USERNAME}</span><!-- EVENT memberlist_view_username_append -->
<!-- IF U_EDIT_SELF --> [ <a href="{U_EDIT_SELF}">{L_EDIT_PROFILE}</a> ]<!-- ENDIF -->
<!-- IF U_USER_ADMIN --> [ <a href="{U_USER_ADMIN}">{L_USER_ADMIN}</a> ]<!-- ENDIF -->
<!-- IF U_USER_BAN --> [ <a href="{U_USER_BAN}">{L_USER_BAN}</a> ]<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/message_body.html b/phpBB/styles/prosilver/template/message_body.html
index 71eca203bc..330203e19e 100644
--- a/phpBB/styles/prosilver/template/message_body.html
+++ b/phpBB/styles/prosilver/template/message_body.html
@@ -8,7 +8,13 @@
<div class="inner">
<h2 class="message-title">{MESSAGE_TITLE}</h2>
<p>{MESSAGE_TEXT}</p>
- <!-- IF SCRIPT_NAME == "search" and not S_BOARD_DISABLED and not S_NO_SEARCH and L_RETURN_TO_SEARCH_ADV --><p><a href="{U_SEARCH}" class="arrow-{S_CONTENT_FLOW_BEGIN}">{L_GO_TO_SEARCH_ADV}</a></p><!-- ENDIF -->
+ <!-- IF SCRIPT_NAME == "search" and not S_BOARD_DISABLED and not S_NO_SEARCH and L_RETURN_TO_SEARCH_ADV -->
+ <p>
+ <a href="{U_SEARCH}" class="arrow-{S_CONTENT_FLOW_BEGIN}" accesskey="r">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_GO_TO_SEARCH_ADV}</span>
+ </a>
+ </p>
+ <!-- ENDIF -->
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/navbar_footer.html b/phpBB/styles/prosilver/template/navbar_footer.html
index b5a705d567..4e3d1e295e 100644
--- a/phpBB/styles/prosilver/template/navbar_footer.html
+++ b/phpBB/styles/prosilver/template/navbar_footer.html
@@ -1,26 +1,68 @@
<div class="navbar" role="navigation">
<div class="inner">
- <ul id="nav-footer" class="linklist bulletin" role="menubar">
- <li class="small-icon icon-home breadcrumbs">
- <!-- IF U_SITE_HOME --><span class="crumb"><a href="{U_SITE_HOME}" data-navbar-reference="home">{L_SITE_HOME}</a></span><!-- ENDIF -->
+ <ul id="nav-footer" class="nav-footer linklist" role="menubar">
+ <li class="breadcrumbs">
+ <!-- IF U_SITE_HOME -->
+ {% spaceless %}
+ <span class="crumb">
+ <a href="{U_SITE_HOME}" data-navbar-reference="home">
+ <i class="icon fa-home fa-fw" aria-hidden="true"></i><span>{L_SITE_HOME}</span>
+ </a>
+ </span>
+ {% endspaceless %}
+ <!-- ENDIF -->
<!-- EVENT overall_footer_breadcrumb_prepend -->
- <span class="crumb"><a href="{U_INDEX}" data-navbar-reference="index">{L_INDEX}</a></span>
+ {% spaceless %}
+ <span class="crumb">
+ <a href="{U_INDEX}" data-navbar-reference="index">
+ <!-- IF not U_SITE_HOME --><i class="icon fa-home fa-fw" aria-hidden="true"></i><!-- ENDIF --><span>{L_INDEX}</span>
+ </a>
+ </span>
+ {% endspaceless %}
<!-- EVENT overall_footer_breadcrumb_append -->
</li>
- <!-- IF U_WATCH_FORUM_LINK and not S_IS_BOT --><li class="small-icon icon-<!-- IF S_WATCHING_FORUM -->unsubscribe<!-- ELSE -->subscribe<!-- ENDIF -->" data-last-responsive="true"><a href="{U_WATCH_FORUM_LINK}" title="{S_WATCH_FORUM_TITLE}" data-ajax="toggle_link" data-toggle-class="small-icon 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_FORUM_LINK and not S_IS_BOT -->
+ <li data-last-responsive="true">
+ <a href="{U_WATCH_FORUM_LINK}" title="{S_WATCH_FORUM_TITLE}" data-ajax="toggle_link" data-toggle-class="icon <!-- IF S_WATCHING_FORUM -->fa-check-square-o<!-- ELSE -->fa-square-o<!-- ENDIF --> fa-fw" data-toggle-text="{S_WATCH_FORUM_TOGGLE}" data-toggle-url="{U_WATCH_FORUM_TOGGLE}">
+ <i class="icon <!-- IF S_WATCHING_FORUM -->fa-square-o<!-- ELSE -->fa-check-square-o<!-- ENDIF --> fa-fw" aria-hidden="true"></i><span>{S_WATCH_FORUM_TITLE}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
<!-- EVENT overall_footer_timezone_before -->
<li class="rightside">{S_TIMEZONE}</li>
<!-- EVENT overall_footer_timezone_after -->
<!-- IF not S_IS_BOT -->
- <li class="small-icon icon-delete-cookies rightside"><a href="{U_DELETE_COOKIES}" data-ajax="true" data-refresh="true" role="menuitem">{L_DELETE_COOKIES}</a></li>
- <!-- IF S_DISPLAY_MEMBERLIST --><li class="small-icon icon-members rightside" data-last-responsive="true"><a href="{U_MEMBERLIST}" title="{L_MEMBERLIST_EXPLAIN}" role="menuitem">{L_MEMBERLIST}</a></li><!-- ENDIF -->
+ <li class="rightside">
+ <a href="{U_DELETE_COOKIES}" data-ajax="true" data-refresh="true" role="menuitem">
+ <i class="icon fa-trash fa-fw" aria-hidden="true"></i><span>{L_DELETE_COOKIES}</span>
+ </a>
+ </li>
+ <!-- IF S_DISPLAY_MEMBERLIST -->
+ <li class="rightside" data-last-responsive="true">
+ <a href="{U_MEMBERLIST}" title="{L_MEMBERLIST_EXPLAIN}" role="menuitem">
+ <i class="icon fa-group fa-fw" aria-hidden="true"></i><span>{L_MEMBERLIST}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
<!-- ENDIF -->
<!-- EVENT overall_footer_teamlink_before -->
- <!-- IF U_TEAM --><li class="small-icon icon-team rightside" data-last-responsive="true"><a href="{U_TEAM}" role="menuitem">{L_THE_TEAM}</a></li><!-- ENDIF -->
+ <!-- IF U_TEAM -->
+ <li class="rightside" data-last-responsive="true">
+ <a href="{U_TEAM}" role="menuitem">
+ <i class="icon fa-shield fa-fw" aria-hidden="true"></i><span>{L_THE_TEAM}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
<!-- EVENT overall_footer_teamlink_after -->
- <!-- IF U_CONTACT_US --><li class="small-icon icon-contact rightside" data-last-responsive="true"><a href="{U_CONTACT_US}" role="menuitem">{L_CONTACT_US}</a></li><!-- ENDIF -->
+ <!-- IF U_CONTACT_US -->
+ <li class="rightside" data-last-responsive="true">
+ <a href="{U_CONTACT_US}" role="menuitem">
+ <i class="icon fa-envelope fa-fw" aria-hidden="true"></i><span>{L_CONTACT_US}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
</ul>
</div>
diff --git a/phpBB/styles/prosilver/template/navbar_header.html b/phpBB/styles/prosilver/template/navbar_header.html
index bdfb5fb87d..77f5dae0c0 100644
--- a/phpBB/styles/prosilver/template/navbar_header.html
+++ b/phpBB/styles/prosilver/template/navbar_header.html
@@ -1,11 +1,13 @@
<div class="navbar" role="navigation">
<div class="inner">
- <ul id="nav-main" class="linklist bulletin" role="menubar">
+ <ul id="nav-main" class="nav-main linklist" role="menubar">
- <li id="quick-links" class="small-icon responsive-menu dropdown-container<!-- IF not S_DISPLAY_QUICK_LINKS and not S_DISPLAY_SEARCH --> hidden<!-- ENDIF -->" data-skip-responsive="true">
- <a href="#" class="responsive-menu-link dropdown-trigger">{L_QUICK_LINKS}</a>
- <div class="dropdown hidden">
+ <li id="quick-links" class="quick-links dropdown-container responsive-menu<!-- IF not S_DISPLAY_QUICK_LINKS and not S_DISPLAY_SEARCH --> hidden<!-- ENDIF -->" data-skip-responsive="true">
+ <a href="#" class="dropdown-trigger">
+ <i class="icon fa-bars fa-fw" aria-hidden="true"></i><span>{L_QUICK_LINKS}</span>
+ </a>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<ul class="dropdown-contents" role="menu">
<!-- EVENT navbar_header_quick_links_before -->
@@ -13,24 +15,60 @@
<!-- IF S_DISPLAY_SEARCH -->
<li class="separator"></li>
<!-- IF S_REGISTERED_USER -->
- <li class="small-icon icon-search-self"><a href="{U_SEARCH_SELF}" role="menuitem">{L_SEARCH_SELF}</a></li>
+ <li>
+ <a href="{U_SEARCH_SELF}" role="menuitem">
+ <i class="icon fa-file-o fa-fw icon-gray" aria-hidden="true"></i><span>{L_SEARCH_SELF}</span>
+ </a>
+ </li>
<!-- ENDIF -->
<!-- IF S_USER_LOGGED_IN -->
- <li class="small-icon icon-search-new"><a href="{U_SEARCH_NEW}" role="menuitem">{L_SEARCH_NEW}</a></li>
+ <li>
+ <a href="{U_SEARCH_NEW}" role="menuitem">
+ <i class="icon fa-file-o fa-fw icon-red" aria-hidden="true"></i><span>{L_SEARCH_NEW}</span>
+ </a>
+ </li>
<!-- ENDIF -->
<!-- IF S_LOAD_UNREADS -->
- <li class="small-icon icon-search-unread"><a href="{U_SEARCH_UNREAD}" role="menuitem">{L_SEARCH_UNREAD}</a></li>
+ <li>
+ <a href="{U_SEARCH_UNREAD}" role="menuitem">
+ <i class="icon fa-file-o fa-fw icon-red" aria-hidden="true"></i><span>{L_SEARCH_UNREAD}</span>
+ </a>
+ </li>
<!-- ENDIF -->
- <li class="small-icon icon-search-unanswered"><a href="{U_SEARCH_UNANSWERED}" role="menuitem">{L_SEARCH_UNANSWERED}</a></li>
- <li class="small-icon icon-search-active"><a href="{U_SEARCH_ACTIVE_TOPICS}" role="menuitem">{L_SEARCH_ACTIVE_TOPICS}</a></li>
- <li class="separator"></li>
- <li class="small-icon icon-search"><a href="{U_SEARCH}" role="menuitem">{L_SEARCH}</a></li>
+ <li>
+ <a href="{U_SEARCH_UNANSWERED}" role="menuitem">
+ <i class="icon fa-file-o fa-fw icon-gray" aria-hidden="true"></i><span>{L_SEARCH_UNANSWERED}</span>
+ </a>
+ </li>
+ <li>
+ <a href="{U_SEARCH_ACTIVE_TOPICS}" role="menuitem">
+ <i class="icon fa-file-o fa-fw icon-blue" aria-hidden="true"></i><span>{L_SEARCH_ACTIVE_TOPICS}</span>
+ </a>
+ </li>
+ <li class="separator"></li>
+ <li>
+ <a href="{U_SEARCH}" role="menuitem">
+ <i class="icon fa-search fa-fw" aria-hidden="true"></i><span>{L_SEARCH}</span>
+ </a>
+ </li>
<!-- ENDIF -->
<!-- IF not S_IS_BOT and (S_DISPLAY_MEMBERLIST or U_TEAM) -->
<li class="separator"></li>
- <!-- IF S_DISPLAY_MEMBERLIST --><li class="small-icon icon-members"><a href="{U_MEMBERLIST}" role="menuitem">{L_MEMBERLIST}</a></li><!-- ENDIF -->
- <!-- IF U_TEAM --><li class="small-icon icon-team"><a href="{U_TEAM}" role="menuitem">{L_THE_TEAM}</a></li><!-- ENDIF -->
+ <!-- IF S_DISPLAY_MEMBERLIST -->
+ <li>
+ <a href="{U_MEMBERLIST}" role="menuitem">
+ <i class="icon fa-group fa-fw" aria-hidden="true"></i><span>{L_MEMBERLIST}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
+ <!-- IF U_TEAM -->
+ <li>
+ <a href="{U_TEAM}" role="menuitem">
+ <i class="icon fa-shield fa-fw" aria-hidden="true"></i><span>{L_THE_TEAM}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
<!-- ENDIF -->
<li class="separator"></li>
@@ -40,67 +78,119 @@
</li>
<!-- EVENT overall_header_navigation_prepend -->
- <li class="small-icon icon-faq" <!-- IF not S_USER_LOGGED_IN -->data-skip-responsive="true"<!-- ELSE -->data-last-responsive="true"<!-- ENDIF -->><a href="{U_FAQ}" rel="help" title="{L_FAQ_EXPLAIN}" role="menuitem">{L_FAQ}</a></li>
+ <li <!-- IF not S_USER_LOGGED_IN -->data-skip-responsive="true"<!-- ELSE -->data-last-responsive="true"<!-- ENDIF -->>
+ <a href="{U_FAQ}" rel="help" title="{L_FAQ_EXPLAIN}" role="menuitem">
+ <i class="icon fa-question-circle fa-fw" aria-hidden="true"></i><span>{L_FAQ}</span>
+ </a>
+ </li>
<!-- EVENT overall_header_navigation_append -->
- <!-- IF U_ACP --><li class="small-icon icon-acp" data-last-responsive="true"><a href="{U_ACP}" title="{L_ACP}" role="menuitem">{L_ACP_SHORT}</a></li><!-- ENDIF -->
- <!-- IF U_MCP --><li class="small-icon icon-mcp" data-last-responsive="true"><a href="{U_MCP}" title="{L_MCP}" role="menuitem">{L_MCP_SHORT}</a></li><!-- ENDIF -->
+ <!-- IF U_ACP -->
+ <li data-last-responsive="true">
+ <a href="{U_ACP}" title="{L_ACP}" role="menuitem">
+ <i class="icon fa-cogs fa-fw" aria-hidden="true"></i><span>{L_ACP_SHORT}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
+ <!-- IF U_MCP -->
+ <li data-last-responsive="true">
+ <a href="{U_MCP}" title="{L_MCP}" role="menuitem">
+ <i class="icon fa-gavel fa-fw" aria-hidden="true"></i><span>{L_MCP_SHORT}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
<!-- IF S_REGISTERED_USER -->
<!-- EVENT navbar_header_user_profile_prepend -->
<li id="username_logged_in" class="rightside <!-- IF CURRENT_USER_AVATAR --> no-bulletin<!-- ENDIF -->" data-skip-responsive="true">
<!-- EVENT navbar_header_username_prepend -->
<div class="header-profile dropdown-container">
- <a href="{U_PROFILE}" class="header-avatar dropdown-trigger"><!-- IF CURRENT_USER_AVATAR -->{CURRENT_USER_AVATAR} <!-- ENDIF -->{CURRENT_USERNAME_SIMPLE}</a>
- <div class="dropdown hidden">
+ <a href="{U_PROFILE}" class="header-avatar dropdown-trigger"><!-- IF CURRENT_USER_AVATAR -->{CURRENT_USER_AVATAR} <!-- ENDIF --> {CURRENT_USERNAME_SIMPLE}</a>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<ul class="dropdown-contents" role="menu">
- <!-- IF U_RESTORE_PERMISSIONS --><li class="small-icon icon-restore-permissions"><a href="{U_RESTORE_PERMISSIONS}">{L_RESTORE_PERMISSIONS}</a></li><!-- ENDIF -->
+ <!-- IF U_RESTORE_PERMISSIONS -->
+ <li>
+ <a href="{U_RESTORE_PERMISSIONS}">
+ <i class="icon fa-refresh fa-fw" aria-hidden="true"></i><span>{L_RESTORE_PERMISSIONS}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
- <!-- EVENT navbar_header_profile_list_before -->
+ <!-- EVENT navbar_header_profile_list_before -->
- <li class="small-icon icon-ucp"><a href="{U_PROFILE}" title="{L_PROFILE}" role="menuitem">{L_PROFILE}</a></li>
- <li class="small-icon icon-profile"><a href="{U_USER_PROFILE}" title="{L_READ_PROFILE}" role="menuitem">{L_READ_PROFILE}</a></li>
+ <li>
+ <a href="{U_PROFILE}" title="{L_PROFILE}" role="menuitem">
+ <i class="icon fa-sliders fa-fw" aria-hidden="true"></i><span>{L_PROFILE}</span>
+ </a>
+ </li>
+ <!-- IF U_USER_PROFILE -->
+ <li>
+ <a href="{U_USER_PROFILE}" title="{L_READ_PROFILE}" role="menuitem">
+ <i class="icon fa-user fa-fw" aria-hidden="true"></i><span>{L_READ_PROFILE}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
<!-- EVENT navbar_header_profile_list_after -->
<li class="separator"></li>
- <li class="small-icon icon-logout"><a href="{U_LOGIN_LOGOUT}" title="{L_LOGIN_LOGOUT}" accesskey="x" role="menuitem">{L_LOGIN_LOGOUT}</a></li>
+ <li>
+ <a href="{U_LOGIN_LOGOUT}" title="{L_LOGIN_LOGOUT}" accesskey="x" role="menuitem">
+ <i class="icon fa-power-off fa-fw" aria-hidden="true"></i><span>{L_LOGIN_LOGOUT}</span>
+ </a>
+ </li>
</ul>
</div>
</div>
<!-- EVENT navbar_header_username_append -->
</li>
<!-- IF S_DISPLAY_PM -->
- <li class="small-icon icon-pm rightside" data-skip-responsive="true">
- <a href="{U_PRIVATEMSGS}" role="menuitem"><span>{L_PRIVATE_MESSAGES} </span><strong class="badge<!-- IF not PRIVATE_MESSAGE_COUNT --> hidden<!-- ENDIF -->">{PRIVATE_MESSAGE_COUNT}</strong></a>
+ <li class="rightside" data-skip-responsive="true">
+ <a href="{U_PRIVATEMSGS}" role="menuitem">
+ <i class="icon fa-inbox fa-fw" aria-hidden="true"></i><span>{L_PRIVATE_MESSAGES} </span><strong class="badge<!-- IF not PRIVATE_MESSAGE_COUNT --> hidden<!-- ENDIF -->">{PRIVATE_MESSAGE_COUNT}</strong>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF S_NOTIFICATIONS_DISPLAY -->
- <li class="small-icon icon-notification dropdown-container dropdown-{S_CONTENT_FLOW_END} rightside" data-skip-responsive="true">
- <a href="{U_VIEW_ALL_NOTIFICATIONS}" id="notification_list_button" class="dropdown-trigger"><span>{L_NOTIFICATIONS} </span><strong class="badge<!-- IF not NOTIFICATIONS_COUNT --> hidden<!-- ENDIF -->">{NOTIFICATIONS_COUNT}</strong></a>
+ <li class="dropdown-container dropdown-{S_CONTENT_FLOW_END} rightside" data-skip-responsive="true">
+ <a href="{U_VIEW_ALL_NOTIFICATIONS}" id="notification_list_button" class="dropdown-trigger">
+ <i class="icon fa-bell fa-fw" aria-hidden="true"></i><span>{L_NOTIFICATIONS} </span><strong class="badge<!-- IF not NOTIFICATIONS_COUNT --> hidden<!-- ENDIF -->">{NOTIFICATIONS_COUNT}</strong>
+ </a>
<!-- INCLUDE notification_dropdown.html -->
</li>
<!-- ENDIF -->
<!-- EVENT navbar_header_user_profile_append -->
- <!-- ELSE -->
- <li class="small-icon icon-logout rightside" data-skip-responsive="true"><a href="{U_LOGIN_LOGOUT}" title="{L_LOGIN_LOGOUT}" accesskey="x" role="menuitem">{L_LOGIN_LOGOUT}</a></li>
+ <!-- ELSE IF not S_IS_BOT -->
+ <li class="rightside" data-skip-responsive="true">
+ <a href="{U_LOGIN_LOGOUT}" title="{L_LOGIN_LOGOUT}" accesskey="x" role="menuitem">
+ <i class="icon fa-power-off fa-fw" aria-hidden="true"></i><span>{L_LOGIN_LOGOUT}</span>
+ </a>
+ </li>
<!-- IF S_REGISTER_ENABLED and not (S_SHOW_COPPA or S_REGISTRATION) -->
- <li class="small-icon icon-register rightside" data-skip-responsive="true"><a href="{U_REGISTER}" role="menuitem">{L_REGISTER}</a></li>
+ <li class="rightside" data-skip-responsive="true">
+ <a href="{U_REGISTER}" role="menuitem">
+ <i class="icon fa-pencil-square-o fa-fw" aria-hidden="true"></i><span>{L_REGISTER}</span>
+ </a>
+ </li>
<!-- ENDIF -->
<!-- EVENT navbar_header_logged_out_content -->
<!-- ENDIF -->
</ul>
- <ul id="nav-breadcrumbs" class="linklist navlinks" role="menubar">
- <!-- DEFINE $MICRODATA = ' itemtype="http://data-vocabulary.org/Breadcrumb" itemscope=""' -->
+ <ul id="nav-breadcrumbs" class="nav-breadcrumbs linklist navlinks" role="menubar">
+ <!-- DEFINE $MICRODATA = ' itemtype="http://schema.org/ListItem" itemprop="itemListElement" itemscope' -->
+ {% set navlink_position = 1 %}
<!-- EVENT overall_header_breadcrumbs_before -->
- <li class="small-icon icon-home breadcrumbs">
- <!-- IF U_SITE_HOME --><span class="crumb"{$MICRODATA}><a href="{U_SITE_HOME}" data-navbar-reference="home" itemprop="url"><span itemprop="title">{L_SITE_HOME}</span></a></span><!-- ENDIF -->
+ <li class="breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">
+ <!-- IF U_SITE_HOME -->
+ <span class="crumb" {$MICRODATA}><a href="{U_SITE_HOME}" itemtype="https://schema.org/Thing" itemscope itemprop="item" data-navbar-reference="home"><i class="icon fa-home fa-fw" aria-hidden="true"></i><span itemprop="name">{L_SITE_HOME}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span>
+ <!-- ENDIF -->
<!-- EVENT overall_header_breadcrumb_prepend -->
- <span class="crumb"{$MICRODATA}><a href="{U_INDEX}" accesskey="h" data-navbar-reference="index" itemprop="url"><span itemprop="title">{L_INDEX}</span></a></span>
+ <span class="crumb" {$MICRODATA}><a href="{U_INDEX}" itemtype="https://schema.org/Thing" itemscope itemprop="item" accesskey="h" data-navbar-reference="index"><!-- IF not U_SITE_HOME --><i class="icon fa-home fa-fw"></i><!-- ENDIF --><span itemprop="name">{L_INDEX}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span>
+
<!-- BEGIN navlinks -->
<!-- EVENT overall_header_navlink_prepend -->
- <span class="crumb"{$MICRODATA}<!-- IF navlinks.MICRODATA --> {navlinks.MICRODATA}<!-- ENDIF -->><a href="{navlinks.U_VIEW_FORUM}" itemprop="url"><span itemprop="title">{navlinks.FORUM_NAME}</span></a></span>
+ <span class="crumb" {$MICRODATA}<!-- IF navlinks.MICRODATA --> {navlinks.MICRODATA}<!-- ENDIF -->><a href="{navlinks.U_VIEW_FORUM}" itemtype="https://schema.org/Thing" itemscope itemprop="item"><span itemprop="name">{navlinks.FORUM_NAME}</span></a><meta itemprop="position" content="{{ navlink_position }}{% set navlink_position = navlink_position + 1 %}" /></span>
<!-- EVENT overall_header_navlink_append -->
<!-- END navlinks -->
<!-- EVENT overall_header_breadcrumb_append -->
@@ -108,7 +198,11 @@
<!-- EVENT overall_header_breadcrumbs_after -->
<!-- IF S_DISPLAY_SEARCH and not S_IN_SEARCH -->
- <li class="rightside responsive-search" style="display: none;"><a href="{U_SEARCH}" title="{L_SEARCH_ADV_EXPLAIN}" role="menuitem">{L_SEARCH}</a></li>
+ <li class="rightside responsive-search">
+ <a href="{U_SEARCH}" title="{L_SEARCH_ADV_EXPLAIN}" role="menuitem">
+ <i class="icon fa-search fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH}</span>
+ </a>
+ </li>
<!-- ENDIF -->
</ul>
diff --git a/phpBB/styles/prosilver/template/notification_dropdown.html b/phpBB/styles/prosilver/template/notification_dropdown.html
index 13d90a9d38..e444d8fb90 100644
--- a/phpBB/styles/prosilver/template/notification_dropdown.html
+++ b/phpBB/styles/prosilver/template/notification_dropdown.html
@@ -32,7 +32,9 @@
</div>
<!-- IF notifications.URL --></a><!-- ENDIF -->
<!-- IF notifications.UNREAD -->
- <a href="{notifications.U_MARK_READ}" class="mark_read icon-mark" data-ajax="notification.mark_read" title="{L_MARK_READ}"></a>
+ <a href="{notifications.U_MARK_READ}" class="mark_read icon-mark" data-ajax="notification.mark_read" title="{L_MARK_READ}">
+ <i class="icon fa-check-circle icon-xl fa-fw" aria-hidden="true"></i><span class="sr-only">{L_MARK_READ}</span>
+ </a>
<!-- ENDIF -->
</li>
<!-- END notifications -->
diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html
index faacdbff42..42c6d56c4b 100644
--- a/phpBB/styles/prosilver/template/overall_footer.html
+++ b/phpBB/styles/prosilver/template/overall_footer.html
@@ -3,28 +3,55 @@
<!-- EVENT overall_footer_page_body_after -->
-<div id="page-footer" role="contentinfo">
+<div id="page-footer" class="page-footer" role="contentinfo">
<!-- INCLUDE navbar_footer.html -->
<div class="copyright">
<!-- EVENT overall_footer_copyright_prepend -->
- {CREDIT_LINE}
- <!-- IF TRANSLATION_INFO --><br />{TRANSLATION_INFO}<!-- ENDIF -->
+ <p class="footer-row">
+ <span class="footer-copyright">{{ CREDIT_LINE }}</span>
+ </p>
+ <!-- IF TRANSLATION_INFO -->
+ <p class="footer-row">
+ <span class="footer-copyright">{{ TRANSLATION_INFO }}</span>
+ </p>
+ <!-- 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 -->
+ <p class="footer-row" role="menu">
+ <a class="footer-link" href="{{ U_PRIVACY }}" title="{{ lang('PRIVACY_LINK') }}" role="menuitem">
+ <span class="footer-link-text">{{ lang('PRIVACY_LINK') }}</span>
+ </a>
+ |
+ <a class="footer-link" href="{{ U_TERMS_USE }}" title="{{ lang('TERMS_LINK') }}" role="menuitem">
+ <span class="footer-link-text">{{ lang('TERMS_LINK') }}</span>
+ </a>
+ </p>
+ <!-- IF DEBUG_OUTPUT -->
+ <p class="footer-row">
+ <span class="footer-info">{{ DEBUG_OUTPUT }}</span>
+ </p>
+ <!-- ENDIF -->
+ <!-- IF U_ACP -->
+ <p class="footer-row">
+ <a class="footer-link text-strong" href="{{ U_ACP }}">{{ lang('ACP') }}</a>
+ </p>
+ <!-- ENDIF -->
</div>
- <div id="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}" data-ajax-error-text-abort="{L_AJAX_ERROR_TEXT_ABORT}" data-ajax-error-text-timeout="{L_AJAX_ERROR_TEXT_TIMEOUT}" data-ajax-error-text-parsererror="{L_AJAX_ERROR_TEXT_PARSERERROR}">
- <div id="darken">&nbsp;</div>
+ <div id="darkenwrapper" class="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}" data-ajax-error-text-abort="{L_AJAX_ERROR_TEXT_ABORT}" data-ajax-error-text-timeout="{L_AJAX_ERROR_TEXT_TIMEOUT}" data-ajax-error-text-parsererror="{L_AJAX_ERROR_TEXT_PARSERERROR}">
+ <div id="darken" class="darken">&nbsp;</div>
</div>
<div id="phpbb_alert" class="phpbb_alert" data-l-err="{L_ERROR}" data-l-timeout-processing-req="{L_TIMEOUT_PROCESSING_REQ}">
- <a href="#" class="alert_close"></a>
+ <a href="#" class="alert_close">
+ <i class="icon fa-times-circle fa-fw" aria-hidden="true"></i>
+ </a>
<h3 class="alert_title">&nbsp;</h3><p class="alert_text"></p>
</div>
<div id="phpbb_confirm" class="phpbb_alert">
- <a href="#" class="alert_close"></a>
+ <a href="#" class="alert_close">
+ <i class="icon fa-times-circle fa-fw" aria-hidden="true"></i>
+ </a>
<div class="alert_text"></div>
</div>
</div>
@@ -36,11 +63,51 @@
<!-- IF not S_IS_BOT -->{RUN_CRON_TASK}<!-- ENDIF -->
</div>
-<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
-<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
-<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
+<script src="{T_JQUERY_LINK}"></script>
+<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
+<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
<!-- INCLUDEJS forum_fn.js -->
<!-- INCLUDEJS ajax.js -->
+<!-- IF S_ALLOW_CDN -->
+ <script>
+ (function($){
+ var $fa_cdn = $('head').find('link[rel="stylesheet"]').first(),
+ $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
+ if ($span.css('fontFamily') !== 'FontAwesome' ) {
+ $fa_cdn.after('<link href="{T_ASSETS_PATH}/css/font-awesome.min.css" rel="stylesheet">');
+ $fa_cdn.remove();
+ }
+ $span.remove();
+ })(jQuery);
+ </script>
+<!-- ENDIF -->
+
+<!-- IF S_COOKIE_NOTICE -->
+ <script src="{T_ASSETS_PATH}/cookieconsent/cookieconsent.min.js?assets_version={T_ASSETS_VERSION}"></script>
+ <script>
+ if (typeof window.cookieconsent === "object") {
+ window.addEventListener("load", function(){
+ window.cookieconsent.initialise({
+ "palette": {
+ "popup": {
+ "background": "#0F538A"
+ },
+ "button": {
+ "background": "#E5E5E5"
+ }
+ },
+ "theme": "classic",
+ "content": {
+ "message": "{LA_COOKIE_CONSENT_MSG}",
+ "dismiss": "{LA_COOKIE_CONSENT_OK}",
+ "link": "{LA_COOKIE_CONSENT_INFO}",
+ "href": "{UA_PRIVACY}"
+ }
+ });
+ });
+ }
+ </script>
+<!-- ENDIF -->
<!-- EVENT overall_footer_after -->
diff --git a/phpBB/styles/prosilver/template/overall_header.html b/phpBB/styles/prosilver/template/overall_header.html
index 8b2e592d02..8265825996 100644
--- a/phpBB/styles/prosilver/template/overall_header.html
+++ b/phpBB/styles/prosilver/template/overall_header.html
@@ -8,14 +8,14 @@
<title><!-- IF UNREAD_NOTIFICATIONS_COUNT -->({UNREAD_NOTIFICATIONS_COUNT}) <!-- ENDIF --><!-- IF not S_VIEWTOPIC and not S_VIEWFORUM -->{SITENAME} - <!-- ENDIF --><!-- IF S_IN_MCP -->{L_MCP} - <!-- ELSEIF S_IN_UCP -->{L_UCP} - <!-- ENDIF -->{PAGE_TITLE}<!-- IF S_VIEWTOPIC or S_VIEWFORUM --> - {SITENAME}<!-- ENDIF --></title>
<!-- IF S_ENABLE_FEEDS -->
- <!-- IF S_ENABLE_FEEDS_OVERALL --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {SITENAME}" href="{U_FEED}"><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_NEWS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_NEWS}" href="{U_FEED}?mode=news"><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_FORUMS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_ALL_FORUMS}" href="{U_FEED}?mode=forums"><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_TOPICS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_TOPICS_NEW}" href="{U_FEED}?mode=topics"><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_TOPICS_ACTIVE --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_TOPICS_ACTIVE}" href="{U_FEED}?mode=topics_active"><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_FORUM and S_FORUM_ID --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FORUM} - {FORUM_NAME}" href="{U_FEED}?f={S_FORUM_ID}"><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_TOPIC and S_TOPIC_ID --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_TOPIC} - {TOPIC_TITLE}" href="{U_FEED}?f={S_FORUM_ID}&amp;t={S_TOPIC_ID}"><!-- ENDIF -->
- <!-- EVENT overall_header_feeds -->
+ <!-- IF S_ENABLE_FEEDS_OVERALL --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {SITENAME}" href="{{ path('phpbb_feed_index') }}"><!-- ENDIF -->
+ <!-- IF S_ENABLE_FEEDS_NEWS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_NEWS}" href="{{ path('phpbb_feed_news') }}"><!-- ENDIF -->
+ <!-- IF S_ENABLE_FEEDS_FORUMS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_ALL_FORUMS}" href="{{ path('phpbb_feed_forums') }}"><!-- ENDIF -->
+ <!-- IF S_ENABLE_FEEDS_TOPICS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_TOPICS_NEW}" href="{{ path('phpbb_feed_topics') }}"><!-- ENDIF -->
+ <!-- IF S_ENABLE_FEEDS_TOPICS_ACTIVE --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_TOPICS_ACTIVE}" href="{{ path('phpbb_feed_topics_active') }}"><!-- ENDIF -->
+ <!-- IF S_ENABLE_FEEDS_FORUM and S_FORUM_ID --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FORUM} - {FORUM_NAME}" href="{{ path('phpbb_feed_forum', { forum_id : S_FORUM_ID } ) }}"><!-- ENDIF -->
+ <!-- IF S_ENABLE_FEEDS_TOPIC and S_TOPIC_ID --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_TOPIC} - {TOPIC_TITLE}" href="{{ path('phpbb_feed_topic', { topic_id : S_TOPIC_ID } ) }}"><!-- ENDIF -->
+ <!-- EVENT overall_header_feeds -->
<!-- ENDIF -->
<!-- IF U_CANONICAL -->
@@ -31,40 +31,39 @@
<!-- IF S_ALLOW_CDN -->
<script>
- WebFontConfig = {
- google: {
- families: ['Open+Sans:600:cyrillic-ext,latin,greek-ext,greek,vietnamese,latin-ext,cyrillic']
- }
- };
+ WebFontConfig = {
+ google: {
+ families: ['Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese']
+ }
+ };
(function(d) {
var wf = d.createElement('script'), s = d.scripts[0];
wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js';
wf.async = true;
s.parentNode.insertBefore(wf, s);
- })(document);
+ })(document);
</script>
<!-- ENDIF -->
<link href="{T_FONT_AWESOME_LINK}" rel="stylesheet">
<link href="{T_STYLESHEET_LINK}" rel="stylesheet">
<link href="{T_STYLESHEET_LANG_LINK}" rel="stylesheet">
-<link href="{T_THEME_PATH}/responsive.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" media="all and (max-width: 700px)">
<!-- IF S_CONTENT_DIRECTION eq 'rtl' -->
- <link href="{T_THEME_PATH}/bidi.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
+ <link href="{T_THEME_PATH}/bidi.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
<!-- ENDIF -->
<!-- IF S_PLUPLOAD -->
- <link href="{T_THEME_PATH}/plupload.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
+ <link href="{T_THEME_PATH}/plupload.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
<!-- ENDIF -->
<!-- IF S_COOKIE_NOTICE -->
- <link href="{T_ASSETS_PATH}/cookieconsent/cookieconsent.min.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
+ <link href="{T_ASSETS_PATH}/cookieconsent/cookieconsent.min.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
<!-- ENDIF -->
<link rel="shortcut icon" type="image/png" href="https://nav.mageia.org/g/favicon.png" />
<!--[if lte IE 9]>
- <link href="{T_THEME_PATH}/tweaks.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
+ <link href="{T_THEME_PATH}/tweaks.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
<![endif]-->
<!-- EVENT overall_header_head_append -->
@@ -78,31 +77,35 @@
<!-- EVENT overall_header_body_before -->
-<div id="wrap">
- <a id="top" class="anchor" accesskey="t"></a>
- <div id="page-header">
- <div class="headerbar" role="banner">
- <!-- EVENT overall_header_headerbar_before -->
- <div class="inner">
-
- <div id="site-description">
- <a id="logo" class="logo" href="<!-- IF U_SITE_HOME -->{U_SITE_HOME}<!-- ELSE -->{U_INDEX}<!-- ENDIF -->" title="<!-- IF U_SITE_HOME -->{L_SITE_HOME}<!-- ELSE -->{L_INDEX}<!-- ENDIF -->">{SITE_LOGO_IMG}</a>
- <h1>{SITENAME}</h1>
- <p>{SITE_DESCRIPTION}</p>
- <p class="skiplink"><a href="#start_here">{L_SKIP}</a></p>
+<div id="wrap" class="wrap">
+ <a id="top" class="top-anchor" accesskey="t"></a>
+ <div id="page-header">
+ <div class="headerbar" role="banner">
+ <!-- EVENT overall_header_headerbar_before -->
+ <div class="inner">
+
+ <div id="site-description" class="site-description">
+ <a id="logo" class="logo" href="<!-- IF U_SITE_HOME -->{U_SITE_HOME}<!-- ELSE -->{U_INDEX}<!-- ENDIF -->" title="<!-- IF U_SITE_HOME -->{L_SITE_HOME}<!-- ELSE -->{L_INDEX}<!-- ENDIF -->"><span class="site_logo"></span></a>
+ <h1>{SITENAME}</h1>
+ <p>{SITE_DESCRIPTION}</p>
+ <p class="skiplink"><a href="#start_here">{L_SKIP}</a></p>
</div>
<!-- EVENT overall_header_searchbox_before -->
<!-- IF S_DISPLAY_SEARCH and not S_IN_SEARCH -->
<div id="search-box" class="search-box search-header" role="search">
- <form action="{U_SEARCH}" method="get" id="search">
- <fieldset>
- <input name="keywords" id="keywords" type="search" maxlength="128" title="{L_SEARCH_KEYWORDS}" class="inputbox search tiny" size="20" value="{SEARCH_WORDS}" placeholder="{L_SEARCH_MINI}" />
- <button class="button icon-button search-icon" type="submit" title="{L_SEARCH}">{L_SEARCH}</button>
- <a href="{U_SEARCH}" class="button icon-button search-adv-icon" title="{L_SEARCH_ADV}">{L_SEARCH_ADV}</a>
- {S_SEARCH_HIDDEN_FIELDS}
- </fieldset>
- </form>
+ <form action="{U_SEARCH}" method="get" id="search">
+ <fieldset>
+ <input name="keywords" id="keywords" type="search" maxlength="128" title="{L_SEARCH_KEYWORDS}" class="inputbox search tiny" size="20" value="{SEARCH_WORDS}" placeholder="{L_SEARCH_MINI}" />
+ <button class="button button-search" type="submit" title="{L_SEARCH}">
+ <i class="icon fa-search fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH}</span>
+ </button>
+ <a href="{U_SEARCH}" class="button button-search-end" title="{L_SEARCH_ADV}">
+ <i class="icon fa-cog fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH_ADV}</span>
+ </a>
+ {S_SEARCH_HIDDEN_FIELDS}
+ </fieldset>
+ </form>
</div>
<!-- ENDIF -->
<!-- EVENT overall_header_searchbox_after -->
@@ -114,13 +117,13 @@
<!-- INCLUDE navbar_header.html -->
</div>
- <!-- EVENT overall_header_page_body_before -->
+ <!-- EVENT overall_header_page_body_before -->
- <a id="start_here" class="anchor"></a>
- <div id="page-body" role="main">
- <!-- IF S_BOARD_DISABLED and S_USER_LOGGED_IN and (U_MCP or U_ACP) -->
- <div id="information" class="rules">
- <div class="inner">
+ <a id="start_here" class="anchor"></a>
+ <div id="page-body" class="page-body" role="main">
+ <!-- IF S_BOARD_DISABLED and S_USER_LOGGED_IN and (U_MCP or U_ACP) -->
+ <div id="information" class="rules">
+ <div class="inner">
<strong>{L_INFORMATION}{L_COLON}</strong> {L_BOARD_DISABLED}
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/pagination.html b/phpBB/styles/prosilver/template/pagination.html
index 88c67459c2..5d484517ad 100644
--- a/phpBB/styles/prosilver/template/pagination.html
+++ b/phpBB/styles/prosilver/template/pagination.html
@@ -1,8 +1,8 @@
<ul>
<!-- IF BASE_URL and TOTAL_PAGES > 6 -->
<li class="dropdown-container dropdown-button-control dropdown-page-jump page-jump">
- <a href="#" class="dropdown-trigger" title="{L_JUMP_TO_PAGE_CLICK}" role="button">{PAGE_NUMBER}</a>
- <div class="dropdown hidden">
+ <a class="button button-icon-only dropdown-trigger" href="#" title="{L_JUMP_TO_PAGE_CLICK}" role="button"><i class="icon fa-level-down fa-rotate-270" aria-hidden="true"></i><span class="sr-only">{PAGE_NUMBER}</span></a>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<ul class="dropdown-contents">
<li>{L_JUMP_TO_PAGE}{L_COLON}</li>
@@ -16,15 +16,15 @@
<!-- ENDIF -->
<!-- BEGIN pagination -->
<!-- IF pagination.S_IS_PREV -->
- <li class="previous"><a href="{pagination.PAGE_URL}" rel="prev" role="button">{L_PREVIOUS}</a></li>
+ <li class="arrow previous"><a class="button button-icon-only" href="{pagination.PAGE_URL}" rel="prev" role="button"><i class="icon fa-chevron-{S_CONTENT_FLOW_BEGIN} fa-fw" aria-hidden="true"></i><span class="sr-only">{L_PREVIOUS}</span></a></li>
<!-- ELSEIF pagination.S_IS_CURRENT -->
<li class="active"><span>{pagination.PAGE_NUMBER}</span></li>
<!-- ELSEIF pagination.S_IS_ELLIPSIS -->
<li class="ellipsis" role="separator"><span>{L_ELLIPSIS}</span></li>
<!-- ELSEIF pagination.S_IS_NEXT -->
- <li class="next"><a href="{pagination.PAGE_URL}" rel="next" role="button">{L_NEXT}</a></li>
+ <li class="arrow next"><a class="button button-icon-only" href="{pagination.PAGE_URL}" rel="next" role="button"><i class="icon fa-chevron-{S_CONTENT_FLOW_END} fa-fw" aria-hidden="true"></i><span class="sr-only">{L_NEXT}</span></a></li>
<!-- ELSE -->
- <li><a href="{pagination.PAGE_URL}" role="button">{pagination.PAGE_NUMBER}</a></li>
+ <li><a class="button" href="{pagination.PAGE_URL}" role="button">{pagination.PAGE_NUMBER}</a></li>
<!-- ENDIF -->
<!-- END pagination -->
</ul>
diff --git a/phpBB/styles/prosilver/template/plupload.html b/phpBB/styles/prosilver/template/plupload.html
index fc663118c1..9425b7d769 100644
--- a/phpBB/styles/prosilver/template/plupload.html
+++ b/phpBB/styles/prosilver/template/plupload.html
@@ -1,5 +1,4 @@
-<script type="text/javascript">
-//<![CDATA[
+<script>
phpbb.plupload = {
i18n: {
'b': '{LA_BYTES_SHORT}',
@@ -46,7 +45,14 @@ phpbb.plupload = {
max_file_size: '{FILESIZE}b',
chunk_size: '{CHUNK_SIZE}b',
unique_names: true,
- filters: [{FILTERS}],
+ filters: {
+ mime_types: [
+ {FILTERS}
+ ],
+ mime_types_max_file_size: [
+ {FILTERS}
+ ],
+ },
{S_RESIZE}
headers: {'X-PHPBB-USING-PLUPLOAD': '1', 'X-Requested-With': 'XMLHttpRequest'},
file_data_name: 'fileupload',
@@ -58,12 +64,12 @@ phpbb.plupload = {
lang: {
ERROR: '{LA_ERROR}',
TOO_MANY_ATTACHMENTS: '{LA_TOO_MANY_ATTACHMENTS}',
+ FORM_INVALID: '{LA_FORM_INVALID}',
},
order: '{ATTACH_ORDER}',
maxFiles: {MAX_ATTACHMENTS},
data: {S_ATTACH_DATA},
}
-//]]>
</script>
<!-- INCLUDEJS {T_ASSETS_PATH}/plupload/plupload.full.min.js -->
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/plupload.js -->
diff --git a/phpBB/styles/prosilver/template/posting_attach_body.html b/phpBB/styles/prosilver/template/posting_attach_body.html
index d7922297a7..0363fe0f05 100644
--- a/phpBB/styles/prosilver/template/posting_attach_body.html
+++ b/phpBB/styles/prosilver/template/posting_attach_body.html
@@ -2,7 +2,7 @@
<div class="inner">
<p>{L_ADD_ATTACHMENT_EXPLAIN} <span class="hidden" id="drag-n-drop-message">{L_PLUPLOAD_DRAG_TEXTAREA}</span></p>
-
+
<fieldset class="fields2" id="attach-panel-basic">
<dl>
<dt><label for="fileupload">{L_FILENAME}{L_COLON}</label></dt>
@@ -17,11 +17,12 @@
</dl>
</fieldset>
- <div id="attach-panel-multi">
+ <div id="attach-panel-multi" class="attach-panel-multi">
<input type="button" class="button2" value="{L_PLUPLOAD_ADD_FILES}" id="add_files" />
</div>
- <div class="panel<!-- IF not .attach_row --> hidden<!-- ENDIF -->" id="file-list-container">
+ {% EVENT posting_attach_body_file_list_before %}
+ <div class="panel<!-- IF not .attach_row --> hidden<!-- ENDIF --> file-list-container" id="file-list-container">
<div class="inner">
<table class="table1 zebra-list fixed-width-table">
<thead>
@@ -32,12 +33,12 @@
<th class="attach-status">{L_PLUPLOAD_STATUS}</th>
</tr>
</thead>
- <tbody class="responsive-skip-empty" id="file-list">
- <tr class="attach-row" id="attach-row-tpl">
+ <tbody class="responsive-skip-empty file-list" id="file-list">
+ <tr class="attach-row attach-row-tpl" id="attach-row-tpl">
<td class="attach-name">
<span class="file-name ellipsis-text"></span>
<span class="attach-controls">
- <input type="button" value="{L_PLACE_INLINE}" class="button2 hidden file-inline-bbcode" />&nbsp;
+ {% if S_BBCODE_ALLOWED %}<input type="button" value="{{ lang('PLACE_INLINE') }}" class="button2 hidden file-inline-bbcode" />&nbsp;{% endif %}
<input type="button" value="{L_DELETE_FILE}" class="button2 file-delete" />
</span>
<span class="clear"></span>
@@ -55,14 +56,18 @@
<span class="file-status"></span>
</td>
</tr>
+ {% EVENT posting_attach_body_attach_row_before %}
<!-- BEGIN attach_row -->
+ {% EVENT posting_attach_body_attach_row_prepend %}
<tr class="attach-row" data-attach-id="{attach_row.ATTACH_ID}">
<td class="attach-name">
<span class="file-name ellipsis-text"><a href="{attach_row.U_VIEW_ATTACHMENT}">{attach_row.FILENAME}</a></span>
+ {% EVENT posting_attach_body_attach_row_controls_prepend %}
<span class="attach-controls">
- <!-- IF S_INLINE_ATTACHMENT_OPTIONS --><input type="button" value="{L_PLACE_INLINE}" class="button2 file-inline-bbcode" />&nbsp; <!-- ENDIF -->
+ {% if S_BBCODE_ALLOWED and S_INLINE_ATTACHMENT_OPTIONS %}<input type="button" value="{{ lang('PLACE_INLINE') }}" class="button2 file-inline-bbcode" />&nbsp;{% endif %}
<input type="submit" name="delete_file[{attach_row.ASSOC_INDEX}]" value="{L_DELETE_FILE}" class="button2 file-delete" />
</span>
+ {% EVENT posting_attach_body_attach_row_controls_append %}
<span class="clear"></span>
</td>
<td class="attach-comment">
@@ -76,10 +81,13 @@
<span class="file-status file-uploaded"></span>
</td>
</tr>
+ {% EVENT posting_attach_body_attach_row_append %}
<!-- END attach_row -->
+ {% EVENT posting_attach_body_attach_row_after %}
</tbody>
</table>
</div>
</div>
+ {% EVENT posting_attach_body_file_list_after %}
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/posting_buttons.html b/phpBB/styles/prosilver/template/posting_buttons.html
index 1555b12369..cb305eee4b 100644
--- a/phpBB/styles/prosilver/template/posting_buttons.html
+++ b/phpBB/styles/prosilver/template/posting_buttons.html
@@ -1,6 +1,5 @@
-<script type="text/javascript">
-// <![CDATA[
+<script>
var form_name = 'postform';
var text_name = <!-- IF $SIG_EDIT -->'signature'<!-- ELSE -->'message'<!-- ENDIF -->;
var load_draft = false;
@@ -11,27 +10,6 @@
var bbtags = new Array('[b]','[/b]','[i]','[/i]','[u]','[/u]','[quote]','[/quote]','[code]','[/code]','[list]','[/list]','[list=]','[/list]','[img]','[/img]','[url]','[/url]','[flash=]', '[/flash]','[size=]','[/size]'<!-- BEGIN custom_tags -->, {custom_tags.BBCODE_NAME}<!-- END custom_tags -->);
var imageTag = false;
- // Helpline messages
- var help_line = {
- b: '{LA_BBCODE_B_HELP}',
- i: '{LA_BBCODE_I_HELP}',
- u: '{LA_BBCODE_U_HELP}',
- q: '{LA_BBCODE_Q_HELP}',
- c: '{LA_BBCODE_C_HELP}',
- l: '{LA_BBCODE_L_HELP}',
- o: '{LA_BBCODE_O_HELP}',
- p: '{LA_BBCODE_P_HELP}',
- w: '{LA_BBCODE_W_HELP}',
- a: '{LA_BBCODE_A_HELP}',
- s: '{LA_BBCODE_S_HELP}',
- f: '{LA_BBCODE_F_HELP}',
- y: '{LA_BBCODE_Y_HELP}',
- d: '{LA_BBCODE_D_HELP}'
- <!-- BEGIN custom_tags -->
- ,cb_{custom_tags.BBCODE_ID}: '{custom_tags.A_BBCODE_HELPLINE}'
- <!-- END custom_tags -->
- }
-
function change_palette()
{
phpbb.toggleDisplay('colour_palette');
@@ -46,8 +24,6 @@
document.getElementById('bbpalette').value = '{LA_FONT_COLOR}';
}
}
-
-// ]]>
</script>
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/editor.js -->
@@ -55,31 +31,56 @@
<div id="colour_palette" style="display: none;">
<dl style="clear: left;">
<dt><label>{L_FONT_COLOR}{L_COLON}</label></dt>
- <dd id="color_palette_placeholder" data-orientation="h" data-height="12" data-width="15" data-bbcode="true"></dd>
+ <dd id="color_palette_placeholder" class="color_palette_placeholder" data-orientation="h" data-height="12" data-width="15" data-bbcode="true"></dd>
</dl>
</div>
<!-- EVENT posting_editor_buttons_before -->
-<div id="format-buttons">
- <input type="button" class="button2 bbcode-b" accesskey="b" name="addbbcode0" value=" B " style="font-weight:bold; width: 30px" onclick="bbstyle(0)" title="{L_BBCODE_B_HELP}" />
- <input type="button" class="button2 bbcode-i" accesskey="i" name="addbbcode2" value=" i " style="font-style:italic; width: 30px" onclick="bbstyle(2)" title="{L_BBCODE_I_HELP}" />
- <input type="button" class="button2 bbcode-u" accesskey="u" name="addbbcode4" value=" u " style="text-decoration: underline; width: 30px" onclick="bbstyle(4)" title="{L_BBCODE_U_HELP}" />
+<div id="format-buttons" class="format-buttons">
+ <button type="button" class="button button-icon-only bbcode-b" accesskey="b" name="addbbcode0" value=" B " onclick="bbstyle(0)" title="{L_BBCODE_B_HELP}">
+ <i class="icon fa-bold fa-fw" aria-hidden="true"></i>
+ </button>
+ <button type="button" class="button button-icon-only bbcode-i" accesskey="i" name="addbbcode2" value=" i " onclick="bbstyle(2)" title="{L_BBCODE_I_HELP}">
+ <i class="icon fa-italic fa-fw" aria-hidden="true"></i>
+ </button>
+ <button type="button" class="button button-icon-only bbcode-u" accesskey="u" name="addbbcode4" value=" u " onclick="bbstyle(4)" title="{L_BBCODE_U_HELP}">
+ <i class="icon fa-underline fa-fw" aria-hidden="true"></i>
+ </button>
<!-- IF S_BBCODE_QUOTE -->
- <input type="button" class="button2 bbcode-quote" accesskey="q" name="addbbcode6" value="Quote" style="width: 50px" onclick="bbstyle(6)" title="{L_BBCODE_Q_HELP}" />
+ <button type="button" class="button button-icon-only bbcode-quote" accesskey="q" name="addbbcode6" value="Quote" onclick="bbstyle(6)" title="{L_BBCODE_Q_HELP}">
+ <i class="icon fa-quote-left fa-fw" aria-hidden="true"></i>
+ </button>
<!-- ENDIF -->
- <input type="button" class="button2 bbcode-code" accesskey="c" name="addbbcode8" value="Code" style="width: 40px" onclick="bbstyle(8)" title="{L_BBCODE_C_HELP}" />
- <input type="button" class="button2 bbcode-list" accesskey="l" name="addbbcode10" value="List" style="width: 40px" onclick="bbstyle(10)" title="{L_BBCODE_L_HELP}" />
- <input type="button" class="button2 bbcode-list-" accesskey="o" name="addbbcode12" value="List=" style="width: 40px" onclick="bbstyle(12)" title="{L_BBCODE_O_HELP}" />
- <input type="button" class="button2 bbcode-asterisk" accesskey="y" name="addlistitem" value="[*]" style="width: 40px" onclick="bbstyle(-1)" title="{L_BBCODE_LISTITEM_HELP}" />
+ <button type="button" class="button button-icon-only bbcode-code" accesskey="c" name="addbbcode8" value="Code" onclick="bbstyle(8)" title="{L_BBCODE_C_HELP}">
+ <i class="icon fa-code fa-fw" aria-hidden="true"></i>
+ </button>
+ <button type="button" class="button button-icon-only bbcode-list" accesskey="l" name="addbbcode10" value="List" onclick="bbstyle(10)" title="{L_BBCODE_L_HELP}">
+ <i class="icon fa-list fa-fw" aria-hidden="true"></i>
+ </button>
+ <button type="button" class="button button-icon-only bbcode-list-" accesskey="o" name="addbbcode12" value="List=" onclick="bbstyle(12)" title="{L_BBCODE_O_HELP}">
+ <i class="icon fa-list-ol fa-fw" aria-hidden="true"></i>
+ </button>
+ <button type="button" class="button button-icon-only bbcode-asterisk" accesskey="y" name="addlistitem" value="[*]" onclick="bbstyle(-1)" title="{L_BBCODE_LISTITEM_HELP}">
+ <i class="icon fa-asterisk fa-fw" aria-hidden="true"></i>
+ </button>
<!-- IF S_BBCODE_IMG -->
- <input type="button" class="button2 bbcode-img" accesskey="p" name="addbbcode14" value="Img" style="width: 40px" onclick="bbstyle(14)" title="{L_BBCODE_P_HELP}" />
+ <button type="button" class="button button-icon-only bbcode-img" accesskey="p" name="addbbcode14" value="Img" onclick="bbstyle(14)" title="{L_BBCODE_P_HELP}">
+ <i class="icon fa-image fa-fw" aria-hidden="true"></i>
+ </button>
<!-- ENDIF -->
<!-- IF S_LINKS_ALLOWED -->
- <input type="button" class="button2 bbcode-url" accesskey="w" name="addbbcode16" value="URL" style="text-decoration: underline; width: 40px" onclick="bbstyle(16)" title="{L_BBCODE_W_HELP}" />
+ <button type="button" class="button button-icon-only bbcode-url" accesskey="w" name="addbbcode16" value="URL" onclick="bbstyle(16)" title="{L_BBCODE_W_HELP}">
+ <i class="icon fa-link fa-fw" aria-hidden="true"></i>
+ </button>
<!-- ENDIF -->
<!-- IF S_BBCODE_FLASH -->
- <input type="button" class="button2 bbcode-flash" accesskey="d" name="addbbcode18" value="Flash" onclick="bbstyle(18)" title="{L_BBCODE_D_HELP}" />
+ <button type="button" class="button button-icon-only bbcode-flash" accesskey="d" name="addbbcode18" value="Flash" onclick="bbstyle(18)" title="{L_BBCODE_D_HELP}">
+ <i class="icon fa-flash fa-fw" aria-hidden="true"></i>
+ </button>
<!-- ENDIF -->
+ <button type="button" class="button button-icon-only bbcode-color" name="bbpalette" id="bbpalette" value="{L_FONT_COLOR}" onclick="change_palette();" title="{L_BBCODE_S_HELP}">
+ <i class="icon fa-tint fa-fw" aria-hidden="true"></i>
+ </button>
<select name="addbbcode20" class="bbcode-size" onchange="bbfontstyle('[size=' + this.form.addbbcode20.options[this.form.addbbcode20.selectedIndex].value + ']', '[/size]');this.form.addbbcode20.selectedIndex = 2;" title="{L_BBCODE_F_HELP}">
<option value="50">{L_FONT_TINY}</option>
<option value="85">{L_FONT_SMALL}</option>
@@ -91,12 +92,13 @@
<!-- ENDIF -->
<!-- ENDIF -->
</select>
- <input type="button" class="button2 bbcode-color" name="bbpalette" id="bbpalette" value="{L_FONT_COLOR}" onclick="change_palette();" title="{L_BBCODE_S_HELP}" />
<!-- EVENT posting_editor_buttons_custom_tags_before -->
<!-- BEGIN custom_tags -->
- <input type="button" class="button2 bbcode-{custom_tags.BBCODE_TAG_CLEAN}" name="addbbcode{custom_tags.BBCODE_ID}" value="{custom_tags.BBCODE_TAG}" onclick="bbstyle({custom_tags.BBCODE_ID})" title="{custom_tags.BBCODE_HELPLINE}" />
+ <button type="button" class="button button-secondary bbcode-{custom_tags.BBCODE_TAG_CLEAN}" name="addbbcode{custom_tags.BBCODE_ID}" value="{custom_tags.BBCODE_TAG}" onclick="bbstyle({custom_tags.BBCODE_ID})" title="{{ custom_tags.BBCODE_HELPLINE|e('html_attr') }}">
+ {custom_tags.BBCODE_TAG}
+ </button>
<!-- END custom_tags -->
</div>
<!-- EVENT posting_editor_buttons_after -->
diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html
index 5258ea09a2..d963c98e08 100644
--- a/phpBB/styles/prosilver/template/posting_editor.html
+++ b/phpBB/styles/prosilver/template/posting_editor.html
@@ -6,7 +6,7 @@
<dt><label for="icon">{L_ICON}{L_COLON}</label></dt>
<dd>
<label for="icon"><input type="radio" name="icon" id="icon" value="0" checked="checked" tabindex="1" /> <!-- IF S_SHOW_TOPIC_ICONS -->{L_NO_TOPIC_ICON}<!-- ELSE -->{L_NO_PM_ICON}<!-- ENDIF --></label>
- <!-- BEGIN topic_icon --><label for="icon-{topic_icon.ICON_ID}"><input type="radio" name="icon" id="icon-{topic_icon.ICON_ID}" value="{topic_icon.ICON_ID}" {topic_icon.S_ICON_CHECKED} tabindex="1" /><img src="{topic_icon.ICON_IMG}" width="{topic_icon.ICON_WIDTH}" height="{topic_icon.ICON_HEIGHT}" alt="{topic_icon.ICON_NAME}" title="" /></label> <!-- END topic_icon -->
+ <!-- BEGIN topic_icon --><label for="icon-{topic_icon.ICON_ID}"><input type="radio" name="icon" id="icon-{topic_icon.ICON_ID}" value="{topic_icon.ICON_ID}" {topic_icon.S_ICON_CHECKED} tabindex="1" /><img src="{topic_icon.ICON_IMG}" width="{topic_icon.ICON_WIDTH}" height="{topic_icon.ICON_HEIGHT}" alt="{topic_icon.ICON_ALT}" title="{topic_icon.ICON_ALT}" /></label> <!-- END topic_icon -->
</dd>
</dl>
<!-- ENDIF -->
@@ -39,8 +39,8 @@
<!-- INCLUDE posting_buttons.html -->
- <div id="smiley-box">
- <!-- EVENT posting_editor_smilies_before -->
+ <div id="smiley-box" class="smiley-box">
+ <!-- EVENT posting_editor_smilies_before -->
<!-- IF S_SMILIES_ALLOWED and .smiley -->
<strong>{L_SMILIES}</strong><br />
<!-- BEGIN smiley -->
@@ -73,7 +73,7 @@
<!-- EVENT posting_editor_message_before -->
- <div id="message-box">
+ <div id="message-box" class="message-box">
<textarea <!-- IF S_UCP_ACTION and not S_PRIVMSGS and not S_EDIT_DRAFT -->name="signature" id="signature" style="height: 9em;"<!-- ELSE -->name="message" id="message"<!-- ENDIF --> rows="15" cols="76" tabindex="4" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" onfocus="initInsertions();" class="inputbox">{MESSAGE}{DRAFT_MESSAGE}{SIGNATURE}</textarea>
</div>
@@ -106,13 +106,13 @@
<!-- ENDIF -->
<!-- IF not S_PRIVMSGS and not S_SHOW_DRAFTS and not $SIG_EDIT eq 1 -->
- <div id="tabs" class="sub-panels" data-show-panel="<!-- IF SHOW_PANEL -->{SHOW_PANEL}<!-- ELSE -->options-panel<!-- ENDIF -->" role="tablist">
+ <div id="tabs" class="tabs sub-panels" data-show-panel="<!-- IF SHOW_PANEL -->{SHOW_PANEL}<!-- ELSE -->options-panel<!-- ENDIF -->" role="tablist">
<ul>
<li id="options-panel-tab" class="tab activetab"><a href="#tabs" data-subpanel="options-panel" role="tab" aria-controls="options-panel"><span>{L_OPTIONS}</span></a></li>
<!-- IF S_SHOW_ATTACH_BOX -->
<li id="attach-panel-tab" class="tab">
<a href="#tabs" data-subpanel="attach-panel" role="tab" aria-controls="attach-panel">
- {L_ATTACHMENTS} <strong id="file-total-progress"><strong id="file-total-progress-bar"></strong></strong>
+ {L_ATTACHMENTS} <strong id="file-total-progress" class="file-total-progress"><strong id="file-total-progress-bar" class="file-total-progress-bar"></strong></strong>
</a>
</li>
<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/posting_layout.html b/phpBB/styles/prosilver/template/posting_layout.html
index 22da32076c..bca9195f0e 100644
--- a/phpBB/styles/prosilver/template/posting_layout.html
+++ b/phpBB/styles/prosilver/template/posting_layout.html
@@ -9,14 +9,14 @@
<!-- IF S_FORUM_RULES -->
<div class="rules<!-- IF U_FORUM_RULES --> rules-link<!-- ENDIF -->">
<div class="inner">
-
+
<!-- IF U_FORUM_RULES -->
<a href="{U_FORUM_RULES}">{L_FORUM_RULES}</a>
<!-- ELSE -->
<strong>{L_FORUM_RULES}</strong><br />
{FORUM_RULES}
<!-- ENDIF -->
-
+
</div>
</div>
<!-- ENDIF -->
@@ -26,10 +26,10 @@
<!-- IF S_DRAFT_LOADED -->
<div class="panel">
<div class="inner">
-
+
<h3>{L_INFORMATION}</h3>
<p>{L_DRAFT_LOADED}</p>
-
+
</div>
</div>
<!-- ENDIF -->
@@ -48,7 +48,7 @@
<dt><label for="to_forum_id">{L_MOVE}{L_COLON}</label></dt>
<dd><select id="to_forum_id" name="to_forum_id">{S_FORUM_SELECT}</select></dd>
</dl>
-
+
<dl>
<dt>&nbsp;</dt>
<dd><input class="button1" type="submit" name="post" value="{L_CONFIRM}" /> <input class="button2" type="submit" name="cancel_unglobalise" value="{L_CANCEL}" /></dd>
@@ -63,7 +63,7 @@
<div class="panel" id="postingbox">
<div class="inner">
-
+
<h3>{L_POST_A}</h3>
<!-- DEFINE $EXTRA_POSTING_OPTIONS = 1 -->
diff --git a/phpBB/styles/prosilver/template/posting_pm_header.html b/phpBB/styles/prosilver/template/posting_pm_header.html
index 032d8c6a6f..7fee914525 100644
--- a/phpBB/styles/prosilver/template/posting_pm_header.html
+++ b/phpBB/styles/prosilver/template/posting_pm_header.html
@@ -32,7 +32,7 @@
<!-- BEGIN to_recipient -->
<li>
<!-- IF not S_EDIT_POST --><input type="submit" name="remove_{to_recipient.TYPE}[{to_recipient.UG_ID}]" value="x" class="button2" /><!-- ENDIF -->
- <!-- IF to_recipient.IS_GROUP --><a href="{to_recipient.U_VIEW}"><strong>{to_recipient.NAME}</strong></a><!-- ELSE -->{to_recipient.NAME_FULL}<!-- ENDIF -->
+ <!-- IF to_recipient.IS_GROUP --><a href="{to_recipient.U_VIEW}" style="color: {{ to_recipient.COLOUR }}"><strong>{to_recipient.NAME}</strong></a><!-- ELSE -->{to_recipient.NAME_FULL}<!-- ENDIF -->
</li>
<!-- END to_recipient -->
</ul>
@@ -49,7 +49,7 @@
<!-- BEGIN bcc_recipient -->
<li>
<!-- IF not S_EDIT_POST --><input type="submit" name="remove_{bcc_recipient.TYPE}[{bcc_recipient.UG_ID}]" value="x" class="button2" /><!-- ENDIF -->
- <!-- IF bcc_recipient.IS_GROUP --><a href="{bcc_recipient.U_VIEW}"><strong>{bcc_recipient.NAME}</strong></a><!-- ELSE -->{bcc_recipient.NAME_FULL}<!-- ENDIF -->
+ <!-- IF bcc_recipient.IS_GROUP --><a href="{bcc_recipient.U_VIEW}" style="color: {{ bcc_recipient.COLOUR }}"><strong>{bcc_recipient.NAME}</strong></a><!-- ELSE -->{bcc_recipient.NAME_FULL}<!-- ENDIF -->
</li>
<!-- END bcc_recipient -->
</ul>
diff --git a/phpBB/styles/prosilver/template/posting_pm_layout.html b/phpBB/styles/prosilver/template/posting_pm_layout.html
index 7f4a0ea8d7..316fa791e4 100644
--- a/phpBB/styles/prosilver/template/posting_pm_layout.html
+++ b/phpBB/styles/prosilver/template/posting_pm_layout.html
@@ -3,10 +3,10 @@
<!-- IF S_DRAFT_LOADED -->
<div class="panel">
<div class="inner">
-
+
<h3>{L_INFORMATION}</h3>
<p>{L_DRAFT_LOADED_PM}</p>
-
+
</div>
</div>
<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/posting_poll_body.html b/phpBB/styles/prosilver/template/posting_poll_body.html
index ee7100aded..795649650d 100644
--- a/phpBB/styles/prosilver/template/posting_poll_body.html
+++ b/phpBB/styles/prosilver/template/posting_poll_body.html
@@ -15,8 +15,8 @@
<!-- IF S_SHOW_POLL_BOX -->
<dl>
- <dt><label for="poll_title">{L_POLL_QUESTION}{L_COLON}</label></dt>
- <dd><input type="text" name="poll_title" id="poll_title" maxlength="255" value="{POLL_TITLE}" class="inputbox" /></dd>
+ <dt><label for="poll_title">{{ lang('POLL_QUESTION') ~ lang('COLON') }}</label></dt>
+ <dd><input type="text" name="poll_title" id="poll_title" maxlength="100" value="{{ POLL_TITLE }}" class="inputbox" /></dd>
</dl>
<dl>
<dt><label for="poll_option_text">{L_POLL_OPTIONS}{L_COLON}</label><br /><span>{L_POLL_OPTIONS_EXPLAIN}</span></dt>
diff --git a/phpBB/styles/prosilver/template/posting_preview.html b/phpBB/styles/prosilver/template/posting_preview.html
index aac117c090..781d0de06b 100644
--- a/phpBB/styles/prosilver/template/posting_preview.html
+++ b/phpBB/styles/prosilver/template/posting_preview.html
@@ -31,6 +31,8 @@
<div class="content">{PREVIEW_MESSAGE}</div>
+ <!-- EVENT posting_preview_content_after -->
+
<!-- IF .attachment -->
<dl class="attachbox">
<dt>{L_ATTACHMENTS}</dt>
diff --git a/phpBB/styles/prosilver/template/posting_review.html b/phpBB/styles/prosilver/template/posting_review.html
index 25b719420b..e5d285e7bf 100644
--- a/phpBB/styles/prosilver/template/posting_review.html
+++ b/phpBB/styles/prosilver/template/posting_review.html
@@ -13,8 +13,17 @@
<!-- ENDIF -->
<div class="postbody" id="ppr{post_review_row.POST_ID}">
- <h3><a href="#ppr{post_review_row.POST_ID}">{post_review_row.POST_SUBJECT}</a></h3>
- <p class="author"><!-- IF S_IS_BOT -->{post_review_row.MINI_POST_IMG}<!-- ELSE --><a href="{post_review_row.U_MINI_POST}">{post_review_row.MINI_POST_IMG}</a><!-- ENDIF --> {L_POST_BY_AUTHOR}<strong> {post_review_row.POST_AUTHOR_FULL}</strong> &raquo; {post_review_row.POST_DATE}</p>
+ <h3><a href="{post_review_row.U_MINI_POST}">{post_review_row.POST_SUBJECT}</a></h3>
+ <p class="author">
+ <!-- IF S_IS_BOT -->
+ <span><i class="icon fa-file fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{post_review_row.MINI_POST}</span></span>
+ <!-- ELSE -->
+ <a href="{post_review_row.U_MINI_POST}" title="{post_review_row.MINI_POST}">
+ <i class="icon fa-file fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{post_review_row.MINI_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ {L_POST_BY_AUTHOR} <!-- EVENT posting_review_row_post_author_username_prepend --><strong>{post_review_row.POST_AUTHOR_FULL}</strong><!-- EVENT posting_review_row_post_author_username_append --> &raquo; {post_review_row.POST_DATE}
+ </p>
<div class="content">{post_review_row.MESSAGE}</div>
<!-- IF post_review_row.S_HAS_ATTACHMENTS -->
diff --git a/phpBB/styles/prosilver/template/posting_smilies.html b/phpBB/styles/prosilver/template/posting_smilies.html
index 3bd51275ec..b5794d5aff 100644
--- a/phpBB/styles/prosilver/template/posting_smilies.html
+++ b/phpBB/styles/prosilver/template/posting_smilies.html
@@ -1,23 +1,21 @@
<!-- INCLUDE simple_header.html -->
-<script type="text/javascript">
-// <![CDATA[
+<script>
var form_name = opener.form_name;
var text_name = opener.text_name;
-// ]]>
</script>
<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/editor.js -->
<h2>{L_SMILIES}</h2>
<div class="panel">
<div class="inner">
- <!-- BEGIN smiley -->
- <a href="#" onclick="initInsertions(); insert_text('{smiley.A_SMILEY_CODE}', true, true); return false;"><img src="{smiley.SMILEY_IMG}" width="{smiley.SMILEY_WIDTH}" height="{smiley.SMILEY_HEIGHT}" alt="{smiley.SMILEY_CODE}" title="{smiley.SMILEY_DESC}" /></a>
+ <!-- BEGIN smiley -->
+ <a href="#" onclick="initInsertions(); insert_text('{smiley.A_SMILEY_CODE}', true, true); return false;"><img src="{smiley.SMILEY_IMG}" width="{smiley.SMILEY_WIDTH}" height="{smiley.SMILEY_HEIGHT}" alt="{smiley.SMILEY_CODE}" title="{smiley.SMILEY_DESC}" /></a>
<!-- END smiley -->
-
+
</div>
</div>
-<!-- IF .pagination -->
+<!-- IF .pagination -->
<div class="pagination">
<!-- INCLUDE pagination.html -->
</div>
diff --git a/phpBB/styles/prosilver/template/posting_topic_review.html b/phpBB/styles/prosilver/template/posting_topic_review.html
index 4d5ab16afe..209dadf327 100644
--- a/phpBB/styles/prosilver/template/posting_topic_review.html
+++ b/phpBB/styles/prosilver/template/posting_topic_review.html
@@ -1,14 +1,12 @@
-<h3 id="review">
+<h3 id="review" class="review">
<span class="right-box"><a href="#review" onclick="viewableArea(getElementById('topicreview'), true); var rev_text = getElementById('review').getElementsByTagName('a').item(0).firstChild; if (rev_text.data == '{LA_EXPAND_VIEW}'){rev_text.data = '{LA_COLLAPSE_VIEW}'; } else if (rev_text.data == '{LA_COLLAPSE_VIEW}'){rev_text.data = '{LA_EXPAND_VIEW}'};">{L_EXPAND_VIEW}</a></span>
{L_TOPIC_REVIEW}{L_COLON} {TOPIC_TITLE}
</h3>
-<div id="topicreview">
-<script type="text/javascript">
-// <![CDATA[
+<div id="topicreview" class="topicreview">
+<script>
bbcodeEnabled = {S_BBCODE_ALLOWED};
-// ]]>
</script>
<!-- BEGIN topic_review_row -->
@@ -26,21 +24,21 @@
<!-- ENDIF -->
<div class="postbody" id="pr{topic_review_row.POST_ID}">
- <h3><a href="#pr{topic_review_row.POST_ID}">{topic_review_row.POST_SUBJECT}</a></h3>
+ <h3><a href="{topic_review_row.U_MINI_POST}">{topic_review_row.POST_SUBJECT}</a></h3>
<!-- IF (topic_review_row.POSTER_QUOTE and topic_review_row.DECODED_MESSAGE) or topic_review_row.U_MCP_DETAILS -->
<ul class="post-buttons">
<!-- IF topic_review_row.U_MCP_DETAILS -->
<li>
- <a href="{topic_review_row.U_MCP_DETAILS}" title="{L_POST_DETAILS}" class="button icon-button info-icon">
- <span>{L_POST_DETAILS}</span>
+ <a href="{topic_review_row.U_MCP_DETAILS}" title="{L_POST_DETAILS}" class="button button-icon-only">
+ <i class="icon fa-info fa-fw" aria-hidden="true"></i><span class="sr-only">{L_POST_DETAILS}</span>
</a>
<li>
<!-- ENDIF -->
<!-- IF topic_review_row.POSTER_QUOTE and topic_review_row.DECODED_MESSAGE -->
<li>
- <a href="#postingbox" onclick="addquote({topic_review_row.POST_ID}, '{topic_review_row.POSTER_QUOTE}', '{LA_WROTE}');" title="{L_QUOTE} {topic_review_row.POST_AUTHOR}" class="button icon-button quote-icon">
- <span>{L_QUOTE} {topic_review_row.POST_AUTHOR}</span>
+ <a href="#postingbox" onclick="addquote({topic_review_row.POST_ID}, '{topic_review_row.POSTER_QUOTE}', '{LA_WROTE}', {post_id:{topic_review_row.POST_ID},time:{topic_review_row.POST_TIME},user_id:{topic_review_row.USER_ID}});" title="{L_QUOTE} {topic_review_row.POST_AUTHOR}" class="button button-icon-only">
+ <i class="icon fa-quote-left fa-fw" aria-hidden="true"></i><span class="sr-only">{L_QUOTE} {topic_review_row.POST_AUTHOR}</span>
</a>
</li>
<!-- ENDIF -->
@@ -48,11 +46,22 @@
<!-- ENDIF -->
<!-- EVENT posting_topic_review_row_post_details_before -->
- <p class="author"><!-- IF S_IS_BOT -->{topic_review_row.MINI_POST_IMG}<!-- ELSE --><a href="{topic_review_row.U_MINI_POST}">{topic_review_row.MINI_POST_IMG}</a><!-- ENDIF --> {L_POST_BY_AUTHOR} <strong>{topic_review_row.POST_AUTHOR_FULL}</strong> &raquo; {topic_review_row.POST_DATE} </p>
+ <p class="author">
+ <!-- IF S_IS_BOT -->
+ <span><i class="icon fa-file fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{topic_review_row.MINI_POST}</span></span>
+ <!-- ELSE -->
+ <a href="{topic_review_row.U_MINI_POST}" title="{topic_review_row.MINI_POST}">
+ <i class="icon fa-file fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{topic_review_row.MINI_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ {L_POST_BY_AUTHOR} <!-- EVENT posting_topic_review_row_post_author_username_prepend --><strong>{topic_review_row.POST_AUTHOR_FULL}</strong><!-- EVENT posting_topic_review_row_post_author_username_append --> &raquo; {topic_review_row.POST_DATE}
+ </p>
<!-- EVENT posting_topic_review_row_post_details_after -->
<div class="content">{topic_review_row.MESSAGE}</div>
+ <!-- EVENT posting_topic_review_row_content_after -->
+
<!-- IF topic_review_row.S_HAS_ATTACHMENTS -->
<dl class="attachbox">
<dt>{L_ATTACHMENTS}</dt>
@@ -73,8 +82,8 @@
<hr />
-<!-- IF S_MCP_REPORT -->
- <p><a href="#report" class="top2">{L_BACK_TO_TOP}</a></p>
-<!-- ELSE -->
- <p><a href="#postingbox" class="top2">{L_BACK_TO_TOP}</a></p>
-<!-- ENDIF -->
+<p>
+ <a href="<!-- IF S_MCP_REPORT -->#report<!-- ELSE -->#postingbox<!-- ENDIF -->" class="top">
+ <i class="icon fa-chevron-circle-up fa-fw icon-gray" aria-hidden="true"></i><span>{L_BACK_TO_TOP}</span>
+ </a>
+</p>
diff --git a/phpBB/styles/prosilver/template/quickreply_editor.html b/phpBB/styles/prosilver/template/quickreply_editor.html
index ca8ccc0a6b..9839494491 100644
--- a/phpBB/styles/prosilver/template/quickreply_editor.html
+++ b/phpBB/styles/prosilver/template/quickreply_editor.html
@@ -10,7 +10,7 @@
<dd><input type="text" name="subject" id="subject" size="45" maxlength="124" tabindex="2" value="{SUBJECT}" class="inputbox autowidth" /></dd>
</dl>
<!-- EVENT quickreply_editor_message_before -->
- <div id="message-box">
+ <div id="message-box" class="message-box">
<textarea style="height: 9em;" name="message" rows="7" cols="76" tabindex="3" class="inputbox"></textarea>
</div>
<!-- EVENT quickreply_editor_message_after -->
diff --git a/phpBB/styles/prosilver/template/report_body.html b/phpBB/styles/prosilver/template/report_body.html
index 2a5e6c9d0e..285e8ec8d7 100644
--- a/phpBB/styles/prosilver/template/report_body.html
+++ b/phpBB/styles/prosilver/template/report_body.html
@@ -8,7 +8,7 @@
<div class="content">
<p><!-- IF S_REPORT_POST -->{L_REPORT_POST_EXPLAIN}<!-- ELSE -->{L_REPORT_MESSAGE_EXPLAIN}<!-- ENDIF --></p>
-
+
<fieldset>
<!-- IF ERROR --><dl><dd class="error">{ERROR}</dd></dl><!-- ENDIF -->
<dl class="fields2">
@@ -19,7 +19,7 @@
<dl class="fields2">
<dt><label for="notify1">{L_REPORT_NOTIFY}{L_COLON}</label><br /><span>{L_REPORT_NOTIFY_EXPLAIN}</span></dt>
<dd>
- <label for="notify1"><input type="radio" name="notify" id="notify1" value="1" <!-- IF not S_NOTIFY -->checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="notify1"><input type="radio" name="notify" id="notify1" value="1" <!-- IF not S_NOTIFY -->checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="notify0"><input type="radio" name="notify" id="notify0" value="0" <!-- IF S_NOTIFY -->checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html
index 4c83e95a1b..9ee13a4224 100644
--- a/phpBB/styles/prosilver/template/search_results.html
+++ b/phpBB/styles/prosilver/template/search_results.html
@@ -8,23 +8,35 @@
<!-- IF PHRASE_SEARCH_DISABLED --> <p><strong>{L_PHRASE_SEARCH_DISABLED}</strong></p><!-- ENDIF -->
<!-- IF SEARCH_TOPIC -->
- <p class="return-link"><a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH_TOPIC}">{L_RETURN_TO_TOPIC}</a></p>
+ <p class="return-link">
+ <a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH_TOPIC}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_RETURN_TO_TOPIC}</span>
+ </a>
+ </p>
<!-- ELSE -->
- <p class="advanced-search-link"><a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH}" title="{L_SEARCH_ADV}">{L_GO_TO_SEARCH_ADV}</a></p>
+ <p class="advanced-search-link">
+ <a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_SEARCH}" title="{L_SEARCH_ADV}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_GO_TO_SEARCH_ADV}</span>
+ </a>
+ </p>
<!-- ENDIF -->
<!-- EVENT search_results_header_after -->
<!-- IF .pagination or SEARCH_MATCHES or TOTAL_MATCHES or PAGE_NUMBER -->
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<!-- IF TOTAL_MATCHES > 0 -->
<div class="search-box" role="search">
<form method="post" action="{S_SEARCH_ACTION}">
<fieldset>
<input class="inputbox search tiny" type="search" name="add_keywords" id="add_keywords" value="" placeholder="{L_SEARCH_IN_RESULTS}" />
- <button class="button icon-button search-icon" type="submit" title="{L_SEARCH}">{L_SEARCH}</button>
- <a href="{U_SEARCH}" class="button icon-button search-adv-icon" title="{L_SEARCH_ADV}">{L_SEARCH_ADV}</a>
+ <button class="button button-search" type="submit" title="{L_SEARCH}">
+ <i class="icon fa-search fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH}</span>
+ </button>
+ <a href="{U_SEARCH}" class="button button-search-end" title="{L_SEARCH_ADV}">
+ <i class="icon fa-cog fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH_ADV}</span>
+ </a>
</fieldset>
</form>
</div>
@@ -52,7 +64,7 @@
<div class="inner">
<ul class="topiclist">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt><div class="list-inner">{L_TOPICS}</div></dt>
<dd class="posts">{L_REPLIES}</dd>
<dd class="views">{L_VIEWS}</dd>
@@ -65,43 +77,81 @@
<!-- BEGIN searchresults -->
<!-- EVENT search_results_topic_before -->
<li class="row<!-- IF searchresults.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
- <dl class="icon {searchresults.TOPIC_IMG_STYLE}">
- <dt <!-- IF searchresults.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{searchresults.TOPIC_FOLDER_IMG_ALT}">
- <!-- IF searchresults.S_UNREAD_TOPIC and not S_IS_BOT --><a href="{searchresults.U_NEWEST_POST}" class="icon-link"></a><!-- ENDIF -->
+ <dl class="row-item {searchresults.TOPIC_IMG_STYLE}">
+ <dt<!-- IF searchresults.TOPIC_ICON_IMG --> style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{searchresults.TOPIC_FOLDER_IMG_ALT}">
+ <!-- IF searchresults.S_UNREAD_TOPIC and not S_IS_BOT --><a href="{searchresults.U_NEWEST_POST}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
-
<!-- EVENT topiclist_row_prepend -->
- <!-- IF searchresults.S_UNREAD_TOPIC and not S_IS_BOT --><a href="{searchresults.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF -->
- <a href="{searchresults.U_VIEW_TOPIC}" class="topictitle">{searchresults.TOPIC_TITLE}</a> {searchresults.ATTACH_ICON_IMG}
- <!-- IF searchresults.S_TOPIC_UNAPPROVED or searchresults.S_POSTS_UNAPPROVED --><a href="{searchresults.U_MCP_QUEUE}">{searchresults.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF searchresults.S_TOPIC_DELETED --><a href="{searchresults.U_MCP_QUEUE}">{DELETED_IMG}</a> <!-- ENDIF -->
- <!-- IF searchresults.S_TOPIC_REPORTED --><a href="{searchresults.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF searchresults.S_UNREAD_TOPIC and not S_IS_BOT -->
+ <a class="unread" href="{searchresults.U_NEWEST_POST}">
+ <i class="icon fa-file fa-fw icon-red icon-md" aria-hidden="true"></i><span class="sr-only">{L_NEW_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ <a href="{searchresults.U_VIEW_TOPIC}" class="topictitle">{searchresults.TOPIC_TITLE}</a>
+ <!-- IF searchresults.S_TOPIC_UNAPPROVED or searchresults.S_POSTS_UNAPPROVED -->
+ <a href="{searchresults.U_MCP_QUEUE}" title="{L_TOPIC_UNAPPROVED}">
+ <i class="icon fa-question fa-fw icon-blue" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_UNAPPROVED}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF searchresults.S_TOPIC_DELETED -->
+ <a href="{searchresults.U_MCP_QUEUE}" title="{L_TOPIC_DELETED}">
+ <i class="icon fa-recycle fa-fw icon-green" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_DELETED}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF searchresults.S_TOPIC_REPORTED -->
+ <a href="{searchresults.U_MCP_REPORT}" title="{L_TOPIC_REPORTED}">
+ <i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_REPORTED}</span>
+ </a>
+ <!-- ENDIF -->
+ <br />
<!-- EVENT topiclist_row_topic_title_after -->
+
+ <!-- IF not S_IS_BOT -->
+ <div class="responsive-show" style="display: none;">
+ {L_LAST_POST} {L_POST_BY_AUTHOR} <!-- EVENT search_results_last_post_author_username_prepend -->{searchresults.LAST_POST_AUTHOR_FULL}<!-- EVENT search_results_last_post_author_username_append --> &laquo; <a href="{searchresults.U_LAST_POST}" title="{L_GOTO_LAST_POST}"><time datetime="{searchresults.LAST_POST_TIME_RFC3339}">{searchresults.LAST_POST_TIME}</time></a>
+ <br />{L_POSTED} {L_IN} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a>
+ </div>
+ <!-- IF searchresults.TOPIC_REPLIES --><span class="responsive-show left-box" style="display: none;">{L_REPLIES}{L_COLON} <strong>{searchresults.TOPIC_REPLIES}</strong></span><!-- ENDIF -->
+ <!-- ENDIF -->
+
+ <div class="responsive-hide left-box">
+ <!-- IF searchresults.S_HAS_POLL --><i class="icon fa-bar-chart fa-fw" aria-hidden="true"></i><!-- ENDIF -->
+ <!-- IF searchresults.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i><!-- ENDIF -->
+ {% EVENT topiclist_row_topic_by_author_before %}
+ {L_POST_BY_AUTHOR} <!-- EVENT search_results_topic_author_username_prepend -->{searchresults.TOPIC_AUTHOR_FULL}<!-- EVENT search_results_topic_author_username_append --> &raquo; <time datetime="{searchresults.FIRST_POST_TIME_RFC3339}">{searchresults.FIRST_POST_TIME}</time> &raquo; {L_IN} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a>
+ {% EVENT topiclist_row_topic_by_author_after %}
+ </div>
+
<!-- IF .searchresults.pagination -->
<div class="pagination">
+ <span><i class="icon fa-clone fa-fw" aria-hidden="true"></i></span>
<ul>
<!-- BEGIN pagination -->
<!-- IF searchresults.pagination.S_IS_PREV -->
<!-- ELSEIF searchresults.pagination.S_IS_CURRENT --><li class="active"><span>{searchresults.pagination.PAGE_NUMBER}</span></li>
<!-- ELSEIF searchresults.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
<!-- ELSEIF searchresults.pagination.S_IS_NEXT -->
- <!-- ELSE --><li><a href="{searchresults.pagination.PAGE_URL}">{searchresults.pagination.PAGE_NUMBER}</a></li>
+ <!-- ELSE --><li><a class="button" href="{searchresults.pagination.PAGE_URL}">{searchresults.pagination.PAGE_NUMBER}</a></li>
<!-- ENDIF -->
<!-- END pagination -->
</ul>
</div>
<!-- ENDIF -->
- <!-- IF searchresults.S_HAS_POLL -->{POLL_IMG} <!-- ENDIF -->
- {L_POST_BY_AUTHOR} {searchresults.TOPIC_AUTHOR_FULL} &raquo; {searchresults.FIRST_POST_TIME} &raquo; {L_IN} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a>
- <!-- EVENT topiclist_row_append -->
+ <!-- EVENT topiclist_row_append -->
</div>
</dt>
- <dd class="posts">{searchresults.TOPIC_REPLIES}</dd>
- <dd class="views">{searchresults.TOPIC_VIEWS}</dd>
- <dd class="lastpost"><span>
- {L_POST_BY_AUTHOR} {searchresults.LAST_POST_AUTHOR_FULL}
- <!-- IF not S_IS_BOT --><a href="{searchresults.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{LAST_POST_IMG}</a> <!-- ENDIF --><br />{searchresults.LAST_POST_TIME}<br /> </span>
+ <dd class="posts">{searchresults.TOPIC_REPLIES} <dfn>{L_REPLIES}</dfn></dd>
+ <dd class="views">{searchresults.TOPIC_VIEWS} <dfn>{L_VIEWS}</dfn></dd>
+ <dd class="lastpost">
+ <span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} <!-- EVENT search_results_last_post_author_username_prepend -->{searchresults.LAST_POST_AUTHOR_FULL}<!-- EVENT search_results_last_post_author_username_append -->
+ <!-- IF not S_IS_BOT -->
+ <a href="{searchresults.U_LAST_POST}" title="{L_GOTO_LAST_POST}">
+ <i class="icon fa-external-link-square fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{VIEW_LATEST_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ <br /><time datetime="{searchresults.LAST_POST_TIME_RFC3339}">{searchresults.LAST_POST_TIME}</time>
+ </span>
</dd>
</dl>
</li>
@@ -133,7 +183,7 @@
<!-- ELSE -->
<dl class="postprofile">
<!-- EVENT search_results_postprofile_before -->
- <dt class="author">{L_POST_BY_AUTHOR} {searchresults.POST_AUTHOR_FULL}</dt>
+ <dt class="author">{L_POST_BY_AUTHOR} <!-- EVENT search_results_post_author_username_prepend -->{searchresults.POST_AUTHOR_FULL}<!-- EVENT search_results_post_author_username_append --></dt>
<dd class="search-result-date">{searchresults.POST_DATE}</dd>
<dd>{L_FORUM}{L_COLON} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a></dd>
<dd>{L_TOPIC}{L_COLON} <a href="{searchresults.U_VIEW_TOPIC}">{searchresults.TOPIC_TITLE}</a></dd>
@@ -146,12 +196,17 @@
<div class="postbody">
<h3><a href="{searchresults.U_VIEW_POST}">{searchresults.POST_SUBJECT}</a></h3>
<div class="content">{searchresults.MESSAGE}</div>
+ <!-- EVENT search_results_content_after -->
</div>
<!-- ENDIF -->
<!-- IF not searchresults.S_IGNORE_POST -->
<ul class="searchresults">
- <li ><a href="{searchresults.U_VIEW_POST}" class="arrow-{S_CONTENT_FLOW_END}">{L_JUMP_TO_POST}</a></li>
+ <li>
+ <a href="{searchresults.U_VIEW_POST}" class="arrow-{S_CONTENT_FLOW_END}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_END} fa-fw icon-black" aria-hidden="true"></i><span>{L_JUMP_TO_POST}</span>
+ </a>
+ </li>
</ul>
<!-- ENDIF -->
@@ -167,24 +222,13 @@
<!-- END searchresults -->
<!-- ENDIF -->
-<!-- IF .pagination or .searchresults or S_SELECT_SORT_KEY or S_SELECT_SORT_DAYS -->
+<div class="action-bar bottom">
+ <!-- IF .searchresults and (S_SELECT_SORT_DAYS or S_SELECT_SORT_KEY) -->
<form method="post" action="{S_SEARCH_ACTION}">
-
- <fieldset class="display-options">
- <!-- IF S_SELECT_SORT_DAYS or S_SELECT_SORT_KEY -->
- <label><!-- IF S_SHOW_TOPICS -->{L_DISPLAY_POSTS}<!-- ELSE -->{L_SORT_BY}</label><label><!-- ENDIF --> {S_SELECT_SORT_DAYS}<!-- IF S_SELECT_SORT_KEY --></label> <label>{S_SELECT_SORT_KEY}</label>
- <label>{S_SELECT_SORT_DIR}<!-- ENDIF --></label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- <!-- ENDIF -->
- </fieldset>
-
+ <!-- INCLUDE display_options.html -->
</form>
+ <!-- ENDIF -->
- <hr />
-<!-- ENDIF -->
-
-<!-- IF .pagination or .searchresults or PAGE_NUMBER -->
-<div class="action-bar bottom">
<div class="pagination">
{SEARCH_MATCHES}
<!-- IF .pagination -->
@@ -194,7 +238,6 @@
<!-- ENDIF -->
</div>
</div>
-<!-- ENDIF -->
<!-- INCLUDE jumpbox.html -->
diff --git a/phpBB/styles/prosilver/template/simple_footer.html b/phpBB/styles/prosilver/template/simple_footer.html
index 77980a9dea..1ef44d1688 100644
--- a/phpBB/styles/prosilver/template/simple_footer.html
+++ b/phpBB/styles/prosilver/template/simple_footer.html
@@ -5,24 +5,28 @@
<!-- IF DEBUG_OUTPUT --><br />{DEBUG_OUTPUT}<!-- ENDIF -->
</div>
- <div id="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}" data-ajax-error-text-abort="{L_AJAX_ERROR_TEXT_ABORT}" data-ajax-error-text-timeout="{L_AJAX_ERROR_TEXT_TIMEOUT}" data-ajax-error-text-parsererror="{L_AJAX_ERROR_TEXT_PARSERERROR}">
- <div id="darken">&nbsp;</div>
+ <div id="darkenwrapper" class="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}" data-ajax-error-text-abort="{L_AJAX_ERROR_TEXT_ABORT}" data-ajax-error-text-timeout="{L_AJAX_ERROR_TEXT_TIMEOUT}" data-ajax-error-text-parsererror="{L_AJAX_ERROR_TEXT_PARSERERROR}">
+ <div id="darken" class="darken">&nbsp;</div>
</div>
- <div id="loading_indicator"></div>
+ <div id="loading_indicator" class="loading_indicator"></div>
<div id="phpbb_alert" class="phpbb_alert" data-l-err="{L_ERROR}" data-l-timeout-processing-req="{L_TIMEOUT_PROCESSING_REQ}">
- <a href="#" class="alert_close"></a>
+ <a href="#" class="alert_close">
+ <i class="icon fa-times-circle fa-fw" aria-hidden="true"></i>
+ </a>
<h3 class="alert_title"></h3><p class="alert_text"></p>
</div>
- <div id="phpbb_confirm" class="phpbb_alert">
- <a href="#" class="alert_close"></a>
+ <div id="phpbb_confirm" class="phpbb_confirm phpbb_alert">
+ <a href="#" class="alert_close">
+ <i class="icon fa-times-circle fa-fw" aria-hidden="true"></i>
+ </a>
<div class="alert_text"></div>
</div>
</div>
-<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
-<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
-<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
+<script src="{T_JQUERY_LINK}"></script>
+<!-- IF S_ALLOW_CDN --><script>window.jQuery || document.write('\x3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}">\x3C/script>');</script><!-- ENDIF -->
+<script src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
<!-- INCLUDEJS forum_fn.js -->
<!-- INCLUDEJS ajax.js -->
@@ -30,5 +34,7 @@
{$SCRIPTS}
+{% EVENT simple_footer_body_after %}
+
</body>
</html>
diff --git a/phpBB/styles/prosilver/template/simple_header.html b/phpBB/styles/prosilver/template/simple_header.html
index 3924aa29d9..905d25096f 100644
--- a/phpBB/styles/prosilver/template/simple_header.html
+++ b/phpBB/styles/prosilver/template/simple_header.html
@@ -11,7 +11,7 @@
<script>
WebFontConfig = {
google: {
- families: ['Open+Sans:600:cyrillic-ext,latin,greek-ext,greek,vietnamese,latin-ext,cyrillic']
+ families: ['Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese']
}
};
@@ -23,9 +23,9 @@
})(document);
</script>
<!-- ENDIF -->
+<link href="{T_FONT_AWESOME_LINK}" rel="stylesheet">
<link href="{T_STYLESHEET_LINK}" rel="stylesheet">
<link href="{T_STYLESHEET_LANG_LINK}" rel="stylesheet">
-<link href="{T_THEME_PATH}/responsive.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" media="all and (max-width: 700px)">
<!-- IF S_CONTENT_DIRECTION eq 'rtl' -->
<link href="{T_THEME_PATH}/bidi.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet">
@@ -49,6 +49,6 @@
<!-- EVENT simple_header_body_before -->
-<div id="wrap">
- <a id="top" class="anchor" accesskey="t"></a>
- <div id="page-body" role="main">
+<div id="wrap" class="wrap">
+ <a id="top" class="top-anchor" accesskey="t"></a>
+ <div id="page-body" class="page-body" role="main">
diff --git a/phpBB/styles/prosilver/template/timezone_option.html b/phpBB/styles/prosilver/template/timezone_option.html
index b8be456489..728dc9487a 100644
--- a/phpBB/styles/prosilver/template/timezone_option.html
+++ b/phpBB/styles/prosilver/template/timezone_option.html
@@ -12,7 +12,7 @@
</dd>
<!-- ENDIF -->
<dd>
- <select name="tz" id="timezone" class="autowidth tz_select">
+ <select name="tz" id="timezone" class="autowidth tz_select timezone">
<option value="">{L_SELECT_TIMEZONE}</option>
<!-- BEGIN timezone_select -->
<optgroup label="{timezone_select.LABEL}" data-tz-value="{timezone_select.VALUE}">
diff --git a/phpBB/styles/prosilver/template/ucp_agreement.html b/phpBB/styles/prosilver/template/ucp_agreement.html
index 943774c6ec..7959925d30 100644
--- a/phpBB/styles/prosilver/template/ucp_agreement.html
+++ b/phpBB/styles/prosilver/template/ucp_agreement.html
@@ -3,8 +3,7 @@
<!-- IF S_SHOW_COPPA or S_REGISTRATION -->
<!-- IF S_LANG_OPTIONS -->
-<script type="text/javascript">
-// <![CDATA[
+<script>
/**
* Change language
*/
@@ -14,8 +13,6 @@
document.forms['register'].change_lang.value = lang_iso;
document.forms['register'].submit();
}
-
-// ]]>
</script>
<form method="post" action="{S_UCP_ACTION}" id="register">
@@ -46,7 +43,8 @@
<div class="inner">
<fieldset class="submit-buttons">
<!-- IF S_SHOW_COPPA -->
- <strong><a href="{U_COPPA_NO}" class="button1">{L_COPPA_NO}</a></strong>&nbsp; <a href="{U_COPPA_YES}" class="button2">{L_COPPA_YES}</a>
+ <input type="submit" name="coppa_no" id="coppa_no" value="{{ L_COPPA_NO }}" class="button1" />
+ <input type="submit" name="coppa_yes" id="coppa_yes" value="{{ L_COPPA_YES }}" class="button2" />
<!-- ELSE -->
<input type="submit" name="agreed" id="agreed" value="{L_AGREE}" class="button1" />&nbsp;
<input type="submit" name="not_agreed" value="{L_NOT_AGREE}" class="button2" />
@@ -65,8 +63,6 @@
<div class="content">
<h2 class="sitename-title">{SITENAME} - {AGREEMENT_TITLE}</h2>
<p>{AGREEMENT_TEXT}</p>
- <hr class="dashed" />
- <p><a href="{U_BACK}" class="button2">{L_BACK}</a></p>
</div>
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/ucp_attachments.html b/phpBB/styles/prosilver/template/ucp_attachments.html
index 1d4963273c..cfdbf9c7ea 100644
--- a/phpBB/styles/prosilver/template/ucp_attachments.html
+++ b/phpBB/styles/prosilver/template/ucp_attachments.html
@@ -6,21 +6,21 @@
<div class="panel">
<div class="inner">
-
+
<p>{L_ATTACHMENTS_EXPLAIN}</p>
<!-- IF .attachrow -->
<div class="action-bar top">
<div class="pagination">
{NUM_ATTACHMENTS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
</div>
-
+
<ul class="topiclist">
<li class="header">
<dl>
@@ -44,27 +44,21 @@
</dt>
<dd class="extra">{attachrow.DOWNLOAD_COUNT}</dd>
<dd class="time"><span>{attachrow.POST_TIME}</span></dd>
- <dd class="mark"><input type="checkbox" name="attachment[{attachrow.ATTACH_ID}]" value="1" /></dd>
+ <dd class="mark"><input type="checkbox" name="attachment[{attachrow.ATTACH_ID}]" value="1"{% if attachrow.S_LOCKED %} disabled title="{{ lang('ATTACHMENT_LOCKED') }}"{% endif %} /></dd>
</dl>
</li>
<!-- END attachrow -->
</ul>
- <fieldset class="display-options">
- <label for="sk">{L_SORT_BY}{L_COLON} <select name="sk" id="sk">{S_SORT_OPTIONS}</select></label>
- <label><select name="sd" id="sd">{S_ORDER_SELECT}</select></label>
- <input class="button2" type="submit" name="sort" value="{L_SORT}" />
+ <div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
{S_FORM_TOKEN}
- </fieldset>
- <hr />
-
- <div class="action-bar bottom">
<div class="pagination">
{TOTAL_ATTACHMENTS} {L_TITLE}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -76,9 +70,9 @@
</div>
</div>
-
+
<!-- IF S_ATTACHMENT_ROWS -->
- <fieldset class="display-actions">
+ <fieldset class="display-actions">
<input class="button2" type="submit" name="delete" value="{L_DELETE_MARKED}" />
<div><a href="#" onclick="marklist('ucp', 'attachment', true); return false;">{L_MARK_ALL}</a> &bull; <a href="#" onclick="marklist('ucp', 'attachment', false); return false;">{L_UNMARK_ALL}</a></div>
{S_FORM_TOKEN}
diff --git a/phpBB/styles/prosilver/template/ucp_auth_link_oauth.html b/phpBB/styles/prosilver/template/ucp_auth_link_oauth.html
index 18316613b0..60061a3139 100644
--- a/phpBB/styles/prosilver/template/ucp_auth_link_oauth.html
+++ b/phpBB/styles/prosilver/template/ucp_auth_link_oauth.html
@@ -1,5 +1,5 @@
<!-- BEGIN oauth -->
- <form id="ucp" method="post" action="{S_UCP_ACTION}">
+ <form id="ucp_oauth_{oauth.SERVICE_ID}" method="post" action="{S_UCP_ACTION}">
<h3>{oauth.SERVICE_NAME}</h3>
<fieldset class="fields2">
diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options_local.html b/phpBB/styles/prosilver/template/ucp_avatar_options_local.html
index 80c7f28ca3..e431b7425e 100644
--- a/phpBB/styles/prosilver/template/ucp_avatar_options_local.html
+++ b/phpBB/styles/prosilver/template/ucp_avatar_options_local.html
@@ -6,7 +6,7 @@
</select></label>
<input type="submit" value="{L_GO}" name="avatar_local_go" class="button2" />
-<div id="gallery">
+<div id="gallery" class="gallery">
<!-- BEGIN avatar_local_row -->
<!-- BEGIN avatar_local_col -->
<label for="av-{avatar_local_row.S_ROW_COUNT}-{avatar_local_row.avatar_local_col.S_ROW_COUNT}"><img src="{avatar_local_row.avatar_local_col.AVATAR_IMAGE}" alt="" /><br />
diff --git a/phpBB/styles/prosilver/template/ucp_footer.html b/phpBB/styles/prosilver/template/ucp_footer.html
index f2f1a68db3..eb07f52e05 100644
--- a/phpBB/styles/prosilver/template/ucp_footer.html
+++ b/phpBB/styles/prosilver/template/ucp_footer.html
@@ -9,6 +9,4 @@
</form>
<!-- ENDIF -->
-<!-- INCLUDE jumpbox.html -->
-
<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/prosilver/template/ucp_groups_manage.html b/phpBB/styles/prosilver/template/ucp_groups_manage.html
index 3b805c4862..f2b4f003e0 100644
--- a/phpBB/styles/prosilver/template/ucp_groups_manage.html
+++ b/phpBB/styles/prosilver/template/ucp_groups_manage.html
@@ -33,9 +33,9 @@
<dl>
<dt><label for="group_type1">{L_GROUP_TYPE}{L_COLON}</label><br /><span>{L_GROUP_TYPE_EXPLAIN}</span></dt>
<dd>
- <label for="group_type1"><input type="radio" class="radio" name="group_type" id="group_type1" value="{GROUP_TYPE_FREE}"{GROUP_FREE} /> {L_GROUP_OPEN}</label>
- <label for="group_type2"><input type="radio" class="radio" name="group_type" id="group_type2" value="{GROUP_TYPE_OPEN}"{GROUP_OPEN} /> {L_GROUP_REQUEST}</label>
- <label for="group_type3"><input type="radio" class="radio" name="group_type" id="group_type3" value="{GROUP_TYPE_CLOSED}"{GROUP_CLOSED} /> {L_GROUP_CLOSED}</label>
+ <label for="group_type1"><input type="radio" class="radio" name="group_type" id="group_type1" value="{GROUP_TYPE_FREE}"{GROUP_FREE} /> {L_GROUP_OPEN}</label>
+ <label for="group_type2"><input type="radio" class="radio" name="group_type" id="group_type2" value="{GROUP_TYPE_OPEN}"{GROUP_OPEN} /> {L_GROUP_REQUEST}</label>
+ <label for="group_type3"><input type="radio" class="radio" name="group_type" id="group_type3" value="{GROUP_TYPE_CLOSED}"{GROUP_CLOSED} /> {L_GROUP_CLOSED}</label>
<label for="group_type4"><input type="radio" class="radio" name="group_type" id="group_type4" value="{GROUP_TYPE_HIDDEN}"{GROUP_HIDDEN} /> {L_GROUP_HIDDEN}</label>
</dd>
</dl>
@@ -58,7 +58,7 @@
<input name="group_colour" type="text" id="group_colour" value="{GROUP_COLOUR}" size="6" maxlength="6" class="inputbox narrow" />
<span style="background-color: #{GROUP_COLOUR};">&nbsp;&nbsp;&nbsp;</span>
[ <a href="#" id="color_palette_toggle">{L_COLOUR_SWATCH}</a> ]
- <div id="color_palette_placeholder" class="hidden" data-orientation="h" data-height="12" data-width="15" data-target="#group_colour"></div>
+ <div id="color_palette_placeholder" class="color_palette_placeholder hidden" data-orientation="h" data-height="12" data-width="15" data-target="#group_colour"></div>
</dd>
</dl>
<dl>
@@ -74,7 +74,7 @@
<fieldset class="submit-buttons">
{S_HIDDEN_FIELDS}
- <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="update" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
@@ -160,8 +160,8 @@
</table>
<!-- IF .pagination -->
- <div class="action-bar bottom">
- <div class="pagination">
+ <div class="action-bar bar-bottom">
+ <div class="pagination">
<!-- INCLUDE pagination.html -->
</div>
</div>
@@ -170,7 +170,7 @@
</div>
</div>
-<fieldset class="display-actions">
+<fieldset class="display-actions">
<select name="action"><option value="">{L_SELECT_OPTION}</option>{S_ACTION_OPTIONS}</select>
<input class="button2" type="submit" name="update" value="{L_SUBMIT}" />
<div><a href="#" onclick="marklist('ucp', 'mark', true); return false;">{L_MARK_ALL}</a> &bull; <a href="#" onclick="marklist('ucp', 'mark', false); return false;">{L_UNMARK_ALL}</a></div>
@@ -187,7 +187,7 @@
<dl>
<dt><label for="default0">{L_USER_GROUP_DEFAULT}{L_COLON}</label><br /><span>{L_USER_GROUP_DEFAULT_EXPLAIN}</span></dt>
<dd>
- <label for="default1"><input type="radio" name="default" id="default1" value="1" /> {L_YES}</label>
+ <label for="default1"><input type="radio" name="default" id="default1" value="1" /> {L_YES}</label>
<label for="default0"><input type="radio" name="default" id="default0" value="0" checked="checked" /> {L_NO}</label>
</dd>
</dl>
diff --git a/phpBB/styles/prosilver/template/ucp_groups_membership.html b/phpBB/styles/prosilver/template/ucp_groups_membership.html
index d7df3b02c2..e824a7b867 100644
--- a/phpBB/styles/prosilver/template/ucp_groups_membership.html
+++ b/phpBB/styles/prosilver/template/ucp_groups_membership.html
@@ -55,7 +55,7 @@
<!-- BEGIN member -->
<!-- IF not member.GROUP_SPECIAL -->
<!-- DEFINE $SHOW_BUTTONS = 1 -->
- <!-- ENDIF -->
+ <!-- ENDIF -->
<li class="row<!-- IF member.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
@@ -73,11 +73,11 @@
</ul>
<!-- ENDIF -->
</div>
-</div>
+</div>
<!-- IF .pending -->
<div class="panel">
- <div class="inner">
+ <div class="inner">
<ul class="topiclist two-columns">
<li class="header">
<dl>
@@ -91,7 +91,7 @@
<!-- BEGIN pending -->
<!-- IF not pending.GROUP_SPECIAL -->
<!-- DEFINE $SHOW_BUTTONS = 1 -->
- <!-- ENDIF -->
+ <!-- ENDIF -->
<li class="row<!-- IF pending.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
@@ -125,7 +125,7 @@
<!-- BEGIN nonmember -->
<!-- IF nonmember.S_CAN_JOIN -->
<!-- DEFINE $SHOW_BUTTONS = 1 -->
- <!-- ENDIF -->
+ <!-- ENDIF -->
<li class="row<!-- IF nonmember.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
@@ -143,7 +143,7 @@
</div>
</div>
<!-- ENDIF -->
-
+
<!-- IF S_CHANGE_DEFAULT or $SHOW_BUTTONS eq 1 -->
<fieldset>
@@ -156,7 +156,7 @@
<!-- IF $SHOW_BUTTONS eq 1 -->
<div class="right-box">
- <label for="action">{L_SELECT}{L_COLON}</label>
+ <label for="action">{L_SELECT}{L_COLON}</label>
<select name="action" id="action">
<option value="join">{L_JOIN_SELECTED}</option>
<option value="resign">{L_RESIGN_SELECTED}</option>
diff --git a/phpBB/styles/prosilver/template/ucp_header.html b/phpBB/styles/prosilver/template/ucp_header.html
index a17f145cbc..98d2eee1a0 100644
--- a/phpBB/styles/prosilver/template/ucp_header.html
+++ b/phpBB/styles/prosilver/template/ucp_header.html
@@ -2,7 +2,7 @@
<h2 class="ucp-title">{L_UCP}</h2>
-<div id="tabs">
+<div id="tabs" class="tabs">
<ul>
<!-- BEGIN t_block1 -->
<li class="tab<!-- IF t_block1.S_SELECTED --> activetab<!-- ENDIF -->"><a href="{t_block1.U_TITLE}">{t_block1.L_TITLE}</a></li>
@@ -19,15 +19,15 @@
<div style="width: 100%;">
- <div id="cp-menu">
- <div id="navigation" role="navigation">
+ <div id="cp-menu" class="cp-menu">
+ <div id="navigation" class="navigation" role="navigation">
<!-- IF S_PRIVMSGS -->
<!-- BEGIN t_block2 -->
<!-- IF S_PRIVMSGS and not t_block2.S_LAST_ROW -->
<ul>
<!-- IF t_block2.S_SELECTED -->
- <li id="active-subsection"><a href="{t_block2.U_TITLE}"><span>{t_block2.L_TITLE}</span></a></li>
+ <li id="active-subsection" class="active-subsection"><a href="{t_block2.U_TITLE}"><span>{t_block2.L_TITLE}</span></a></li>
<!-- ELSE -->
<li><a href="{t_block2.U_TITLE}"><span>{t_block2.L_TITLE}</span></a></li>
<!-- ENDIF -->
@@ -39,7 +39,7 @@
<!-- BEGIN folder -->
<!-- IF folder.S_FIRST_ROW --><ul><!-- ENDIF -->
<!-- IF folder.S_CUR_FOLDER -->
- <li id="active-subsection"><a href="{folder.U_FOLDER}"><!-- IF folder.UNREAD_MESSAGES > 0 --><strong>{folder.FOLDER_NAME} ({folder.UNREAD_MESSAGES})</strong><!-- ELSE -->{folder.FOLDER_NAME}<!-- ENDIF --></a></li>
+ <li id="active-subsection" class="active-subsection"><a href="{folder.U_FOLDER}"><!-- IF folder.UNREAD_MESSAGES > 0 --><strong>{folder.FOLDER_NAME} ({folder.UNREAD_MESSAGES})</strong><!-- ELSE -->{folder.FOLDER_NAME}<!-- ENDIF --></a></li>
<!-- ELSE -->
<li><a href="{folder.U_FOLDER}"><span><!-- IF folder.UNREAD_MESSAGES > 0 --><strong>{folder.FOLDER_NAME} ({folder.UNREAD_MESSAGES})</strong><!-- ELSE -->{folder.FOLDER_NAME}<!-- ENDIF --></span></a></li>
<!-- ENDIF -->
@@ -52,7 +52,7 @@
<!-- BEGIN t_block2 -->
<!-- IF (S_PRIVMSGS and t_block2.S_LAST_ROW) or not S_PRIVMSGS -->
<!-- IF t_block2.S_SELECTED -->
- <li id="active-subsection"><a href="{t_block2.U_TITLE}"><span>{t_block2.L_TITLE}</span></a></li>
+ <li id="active-subsection" class="active-subsection"><a href="{t_block2.U_TITLE}"><span>{t_block2.L_TITLE}</span></a></li>
<!-- ELSE -->
<li><a href="{t_block2.U_TITLE}"><span>{t_block2.L_TITLE}</span></a></li>
<!-- ENDIF -->
@@ -98,4 +98,4 @@
</div>
- <div id="cp-main" class="ucp-main panel-container">
+ <div id="cp-main" class="cp-main ucp-main panel-container">
diff --git a/phpBB/styles/prosilver/template/ucp_main_bookmarks.html b/phpBB/styles/prosilver/template/ucp_main_bookmarks.html
index f74728bdb3..25647afe1a 100644
--- a/phpBB/styles/prosilver/template/ucp_main_bookmarks.html
+++ b/phpBB/styles/prosilver/template/ucp_main_bookmarks.html
@@ -16,7 +16,7 @@
<!-- IF .topicrow -->
<ul class="topiclist missing-column">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt><div class="list-inner">{L_BOOKMARKS}</div></dt>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
<dd class="mark">{L_MARK}</dd>
@@ -34,13 +34,26 @@
<dd class="mark"><input type="checkbox" name="t[{topicrow.TOPIC_ID}]" id="t{topicrow.TOPIC_ID}" /></dd>
</dl>
<!-- ELSE -->
- <dl class="icon {topicrow.TOPIC_IMG_STYLE}">
+ <dl class="row-item {topicrow.TOPIC_IMG_STYLE}">
<dt<!-- IF topicrow.TOPIC_ICON_IMG --> style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}">
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="icon-link"></a><!-- ENDIF -->
+ <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF topicrow.S_UNREAD_TOPIC -->
+ <a class="unread" href="{topicrow.U_NEWEST_POST}">
+ <i class="icon fa-file fa-fw icon-red icon-md" aria-hidden="true"></i><span class="sr-only">{NEW_POST}</span>
+ </a>
+ <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
+ <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED -->
+ <a href="{topicrow.U_MCP_QUEUE}" title="{L_TOPIC_UNAPPROVED}">
+ <i class="icon fa-question fa-fw icon-blue" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_UNAPPROVED}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_REPORTED -->
+ <a href="{topicrow.U_MCP_REPORT}" title="{L_TOPIC_REPORTED}">
+ <i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_REPORTED}</span>
+ </a>
+ <!-- ENDIF -->
+ <br />
<!-- IF .topicrow.pagination -->
<div class="pagination">
<ul>
@@ -56,18 +69,21 @@
</div>
<!-- ENDIF -->
<div class="responsive-hide">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</div>
<div class="responsive-show" style="display: none;">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL} &laquo;
<a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{topicrow.LAST_POST_TIME}</a>
</div>
</div>
</dt>
<dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
- <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{LAST_POST_IMG}</a> <br />{topicrow.LAST_POST_TIME}</span>
+ <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">
+ <i class="icon fa-external-link-square fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{VIEW_LATEST_POST}</span>
+ </a>
+ <br />{topicrow.LAST_POST_TIME}</span>
</dd>
<dd class="mark"><input type="checkbox" name="t[{topicrow.TOPIC_ID}]" id="t{topicrow.TOPIC_ID}" /></dd>
</dl>
@@ -76,12 +92,12 @@
<!-- END topicrow -->
</ul>
- <div class="action-bar bottom">
+ <div class="action-bar bar-bottom">
<div class="pagination">
{TOTAL_TOPICS}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/ucp_main_front.html b/phpBB/styles/prosilver/template/ucp_main_front.html
index 056ea300d8..04b568f623 100644
--- a/phpBB/styles/prosilver/template/ucp_main_front.html
+++ b/phpBB/styles/prosilver/template/ucp_main_front.html
@@ -13,11 +13,16 @@
<ul class="topiclist cplist two-long-columns">
<!-- BEGIN topicrow -->
<li class="row<!-- IF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
- <dl class="icon {topicrow.TOPIC_IMG_STYLE}">
+ <dl class="row-item {topicrow.TOPIC_IMG_STYLE}">
<dt <!-- IF topicrow.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->>
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="icon-link"></a><!-- ENDIF -->
+ <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
- <!-- IF topicrow.S_UNREAD --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a><br />
+ <!-- IF topicrow.S_UNREAD -->
+ <a class="unread" href="{topicrow.U_NEWEST_POST}">
+ <i class="icon fa-file fa-fw icon-red icon-md" aria-hidden="true"></i><span class="sr-only">{NEW_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ <a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a><br />
<!-- IF .topicrow.pagination -->
<div class="pagination">
<ul>
@@ -33,17 +38,22 @@
</div>
<!-- ENDIF -->
<div class="responsive-hide">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</div>
<div class="responsive-show" style="display: none;">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL} &laquo; <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{topicrow.LAST_POST_TIME}</a>
</div>
</div>
</dt>
- <dd class="lastpost"><span>{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
- <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{LAST_POST_IMG}</a> <br />{topicrow.LAST_POST_TIME}</span>
+ <dd class="lastpost">
+ <span>{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
+ <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">
+ <i class="icon fa-external-link-square fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{VIEW_LATEST_POST}</span>
+ </a>
+ <br />{topicrow.LAST_POST_TIME}
+ </span>
</dd>
</dl>
</li>
@@ -61,7 +71,7 @@
<dt>{L_TOTAL_POSTS}{L_COLON}</dt> <dd><!-- IF POSTS_PCT -->{POSTS}<!-- IF S_DISPLAY_SEARCH --> | <strong><a href="{U_SEARCH_USER}">{L_SEARCH_YOUR_POSTS}</a></strong><!-- ENDIF --><br />({POSTS_DAY} / {POSTS_PCT})<!-- ELSE -->{POSTS}<!-- ENDIF --></dd>
<!-- IF ACTIVE_FORUM != '' --><dt>{L_ACTIVE_IN_FORUM}{L_COLON}</dt> <dd><strong><a href="{U_ACTIVE_FORUM}">{ACTIVE_FORUM}</a></strong><br />({ACTIVE_FORUM_POSTS} / {ACTIVE_FORUM_PCT})</dd><!-- ENDIF -->
<!-- IF ACTIVE_TOPIC != '' --><dt>{L_ACTIVE_IN_TOPIC}{L_COLON}</dt> <dd><strong><a href="{U_ACTIVE_TOPIC}">{ACTIVE_TOPIC}</a></strong><br />({ACTIVE_TOPIC_POSTS} / {ACTIVE_TOPIC_PCT})</dd><!-- ENDIF -->
- <!-- IF WARNINGS --><dt>{L_YOUR_WARNINGS}{L_COLON}</dt> <dd class="error">{WARNING_IMG} [{WARNINGS}]</dd><!-- ENDIF -->
+ <!-- IF WARNINGS --><dt>{L_YOUR_WARNINGS}{L_COLON}</dt> <dd class="error"><i class="icon fa-exclamation-triangle fa-fw icon-red" aria-hidden="true"></i> [{WARNINGS}]</dd><!-- ENDIF -->
<!-- EVENT ucp_main_front_user_activity_append -->
</dl>
<!-- EVENT ucp_main_front_user_activity_after -->
diff --git a/phpBB/styles/prosilver/template/ucp_main_subscribed.html b/phpBB/styles/prosilver/template/ucp_main_subscribed.html
index 2d65b800a0..d8de7fd093 100644
--- a/phpBB/styles/prosilver/template/ucp_main_subscribed.html
+++ b/phpBB/styles/prosilver/template/ucp_main_subscribed.html
@@ -11,7 +11,7 @@
<!-- IF .forumrow -->
<ul class="topiclist missing-column">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt><div class="list-inner">{L_WATCHED_FORUMS}</div></dt>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
<dd class="mark">{L_MARK}</dd>
@@ -22,9 +22,9 @@
<!-- BEGIN forumrow -->
<li class="row<!-- IF forumrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
- <dl class="icon {forumrow.FORUM_IMG_STYLE}">
+ <dl class="row-item {forumrow.FORUM_IMG_STYLE}">
<dt>
- <!-- IF forumrow.S_UNREAD_FORUM --><a href="{forumrow.U_VIEWFORUM}" class="icon-link"></a><!-- ENDIF -->
+ <!-- IF forumrow.S_UNREAD_FORUM --><a href="{forumrow.U_VIEWFORUM}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
<a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a><br />
{forumrow.FORUM_DESC}
@@ -35,9 +35,16 @@
<!-- ENDIF -->
</div>
</dt>
- <dd class="lastpost"><!-- IF forumrow.LAST_POST_TIME --><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {forumrow.LAST_POST_AUTHOR_FULL}
- <a href="{forumrow.U_LAST_POST}">{LAST_POST_IMG}</a> <br />{forumrow.LAST_POST_TIME}</span>
- <!-- ELSE -->{L_NO_POSTS}<br />&nbsp;<!-- ENDIF -->
+ <dd class="lastpost">
+ <!-- IF forumrow.LAST_POST_TIME -->
+ <span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {forumrow.LAST_POST_AUTHOR_FULL}
+ <a href="{forumrow.U_LAST_POST}">
+ <i class="icon fa-external-link-square fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{VIEW_LATEST_POST}</span>
+ </a>
+ <br />{forumrow.LAST_POST_TIME}</span>
+ <!-- ELSE -->
+ {L_NO_POSTS}<br />&nbsp;
+ <!-- ENDIF -->
</dd>
<dd class="mark"><input type="checkbox" name="f[{forumrow.FORUM_ID}]" id="f{forumrow.FORUM_ID}" /></dd>
</dl>
@@ -47,7 +54,7 @@
<!-- ELSEIF S_FORUM_NOTIFY -->
<ul class="topiclist">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt>{L_WATCHED_FORUMS}</dt>
</dl>
</li>
@@ -59,7 +66,7 @@
<!-- IF .topicrow -->
<ul class="topiclist missing-column">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt><div class="list-inner">{L_WATCHED_TOPICS}</div></dt>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
<dd class="mark">{L_MARK}</dd>
@@ -70,13 +77,26 @@
<!-- BEGIN topicrow -->
<li class="row<!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ELSEIF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
- <dl class="icon {topicrow.TOPIC_IMG_STYLE}">
+ <dl class="row-item {topicrow.TOPIC_IMG_STYLE}">
<dt<!-- IF topicrow.TOPIC_ICON_IMG --> style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}">
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="icon-link"></a><!-- ENDIF -->
+ <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF topicrow.S_UNREAD_TOPIC -->
+ <a class="unread" href="{topicrow.U_NEWEST_POST}">
+ <i class="icon fa-file fa-fw icon-red icon-md" aria-hidden="true"></i><span class="sr-only">{NEW_POST}</span>
+ </a>
+ <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
+ <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED -->
+ <a href="{topicrow.U_MCP_QUEUE}" title="{L_TOPIC_UNAPPROVED}">
+ <i class="icon fa-question fa-fw icon-blue" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_UNAPPROVED}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_REPORTED -->
+ <a href="{topicrow.U_MCP_REPORT}" title="{L_TOPIC_REPORTED}">
+ <i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_REPORTED}</span>
+ </a>
+ <!-- ENDIF -->
+ <br />
<!-- IF .topicrow.pagination -->
<div class="pagination">
<ul>
@@ -92,17 +112,20 @@
</div>
<!-- ENDIF -->
<div class="responsive-hide">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</div>
<div class="responsive-show" style="display: none;">
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF -->
{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL} &laquo; <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{topicrow.LAST_POST_TIME}</a>
</div>
</div>
</dt>
<dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
- <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{LAST_POST_IMG}</a> <br />{topicrow.LAST_POST_TIME}</span>
+ <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">
+ <i class="icon fa-external-link-square fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{VIEW_LATEST_POST}</span>
+ </a>
+ <br />{topicrow.LAST_POST_TIME}</span>
</dd>
<dd class="mark"><input type="checkbox" name="t[{topicrow.TOPIC_ID}]" id="t{topicrow.TOPIC_ID}" /></dd>
</dl>
@@ -110,7 +133,7 @@
<!-- END topicrow -->
</ul>
- <div class="action-bar bottom">
+ <div class="action-bar bar-bottom">
<div class="pagination">
{TOTAL_TOPICS}
<!-- IF .pagination -->
@@ -124,7 +147,7 @@
<!-- ELSEIF S_TOPIC_NOTIFY -->
<ul class="topiclist">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt>{L_WATCHED_TOPICS}</dt>
</dl>
</li>
diff --git a/phpBB/styles/prosilver/template/ucp_notifications.html b/phpBB/styles/prosilver/template/ucp_notifications.html
index 500bae0c47..55e30477d2 100644
--- a/phpBB/styles/prosilver/template/ucp_notifications.html
+++ b/phpBB/styles/prosilver/template/ucp_notifications.html
@@ -16,7 +16,6 @@
<!-- BEGIN notification_methods -->
<th class="mark">{notification_methods.NAME}</th>
<!-- END notification_methods -->
- <th class="mark">{L_NOTIFICATIONS}</th>
</tr>
</thead>
<tbody>
@@ -32,9 +31,8 @@
<!-- IF notification_types.EXPLAIN --><br />&nbsp; &nbsp;{notification_types.EXPLAIN}<!-- ENDIF -->
</td>
<!-- BEGIN notification_methods -->
- <td class="mark"><input type="checkbox" name="{notification_types.TYPE}_{notification_methods.METHOD}"<!-- IF notification_methods.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
+ <td class="mark"><input type="checkbox" name="{notification_types.TYPE}_{notification_types.notification_methods.METHOD}"<!-- IF notification_types.notification_methods.AVAILABLE and notification_types.notification_methods.SUBSCRIBED --> checked="checked"<!-- ENDIF --><!-- IF not notification_types.notification_methods.AVAILABLE --> disabled="disabled"<!-- ENDIF --> /></td>
<!-- END notification_methods -->
- <td class="mark"><input type="checkbox" name="{notification_types.TYPE}_notification"<!-- IF notification_types.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
</tr>
<!-- ENDIF -->
<!-- END notification_types -->
@@ -42,7 +40,7 @@
</table>
<!-- ELSE -->
<!-- IF .notification_list -->
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<div class="pagination">
<!-- IF U_MARK_ALL --><a href="{U_MARK_ALL}" class="mark">{L_NOTIFICATIONS_MARK_ALL_READ}</a> &bull; <!-- ENDIF -->
{L_NOTIFICATIONS} [<strong>{TOTAL_COUNT}</strong>]
@@ -68,12 +66,12 @@
<li class="row<!-- IF notification_list.UNREAD --> bg3<!-- ELSE --><!-- IF notification_list.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- ENDIF --><!-- IF notification_list.STYLING --> {notification_list.STYLING}<!-- ENDIF -->">
<dl>
<dt>
- <div class="list-inner">
+ <div class="list-inner">
<!-- IF notification_list.AVATAR -->{notification_list.AVATAR}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF -->
<div class="notifications">
<!-- IF notification_list.URL --><a href="<!-- IF notification_list.UNREAD -->{notification_list.U_MARK_READ}<!-- ELSE -->{notification_list.URL}<!-- ENDIF -->"><!-- ENDIF -->
<p class="notifications_title">{notification_list.FORMATTED_TITLE}<!-- IF notification_list.REFERENCE --> {notification_list.REFERENCE}<!-- ENDIF --></p>
- <!-- IF notification_list.URL --></a><!-- ENDIF -->
+ <!-- IF notification_list.URL --></a><!-- ENDIF -->
<!-- IF notification_list.FORUM --><p class="notifications_forum">{notification_list.FORUM}</p><!-- ENDIF -->
<!-- IF notification_list.REASON --><p class="notifications_reason">{notification_list.REASON}</p><!-- ENDIF -->
<p class="notifications_time">{notification_list.TIME}</p>
@@ -88,7 +86,7 @@
</ul>
</div>
- <div class="action-bar bottom">
+ <div class="action-bar bar-bottom">
<div class="pagination">
{L_NOTIFICATIONS} [<strong>{TOTAL_COUNT}</strong>]
<!-- IF .pagination -->
diff --git a/phpBB/styles/prosilver/template/ucp_pm_history.html b/phpBB/styles/prosilver/template/ucp_pm_history.html
index 28f217ef66..b53eb0c7ec 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_history.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_history.html
@@ -1,15 +1,13 @@
-<h3 id="review">
+<h3 id="review" class="review">
<span class="right-box"><a href="#review" onclick="viewableArea(getElementById('topicreview'), true); var rev_text = getElementById('review').getElementsByTagName('a').item(0).firstChild; if (rev_text.data == '{LA_EXPAND_VIEW}'){rev_text.data = '{LA_COLLAPSE_VIEW}'; } else if (rev_text.data == '{LA_COLLAPSE_VIEW}'){rev_text.data = '{LA_EXPAND_VIEW}'};">{L_EXPAND_VIEW}</a></span>
{L_MESSAGE_HISTORY}{L_COLON}
</h3>
<!-- EVENT ucp_pm_history_review_before -->
-<div id="topicreview">
- <script type="text/javascript">
- // <![CDATA[
+<div id="topicreview" class="topicreview">
+ <script>
bbcodeEnabled = {S_BBCODE_ALLOWED};
- // ]]>
</script>
<!-- BEGIN history_row -->
<div class="post <!-- IF history_row.S_ROW_COUNT is even -->bg1<!-- ELSE -->bg2<!-- ENDIF -->">
@@ -25,8 +23,8 @@
<!-- EVENT ucp_pm_history_post_buttons_before -->
<!-- IF history_row.U_QUOTE or history_row.MESSAGE_AUTHOR_QUOTE -->
<li>
- <a <!-- IF history_row.U_QUOTE -->href="{history_row.U_QUOTE}"<!-- ELSE -->href="#postingbox" onclick="addquote({history_row.MSG_ID}, '{history_row.MESSAGE_AUTHOR_QUOTE}', '{LA_WROTE}');"<!-- ENDIF --> title="{L_QUOTE} {history_row.MESSAGE_AUTHOR}" class="button icon-button quote-icon">
- <span>{L_QUOTE} {history_row.MESSAGE_AUTHOR}</span>
+ <a <!-- IF history_row.U_QUOTE -->href="{history_row.U_QUOTE}"<!-- ELSE -->href="#postingbox" onclick="addquote({history_row.MSG_ID}, '{history_row.MESSAGE_AUTHOR_QUOTE}', '{LA_WROTE}', {time:{history_row.MESSAGE_TIME},user_id:{history_row.USER_ID}});"<!-- ENDIF --> title="{L_QUOTE} {history_row.MESSAGE_AUTHOR}" class="button button-icon-only">
+ <i class="icon fa-quote-left fa-fw" aria-hidden="true"></i><span class="sr-only">{L_QUOTE} {history_row.MESSAGE_AUTHOR}</span>
</a>
</li>
<!-- ENDIF -->
@@ -35,8 +33,11 @@
<!-- ENDIF -->
<!-- EVENT ucp_pm_history_post_buttons_list_after -->
- <p class="author">{history_row.MINI_POST_IMG} {L_SENT_AT}{L_COLON} <strong>{history_row.SENT_DATE}</strong><br />
- {L_MESSAGE_BY_AUTHOR} {history_row.MESSAGE_AUTHOR_FULL}</p>
+ <p class="author">
+ <span><i class="icon fa-file fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{history_row.MINI_POST}</span></span> {L_SENT_AT}{L_COLON} <strong>{history_row.SENT_DATE}</strong>
+ <br />
+ {L_MESSAGE_BY_AUTHOR} <!-- EVENT ucp_pm_history_row_message_author_username_prepend -->{history_row.MESSAGE_AUTHOR_FULL}<!-- EVENT ucp_pm_history_row_message_author_username_append -->
+ </p>
<div class="content"><!-- IF history_row.MESSAGE -->{history_row.MESSAGE}<!-- ELSE --><span class="error">{L_MESSAGE_REMOVED_FROM_OUTBOX}</span><!-- ENDIF --></div>
<div id="message_{history_row.MSG_ID}" style="display: none;">{history_row.DECODED_MESSAGE}</div>
</div>
@@ -48,4 +49,8 @@
<!-- EVENT ucp_pm_history_review_after -->
<hr />
-<p><a href="#cp-main" class="top2">{L_BACK_TO_TOP}</a></p>
+<p>
+ <a href="#cp-main" class="top">
+ <i class="icon fa-chevron-circle-up fa-fw icon-gray" aria-hidden="true"></i><span>{L_BACK_TO_TOP}</span>
+ </a>
+</p>
diff --git a/phpBB/styles/prosilver/template/ucp_pm_message_header.html b/phpBB/styles/prosilver/template/ucp_pm_message_header.html
index 7be51e0034..6ad9e9cab6 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_message_header.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_message_header.html
@@ -6,38 +6,45 @@
<div class="inner">
<!-- IF FOLDER_STATUS and FOLDER_MAX_MESSAGES neq 0 --><p>{FOLDER_STATUS}</p><!-- ENDIF -->
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<!-- IF U_POST_REPLY_PM or U_POST_NEW_TOPIC or U_FORWARD_PM -->
- <div class="buttons">
- <!-- IF U_POST_REPLY_PM -->
- <a title="{L_POST_REPLY_PM}" href="{U_POST_REPLY_PM}" class="button icon-button pmreply-icon">
- {L_BUTTON_PM_REPLY}
- </a>
- <!-- ELSEIF U_POST_NEW_TOPIC -->
- <a href="{U_POST_NEW_TOPIC}" accesskey="n" title="{L_UCP_PM_COMPOSE}" class="button icon-button newpm-icon">
- {L_BUTTON_PM_NEW}
- </a>
- <!-- ENDIF -->
- <!-- IF U_FORWARD_PM -->
- <a title="{L_POST_FORWARD_PM}" href="{U_FORWARD_PM}" class="button icon-button forwardpm-icon">
- {L_BUTTON_PM_FORWARD}
- </a>
- <!-- ENDIF -->
- <!-- IF U_POST_REPLY_PM and S_PM_RECIPIENTS gt 1 -->
- <a title="{L_REPLY_TO_ALL}" href="{U_POST_REPLY_ALL}" class="button icon-button reply-all">
- {L_BUTTON_PM_REPLY_ALL}
- </a>
- <!-- ENDIF -->
- </div>
+ <!-- IF U_POST_REPLY_PM -->
+ <a title="{L_POST_REPLY_PM}" href="{U_POST_REPLY_PM}" class="button">
+ <span>{L_BUTTON_PM_REPLY}</span> <i class="icon fa-reply fa-fw" aria-hidden="true"></i>
+ </a>
+ <!-- ELSEIF U_POST_NEW_TOPIC -->
+ <a href="{U_POST_NEW_TOPIC}" accesskey="n" title="{L_UCP_PM_COMPOSE}" class="button">
+ <span>{L_BUTTON_PM_NEW}</span> <i class="icon fa-pencil fa-fw" aria-hidden="true"></i>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF U_FORWARD_PM -->
+ <a title="{L_POST_FORWARD_PM}" href="{U_FORWARD_PM}" class="button">
+ <span>{L_BUTTON_PM_FORWARD}</span> <i class="icon fa-mail-forward fa-fw" aria-hidden="true"></i>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF U_POST_REPLY_PM and S_PM_RECIPIENTS gt 1 -->
+ <a title="{L_REPLY_TO_ALL}" href="{U_POST_REPLY_ALL}" class="button">
+ <span>{L_BUTTON_PM_REPLY_ALL}</span> <i class="icon fa-pencil fa-fw" aria-hidden="true"></i>
+ </a>
+ <!-- ENDIF -->
<!-- ENDIF -->
<!-- IF not S_IS_BOT and U_PRINT_PM -->
<div class="dropdown-container dropdown-button-control topic-tools">
- <span title="{L_PM_TOOLS}" class="dropdown-trigger dropdown-select button icon-button tools-icon"></span>
- <div class="dropdown hidden">
+ <span title="{L_PM_TOOLS}" class="button button-secondary dropdown-trigger dropdown-select">
+ <i class="icon fa-wrench fa-fw" aria-hidden="true"></i>
+ <span class="caret"><i class="icon fa-sort-down fa-fw" aria-hidden="true"></i></span>
+ </span>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<ul class="dropdown-contents">
- <!-- IF U_PRINT_PM --><li class="small-icon icon-print"><a href="{U_PRINT_PM}" title="{L_PRINT_PM}" accesskey="p">{L_PRINT_PM}</a></li><!-- ENDIF -->
+ <!-- IF U_PRINT_PM -->
+ <li>
+ <a href="{U_PRINT_PM}" title="{L_PRINT_PM}" accesskey="p">
+ <i class="icon fa-print fa-fw" aria-hidden="true"></i><span>{L_PRINT_PM}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
</ul>
</div>
</div>
@@ -46,7 +53,9 @@
<!-- IF TOTAL_MESSAGES or S_VIEW_MESSAGE -->
<div class="pagination">
<!-- IF S_VIEW_MESSAGE -->
- <a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_CURRENT_FOLDER}">{L_RETURN_TO_FOLDER}</a>
+ <a class="arrow-{S_CONTENT_FLOW_BEGIN}" href="{U_CURRENT_FOLDER}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_RETURN_TO_FOLDER}</span>
+ </a>
<!-- ELSEIF FOLDER_CUR_MESSAGES neq 0 -->
<!-- IF U_MARK_ALL --><a href="{U_MARK_ALL}" class="mark">{L_PM_MARK_ALL_READ}</a> &bull; <!-- ENDIF -->
{TOTAL_MESSAGES}
diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html
index 47e4d1c63a..a290313df7 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html
@@ -57,9 +57,9 @@
<!-- BEGIN messagerow -->
<li class="row<!-- IF messagerow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF messagerow.PM_CLASS --> {messagerow.PM_CLASS}<!-- ENDIF -->">
- <dl class="icon {messagerow.FOLDER_IMG_STYLE}">
+ <dl class="row-item {messagerow.FOLDER_IMG_STYLE}">
<dt<!-- IF messagerow.PM_ICON_URL and S_PM_ICONS --> style="background-image: url({messagerow.PM_ICON_URL}); background-repeat: no-repeat;"<!-- ENDIF -->>
- <!-- IF messagerow.S_PM_UNREAD and not messagerow.S_PM_DELETED --><a href="{messagerow.U_VIEW_PM}" class="icon-link"></a><!-- ENDIF -->
+ <!-- IF messagerow.S_PM_UNREAD and not messagerow.S_PM_DELETED --><a href="{messagerow.U_VIEW_PM}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
<!-- IF messagerow.S_PM_DELETED -->
@@ -71,8 +71,11 @@
<!-- IF messagerow.S_AUTHOR_DELETED -->
<br /><em class="small">{L_PM_FROM_REMOVED_AUTHOR}</em>
<!-- ENDIF -->
-
- <!-- IF messagerow.S_PM_REPORTED --><a href="{messagerow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --> {messagerow.ATTACH_ICON_IMG}<br />
+ <!-- IF messagerow.S_PM_REPORTED -->
+ <a href="{messagerow.U_MCP_REPORT}">
+ <i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><span class="sr-only">{PM_REPORTED}</span>
+ </a>
+ <!-- ENDIF --> <!-- IF messagerow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i> <!-- ENDIF --><br />
<!-- IF S_SHOW_RECIPIENTS -->{L_MESSAGE_TO} {messagerow.RECIPIENTS}<!-- ELSE -->{L_MESSAGE_BY_AUTHOR} {messagerow.MESSAGE_AUTHOR_FULL} &raquo; {messagerow.SENT_TIME}<!-- ENDIF -->
</div>
@@ -101,15 +104,18 @@
<select name="mark_option">{S_MARK_OPTIONS}{S_MOVE_MARKED_OPTIONS}</select> <input class="button2" type="submit" name="submit_mark" value="{L_GO}" />
<div><a href="#" onclick="marklist('viewfolder', 'marked_msg', true); return false;">{L_MARK_ALL}</a> &bull; <a href="#" onclick="marklist('viewfolder', 'marked_msg', false); return false;">{L_UNMARK_ALL}</a></div>
</fieldset>
-
+
<hr />
-
+
<div class="action-bar bottom">
+ <!-- INCLUDE display_options.html -->
+ <input type="hidden" name="cur_folder_id" value="{CUR_FOLDER_ID}" />
+
<div class="pagination">
{TOTAL_MESSAGES}
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
&bull; {PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -119,16 +125,6 @@
</div>
</div>
- <!-- IF FOLDER_CUR_MESSAGES neq 0 -->
- <fieldset class="display-options">
- <label>{L_DISPLAY}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label>
- <label>{S_SELECT_SORT_DIR}</label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- <input type="hidden" name="cur_folder_id" value="{CUR_FOLDER_ID}" />
- </fieldset>
- <!-- ENDIF -->
-
<!-- INCLUDE ucp_pm_message_footer.html -->
<!-- ENDIF -->
<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
index 009a9bf975..7cb44a0189 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
@@ -8,8 +8,16 @@
<!-- IF S_DISPLAY_HISTORY and (U_VIEW_PREVIOUS_HISTORY or U_VIEW_NEXT_HISTORY) -->
<fieldset class="display-options clearfix">
- <!-- IF U_VIEW_PREVIOUS_HISTORY --><a href="{U_VIEW_PREVIOUS_HISTORY}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}">{L_VIEW_PREVIOUS_HISTORY}</a><!-- ENDIF -->
- <!-- IF U_VIEW_NEXT_HISTORY --><a href="{U_VIEW_NEXT_HISTORY}" class="right-box arrow-{S_CONTENT_FLOW_END}">{L_VIEW_NEXT_HISTORY}</a><!-- ENDIF -->
+ <!-- IF U_VIEW_PREVIOUS_HISTORY -->
+ <a href="{U_VIEW_PREVIOUS_HISTORY}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_PREVIOUS_HISTORY}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF U_VIEW_NEXT_HISTORY -->
+ <a href="{U_VIEW_NEXT_HISTORY}" class="right-box arrow-{S_CONTENT_FLOW_END}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_END} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_NEXT_HISTORY}</span>
+ </a>
+ <!-- ENDIF -->
</fieldset>
<!-- ENDIF -->
@@ -47,8 +55,8 @@
<dd class="profile-contact">
<strong>{L_CONTACT}{L_COLON}</strong>
<div class="dropdown-container dropdown-left">
- <a href="#" class="dropdown-trigger"><span class="imageset icon_contact" title="{CONTACT_USER}">{CONTACT_USER}</span></a>
- <div class="dropdown hidden">
+ <a href="#" class="dropdown-trigger" title="{CONTACT_USER}"><i class="icon fa-commenting-o fa-fw icon-lg" aria-hidden="true"></i><span class="sr-only">{CONTACT_USER}</span></a>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<div class="dropdown-contents contact-icons">
<!-- BEGIN contact -->
@@ -82,22 +90,30 @@
<!-- EVENT ucp_pm_viewmessage_post_buttons_before -->
<!-- IF U_EDIT -->
<li>
- <a href="{U_EDIT}" title="{L_POST_EDIT_PM}" class="button icon-button edit-icon"><span>{L_POST_EDIT_PM}</span></a>
+ <a href="{U_EDIT}" title="{L_POST_EDIT_PM}" class="button button-icon-only">
+ <i class="icon fa-pencil fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_EDIT}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF U_DELETE -->
<li>
- <a href="{U_DELETE}" title="{L_DELETE_MESSAGE}" class="button icon-button delete-icon"><span>{L_DELETE_MESSAGE}</span></a>
+ <a href="{U_DELETE}" title="{L_DELETE_MESSAGE}" class="button button-icon-only">
+ <i class="icon fa-times fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_DELETE}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF U_REPORT -->
<li>
- <a href="{U_REPORT}" title="{L_REPORT_PM}" class="button icon-button report-icon"><span>{L_REPORT_PM}</span></a>
+ <a href="{U_REPORT}" title="{L_REPORT_PM}" class="button button-icon-only">
+ <i class="icon fa-exclamation fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_REPORT}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF U_QUOTE -->
<li>
- <a href="{U_QUOTE}" title="{L_POST_QUOTE_PM}" class="button icon-button quote-icon"><span>{L_POST_QUOTE_PM}</span></a>
+ <a href="{U_QUOTE}" title="{L_POST_QUOTE_PM}" class="button button-icon-only">
+ <i class="icon fa-quote-left fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_QUOTE}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- EVENT ucp_pm_viewmessage_post_buttons_after -->
@@ -108,8 +124,8 @@
<p class="author">
<strong>{L_SENT_AT}{L_COLON}</strong> {SENT_DATE}
<br /><strong>{L_PM_FROM}{L_COLON}</strong> {MESSAGE_AUTHOR_FULL}
- <!-- IF S_TO_RECIPIENT --><br /><strong>{L_TO}{L_COLON}</strong> <!-- BEGIN to_recipient --><!-- IF to_recipient.NAME_FULL -->{to_recipient.NAME_FULL}<!-- ELSE --><a href="{to_recipient.U_VIEW}" style="color:<!-- IF to_recipient.COLOUR -->{to_recipient.COLOUR}<!-- ELSEIF to_recipient.IS_GROUP -->#0000FF<!-- ENDIF -->;">{to_recipient.NAME}</a><!-- ENDIF -->&nbsp;<!-- END to_recipient --><!-- ENDIF -->
- <!-- IF S_BCC_RECIPIENT --><br /><strong>{L_BCC}{L_COLON}</strong> <!-- BEGIN bcc_recipient --><!-- IF bcc_recipient.NAME_FULL -->{bcc_recipient.NAME_FULL}<!-- ELSE --><a href="{bcc_recipient.U_VIEW}" style="color:<!-- IF bcc_recipient.COLOUR -->{bcc_recipient.COLOUR}<!-- ELSEIF bcc_recipient.IS_GROUP -->#0000FF<!-- ENDIF -->;">{bcc_recipient.NAME}</a><!-- ENDIF -->&nbsp;<!-- END bcc_recipient --><!-- ENDIF -->
+ <!-- IF S_TO_RECIPIENT --><br /><strong>{L_TO}{L_COLON}</strong> <!-- BEGIN to_recipient --><!-- IF to_recipient.NAME_FULL -->{to_recipient.NAME_FULL}<!-- ELSE --><a href="{to_recipient.U_VIEW}"<!-- IF to_recipient.COLOUR --> style="color:{to_recipient.COLOUR};"<!-- ENDIF -->><strong>{to_recipient.NAME}</strong></a><!-- ENDIF -->&nbsp;<!-- END to_recipient --><!-- ENDIF -->
+ <!-- IF S_BCC_RECIPIENT --><br /><strong>{L_BCC}{L_COLON}</strong> <!-- BEGIN bcc_recipient --><!-- IF bcc_recipient.NAME_FULL -->{bcc_recipient.NAME_FULL}<!-- ELSE --><a href="{bcc_recipient.U_VIEW}"<!-- IF bcc_recipient.COLOUR --> style="color:{bcc_recipient.COLOUR};"<!-- ENDIF -->><strong>{bcc_recipient.NAME}</strong></a><!-- ENDIF -->&nbsp;<!-- END bcc_recipient --><!-- ENDIF -->
</p>
@@ -141,7 +157,12 @@
<!-- ENDIF -->
</div>
- <div class="back2top"><a href="#top" class="top" title="{L_BACK_TO_TOP}">{L_BACK_TO_TOP}</a></div>
+ <div class="back2top">
+ <a href="#top" class="top" title="{L_BACK_TO_TOP}">
+ <i class="icon fa-chevron-circle-up fa-fw icon-gray" aria-hidden="true"></i>
+ <span class="sr-only">{L_BACK_TO_TOP}</span>
+ </a>
+ </div>
</div>
</div>
@@ -149,10 +170,18 @@
<!-- EVENT ucp_pm_viewmessage_options_before -->
<!-- IF S_VIEW_MESSAGE -->
<fieldset class="display-options">
- <!-- IF U_PREVIOUS_PM --><a href="{U_PREVIOUS_PM}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}">{L_VIEW_PREVIOUS_PM}</a><!-- ENDIF -->
- <!-- IF U_NEXT_PM --><a href="{U_NEXT_PM}" class="right-box arrow-{S_CONTENT_FLOW_END}">{L_VIEW_NEXT_PM}</a><!-- ENDIF -->
<!-- IF S_MARK_OPTIONS --><label for="mark_option"><select name="mark_option" id="mark_option">{S_MARK_OPTIONS}</select></label>&nbsp;<input class="button2" type="submit" name="submit_mark" value="{L_GO}" /><!-- ENDIF -->
+ <!-- IF U_PREVIOUS_PM -->
+ <a href="{U_PREVIOUS_PM}" class="left-box arrow-{S_CONTENT_FLOW_BEGIN}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_PREVIOUS_PM}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF U_NEXT_PM -->
+ <a href="{U_NEXT_PM}" class="right-box arrow-{S_CONTENT_FLOW_END}">
+ <i class="icon fa-angle-{S_CONTENT_FLOW_END} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_NEXT_PM}</span>
+ </a>
+ <!-- ENDIF -->
<!-- IF not S_UNREAD and not S_SPECIAL_FOLDER --><label for="dest_folder"><!-- IF S_VIEW_MESSAGE -->{L_MOVE_TO_FOLDER}{L_COLON} <!-- ELSE -->{L_MOVE_MARKED_TO_FOLDER}<!-- ENDIF --> <select name="dest_folder" id="dest_folder">{S_TO_FOLDER_OPTIONS}</select></label> <input class="button2" type="submit" name="move_pm" value="{L_GO}" /><!-- ENDIF -->
<input type="hidden" name="marked_msg_id[]" value="{MSG_ID}" />
<input type="hidden" name="cur_folder_id" value="{CUR_FOLDER_ID}" />
diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html
index d431561834..41ff5b898a 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html
@@ -8,11 +8,12 @@
<title>{SITENAME} &bull; {PAGE_TITLE}</title>
<link href="{T_THEME_PATH}/print.css" rel="stylesheet">
+<link href="{T_THEME_PATH}/bidi.css" rel="stylesheet">
<!-- EVENT ucp_pm_viewmessage_print_head_append -->
</head>
<body id="phpbb">
-<div id="wrap">
- <a id="top" class="anchor" accesskey="t"></a>
+<div id="wrap" class="wrap">
+ <a id="top" class="top-anchor" accesskey="t"></a>
<div id="page-header">
<h1>{SITENAME}</h1>
@@ -21,7 +22,7 @@
<h2>{L_PRIVATE_MESSAGING}</h2>
</div>
- <div id="page-body">
+ <div id="page-body" class="page-body">
<div class="page-number">{PAGE_NUMBER}</div>
<div class="post">
<h3>{SUBJECT}</h3>
@@ -39,9 +40,16 @@
<hr />
</div>
- <div id="page-footer">
+ <div id="page-footer" class="page-footer">
<div class="page-number">{S_TIMEZONE}<br />{PAGE_NUMBER}</div>
- <div class="copyright">Powered by phpBB&reg; Forum Software &copy; phpBB Limited<br />https://www.phpbb.com/</div>
+ <div class="copyright">
+ <p>{{ CREDIT_LINE }}
+ </p>
+ {% if TRANSLATION_INFO %}
+ <p>{{ TRANSLATION_INFO }}
+ </p>
+ {% endif %}
+ </div>
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/ucp_prefs_personal.html b/phpBB/styles/prosilver/template/ucp_prefs_personal.html
index 4cd9f6655b..1650705d4b 100644
--- a/phpBB/styles/prosilver/template/ucp_prefs_personal.html
+++ b/phpBB/styles/prosilver/template/ucp_prefs_personal.html
@@ -85,8 +85,7 @@
</fieldset>
</form>
-<script type="text/javascript">
-// <![CDATA[
+<script>
var date_format = '{A_DATE_FORMAT}';
var default_dateformat = '{A_DEFAULT_DATEFORMAT}';
@@ -118,7 +117,6 @@
}
window.onload = customDates;
-// ]]>
</script>
<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/prosilver/template/ucp_prefs_post.html b/phpBB/styles/prosilver/template/ucp_prefs_post.html
index 891e49af6f..169d41bf72 100644
--- a/phpBB/styles/prosilver/template/ucp_prefs_post.html
+++ b/phpBB/styles/prosilver/template/ucp_prefs_post.html
@@ -12,39 +12,39 @@
<dl>
<dt><label for="bbcode1">{L_DEFAULT_BBCODE}{L_COLON}</label></dt>
<dd>
- <label for="bbcode1"><input type="radio" name="bbcode" id="bbcode1" value="1"<!-- IF S_BBCODE --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="bbcode1"><input type="radio" name="bbcode" id="bbcode1" value="1"<!-- IF S_BBCODE --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="bbcode0"><input type="radio" name="bbcode" id="bbcode0" value="0"<!-- IF not S_BBCODE --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="smilies1">{L_DEFAULT_SMILIES}{L_COLON}</label></dt>
<dd>
- <label for="smilies1"><input type="radio" name="smilies" id="smilies1" value="1"<!-- IF S_SMILIES --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="smilies1"><input type="radio" name="smilies" id="smilies1" value="1"<!-- IF S_SMILIES --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="smilies0"><input type="radio" name="smilies" id="smilies0" value="0"<!-- IF not S_SMILIES --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="sig1">{L_DEFAULT_ADD_SIG}{L_COLON}</label></dt>
<dd>
- <label for="sig1"><input type="radio" name="sig" id="sig1" value="1"<!-- IF S_SIG --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="sig1"><input type="radio" name="sig" id="sig1" value="1"<!-- IF S_SIG --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="sig0"><input type="radio" name="sig" id="sig0" value="0"<!-- IF not S_SIG --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="notify1">{L_DEFAULT_NOTIFY}{L_COLON}</label></dt>
<dd>
- <label for="notify1"><input type="radio" name="notify" id="notify1" value="1"<!-- IF S_NOTIFY --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="notify1"><input type="radio" name="notify" id="notify1" value="1"<!-- IF S_NOTIFY --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="notify0"><input type="radio" name="notify" id="notify0" value="0"<!-- IF not S_NOTIFY --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<!-- EVENT ucp_prefs_post_append -->
</fieldset>
-
+
</div>
</div>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="submit" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/ucp_prefs_view.html b/phpBB/styles/prosilver/template/ucp_prefs_view.html
index 7f8d0a344c..4b7142fbea 100644
--- a/phpBB/styles/prosilver/template/ucp_prefs_view.html
+++ b/phpBB/styles/prosilver/template/ucp_prefs_view.html
@@ -13,35 +13,35 @@
<dl>
<dt><label for="images1">{L_VIEW_IMAGES}{L_COLON}</label></dt>
<dd>
- <label for="images1"><input type="radio" name="images" id="images1" value="1"<!-- IF S_IMAGES --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="images1"><input type="radio" name="images" id="images1" value="1"<!-- IF S_IMAGES --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="images0"><input type="radio" name="images" id="images0" value="0"<!-- IF not S_IMAGES --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="flash0">{L_VIEW_FLASH}{L_COLON}</label></dt>
<dd>
- <label for="flash1"><input type="radio" name="flash" id="flash1" value="1"<!-- IF S_FLASH --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="flash1"><input type="radio" name="flash" id="flash1" value="1"<!-- IF S_FLASH --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="flash0"><input type="radio" name="flash" id="flash0" value="0"<!-- IF not S_FLASH --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="smilies1">{L_VIEW_SMILIES}{L_COLON}</label></dt>
<dd>
- <label for="smilies1"><input type="radio" name="smilies" id="smilies1" value="1"<!-- IF S_SMILIES --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="smilies1"><input type="radio" name="smilies" id="smilies1" value="1"<!-- IF S_SMILIES --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="smilies0"><input type="radio" name="smilies" id="smilies0" value="0"<!-- IF not S_SMILIES --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="sigs1">{L_VIEW_SIGS}{L_COLON}</label></dt>
<dd>
- <label for="sigs1"><input type="radio" name="sigs" id="sigs1" value="1"<!-- IF S_SIGS --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="sigs1"><input type="radio" name="sigs" id="sigs1" value="1"<!-- IF S_SIGS --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="sigs0"><input type="radio" name="sigs" id="sigs0" value="0"<!-- IF not S_SIGS --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
<dl>
<dt><label for="avatars1">{L_VIEW_AVATARS}{L_COLON}</label></dt>
<dd>
- <label for="avatars1"><input type="radio" name="avatars" id="avatars1" value="1"<!-- IF S_AVATARS --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="avatars1"><input type="radio" name="avatars" id="avatars1" value="1"<!-- IF S_AVATARS --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="avatars0"><input type="radio" name="avatars" id="avatars0" value="0"<!-- IF not S_AVATARS --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
@@ -49,7 +49,7 @@
<dl>
<dt><label for="wordcensor1">{L_DISABLE_CENSORS}{L_COLON}</label></dt>
<dd>
- <label for="wordcensor1"><input type="radio" name="wordcensor" id="wordcensor1" value="1"<!-- IF S_DISABLE_CENSORS --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
+ <label for="wordcensor1"><input type="radio" name="wordcensor" id="wordcensor1" value="1"<!-- IF S_DISABLE_CENSORS --> checked="checked"<!-- ENDIF --> /> {L_YES}</label>
<label for="wordcensor0"><input type="radio" name="wordcensor" id="wordcensor0" value="0"<!-- IF not S_DISABLE_CENSORS --> checked="checked"<!-- ENDIF --> /> {L_NO}</label>
</dd>
</dl>
@@ -89,7 +89,7 @@
</div>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="submit" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/ucp_profile_profile_info.html b/phpBB/styles/prosilver/template/ucp_profile_profile_info.html
index 69eda8c42c..ac0cd153c2 100644
--- a/phpBB/styles/prosilver/template/ucp_profile_profile_info.html
+++ b/phpBB/styles/prosilver/template/ucp_profile_profile_info.html
@@ -13,7 +13,7 @@
<!-- EVENT ucp_profile_profile_info_before -->
<!-- IF S_BIRTHDAYS_ENABLED -->
<dl>
- <dt><label for="bday_day">{L_BIRTHDAY}{L_COLON}</label><br /><span>{L_BIRTHDAY_EXPLAIN}</span></dt>
+ <dt><label for="bday_day">{L_BIRTHDAY}{L_COLON}{% EVENT ucp_profile_profile_info_birthday_label_append %}</label><br /><span>{L_BIRTHDAY_EXPLAIN}</span></dt>
<dd>
<label for="bday_day">{L_DAY}{L_COLON} <select name="bday_day" id="bday_day">{S_BIRTHDAY_DAY_OPTIONS}</select></label>
<label for="bday_month">{L_MONTH}{L_COLON} <select name="bday_month" id="bday_month">{S_BIRTHDAY_MONTH_OPTIONS}</select></label>
diff --git a/phpBB/styles/prosilver/template/ucp_profile_reg_details.html b/phpBB/styles/prosilver/template/ucp_profile_reg_details.html
index 462a7f8f20..f62d3cf37d 100644
--- a/phpBB/styles/prosilver/template/ucp_profile_reg_details.html
+++ b/phpBB/styles/prosilver/template/ucp_profile_reg_details.html
@@ -31,7 +31,7 @@
<dd><input type="password" name="password_confirm" id="password_confirm" maxlength="255" value="{PASSWORD_CONFIRM}" class="inputbox" title="{L_CONFIRM_PASSWORD}" autocomplete="off" /></dd>
</dl>
<!-- ENDIF -->
- <!-- EVENT ucp_profile_register_details_after -->
+ <!-- EVENT ucp_profile_register_details_after -->
</fieldset>
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/ucp_profile_signature.html b/phpBB/styles/prosilver/template/ucp_profile_signature.html
index 614f6f440d..ed28b7ab02 100644
--- a/phpBB/styles/prosilver/template/ucp_profile_signature.html
+++ b/phpBB/styles/prosilver/template/ucp_profile_signature.html
@@ -24,6 +24,7 @@
<!-- INCLUDE posting_editor.html -->
<h3>{L_OPTIONS}</h3>
<fieldset>
+ {% EVENT ucp_profile_signature_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/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html
index 38413addba..bf39990c35 100644
--- a/phpBB/styles/prosilver/template/ucp_register.html
+++ b/phpBB/styles/prosilver/template/ucp_register.html
@@ -1,7 +1,6 @@
<!-- INCLUDE overall_header.html -->
-<script type="text/javascript">
-// <![CDATA[
+<script>
/**
* Change language
*/
@@ -11,7 +10,6 @@
document.forms['register'].change_lang.value = lang_iso;
document.forms['register'].submit.click();
}
-// ]]>
</script>
<form id="register" method="post" action="{S_UCP_ACTION}"{S_FORM_ENCTYPE}>
diff --git a/phpBB/styles/prosilver/template/ucp_remind.html b/phpBB/styles/prosilver/template/ucp_remind.html
index 0ab1251d9e..8b700de430 100644
--- a/phpBB/styles/prosilver/template/ucp_remind.html
+++ b/phpBB/styles/prosilver/template/ucp_remind.html
@@ -9,14 +9,19 @@
<h2>{L_SEND_PASSWORD}</h2>
<fieldset>
+ {% if USERNAME_REQUIRED %}
+ <p class="error">{{ lang('EMAIL_NOT_UNIQUE') }}</p>
+ {% endif %}
<dl>
- <dt><label for="username">{L_USERNAME}{L_COLON}</label></dt>
- <dd><input class="inputbox narrow" type="text" name="username" id="username" size="25" /></dd>
+ <dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label><br /><span>{L_EMAIL_REMIND}</span></dt>
+ <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" value="{{ EMAIL }}" autofocus /></dd>
</dl>
+ {% if USERNAME_REQUIRED %}
<dl>
- <dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label><br /><span>{L_EMAIL_REMIND}</span></dt>
- <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" /></dd>
+ <dt><label for="username">{L_USERNAME}{L_COLON}</label></dt>
+ <dd><input class="inputbox narrow" type="text" name="username" id="username" size="25" /></dd>
</dl>
+ {% endif %}
<dl>
<dt>&nbsp;</dt>
<dd>{S_HIDDEN_FIELDS}<input type="submit" name="submit" id="submit" class="button1" value="{L_SUBMIT}" tabindex="2" />&nbsp; <input type="reset" value="{L_RESET}" name="reset" class="button2" /></dd>
diff --git a/phpBB/styles/prosilver/template/ucp_zebra_foes.html b/phpBB/styles/prosilver/template/ucp_zebra_foes.html
index 712479dc18..2a0f6e0dea 100644
--- a/phpBB/styles/prosilver/template/ucp_zebra_foes.html
+++ b/phpBB/styles/prosilver/template/ucp_zebra_foes.html
@@ -32,7 +32,7 @@
</div>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="submit" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/ucp_zebra_friends.html b/phpBB/styles/prosilver/template/ucp_zebra_friends.html
index fac0a18706..e584d876b8 100644
--- a/phpBB/styles/prosilver/template/ucp_zebra_friends.html
+++ b/phpBB/styles/prosilver/template/ucp_zebra_friends.html
@@ -34,7 +34,7 @@
</div>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="submit" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html
index f6fc07ea55..40beb784d7 100644
--- a/phpBB/styles/prosilver/template/viewforum_body.html
+++ b/phpBB/styles/prosilver/template/viewforum_body.html
@@ -35,18 +35,19 @@
<!-- ENDIF -->
<!-- IF S_DISPLAY_POST_INFO or .pagination or TOTAL_POSTS or TOTAL_TOPICS -->
- <div class="action-bar top">
+ <div class="action-bar bar-top">
<!-- IF not S_IS_BOT and S_DISPLAY_POST_INFO -->
- <div class="buttons">
<!-- EVENT viewforum_buttons_top_before -->
- <a href="{U_POST_NEW_TOPIC}" class="button icon-button <!-- IF S_IS_LOCKED -->locked-icon<!-- ELSE -->post-icon<!-- ENDIF -->" title="<!-- IF S_IS_LOCKED -->{L_FORUM_LOCKED}<!-- ELSE -->{L_POST_TOPIC}<!-- ENDIF -->">
- <!-- IF S_IS_LOCKED -->{L_BUTTON_FORUM_LOCKED}<!-- ELSE -->{L_BUTTON_NEW_TOPIC}<!-- ENDIF -->
- </a>
-
+ <a href="{U_POST_NEW_TOPIC}" class="button" title="<!-- IF S_IS_LOCKED -->{L_FORUM_LOCKED}<!-- ELSE -->{L_POST_TOPIC}<!-- ENDIF -->">
+ <!-- IF S_IS_LOCKED -->
+ <span>{L_BUTTON_FORUM_LOCKED}</span> <i class="icon fa-lock fa-fw" aria-hidden="true"></i>
+ <!-- ELSE -->
+ <span>{L_BUTTON_NEW_TOPIC}</span> <i class="icon fa-pencil fa-fw" aria-hidden="true"></i>
+ <!-- ENDIF -->
+ </a>
<!-- EVENT viewforum_buttons_top_after -->
- </div>
<!-- ENDIF -->
<!-- IF S_DISPLAY_SEARCHBOX -->
@@ -54,8 +55,12 @@
<form method="get" id="forum-search" action="{S_SEARCHBOX_ACTION}">
<fieldset>
<input class="inputbox search tiny" type="search" name="keywords" id="search_keywords" size="20" placeholder="{L_SEARCH_FORUM}" />
- <button class="button icon-button search-icon" type="submit" title="{L_SEARCH}">{L_SEARCH}</button>
- <a href="{U_SEARCH}" class="button icon-button search-adv-icon" title="{L_SEARCH_ADV}">{L_SEARCH_ADV}</a>
+ <button class="button button-search" type="submit" title="{L_SEARCH}">
+ <i class="icon fa-search fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH}</span>
+ </button>
+ <a href="{U_SEARCH}" class="button button-search-end" title="{L_SEARCH_ADV}">
+ <i class="icon fa-cog fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH_ADV}</span>
+ </a>
{S_SEARCH_LOCAL_HIDDEN_FIELDS}
</fieldset>
</form>
@@ -109,6 +114,7 @@
<dd><input type="submit" name="login" tabindex="5" value="{L_LOGIN}" class="button1" /></dd>
</dl>
{S_LOGIN_REDIRECT}
+ {S_FORM_TOKEN_LOGIN}
</fieldset>
</div>
@@ -136,7 +142,7 @@
<div class="inner">
<ul class="topiclist">
<li class="header">
- <dl class="icon">
+ <dl class="row-item">
<dt<!-- IF S_DISPLAY_ACTIVE --> id="active_topics"<!-- ENDIF -->><div class="list-inner"><!-- IF S_DISPLAY_ACTIVE -->{L_ACTIVE_TOPICS}<!-- ELSEIF topicrow.S_TOPIC_TYPE_SWITCH and (topicrow.S_POST_ANNOUNCE or topicrow.S_POST_GLOBAL) -->{L_ANNOUNCEMENTS}<!-- ELSE -->{L_TOPICS}<!-- ENDIF --></div></dt>
<dd class="posts">{L_REPLIES}</dd>
<dd class="views">{L_VIEWS}</dd>
@@ -150,53 +156,84 @@
<!-- EVENT viewforum_body_topicrow_row_before -->
<li class="row<!-- IF topicrow.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_POST_GLOBAL --> global-announce<!-- ENDIF --><!-- IF topicrow.S_POST_ANNOUNCE --> announce<!-- ENDIF --><!-- IF topicrow.S_POST_STICKY --> sticky<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->">
<!-- EVENT viewforum_body_topic_row_prepend -->
- <dl class="icon {topicrow.TOPIC_IMG_STYLE}">
- <dt<!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS --> style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}">
- <!-- IF topicrow.S_UNREAD_TOPIC and not S_IS_BOT --><a href="{topicrow.U_NEWEST_POST}" class="icon-link"></a><!-- ENDIF -->
+ <dl class="row-item {topicrow.TOPIC_IMG_STYLE}">
+ <dt<!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS --> style="background-image: url('{T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}'); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}">
+ <!-- IF topicrow.S_UNREAD_TOPIC and not S_IS_BOT --><a href="{topicrow.U_NEWEST_POST}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
<!-- EVENT topiclist_row_prepend -->
- <!-- IF topicrow.S_UNREAD_TOPIC and not S_IS_BOT --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_DELETED --><a href="{topicrow.U_MCP_QUEUE}">{DELETED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF topicrow.S_UNREAD_TOPIC and not S_IS_BOT -->
+ <a class="unread" href="{topicrow.U_NEWEST_POST}">
+ <i class="icon fa-file fa-fw icon-red icon-md" aria-hidden="true"></i><span class="sr-only">{NEW_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF topicrow.U_VIEW_TOPIC --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a><!-- ELSE -->{topicrow.TOPIC_TITLE}<!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED -->
+ <a href="{topicrow.U_MCP_QUEUE}" title="<!-- IF topicrow.S_TOPIC_UNAPPROVED -->{L_TOPIC_UNAPPROVED}<!-- ELSE -->{L_POSTS_UNAPPROVED}<!-- ENDIF -->">
+ <i class="icon fa-question fa-fw icon-blue" aria-hidden="true"></i><span class="sr-only"><!-- IF topicrow.S_TOPIC_UNAPPROVED -->{L_TOPIC_UNAPPROVED}<!-- ELSE -->{L_POSTS_UNAPPROVED}<!-- ENDIF --></span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_DELETED -->
+ <a href="{topicrow.U_MCP_QUEUE}" title="{L_TOPIC_DELETED}">
+ <i class="icon fa-recycle fa-fw icon-green" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_DELETED}</span>
+ </a>
+ <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_REPORTED -->
+ <a href="{topicrow.U_MCP_REPORT}" title="{L_TOPIC_REPORTED}">
+ <i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><span class="sr-only">{L_TOPIC_REPORTED}</span>
+ </a>
+ <!-- ENDIF -->
+ <br />
<!-- EVENT topiclist_row_topic_title_after -->
+
<!-- IF not S_IS_BOT -->
<div class="responsive-show" style="display: none;">
- {L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL} &laquo; <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{topicrow.LAST_POST_TIME}</a>
+ {L_LAST_POST} {L_POST_BY_AUTHOR} <!-- EVENT viewforum_body_last_post_author_username_prepend -->{topicrow.LAST_POST_AUTHOR_FULL}<!-- EVENT viewforum_body_last_post_author_username_append --> &laquo; <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}"><time datetime="{topicrow.LAST_POST_TIME_RFC3339}">{topicrow.LAST_POST_TIME}</time></a>
<!-- IF topicrow.S_POST_GLOBAL and FORUM_ID != topicrow.FORUM_ID --><br />{L_POSTED} {L_IN} <a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a><!-- ENDIF -->
</div>
- <!-- IF topicrow.REPLIES --><span class="responsive-show left-box" style="display: none;">{L_REPLIES}{L_COLON} <strong>{topicrow.REPLIES}</strong></span><!-- ENDIF -->
+ <!-- IF topicrow.REPLIES -->
+ <span class="responsive-show left-box" style="display: none;">{L_REPLIES}{L_COLON} <strong>{topicrow.REPLIES}</strong></span>
+ <!-- ENDIF -->
<!-- ENDIF -->
+ <div class="topic-poster responsive-hide left-box">
+ <!-- IF topicrow.S_HAS_POLL --><i class="icon fa-bar-chart fa-fw" aria-hidden="true"></i><!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG --><i class="icon fa-paperclip fa-fw" aria-hidden="true"></i><!-- ENDIF -->
+ {% EVENT topiclist_row_topic_by_author_before %}
+ {L_POST_BY_AUTHOR} <!-- EVENT viewforum_body_topic_author_username_prepend -->{topicrow.TOPIC_AUTHOR_FULL}<!-- EVENT viewforum_body_topic_author_username_append --> &raquo; <time datetime="{topicrow.FIRST_POST_TIME_RFC3339}">{topicrow.FIRST_POST_TIME}</time>
+ {% EVENT topiclist_row_topic_by_author_after %}
+ <!-- IF topicrow.S_POST_GLOBAL and FORUM_ID != topicrow.FORUM_ID --> &raquo; {L_IN} <a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a><!-- ENDIF -->
+ </div>
+
<!-- IF .topicrow.pagination -->
<div class="pagination">
+ <span><i class="icon fa-clone fa-fw" aria-hidden="true"></i></span>
<ul>
<!-- BEGIN pagination -->
<!-- IF topicrow.pagination.S_IS_PREV -->
<!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
<!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
<!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
+ <!-- ELSE --><li><a class="button" href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
<!-- ENDIF -->
<!-- END pagination -->
</ul>
</div>
<!-- ENDIF -->
- <div class="responsive-hide">
- <!-- IF topicrow.S_HAS_POLL -->{POLL_IMG} <!-- ENDIF -->
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->
- {L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
- <!-- IF topicrow.S_POST_GLOBAL and FORUM_ID != topicrow.FORUM_ID --> &raquo; {L_IN} <a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a><!-- ENDIF -->
- </div>
-
<!-- EVENT topiclist_row_append -->
</div>
</dt>
<dd class="posts">{topicrow.REPLIES} <dfn>{L_REPLIES}</dfn></dd>
<dd class="views">{topicrow.VIEWS} <dfn>{L_VIEWS}</dfn></dd>
- <dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
- <!-- IF not S_IS_BOT --><a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">{LAST_POST_IMG}</a> <!-- ENDIF --><br />{topicrow.LAST_POST_TIME}</span>
+ <dd class="lastpost">
+ <span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} <!-- EVENT viewforum_body_last_post_author_username_prepend -->{topicrow.LAST_POST_AUTHOR_FULL}<!-- EVENT viewforum_body_last_post_author_username_append -->
+ <!-- IF not S_IS_BOT and topicrow.U_LAST_POST -->
+ <a href="{topicrow.U_LAST_POST}" title="{L_GOTO_LAST_POST}">
+ <i class="icon fa-external-link-square fa-fw icon-lightgray icon-md" aria-hidden="true"></i><span class="sr-only">{VIEW_LATEST_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ <br /><time datetime="{topicrow.LAST_POST_TIME_RFC3339}">{topicrow.LAST_POST_TIME}</time>
+ </span>
</dd>
</dl>
<!-- EVENT viewforum_body_topic_row_append -->
@@ -216,35 +253,35 @@
<strong>{L_NO_TOPICS}</strong>
</div>
</div>
+ <!-- ELSE IF not S_HAS_SUBFORUM -->
+ <div class="panel">
+ <div class="inner">
+ <strong>{L_NO_FORUMS_IN_CATEGORY}</strong>
+ </div>
+ </div>
<!-- ENDIF -->
<!-- END topicrow -->
-<!-- IF S_SELECT_SORT_DAYS and not S_DISPLAY_ACTIVE -->
- <form method="post" action="{S_FORUM_ACTION}">
- <fieldset class="display-options">
- <!-- IF not S_IS_BOT -->
- <label>{L_DISPLAY_TOPICS}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label>
- <label>{S_SELECT_SORT_DIR}</label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- <!-- ENDIF -->
- </fieldset>
- </form>
- <hr />
-<!-- ENDIF -->
-
<!-- IF .topicrow and not S_DISPLAY_ACTIVE -->
- <div class="action-bar bottom">
+ <div class="action-bar bar-bottom">
<!-- IF not S_IS_BOT and S_DISPLAY_POST_INFO -->
- <div class="buttons">
- <!-- EVENT viewforum_buttons_bottom_before -->
+ <!-- EVENT viewforum_buttons_bottom_before -->
- <a href="{U_POST_NEW_TOPIC}" class="button icon-button <!-- IF S_IS_LOCKED -->locked-icon<!-- ELSE -->post-icon<!-- ENDIF -->" title="<!-- IF S_IS_LOCKED -->{L_FORUM_LOCKED}<!-- ELSE -->{L_POST_TOPIC}<!-- ENDIF -->">
- <!-- IF S_IS_LOCKED -->{L_BUTTON_FORUM_LOCKED}<!-- ELSE -->{L_BUTTON_NEW_TOPIC}<!-- ENDIF -->
- </a>
+ <a href="{U_POST_NEW_TOPIC}" class="button" title="<!-- IF S_IS_LOCKED -->{L_FORUM_LOCKED}<!-- ELSE -->{L_POST_TOPIC}<!-- ENDIF -->">
+ <!-- IF S_IS_LOCKED -->
+ <span>{L_BUTTON_FORUM_LOCKED}</span> <i class="icon fa-lock fa-fw" aria-hidden="true"></i>
+ <!-- ELSE -->
+ <span>{L_BUTTON_NEW_TOPIC}</span> <i class="icon fa-pencil fa-fw" aria-hidden="true"></i>
+ <!-- ENDIF -->
+ </a>
- <!-- EVENT viewforum_buttons_bottom_after -->
- </div>
+ <!-- EVENT viewforum_buttons_bottom_after -->
+ <!-- ENDIF -->
+
+ <!-- IF S_SELECT_SORT_DAYS and not S_IS_BOT -->
+ <form method="post" action="{S_FORUM_ACTION}">
+ <!-- INCLUDE display_options.html -->
+ </form>
<!-- ENDIF -->
<div class="pagination">
diff --git a/phpBB/styles/prosilver/template/viewonline_body.html b/phpBB/styles/prosilver/template/viewonline_body.html
index ee1672c6c9..c019977179 100644
--- a/phpBB/styles/prosilver/template/viewonline_body.html
+++ b/phpBB/styles/prosilver/template/viewonline_body.html
@@ -3,11 +3,11 @@
<h2 class="viewonline-title">{TOTAL_REGISTERED_USERS_ONLINE}</h2>
<p>{TOTAL_GUEST_USERS_ONLINE}<!-- IF S_SWITCH_GUEST_DISPLAY --> &bull; <a href="{U_SWITCH_GUEST_DISPLAY}">{L_SWITCH_GUEST_DISPLAY}</a><!-- ENDIF --></p>
-<div class="action-bar top">
+<div class="action-bar bar-top">
<div class="pagination">
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
{PAGE_NUMBER}
<!-- ENDIF -->
</div>
@@ -15,7 +15,7 @@
<div class="forumbg forumbg-table">
<div class="inner">
-
+
<table class="table1">
<!-- IF .user_row -->
@@ -29,7 +29,7 @@
<tbody>
<!-- BEGIN user_row -->
<tr class="<!-- IF user_row.S_ROW_COUNT is odd -->bg1<!-- ELSE -->bg2<!-- ENDIF -->">
- <td>{user_row.USERNAME_FULL}<!-- IF user_row.USER_IP --> <span style="float: {S_CONTENT_FLOW_END};">{L_IP}{L_COLON} <a href="{user_row.U_USER_IP}">{user_row.USER_IP}</a> &#187; <a href="{user_row.U_WHOIS}" onclick="popup(this.href, 750, 500); return false;">{L_WHOIS}</a></span><!-- ENDIF -->
+ <td><!-- EVENT viewonline_body_username_prepend -->{user_row.USERNAME_FULL}<!-- EVENT viewonline_body_username_append --><!-- IF user_row.USER_IP --> <span style="float: {S_CONTENT_FLOW_END};">{L_IP}{L_COLON} <a href="{user_row.U_USER_IP}">{user_row.USER_IP}</a> &#187; <a href="{user_row.U_WHOIS}" onclick="popup(this.href, 750, 500); return false;">{L_WHOIS}</a></span><!-- ENDIF -->
<!-- IF user_row.USER_BROWSER --><br />{user_row.USER_BROWSER}<!-- ENDIF --></td>
<td class="info"><a href="{user_row.U_FORUM_LOCATION}">{user_row.FORUM_LOCATION}</a></td>
<td class="active">{user_row.LASTUPDATE}</td>
@@ -43,17 +43,17 @@
<!-- ENDIF -->
</tbody>
</table>
-
+
</div>
</div>
<!-- IF LEGEND --><p><em>{L_LEGEND}{L_COLON} {LEGEND}</em></p><!-- ENDIF -->
-<div class="action-bar bottom">
+<div class="action-bar bar-bottom">
<div class="pagination">
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
{PAGE_NUMBER}
<!-- ENDIF -->
</div>
diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html
index 22a77779bf..9bfa07e52b 100644
--- a/phpBB/styles/prosilver/template/viewtopic_body.html
+++ b/phpBB/styles/prosilver/template/viewtopic_body.html
@@ -1,5 +1,6 @@
<!-- INCLUDE overall_header.html -->
+<!-- EVENT viewtopic_topic_title_before -->
<h2 class="topic-title"><!-- EVENT viewtopic_topic_title_prepend --><a href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a><!-- EVENT viewtopic_topic_title_append --></h2>
<!-- EVENT viewtopic_topic_title_after -->
<!-- NOTE: remove the style="display: none" when you want to have the forum description on the topic body -->
@@ -26,20 +27,20 @@
</div>
<!-- ENDIF -->
-<div class="action-bar top">
-
- <div class="buttons">
- <!-- EVENT viewtopic_buttons_top_before -->
+<div class="action-bar bar-top">
+ <!-- EVENT viewtopic_buttons_top_before -->
<!-- IF not S_IS_BOT and S_DISPLAY_REPLY_INFO -->
- <a href="{U_POST_REPLY_TOPIC}" class="button icon-button <!-- IF S_IS_LOCKED -->locked-icon<!-- ELSE -->reply-icon<!-- ENDIF -->" title="<!-- IF S_IS_LOCKED -->{L_TOPIC_LOCKED}<!-- ELSE -->{L_POST_REPLY}<!-- ENDIF -->">
- <!-- IF S_IS_LOCKED -->{L_BUTTON_TOPIC_LOCKED}<!-- ELSE -->{L_BUTTON_POST_REPLY}<!-- ENDIF -->
+ <a href="{U_POST_REPLY_TOPIC}" class="button" title="<!-- IF S_IS_LOCKED -->{L_TOPIC_LOCKED}<!-- ELSE -->{L_POST_REPLY}<!-- ENDIF -->">
+ <!-- IF S_IS_LOCKED -->
+ <span>{L_BUTTON_TOPIC_LOCKED}</span> <i class="icon fa-lock fa-fw" aria-hidden="true"></i>
+ <!-- ELSE -->
+ <span>{L_BUTTON_POST_REPLY}</span> <i class="icon fa-reply fa-fw" aria-hidden="true"></i>
+ <!-- ENDIF -->
</a>
<!-- ENDIF -->
- <!-- EVENT viewtopic_buttons_top_after -->
- </div>
-
+ <!-- EVENT viewtopic_buttons_top_after -->
<!-- INCLUDE viewtopic_topic_tools.html -->
<!-- EVENT viewtopic_dropdown_top_custom -->
@@ -48,8 +49,12 @@
<form method="get" id="topic-search" action="{S_SEARCHBOX_ACTION}">
<fieldset>
<input class="inputbox search tiny" type="search" name="keywords" id="search_keywords" size="20" placeholder="{L_SEARCH_TOPIC}" />
- <button class="button icon-button search-icon" type="submit" title="{L_SEARCH}">{L_SEARCH}</button>
- <a href="{U_SEARCH}" class="button icon-button search-adv-icon" title="{L_SEARCH_ADV}">{L_SEARCH_ADV}</a>
+ <button class="button button-search" type="submit" title="{L_SEARCH}">
+ <i class="icon fa-search fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH}</span>
+ </button>
+ <a href="{U_SEARCH}" class="button button-search-end" title="{L_SEARCH_ADV}">
+ <i class="icon fa-cog fa-fw" aria-hidden="true"></i><span class="sr-only">{L_SEARCH_ADV}</span>
+ </a>
{S_SEARCH_LOCAL_HIDDEN_FIELDS}
</fieldset>
</form>
@@ -174,8 +179,10 @@
<dd class="profile-contact">
<strong>{L_CONTACT}{L_COLON}</strong>
<div class="dropdown-container dropdown-left">
- <a href="#" class="dropdown-trigger"><span class="imageset icon_contact" title="{postrow.CONTACT_USER}">{postrow.CONTACT_USER}</span></a>
- <div class="dropdown hidden">
+ <a href="#" class="dropdown-trigger" title="{postrow.CONTACT_USER}">
+ <i class="icon fa-commenting-o fa-fw icon-lg" aria-hidden="true"></i><span class="sr-only">{postrow.CONTACT_USER}</span>
+ </a>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<div class="dropdown-contents contact-icons">
<!-- BEGIN contact -->
@@ -217,7 +224,7 @@
<div id="post_content{postrow.POST_ID}"<!-- IF postrow.S_POST_HIDDEN --> style="display: none;"<!-- ENDIF -->>
<!-- EVENT viewtopic_body_post_subject_before -->
- <h3 <!-- IF postrow.S_FIRST_ROW -->class="first"<!-- ENDIF -->><!-- IF postrow.POST_ICON_IMG --><img src="{T_ICONS_PATH}{postrow.POST_ICON_IMG}" width="{postrow.POST_ICON_IMG_WIDTH}" height="{postrow.POST_ICON_IMG_HEIGHT}" alt="" /> <!-- ENDIF --><a href="#p{postrow.POST_ID}">{postrow.POST_SUBJECT}</a></h3>
+ <h3 <!-- IF postrow.S_FIRST_ROW -->class="first"<!-- ENDIF -->><!-- IF postrow.POST_ICON_IMG --><img src="{T_ICONS_PATH}{postrow.POST_ICON_IMG}" width="{postrow.POST_ICON_IMG_WIDTH}" height="{postrow.POST_ICON_IMG_HEIGHT}" alt="{postrow.POST_ICON_IMG_ALT}" title="{postrow.POST_ICON_IMG_ALT}" /> <!-- ENDIF --><a href="{postrow.U_MINI_POST}">{postrow.POST_SUBJECT}</a></h3>
<!-- DEFINE $SHOW_POST_BUTTONS = (postrow.U_EDIT or postrow.U_DELETE or postrow.U_REPORT or postrow.U_WARN or postrow.U_INFO or postrow.U_QUOTE) -->
<!-- EVENT viewtopic_body_post_buttons_list_before -->
@@ -227,32 +234,44 @@
<!-- EVENT viewtopic_body_post_buttons_before -->
<!-- IF postrow.U_EDIT -->
<li>
- <a href="{postrow.U_EDIT}" title="{L_EDIT_POST}" class="button icon-button edit-icon"><span>{L_BUTTON_EDIT}</span></a>
+ <a href="{postrow.U_EDIT}" title="{L_EDIT_POST}" class="button button-icon-only">
+ <i class="icon fa-pencil fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_EDIT}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF postrow.U_DELETE -->
<li>
- <a href="{postrow.U_DELETE}" title="{L_DELETE_POST}" class="button icon-button delete-icon"><span>{L_DELETE_POST}</span></a>
+ <a href="{postrow.U_DELETE}" title="{L_DELETE_POST}" class="button button-icon-only">
+ <i class="icon fa-times fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_DELETE}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF postrow.U_REPORT -->
<li>
- <a href="{postrow.U_REPORT}" title="{L_REPORT_POST}" class="button icon-button report-icon"><span>{L_REPORT_POST}</span></a>
+ <a href="{postrow.U_REPORT}" title="{L_REPORT_POST}" class="button button-icon-only">
+ <i class="icon fa-exclamation fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_REPORT}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF postrow.U_WARN -->
<li>
- <a href="{postrow.U_WARN}" title="{L_WARN_USER}" class="button icon-button warn-icon"><span>{L_WARN_USER}</span></a>
+ <a href="{postrow.U_WARN}" title="{L_WARN_USER}" class="button button-icon-only">
+ <i class="icon fa-exclamation-triangle fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_WARN}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF postrow.U_INFO -->
<li>
- <a href="{postrow.U_INFO}" title="{L_INFORMATION}" class="button icon-button info-icon"><span>{L_INFORMATION}</span></a>
+ <a href="{postrow.U_INFO}" title="{L_INFORMATION}" class="button button-icon-only">
+ <i class="icon fa-info fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_INFORMATION}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF postrow.U_QUOTE -->
<li>
- <a href="{postrow.U_QUOTE}" title="{L_REPLY_WITH_QUOTE}" class="button icon-button quote-icon"><span>{L_QUOTE}</span></a>
+ <a href="{postrow.U_QUOTE}" title="{L_REPLY_WITH_QUOTE}" class="button button-icon-only">
+ <i class="icon fa-quote-left fa-fw" aria-hidden="true"></i><span class="sr-only">{L_BUTTON_QUOTE}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- EVENT viewtopic_body_post_buttons_after -->
@@ -262,12 +281,22 @@
<!-- EVENT viewtopic_body_post_buttons_list_after -->
<!-- EVENT viewtopic_body_postrow_post_details_before -->
- <p class="author"><!-- IF S_IS_BOT -->{postrow.MINI_POST_IMG}<!-- ELSE --><a href="{postrow.U_MINI_POST}">{postrow.MINI_POST_IMG}</a><!-- ENDIF --><span class="responsive-hide">{L_POST_BY_AUTHOR} <strong>{postrow.POST_AUTHOR_FULL}</strong> &raquo; </span>{postrow.POST_DATE} </p>
+ <p class="author">
+ <!-- IF S_IS_BOT -->
+ <span><i class="icon fa-file fa-fw <!-- IF postrow.S_UNREAD_POST -->icon-red<!-- ELSE -->icon-lightgray<!-- ENDIF --> icon-md" aria-hidden="true"></i><span class="sr-only">{postrow.MINI_POST}</span></span>
+ <!-- ELSE -->
+ <a class="unread" href="{postrow.U_MINI_POST}" title="{postrow.MINI_POST}">
+ <i class="icon fa-file fa-fw <!-- IF postrow.S_UNREAD_POST -->icon-red<!-- ELSE -->icon-lightgray<!-- ENDIF --> icon-md" aria-hidden="true"></i><span class="sr-only">{postrow.MINI_POST}</span>
+ </a>
+ <!-- ENDIF -->
+ <span class="responsive-hide">{L_POST_BY_AUTHOR} <strong>{postrow.POST_AUTHOR_FULL}</strong> &raquo; </span><time datetime="{postrow.POST_DATE_RFC3339}">{postrow.POST_DATE}</time>
+ </p>
<!-- EVENT viewtopic_body_postrow_post_details_after -->
<!-- IF postrow.S_POST_UNAPPROVED -->
<form method="post" class="mcp_approve" action="{postrow.U_APPROVE_ACTION}">
<p class="post-notice unapproved">
+ <span><i class="icon fa-question icon-red fa-fw" aria-hidden="true"></i></span>
<strong>{L_POST_UNAPPROVED_ACTION}</strong>
<input class="button2" type="submit" value="{L_DISAPPROVE}" name="action[disapprove]" />
<input class="button1" type="submit" value="{L_APPROVE}" name="action[approve]" />
@@ -291,12 +320,14 @@
<!-- IF postrow.S_POST_REPORTED -->
<p class="post-notice reported">
- <a href="{postrow.U_MCP_REPORT}"><strong>{L_POST_REPORTED}</strong></a>
+ <a href="{postrow.U_MCP_REPORT}"><i class="icon fa-exclamation fa-fw icon-red" aria-hidden="true"></i><strong>{L_POST_REPORTED}</strong></a>
</p>
<!-- ENDIF -->
<div class="content">{postrow.MESSAGE}</div>
+ <!-- EVENT viewtopic_body_postrow_content_after -->
+
<!-- IF postrow.S_HAS_ATTACHMENTS -->
<dl class="attachbox">
<dt>
@@ -332,7 +363,14 @@
</div>
<!-- EVENT viewtopic_body_postrow_back2top_before -->
- <div class="back2top"><!-- EVENT viewtopic_body_postrow_back2top_prepend --><a href="#top" class="top" title="{L_BACK_TO_TOP}">{L_BACK_TO_TOP}</a><!-- EVENT viewtopic_body_postrow_back2top_append --></div>
+ <div class="back2top">
+ <!-- EVENT viewtopic_body_postrow_back2top_prepend -->
+ <a href="#top" class="top" title="{L_BACK_TO_TOP}">
+ <i class="icon fa-chevron-circle-up fa-fw icon-gray" aria-hidden="true"></i>
+ <span class="sr-only">{L_BACK_TO_TOP}</span>
+ </a>
+ <!-- EVENT viewtopic_body_postrow_back2top_append -->
+ </div>
<!-- EVENT viewtopic_body_postrow_back2top_after -->
</div>
@@ -346,39 +384,36 @@
<!-- INCLUDE quickreply_editor.html -->
<!-- ENDIF -->
-<!-- IF S_NUM_POSTS > 1 or .pagination -->
- <form id="viewtopic" method="post" action="{S_TOPIC_ACTION}">
- <fieldset class="display-options" style="margin-top: 0; ">
- <!-- IF not S_IS_BOT -->
- <label>{L_DISPLAY_POSTS}{L_COLON} {S_SELECT_SORT_DAYS}</label>
- <label>{L_SORT_BY} {S_SELECT_SORT_KEY}</label> <label>{S_SELECT_SORT_DIR}</label>
- <input type="submit" name="sort" value="{L_GO}" class="button2" />
- <!-- ENDIF -->
- </fieldset>
- </form>
- <hr />
-<!-- ENDIF -->
-
<!-- EVENT viewtopic_body_topic_actions_before -->
-<div class="action-bar bottom">
- <div class="buttons">
- <!-- EVENT viewtopic_buttons_bottom_before -->
+ <div class="action-bar bar-bottom">
+ <!-- EVENT viewtopic_buttons_bottom_before -->
<!-- IF not S_IS_BOT and S_DISPLAY_REPLY_INFO -->
- <a href="{U_POST_REPLY_TOPIC}" class="button icon-button <!-- IF S_IS_LOCKED -->locked-icon<!-- ELSE -->reply-icon<!-- ENDIF -->" title="<!-- IF S_IS_LOCKED -->{L_TOPIC_LOCKED}<!-- ELSE -->{L_POST_REPLY}<!-- ENDIF -->">
- <!-- IF S_IS_LOCKED -->{L_BUTTON_TOPIC_LOCKED}<!-- ELSE -->{L_BUTTON_POST_REPLY}<!-- ENDIF -->
+ <a href="{U_POST_REPLY_TOPIC}" class="button" title="<!-- IF S_IS_LOCKED -->{L_TOPIC_LOCKED}<!-- ELSE -->{L_POST_REPLY}<!-- ENDIF -->">
+ <!-- IF S_IS_LOCKED -->
+ <span>{L_BUTTON_TOPIC_LOCKED}</span> <i class="icon fa-lock fa-fw" aria-hidden="true"></i>
+ <!-- ELSE -->
+ <span>{L_BUTTON_POST_REPLY}</span> <i class="icon fa-reply fa-fw" aria-hidden="true"></i>
+ <!-- ENDIF -->
</a>
<!-- ENDIF -->
-
- <!-- EVENT viewtopic_buttons_bottom_after -->
- </div>
+ <!-- EVENT viewtopic_buttons_bottom_after -->
<!-- INCLUDE viewtopic_topic_tools.html -->
+ <!-- IF (S_NUM_POSTS > 1 or .pagination) and not S_IS_BOT -->
+ <form method="post" action="{S_TOPIC_ACTION}">
+ <!-- INCLUDE display_options.html -->
+ </form>
+ <!-- ENDIF -->
+
<!-- IF .quickmod -->
- <div class="dropdown-container dropdown-container-{S_CONTENT_FLOW_BEGIN} dropdown-up dropdown-{S_CONTENT_FLOW_END} dropdown-button-control" id="quickmod">
- <span title="{L_QUICK_MOD}" class="dropdown-trigger button icon-button modtools-icon dropdown-select">{L_QUICK_MOD}</span>
- <div class="dropdown hidden">
+ <div class="quickmod dropdown-container dropdown-container-left dropdown-up dropdown-{S_CONTENT_FLOW_END} dropdown-button-control" id="quickmod">
+ <span title="{L_QUICK_MOD}" class="button button-secondary dropdown-trigger dropdown-select">
+ <i class="icon fa-gavel fa-fw" aria-hidden="true"></i><span class="sr-only">{L_QUICK_MOD}</span>
+ <span class="caret"><i class="icon fa-sort-down fa-fw" aria-hidden="true"></i></span>
+ </span>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<ul class="dropdown-contents">
<!-- BEGIN quickmod -->
@@ -389,7 +424,7 @@
</div>
</div>
<!-- ENDIF -->
-
+
<!-- EVENT viewtopic_dropdown_bottom_custom -->
<!-- IF .pagination or TOTAL_POSTS -->
@@ -402,7 +437,6 @@
<!-- ENDIF -->
</div>
<!-- ENDIF -->
- <div class="clear"></div>
</div>
<!-- EVENT viewtopic_body_footer_before -->
diff --git a/phpBB/styles/prosilver/template/viewtopic_print.html b/phpBB/styles/prosilver/template/viewtopic_print.html
index 919c9397e1..658062f9fd 100644
--- a/phpBB/styles/prosilver/template/viewtopic_print.html
+++ b/phpBB/styles/prosilver/template/viewtopic_print.html
@@ -8,11 +8,12 @@
<title>{SITENAME} &bull; {PAGE_TITLE}</title>
<link href="{T_THEME_PATH}/print.css" rel="stylesheet">
+<link href="{T_THEME_PATH}/bidi.css" rel="stylesheet">
<!-- EVENT viewtopic_print_head_append -->
</head>
-<body id="phpbb">
-<div id="wrap">
- <a id="top" class="anchor" accesskey="t"></a>
+<body id="phpbb" class="{S_CONTENT_DIRECTION}">
+<div id="wrap" class="wrap">
+ <a id="top" class="top-anchor" accesskey="t"></a>
<div id="page-header">
<h1>{SITENAME}</h1>
@@ -22,7 +23,7 @@
<p><a href="{U_TOPIC}">{U_TOPIC}</a></p>
</div>
- <div id="page-body">
+ <div id="page-body" class="page-body">
<div class="page-number">{PAGE_NUMBER}</div>
<!-- BEGIN postrow -->
<div class="post">
@@ -35,9 +36,16 @@
<!-- END postrow -->
</div>
- <div id="page-footer">
+ <div id="page-footer" class="page-footer">
<div class="page-number">{S_TIMEZONE}<br />{PAGE_NUMBER}</div>
- <div class="copyright">Powered by phpBB&reg; Forum Software &copy; phpBB Limited<br />https://www.phpbb.com/</div>
+ <div class="copyright">
+ <p>{{ CREDIT_LINE }}
+ </p>
+ {% if TRANSLATION_INFO %}
+ <p>{{ TRANSLATION_INFO }}
+ </p>
+ {% endif %}
+ </div>
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/viewtopic_topic_tools.html b/phpBB/styles/prosilver/template/viewtopic_topic_tools.html
index 8378e3bcf4..272a434f6a 100644
--- a/phpBB/styles/prosilver/template/viewtopic_topic_tools.html
+++ b/phpBB/styles/prosilver/template/viewtopic_topic_tools.html
@@ -1,23 +1,48 @@
<!-- IF not S_IS_BOT and (U_WATCH_TOPIC or U_BOOKMARK_TOPIC or U_BUMP_TOPIC or U_EMAIL_TOPIC or U_PRINT_TOPIC or S_DISPLAY_TOPIC_TOOLS) -->
<div class="dropdown-container dropdown-button-control topic-tools">
- <span title="{L_TOPIC_TOOLS}" class="button icon-button tools-icon dropdown-trigger dropdown-select"></span>
- <div class="dropdown hidden">
+ <span title="{L_TOPIC_TOOLS}" class="button button-secondary dropdown-trigger dropdown-select">
+ <i class="icon fa-wrench fa-fw" aria-hidden="true"></i>
+ <span class="caret"><i class="icon fa-sort-down fa-fw" aria-hidden="true"></i></span>
+ </span>
+ <div class="dropdown">
<div class="pointer"><div class="pointer-inner"></div></div>
<ul class="dropdown-contents">
<!-- EVENT viewtopic_topic_tools_before -->
<!-- IF U_WATCH_TOPIC -->
- <li class="small-icon icon-<!-- IF S_WATCHING_TOPIC -->unsubscribe<!-- ELSE -->subscribe<!-- ENDIF -->">
- <a href="{U_WATCH_TOPIC}" class="watch-topic-link" title="{S_WATCH_TOPIC_TITLE}" data-ajax="toggle_link" data-toggle-class="small-icon icon-<!-- IF not S_WATCHING_TOPIC -->unsubscribe<!-- ELSE -->subscribe<!-- ENDIF -->" data-toggle-text="{S_WATCH_TOPIC_TOGGLE}" data-toggle-url="{U_WATCH_TOPIC_TOGGLE}" data-update-all=".watch-topic-link">{S_WATCH_TOPIC_TITLE}</a>
+ <li>
+ <a href="{U_WATCH_TOPIC}" class="watch-topic-link" title="{S_WATCH_TOPIC_TITLE}" data-ajax="toggle_link" data-toggle-class="icon <!-- IF S_WATCHING_TOPIC -->fa-check-square-o<!-- ELSE -->fa-square-o<!-- ENDIF --> fa-fw" data-toggle-text="{S_WATCH_TOPIC_TOGGLE}" data-toggle-url="{U_WATCH_TOPIC_TOGGLE}" data-update-all=".watch-topic-link">
+ <i class="icon <!-- IF S_WATCHING_TOPIC -->fa-square-o<!-- ELSE -->fa-check-square-o<!-- ENDIF --> fa-fw" aria-hidden="true"></i><span>{S_WATCH_TOPIC_TITLE}</span>
+ </a>
</li>
<!-- ENDIF -->
<!-- IF U_BOOKMARK_TOPIC -->
- <li class="small-icon icon-bookmark">
- <a href="{U_BOOKMARK_TOPIC}" class="bookmark-link" title="{L_BOOKMARK_TOPIC}" data-ajax="alt_text" data-alt-text="{S_BOOKMARK_TOGGLE}" data-update-all=".bookmark-link">{S_BOOKMARK_TOPIC}</a>
+ <li>
+ <a href="{U_BOOKMARK_TOPIC}" class="bookmark-link" title="{L_BOOKMARK_TOPIC}" data-ajax="alt_text" data-alt-text="{S_BOOKMARK_TOGGLE}" data-update-all=".bookmark-link">
+ <i class="icon fa-bookmark-o fa-fw" aria-hidden="true"></i><span>{S_BOOKMARK_TOPIC}</span>
+ </a>
</li>
<!-- ENDIF -->
- <!-- IF U_BUMP_TOPIC --><li class="small-icon icon-bump"><a href="{U_BUMP_TOPIC}" title="{L_BUMP_TOPIC}" data-ajax="true">{L_BUMP_TOPIC}</a></li><!-- ENDIF -->
- <!-- IF U_EMAIL_TOPIC --><li class="small-icon icon-sendemail"><a href="{U_EMAIL_TOPIC}" title="{L_EMAIL_TOPIC}">{L_EMAIL_TOPIC}</a></li><!-- ENDIF -->
- <!-- IF U_PRINT_TOPIC --><li class="small-icon icon-print"><a href="{U_PRINT_TOPIC}" title="{L_PRINT_TOPIC}" accesskey="p">{L_PRINT_TOPIC}</a></li><!-- ENDIF -->
+ <!-- IF U_BUMP_TOPIC -->
+ <li>
+ <a href="{U_BUMP_TOPIC}" title="{L_BUMP_TOPIC}" data-ajax="true">
+ <i class="icon fa-level-up fa-fw" aria-hidden="true"></i><span>{L_BUMP_TOPIC}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
+ <!-- IF U_EMAIL_TOPIC -->
+ <li>
+ <a href="{U_EMAIL_TOPIC}" title="{L_EMAIL_TOPIC}">
+ <i class="icon fa-envelope-o fa-fw" aria-hidden="true"></i><span>{L_EMAIL_TOPIC}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
+ <!-- IF U_PRINT_TOPIC -->
+ <li>
+ <a href="{U_PRINT_TOPIC}" title="{L_PRINT_TOPIC}" accesskey="p">
+ <i class="icon fa-print fa-fw" aria-hidden="true"></i><span>{L_PRINT_TOPIC}</span>
+ </a>
+ </li>
+ <!-- ENDIF -->
<!-- EVENT viewtopic_topic_tools_after -->
</ul>
</div>
diff --git a/phpBB/styles/prosilver/theme/base.css b/phpBB/styles/prosilver/theme/base.css
new file mode 100644
index 0000000000..98c57d9264
--- /dev/null
+++ b/phpBB/styles/prosilver/theme/base.css
@@ -0,0 +1,115 @@
+/* --------------------------------------------------------------
+ $Base
+-------------------------------------------------------------- */
+
+/** {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+*:before,
+*:after {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}*/
+
+/* Define your base font-size here; most elements will inherit this. _NO__DOTCOMMA__AFTER__*/
+html {
+ font-size: 1em; /* Assuming 16px... */
+ line-height: 1.5; /* 24px (This is now our magic number; all subsequent margin-bottoms and line-heights want to be a multiple of this number in order to maintain vertical rhythm.) _NO__DOTCOMMA__AFTER__*/
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+body {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ color: #333333;
+ background-color: #ffffff;
+}
+
+input,
+button,
+select,
+textarea {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+}
+
+figure { margin: 0 }
+img { vertical-align: middle }
+
+hr {
+ margin-top: 20px;
+ margin-bottom: 20px;
+ border: 0;
+ border-top: 1px solid #e5e5e5;
+}
+
+a {
+ color: #428bca;
+ text-decoration: none;
+}
+
+a:hover,
+a:focus,
+a:active {
+ color: #2a6496;
+ text-decoration: underline;
+}
+
+blockquote,
+dl,
+dd,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+figure,
+p,
+pre { margin: 0 }
+button {
+ background: transparent;
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * Work around a Firefox/IE bug where the transparent `button` background
+ * results in a loss of the default `button` focus styles.
+ */
+button:focus {
+ outline: 1px dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+}
+
+fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
+iframe { border: 0 }
+ol,
+ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+/**
+ * Suppress the focus outline on links that cannot be accessed via keyboard.
+ * This prevents an unwanted focus outline from appearing around elements that
+ * might still respond to pointer events.
+ */
+[tabindex="-1"]:focus { outline: none !important }
+
+/**
+ * Remove double underline from recent version of firefox
+ */
+abbr[title] {
+ text-decoration: none;
+}
+
diff --git a/phpBB/styles/prosilver/theme/bidi.css b/phpBB/styles/prosilver/theme/bidi.css
index f3468ebcf2..79b769b1e7 100644
--- a/phpBB/styles/prosilver/theme/bidi.css
+++ b/phpBB/styles/prosilver/theme/bidi.css
@@ -13,6 +13,10 @@
text-align: left;
}
+.rtl p.jumpbox-return {
+ float: right;
+}
+
.rtl div.rules ul {
margin-left: 0;
margin-right: 20px;
@@ -20,6 +24,11 @@
/* Main blocks
---------------------------------------- */
+.rtl .icon {
+ padding-right: 0;
+ padding-left: 2px;
+}
+
.rtl .logo {
float: right;
padding: 10px 10px 0 13px;
@@ -27,11 +36,11 @@
/* Site Description
--------------------------------------------- */
-.rtl #site-description {
+.rtl .site-description {
float: right;
}
-.rtl #site-description h1 {
+.rtl .site-description h1 {
margin-left: 0;
}
@@ -81,14 +90,9 @@
padding-right: 0;
}
-.rtl ul.linklist li.responsive-menu a.responsive-menu-link:before {
- left: auto;
- right: 0;
-}
-
/* Dropdown menu
---------------------------------------- */
-.rtl .dropdown-container.topic-tools {
+.rtl .dropdown-container.topic-tools, .rtl .dropdown-container-left {
float: right;
}
@@ -114,12 +118,17 @@
text-align: right;
}
-.rtl .dropdown-extended .header .header_settings {
+.rtl .dropdown-extended .header .header_settings, .rtl .dropdown-container-right {
float: left;
}
+.rtl .jumpbox .dropdown-contents a {
+ margin-right: 0;
+ margin-left: 20px;
+}
+
/* Notifications
-----------------------------------------*/
+-----------------------------------------*/
.rtl .notification_list ul li img {
float: right;
margin-left: 5px;
@@ -230,6 +239,10 @@
/* Pagination
---------------------------------------- */
+.rtl .page-number {
+ float: left;
+}
+
.rtl .pagination {
text-align: left;
float: left;
@@ -261,23 +274,26 @@
margin-right: 0;
}
-.pagination li.previous a { background-position: -50px 2px; }
-.pagination li.next a { background-position: -30px 2px; }
-.pagination li.previous a:hover { background-position: -50px -18px; }
-.pagination li.next a:hover { background-position: -30px -18px; }
-
-/* Miscellaneous styles
+/* Action Bar styles
---------------------------------------- */
-.rtl #forum-permissions {
- float: left;
- padding-right: 5px;
- padding-left: 0;
- margin-right: 5px;
- margin-left: 0;
- text-align: left;
+.rtl .action-bar .button {
+ margin-right: 0;
+ float: right;
}
-.rtl #quick-links {
+.rtl .action-bar > .button {
+ margin-left: 5px;
+ float: right;
+}
+
+.rtl .action-bar .dropdown-button-control .button {
+ margin-left: 5px;
+}
+
+
+/* Miscellaneous styles
+---------------------------------------- */
+.rtl .quick-links {
margin-left: 7px;
margin-right: 0;
}
@@ -296,11 +312,6 @@
* links.css
*/
-/* Back to top of page */
-.rtl .back2top {
- text-align: left;
-}
-
/* Links adjustment to correctly display an order of rtl/ltr mixed content */
.rtl a {
direction: rtl;
@@ -309,7 +320,6 @@
li.breadcrumbs span:first-child > a {
padding-left: 0;
- padding-right: 19px;
}
/* Notification mark read link */
@@ -319,14 +329,9 @@ li.breadcrumbs span:first-child > a {
right: auto;
}
-.rtl a.top {
+.rtl .back2top .top {
float: left;
-}
-
-.rtl a.top2 {
- background-position: 100% 50%;
- padding-left: 0;
- padding-right: 15px;
+ margin-left: -10px;
}
.rtl .skiplink {
@@ -416,26 +421,26 @@ li.breadcrumbs span:first-child > a {
padding-right: 1px;
}
-.rtl dl.icon {
+.rtl dl.row-item{
background-position: 99.5% 50%;
}
-.rtl li.header dl.icon dt .list-inner {
+.rtl li.header dl.row-item dt .list-inner {
/* Tweak for headers alignment when folder icon used */
padding-right: 0;
padding-left: 50px;
}
-.rtl dl.icon dt {
+.rtl dl.row-item dt {
background-position: 99.5% 95%; /* Position of topic icon */
}
-.rtl dl.icon dt .list-inner {
+.rtl dl.row-item dt .list-inner {
padding-left: 5px;
padding-right: 45px; /* Space for folder icon */
}
-.rtl dl a.icon-link { /* topic row icon links */
+.rtl dl a.row-item-link { /* topic row icon links */
display: inline-block;
left: auto;
right: 0;
@@ -450,6 +455,10 @@ li.breadcrumbs span:first-child > a {
/* Post body styles
----------------------------------------*/
+.rtl .date {
+ float: left;
+}
+
.rtl .postbody, .rtl .postbody h3 {
float: right;
}
@@ -461,7 +470,6 @@ li.breadcrumbs span:first-child > a {
.rtl p.post-notice {
padding-left: 5px;
- padding-right: 26px;
}
.rtl p.post-notice:before {
@@ -471,7 +479,7 @@ li.breadcrumbs span:first-child > a {
/* Topic review panel
----------------------------------------*/
-.rtl #topicreview {
+.rtl .topicreview {
padding-right: 0;
padding-left: 5px;
}
@@ -501,7 +509,6 @@ li.breadcrumbs span:first-child > a {
/* Quote block */
.rtl blockquote {
margin: 0.5em 25px 0 1px;
- background-position: 99% 8px;
}
.rtl blockquote blockquote {
@@ -511,10 +518,13 @@ li.breadcrumbs span:first-child > a {
.rtl blockquote cite {
/* Username/source of quoter */
- margin-right: 20px;
margin-left: 0;
}
+.rtl blockquote cite:before, .rtl .uncited:before {
+ padding-left: 5px;
+}
+
.rtl blockquote .codebox {
margin-right: 0;
}
@@ -602,48 +612,12 @@ li.breadcrumbs span:first-child > a {
/**
* buttons.css
*/
-.rtl .dropdown-select {
- padding-left: 24px;
- padding-right: 8px;
-}
-
-.rtl .icon-button:before {
- float: left;
- margin-left: 0;
- margin-right: 2px;
-}
-
-.rtl .dropdown-select.icon-button:before {
- margin-left: 4px;
- margin-right: 0;
-}
-
-.rtl .dropdown-select:after {
- border-left: 0;
- border-right-style: solid;
- border-right-width: 1px;
- left: 0;
- right: auto;
-}
-
-.rtl .buttons, .rtl .buttons .button {
- float: right;
-}
-
-.rtl .buttons .button, .rtl .dropdown-select {
- margin-left: 5px;
- margin-right: 0;
-}
-
-/* Icon images
----------------------------------------- */
-.rtl .small-icon {
- background-position: 100% 50%;
-}
-.rtl .small-icon > a {
- padding-left: 0;
- padding-right: 19px;
+.rtl .caret {
+ border-right: 1px solid;
+ border-right-color: inherit;
+ border-left: none;
+ right: 6px;
}
/* Post control buttons
@@ -661,10 +635,6 @@ li.breadcrumbs span:first-child > a {
float: right;
}
-.post-buttons .icon-button:before {
- margin-right: 0;
-}
-
/* Poster contact icons
----------------------------------------*/
.rtl .contact-icons a {
@@ -687,20 +657,20 @@ li.breadcrumbs span:first-child > a {
/* Main CP box
----------------------------------------*/
-.rtl #cp-menu {
+.rtl .cp-menu {
float: right;
}
-.rtl #cp-main {
+.rtl .cp-main {
float: right;
}
-.rtl #cp-main .panel ol {
+.rtl .cp-main .panel ol {
margin-right: 2em;
margin-left: 0;
}
-.rtl #cp-main .buttons {
+.rtl .cp-main .buttons {
margin-right: 0;
margin-left: 0;
}
@@ -711,52 +681,52 @@ li.breadcrumbs span:first-child > a {
/* CP tabbed menu
----------------------------------------*/
-.rtl #tabs {
+.rtl .tabs {
margin-left: 0;
margin-right: 7px;
}
-.rtl #tabs .tab {
+.rtl .tabs .tab {
float: right;
}
-.rtl #tabs .tab > a {
+.rtl .tabs .tab > a {
margin-left: 1px;
margin-right: 0;
}
/* Mini tabbed menu used in MCP
----------------------------------------*/
-.rtl #minitabs {
+.rtl .minitabs {
float: left;
margin-right: 0;
margin-left: 7px;
}
-.rtl #minitabs .tab {
+.rtl .minitabs .tab {
float: left;
}
-.rtl #minitabs .tab > a {
+.rtl .minitabs .tab > a {
margin-right: 2px;
margin-left: 0;
}
/* Responsive tabs
----------------------------------------*/
-.rtl #tabs .dropdown {
+.rtl .tabs .dropdown {
margin-left: -2px;
}
-.rtl #tabs .dropdown li {
+.rtl .tabs .dropdown li {
text-align: left;
}
-.rtl #minitabs .dropdown {
+.rtl .minitabs .dropdown {
margin-left: -4px;
}
-.rtl #minitabs .dropdown li {
+.rtl .minitabs .dropdown li {
text-align: right;
}
@@ -764,7 +734,7 @@ li.breadcrumbs span:first-child > a {
----------------------------------------*/
@media only screen and (max-width: 900px), only screen and (max-device-width: 900px)
{
- .rtl #cp-menu, .rtl #navigation, .rtl #cp-main {
+ .rtl .cp-menu, .rtl .navigation, .rtl .cp-main {
float: none;
}
}
@@ -774,7 +744,7 @@ li.breadcrumbs span:first-child > a {
/* Preferences pane layout
----------------------------------------*/
-.rtl #cp-main h2 {
+.rtl .cp-main h2 {
margin-left: 0;
margin-right: 10px;
}
@@ -815,7 +785,7 @@ li.breadcrumbs span:first-child > a {
}
/* Avatar gallery */
-.rtl #gallery label {
+.rtl .gallery label {
float: right;
}
@@ -823,7 +793,7 @@ li.breadcrumbs span:first-child > a {
----------------------------------------*/
@media only screen and (max-width: 900px), only screen and (max-device-width: 900px)
{
- .rtl #cp-menu, .rtl #navigation, .rtl #cp-main {
+ .rtl .cp-menu, .rtl .navigation, .rtl .cp-main {
float: none;
}
}
@@ -910,6 +880,10 @@ li.breadcrumbs span:first-child > a {
padding-right: 0;
}
+.rtl .dropdown fieldset.display-options label {
+ text-align: left;
+}
+
/* Display actions for ucp and mcp pages */
.rtl fieldset.display-actions {
text-align: left;
@@ -935,7 +909,7 @@ li.breadcrumbs span:first-child > a {
----------------------------------------*/
/* Emoticons panel */
-.rtl #smiley-box {
+.rtl .smiley-box {
float: left;
}
@@ -955,16 +929,20 @@ li.breadcrumbs span:first-child > a {
padding: 3px;
}
-.rtl .search-box .button {
+.rtl .button-search,
+.button-search-end {
float: right;
}
-.rtl .search-box a.button {
+.rtl .button-search-end {
+ border-radius: 4px 0 0 4px;
border-left-width: 1px;
border-right-width: 0;
+}
+
+.rtl .search-header .button-search-end {
+ border: 0;
border-radius: 4px 0 0 4px;
- padding-left: 5px;
- padding-right: 3px;
}
.rtl .search-header {
@@ -973,47 +951,14 @@ li.breadcrumbs span:first-child > a {
margin-left: 5px;
}
-.rtl input.search {
- background-position: right 1px;
- padding-right: 17px;
- padding-left: 0;
-}
-
-
/* Form button styles
---------------------------------------- */
/** Reference: Bug #27155 */
-.rtl #wrap, .rtl .headerbar, .rtl #site-description, .rtl .navbar {
+.rtl .wrap, .rtl .headerbar, .rtl .site-description, .rtl .navbar {
position: relative;
}
-/* Former imageset */
-.rtl .imageset.forum_link, .rtl .imageset.forum_read, .rtl .imageset.forum_read_locked, .rtl .imageset.forum_read_subforum, .rtl .imageset.forum_unread, .rtl .imageset.forum_unread_locked, .rtl .imageset.forum_unread_subforum, .rtl .imageset.topic_moved, .rtl .imageset.topic_read, .rtl .imageset.topic_read_mine, .rtl .imageset.topic_read_hot, .rtl .imageset.topic_read_hot_mine, .rtl .imageset.topic_read_locked, .rtl .imageset.topic_read_locked_mine, .rtl .imageset.topic_unread, .rtl .imageset.topic_unread_mine, .rtl .imageset.topic_unread_hot, .rtl .imageset.topic_unread_hot_mine, .rtl .imageset.topic_unread_locked, .rtl .imageset.topic_unread_locked_mine, .rtl .imageset.sticky_read, .rtl .imageset.sticky_read_mine, .rtl .imageset.sticky_read_locked, .rtl .imageset.sticky_read_locked_mine, .rtl .imageset.sticky_unread, .rtl .imageset.sticky_unread_mine, .rtl .imageset.sticky_unread_locked, .rtl .imageset.sticky_unread_locked_mine, .rtl .imageset.announce_read, .rtl .imageset.announce_read_mine, .rtl .imageset.announce_read_locked, .rtl .imageset.announce_read_locked_mine, .rtl .imageset.announce_unread, .rtl .imageset.announce_unread_mine, .rtl .imageset.announce_unread_locked, .rtl .imageset.announce_unread_locked_mine, .rtl .imageset.global_read, .rtl .imageset.global_read_mine, .rtl .imageset.global_read_locked, .rtl .imageset.global_read_locked_mine, .rtl .imageset.global_unread, .rtl .imageset.global_unread_mine, .rtl .imageset.global_unread_locked, .rtl .imageset.global_unread_locked_mine, .rtl .imageset.pm_read, .rtl .imageset.pm_unread {
- padding-right: 27px;
- padding-left: 0;
-}
-.rtl .imageset.subforum_read, .rtl .imageset.subforum_unread, .rtl .imageset.icon_post_target, .rtl .imageset.icon_post_target_unread, .rtl .imageset.icon_topic_latest, .rtl .imageset.icon_topic_newest {
- padding-right: 11px;
- padding-left: 0;
-}
-.rtl .imageset.icon_back_top {
- padding-right: 11px;
- padding-left: 0;
-}
-.rtl .imageset.icon_contact_aim, .rtl .imageset.phpbb_aol-icon, .rtl .imageset.icon_contact_email, .rtl .imageset.icon_contact_icq, .rtl .imageset.phpbb_icq-icon, .rtl .imageset.icon_contact_jabber, .rtl .imageset.icon_contact_msnm, .rtl .imageset.phpbb_wlm-icon, .rtl .imageset.icon_contact_www, .rtl .imageset.phpbb_website-icon, .rtl .imageset.icon_contact_yahoo, .rtl .imageset.phpbb_yahoo-icon, .rtl .imageset.icon_post_delete, .rtl .imageset.icon_post_info, .rtl .imageset.icon_post_report, .rtl .imageset.icon_user_warn {
- padding-right: 20px;
- padding-left: 0;
-}
-.rtl .imageset.icon_topic_attach {
- padding-right: 7px;
- padding-left: 0;
-}
-.rtl .imageset.icon_topic_reported, .rtl .imageset.icon_topic_unapproved {
- padding-right: 16px;
- padding-left: 0;
-}
-
/**
* plupload.css
*/
@@ -1136,4 +1081,10 @@ li.breadcrumbs span:first-child > a {
.captcha-panel dd.captcha {
margin-right: 0;
}
+
+ .rtl p.responsive-center {
+ float: none;
+ text-align: center;
+ margin-bottom: 5px;
+ }
}
diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css
index a816c7f7f2..575c41aaef 100644
--- a/phpBB/styles/prosilver/theme/buttons.css
+++ b/phpBB/styles/prosilver/theme/buttons.css
@@ -2,125 +2,71 @@
---------------------------------------- */
.button {
- cursor: pointer;
display: inline-block;
- height: 18px;
- font-size: 1.2em;
+ padding: 2px 8px;
+ font-size: 13px;
+ font-weight: 600;
+ font-family: "Open Sans", "Droid Sans", Verdana, Arial, Helvetica;
+ line-height: 1.4;
+ text-align: center;
white-space: nowrap;
+ vertical-align: middle;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
border: 1px solid transparent;
border-radius: 4px;
- background: transparent none 0 0 repeat-x;
- padding: 2px 8px;
- font-family: "Open Sans", "Droid Sans", Verdana, Arial, Helvetica;
- position: relative;
- text-decoration: none !important;
- outline-style: none !important;
- vertical-align: bottom;
}
-.dropdown-select {
- padding-right: 24px;
+.button:focus,
+.button:hover {
+ text-decoration: none;
+ outline: none;
}
-.icon-button:before {
- background: transparent 0 0 no-repeat;
- content: '';
- display: inline-block;
- float: right;
- height: 12px;
- margin: 3px 0 0 2px;
- width: 12px;
-}
-
-.dropdown-select.icon-button:before {
- margin-right: 4px;
-}
-
-.dropdown-select:after {
- background-position: -103px 10px;
+.caret {
border-left: 1px solid;
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- height: 22px;
- width: 16px;
+ position: relative;
+ right: -6px;
}
-.dropdown-visible .dropdown-select:after, .nojs .dropdown-container:hover .dropdown-select:after {
- background-position: -103px -10px;
+.caret i {
+ vertical-align: top;
}
-.buttons, .buttons .button {
+/* Posting page styles
+----------------------------------------*/
+.button-search,
+.button-search-end {
float: left;
-}
-
-.buttons .button, .dropdown-select {
- margin-right: 5px;
-}
-
-#jumpbox .dropdown-select {
+ border-radius: 0;
margin: 0;
+ padding: 2px 5px;
}
-/* Big button images */
-.reply-icon:before, .pmreply-icon:before { background-position: -20px 0; }
-.reply-icon:hover:before, .pmreply-icon:hover:before { background-position: -20px -20px; }
-
-.post-icon:before, .newpm-icon:before, .reply-all:before { background-position: 0 0; }
-.post-icon:hover:before,
-.newpm-icon:hover:before,
-.reply-all:hover:before { background-position: 0 -20px; }
-
-.locked-icon:before { background-position: -60px 0; }
-.locked-icon:hover:before { background-position: -60px -20px; }
-
-.forwardpm-icon:before { background-position: -40px 0; }
-.forwardpm-icon:hover:before { background-position: -40px -20px; }
-
-.modtools-icon {
- font-size: 0;
+.button-search-end {
+ border-left-width: 0;
+ border-radius: 0 4px 4px 0;
}
-.tools-icon:before, .modtools-icon:before, .search-icon:before, .search-adv-icon:before {
- background-position: -80px 0;
- height: 16px;
- margin-top: 2px;
- width: 16px;
+.search-header .button-search,
+.search-header .button-search-end {
+ border-top-width: 0;
+ border-bottom-width: 0;
+ padding: 3px 5px;
}
-.dropdown-visible .tools-icon:before,
-.nojs .dropdown-container:hover .tools-icon:before { background-position: -80px -20px; }
-
-.search-icon:before { background-position: -245px 0; }
-.search-icon:hover:before { background-position: -245px -20px; }
-
-.search-adv-icon:before { background-position: -265px 0; }
-.search-adv-icon:hover:before { background-position: -265px -20px; }
-
-.modtools-icon:before { background-position: -225px 0; }
-.dropdown-visible .modtools-icon:before,
-.nojs .dropdown-container:hover .modtools-icon:before { background-position: -225px -20px; }
-
-/* Icon images
----------------------------------------- */
-.small-icon {
- background-position: 0 50%;
- background-repeat: no-repeat;
- background-image: none;
+.search-header .button-search-end {
+ border-right-width: 0;
}
-.small-icon > a {
- display: inline-block;
- padding: 0 0 0 18px;
-}
-
-ul.linklist.bulletin > li.small-icon:before {
- display: none;
-}
-
-.dropdown .small-icon > a {
- display: block;
+.button-icon-only {
+ padding-left: 3px;
+ padding-right: 3px;
}
/* Poster contact icons
@@ -157,21 +103,6 @@ ul.linklist.bulletin > li.small-icon:before {
clear: left;
}
-/* Profile icons */
-.pm-icon { background-position: 0 0; }
-.email-icon { background-position: -21px 0; }
-.jabber-icon { background-position: -80px 0; }
-.phpbb_icq-icon { background-position: -61px 0 ; }
-.phpbb_wlm-icon { background-position: -182px 0; }
-.phpbb_aol-icon { background-position: -244px 0; }
-.phpbb_website-icon { background-position: -40px 0; }
-.phpbb_youtube-icon { background-position: -98px 0; }
-.phpbb_facebook-icon { background-position: -119px 0; }
-.phpbb_googleplus-icon { background-position: -140px 0; }
-.phpbb_skype-icon { background-position: -161px 0; }
-.phpbb_twitter-icon { background-position: -203px 0; }
-.phpbb_yahoo-icon { background-position: -224px 0; }
-
/* Post control buttons
--------------------------------------------- */
.post-buttons {
@@ -193,41 +124,19 @@ ul.linklist.bulletin > li.small-icon:before {
margin-right: 3px;
}
-.post-buttons .icon-button {
- padding: 0 5px;
+.post-buttons .button, .format-buttons .button {
+ padding-left: 3px;
+ padding-right: 3px;
}
-.hastouch .post-buttons .icon-button {
- padding: 2px 8px;
+.hastouch .post-buttons {
+ margin-right: 10px;
}
-.post-buttons .icon-button span {
- display: block;
- height: 0;
- overflow: hidden;
- position: absolute;
- width: 1px;
-}
-
-.post-buttons .icon-button:before {
- margin-left: 0;
+.post-buttons .button span {
+ font-size: 0;
}
-.quote-icon:before { background-position: -122px 0; }
-.quote-icon:hover:before { background-position: -122px -21px; }
-.edit-icon:before { background-position: -137px 0; }
-.edit-icon:hover:before { background-position: -137px -21px; }
-.warn-icon:before { background-position: -208px 0; }
-.warn-icon:hover:before { background-position: -208px -21px; }
-.delete-icon:before { background-position: -152px 0; }
-.delete-icon:hover:before { background-position: -152px -21px; }
-.report-icon:before { background-position: -165px 0; }
-.report-icon:hover:before { background-position: -165px -21px; }
-.info-icon:before { background-position: -175px 0; }
-.info-icon:hover:before { background-position: -175px -21px; }
-.button.responsive-menu-link:before { background-position: -191px 0; }
-.button.responsive-menu-link:hover:before { background-position: -191px -21px; }
-
/* Responsive buttons in post body */
.post-buttons .dropdown {
top: 18px;
@@ -248,3 +157,37 @@ button::-moz-focus-inner {
padding: 0;
border: 0
}
+
+/* Deprecated as of version 3.2
+-------------------------------------------------*/
+.small-icon {
+ background-position: 0 50%;
+ background-repeat: no-repeat;
+ background-image: none;
+}
+
+.dropdown .small-icon {
+ background-position: 5px 50%;
+ padding: 5px;
+}
+
+.small-icon > a {
+ padding: 0 0 0 18px;
+}
+
+ul.linklist.bulletin > li.small-icon:before {
+ display: none;
+}
+
+.dropdown .small-icon > a {
+ display: block;
+}
+
+.rtl .small-icon {
+ background-position: 100% 50%;
+}
+
+.rtl .small-icon > a {
+ padding-left: 0;
+ padding-right: 19px;
+}
diff --git a/phpBB/styles/prosilver/theme/colours.css b/phpBB/styles/prosilver/theme/colours.css
index 9095e61369..ffaa71034f 100644
--- a/phpBB/styles/prosilver/theme/colours.css
+++ b/phpBB/styles/prosilver/theme/colours.css
@@ -26,45 +26,85 @@ hr {
border-top-color: #CCCCCC;
}
-/* Search box
---------------------------------------------- */
+/*
+--------------------------------------------------------------
+Colours and backgrounds for links.css
+-------------------------------------------------------------- */
-.search-box .inputbox,
-.search-box .inputbox:hover,
-.search-box .inputbox:focus,
-.search-box .button:hover {
- border-color: #C7C3BF;
+a { color: #105289; }
+a:hover { color: #D31141; }
+
+/* Links on gradient backgrounds */
+.forumbg .header a, .forabg .header a, th a {
+ color: #FFFFFF;
}
-.search-header {
- box-shadow: 0 0 10px #0075B0;
+.forumbg .header a:hover, .forabg .header a:hover, th a:hover {
+ color: #A8D8FF;
+}
+
+/* Notification mark read link */
+.dropdown-extended a.mark_read {
+ background-color: #FFFFFF;
+}
+
+/* Post body links */
+.postlink {
+ border-bottom-color: #368AD2;
+ color: #368AD2;
+}
+
+.postlink:visited {
+ border-bottom-color: #5D8FBD;
+ color: #5D8FBD;
+}
+
+.postlink:hover {
+ background-color: #D0E4F6;
+ color: #0D4473;
+}
+
+.signature a, .signature a:hover {
+ background-color: transparent;
+}
+
+/* Back to top of page */
+.top i {
+ color: #999999;
+}
+
+/* Arrow links */
+.arrow-left:hover, .arrow-right:hover {
+ color: #368AD2;
}
/* Round cornered boxes and backgrounds
---------------------------------------- */
-#wrap {
+.wrap {
background-color: #FFF;
border-color: #E6E9ED;
}
.headerbar {
- background-color: #12A3EB;
- background-image: url("./images/bg_header.gif");
color: #FFFFFF;
}
-.navbar {
- background-color: #cadceb;
+.headerbar, .forumbg {
+ background-color: #12A3EB;
+ background-image: -webkit-linear-gradient(top, #6ACEFF 0%, #0076B1 2px, #12A3EB 92px, #12A3EB 100%);
+ background-image: linear-gradient(to bottom, #6ACEFF 0%,#0076B1 2px,#12A3EB 92px,#12A3EB 100%);
+ background-repeat: repeat-x;
}
.forabg {
- background-color: #0076b1;
- background-image: url("./images/bg_list.gif");
+ background-color: #0076B1;
+ background-image: -webkit-linear-gradient(top, #6ACEFF 0%, #12A3EB 2px, #0076B1 92px, #0076B1 100%);
+ background-image: linear-gradient(to bottom, #6ACEFF 0%,#12A3EB 2px,#0076B1 92px,#0076B1 100%);
+ background-repeat: repeat-x;
}
-.forumbg {
- background-color: #12A3EB;
- background-image: url("./images/bg_header.gif");
+.navbar {
+ background-color: #CADCEB;
}
.panel {
@@ -89,15 +129,15 @@ table.zebra-list tr:nth-child(odd) td, ul.zebra-list li:nth-child(odd) {
}
.bg2 {
- background-color: #e1ebf2;
+ background-color: #E1EBF2;
}
table.zebra-list tr:nth-child(even) td, ul.zebra-list li:nth-child(even) {
- background-color: #e1ebf2;
+ background-color: #E1EBF2;
}
.bg3 {
- background-color: #cadceb;
+ background-color: #CADCEB;
}
.ucprowbg {
@@ -108,6 +148,10 @@ table.zebra-list tr:nth-child(even) td, ul.zebra-list li:nth-child(even) {
background-color: #E7E8EA;
}
+.site_logo {
+ background-image: url("./images/site_logo.gif");
+}
+
/* Horizontal lists
----------------------------------------*/
@@ -162,152 +206,111 @@ dl.details dd {
color: #1198D9;
}
-/* Pagination
+/* Icon styles
---------------------------------------- */
-
-.pagination li a {
- background-color: #ECEDEE;
- border-color: #B4BAC0;
- color: #5C758C;
-}
-
-.pagination li.ellipsis span {
- background-color: transparent;
- color: #000000;
-}
-
-.pagination li.active span {
- background-color: #4692BF;
- border-color: #4692BF;
- color: #FFFFFF;
+.icon.icon-blue, a:hover .icon.icon-blue {
+ color: #196db5;
}
-.pagination li a:hover, .pagination .dropdown-visible a.dropdown-trigger, .nojs .pagination .dropdown-container:hover a.dropdown-trigger {
- background-color: #368AD2;
- border-color: #368AD2;
- color: #FFFFFF;
+.icon.icon-green, a:hover .icon.icon-green{
+ color: #1b9A1B;
}
-.pagination li.next a, .pagination li.previous a, .pagination li.page-jump a {
- background-image: url("./images/icons_pagination.png");
+.icon.icon-red, a:hover .icon.icon-red{
+ color: #BC2A4D;
}
-/* Pagination in viewforum for multipage topics */
-.row .pagination {
- background-image: url("./images/icon_pages.gif");
+.icon.icon-orange, a:hover .icon.icon-orange{
+ color: #FF6600;
}
-/* Miscellaneous styles
----------------------------------------- */
-
-.copyright {
- color: #555555;
+.icon.icon-bluegray, a:hover .icon.icon-bluegray{
+ color: #536482;
}
-.error {
- color: #BC2A4D;
+.icon.icon-gray, a:hover .icon.icon-gray{
+ color: #777777;
}
-.reported {
- background-color: #F7ECEF;
+.icon.icon-lightgray, a:hover .icon.icon-lightgray{
+ color: #999999;
}
-li.reported:hover {
- background-color: #ECD5D8 !important;
-}
-.sticky, .announce {
- /* you can add a background for stickies and announcements*/
+.icon.icon-black, a:hover .icon.icon-black{
+ color: #333333;
}
-div.rules {
- background-color: #ECD5D8;
- color: #BC2A4D;
+.alert_close .icon:before {
+ background-color: #FFFFFF;
}
-p.post-notice {
- background-color: #ECD5D8;
- background-image: none;
+/* Jumpbox */
+.jumpbox .dropdown li {
+ border-top-color: #CCCCCC;
}
-p.post-notice.deleted:before {
- background-image: url("./images/icon_topic_deleted.png");
+.jumpbox-cat-link {
+ background-color: #0076b1;
+ border-top-color: #0076B1;
+ color: #FFFFFF;
}
-p.post-notice.unapproved:before {
- background-image: url("./images/icon_topic_unapproved.gif");
+.jumpbox-cat-link:hover {
+ background-color: #12A3EB;
+ border-top-color: #12A3EB;
+ color: #FFFFFF;
}
-p.post-notice.reported:before, p.post-notice.error:before {
- background-image: url("./images/icon_topic_reported.gif");
+.jumpbox-forum-link {
+ background-color: #E1EBF2;
}
-/*
---------------------------------------------------------------
-Colours and backgrounds for links.css
--------------------------------------------------------------- */
-
-a { color: #105289; }
-a:hover { color: #D31141; }
-
-/* Links on gradient backgrounds */
-.forumbg .header a, .forabg .header a, th a {
- color: #FFFFFF;
+.jumpbox-forum-link:hover {
+ background-color: #F6F4D0;
}
-.forumbg .header a:hover, .forabg .header a:hover, th a:hover {
- color: #A8D8FF;
+.jumpbox .dropdown .pointer-inner {
+ border-color: #E1EBF2 transparent;
}
-/* Notification mark read link */
-.dropdown-extended a.mark_read {
- background-color: #FFFFFF;
+.jumpbox-sub-link {
+ background-color: #E1EBF2;
}
-/* Post body links */
-.postlink {
- border-bottom-color: #368AD2;
- color: #368AD2;
+.jumpbox-sub-link:hover {
+ background-color: #F1F8FF;
}
-.postlink:visited {
- border-bottom-color: #5D8FBD;
- color: #5D8FBD;
-}
+/* Miscellaneous styles
+---------------------------------------- */
-.postlink:hover {
- background-color: #D0E4F6;
- color: #0D4473;
+.copyright {
+ color: #555555;
}
-.signature a, .signature a:hover {
- background-color: transparent;
+.error {
+ color: #BC2A4D;
}
-/* Back to top of page */
-a.top {
- background-image: url("./images/icon_back_top.gif");
+.reported {
+ background-color: #F7ECEF;
}
-a.top2 {
- background-image: url("./images/icon_back_top.gif");
+li.reported:hover {
+ background-color: #ECD5D8 !important;
}
-
-/* Arrow links */
-a.arrow-up { background-image: url("./images/arrow_up.gif"); }
-a.arrow-down { background-image: url("./images/arrow_down.gif"); }
-a.arrow-left { background-image: url("./images/arrow_left.gif"); }
-a.arrow-right { background-image: url("./images/arrow_right.gif"); }
-
-a.arrow-up:hover {
- background-color: transparent;
+.sticky, .announce {
+ /* you can add a background for stickies and announcements*/
}
-a.arrow-left:hover {
- color: #368AD2;
+div.rules {
+ background-color: #ECD5D8;
+ color: #BC2A4D;
}
-a.arrow-right:hover {
- color: #368AD2;
+p.post-notice {
+ background-color: #ECD5D8;
+ background-image: none;
}
/*
@@ -316,8 +319,10 @@ Colours and backgrounds for content.css
-------------------------------------------------------------- */
ul.forums {
- background-color: #eef5f9;
- background-image: url("./images/gradient.gif");
+ background-color: #EEF5F9; /* Old browsers */ /* FF3.6+ */
+ background-image: -webkit-linear-gradient(top, #D2E0EB 0%, #EEF5F9 100%);
+ background-image: linear-gradient(to bottom, #D2E0EB 0%,#EEF5F9 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#D2E0EB', endColorstr='#EEF5F9',GradientType=0 ); /* IE6-9 */
}
ul.topiclist li {
@@ -329,18 +334,10 @@ ul.topiclist dd {
}
.rtl ul.topiclist dd {
- border-right-color: #fff;
+ border-right-color: #FFFFFF;
border-left-color: transparent;
}
-ul.topiclist li.row dt a.subforum.read {
- background-image: url("./images/subforum_read.gif");
-}
-
-ul.topiclist li.row dt a.subforum.unread {
- background-image: url("./images/subforum_unread.gif");
-}
-
li.row {
border-top-color: #FFFFFF;
border-bottom-color: #00608F;
@@ -412,14 +409,9 @@ dl.faq dt {
/* Quote block */
blockquote {
background-color: #EBEADD;
- background-image: url("./images/quote.gif");
border-color:#DBDBCE;
}
-.rtl blockquote {
- background-image: url("./images/quote_rtl.gif");
-}
-
blockquote blockquote {
/* Nested quotes */
background-color:#EFEED9;
@@ -444,13 +436,6 @@ blockquote blockquote blockquote {
color: #2E8B57;
}
-.syntaxbg { color: #FFFFFF; }
-.syntaxcomment { color: #FF8000; }
-.syntaxdefault { color: #0000BB; }
-.syntaxhtml { color: #000000; }
-.syntaxkeyword { color: #007700; }
-.syntaxstring { color: #DD0000; }
-
/* Attachments
----------------------------------------*/
.attachbox {
@@ -600,130 +585,165 @@ Colours and backgrounds for buttons.css
-------------------------------------------------------------- */
.button {
border-color: #C7C3BF;
- background-color: #FFFFFF;
- background-image: -moz-linear-gradient(top, #FFFFFF, #E9E9E9);
- background-image: -webkit-linear-gradient(top, #FFFFFF, #E9E9E9);
- background-image: -o-linear-gradient(top, #FFFFFF, #E9E9E9);
- background-image: linear-gradient(to bottom, #FFFFFF, #E9E9E9);
- -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#FFFFFF', EndColorStr='#E9E9E9')";
+ background-color: #E9E9E9; /* Old browsers */ /* FF3.6+ */
+ background-image: -webkit-linear-gradient(top, #FFFFFF 0%, #E9E9E9 100%);
+ background-image: linear-gradient(to bottom, #FFFFFF 0%,#E9E9E9 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#E9E9E9',GradientType=0 ); /* IE6-9 */
box-shadow: 0 0 0 1px #FFFFFF inset;
-webkit-box-shadow: 0 0 0 1px #FFFFFF inset;
color: #D31141;
}
-.dropdown-select {
- color: #536482;
+.button:hover,
+.button:focus {
+ border-color: #0A8ED0;
+ background-color: #FFFFFF; /* Old browsers */ /* FF3.6+ */
+ background-image: -webkit-linear-gradient(top, #E9E9E9 0%, #FFFFFF 100%);
+ background-image: linear-gradient(to bottom, #E9E9E9 0%,#FFFFFF 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#E9E9E9', endColorstr='#FFFFFF',GradientType=0 ); /* IE6-9 */
+ text-shadow: 1px 1px 0 #FFFFFF, -1px -1px 0 #FFFFFF, -1px -1px 0 rgba(188, 42, 77, 0.2);
}
-.button:hover, .dropdown-visible .dropdown-select, .nojs .dropdown-container:hover .dropdown-select {
- border-color: #0a8ed0;
- background-image: -moz-linear-gradient(top, #E9E9E9, #FFFFFF);
- background-image: -webkit-linear-gradient(top, #E9E9E9, #FFFFFF);
- background-image: -o-linear-gradient(top, #E9E9E9, #FFFFFF);
- background-image: linear-gradient(to bottom, #E9E9E9, #FFFFFF);
- -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#E9E9E9', EndColorStr='#FFFFFF')";
- text-shadow: 1px 1px 0 #FFFFFF, -1px -1px 0 #FFFFFF, -1px -1px 0 rgba(188, 42, 77, 0.2);
+
+.button .icon,
+.button-secondary {
+ color: #8f8f8f;
}
-.dropdown-select:after { border-color: #DADADA; }
-.dropdown-select:hover { border-color: #C7C3BF; }
+.button-secondary:focus,
+.button-secondary:hover,
+.button:focus .icon,
+.button:hover .icon {
+ color: #0A8ED0;
+}
-.dropdown-visible .dropdown-select, .dropdown-visible .dropdown-select:hover, .nojs .dropdown-container:hover .dropdown-select {
- border-color: #A6B2BA;
- color: #105289;
+.button-search:hover,
+.button-search-end:hover {
+ border-color: #C7C3BF;
}
+.caret { border-color: #DADADA; }
+.caret { border-color: #C7C3BF; }
+
.contact-icons a { border-color: #DCDCDC; }
.contact-icons a:hover { background-color: #F2F6F9; }
+/* Pagination
+---------------------------------------- */
+
+.pagination li a {
+ background: #ECEDEE;
+ filter: none;
+ border-color: #B4BAC0;
+ box-shadow: none;
+ -webkit-box-shadow: none;
+ color: #5C758C;
+}
+
+.pagination li.ellipsis span {
+ background: transparent;
+ color: #000000;
+}
+
+.pagination li.active span {
+ background: #4692BF;
+ border-color: #4692BF;
+ color: #FFFFFF;
+}
+
+.pagination li a:hover, .pagination li a:hover .icon, .pagination .dropdown-visible a.dropdown-trigger, .nojs .pagination .dropdown-container:hover a.dropdown-trigger {
+ background: #368AD2;
+ border-color: #368AD2;
+ filter: none;
+ color: #FFFFFF;
+ text-shadow: none;
+}
+
+/* Search box
+--------------------------------------------- */
+
+.search-box .inputbox,
+.search-box .inputbox:hover,
+.search-box .inputbox:focus {
+ border-color: #C7C3BF;
+}
+
+.search-header {
+ box-shadow: 0 0 10px #0075B0;
+}
+
/* Icon images
---------------------------------------- */
-.icon-acp { background-image: url("./images/icon_acp.gif"); }
-.icon-bookmark { background-image: url("./images/icon_bookmark.gif"); }
-.icon-bump { background-image: url("./images/icon_bump.gif"); }
-.icon-contact { background-image: url("./images/icon_pm.gif"); }
-.icon-delete-cookies { background-image: url("./images/icon_delete_cookies.gif"); }
-.icon-download { background-image: url("./images/icon_download.gif"); }
-.icon-faq { background-image: url("./images/icon_faq.gif"); }
-.icon-home { background-image: url("./images/icon_home.gif"); }
-.icon-logout { background-image: url("./images/icon_logout.gif"); }
-.icon-mark { background-image: url("./images/icon_mark.gif"); }
-.icon-mcp { background-image: url("./images/icon_mcp.gif"); }
-.icon-members { background-image: url("./images/icon_members.gif"); }
-.icon-notification { background-image: url("./images/icon_notification.gif"); }
-.icon-pages { background-image: url("./images/icon_pages.gif"); }
-.icon-pm { background-image: url("./images/icon_pm.gif"); }
-.icon-print { background-image: url("./images/icon_print.gif"); }
-.icon-profile { background-image: url("./images/icon_profile.gif"); }
-.icon-register { background-image: url("./images/icon_register.gif"); }
-.icon-search, .responsive-search a { background-image: url("./images/icon_search.gif"); }
-.icon-search-active { background-image: url("./images/subforum_read.gif"); }
-.icon-search-new { background-image: url("./images/subforum_unread.gif"); }
-.icon-search-self { background-image: url("./images/icon_topic_latest.gif"); }
-.icon-search-unanswered { background-image: url("./images/icon_post_target.gif"); }
-.icon-search-unread { background-image: url("./images/subforum_unread.gif"); }
-.icon-sendemail { background-image: url("./images/icon_sendemail.gif"); }
-.icon-subscribe { background-image: url("./images/icon_subscribe.gif"); }
-.icon-team { background-image: url("./images/icon_team.gif"); }
-.icon-ucp { background-image: url("./images/icon_ucp.gif"); }
-.icon-unsubscribe { background-image: url("./images/icon_unsubscribe.gif"); }
+
+.contact-icon { background-image: url("./images/icons_contact.png"); }
/* Profile & navigation icons */
-.contact-icon { background-image: url("./images/icons_contact.png"); }
-.icon-button:before, .dropdown-select:after { background-image: url("./images/icons_button.png"); }
+.pm-icon { background-position: 0 0; }
+.email-icon { background-position: -21px 0; }
+.jabber-icon { background-position: -80px 0; }
+.phpbb_icq-icon { background-position: -61px 0 ; }
+.phpbb_wlm-icon { background-position: -182px 0; }
+.phpbb_aol-icon { background-position: -244px 0; }
+.phpbb_website-icon { background-position: -40px 0; }
+.phpbb_youtube-icon { background-position: -98px 0; }
+.phpbb_facebook-icon { background-position: -119px 0; }
+.phpbb_googleplus-icon { background-position: -140px 0; }
+.phpbb_skype-icon { background-position: -161px 0; }
+.phpbb_twitter-icon { background-position: -203px 0; }
+.phpbb_yahoo-icon { background-position: -224px 0; }
/* Forum icons & Topic icons */
-.global_read { background-image: url("./images/announce_read.gif"); }
-.global_read_mine { background-image: url("./images/announce_read_mine.gif"); }
-.global_read_locked { background-image: url("./images/announce_read_locked.gif"); }
-.global_read_locked_mine { background-image: url("./images/announce_read_locked_mine.gif"); }
-.global_unread { background-image: url("./images/announce_unread.gif"); }
-.global_unread_mine { background-image: url("./images/announce_unread_mine.gif"); }
-.global_unread_locked { background-image: url("./images/announce_unread_locked.gif"); }
-.global_unread_locked_mine { background-image: url("./images/announce_unread_locked_mine.gif"); }
-
-.announce_read { background-image: url("./images/announce_read.gif"); }
-.announce_read_mine { background-image: url("./images/announce_read_mine.gif"); }
-.announce_read_locked { background-image: url("./images/announce_read_locked.gif"); }
-.announce_read_locked_mine { background-image: url("./images/announce_read_locked_mine.gif"); }
-.announce_unread { background-image: url("./images/announce_unread.gif"); }
-.announce_unread_mine { background-image: url("./images/announce_unread_mine.gif"); }
-.announce_unread_locked { background-image: url("./images/announce_unread_locked.gif"); }
-.announce_unread_locked_mine { background-image: url("./images/announce_unread_locked_mine.gif"); }
-
-.forum_link { background-image: url("./images/forum_link.gif"); }
-.forum_read { background-image: url("./images/forum_read.gif"); }
-.forum_read_locked { background-image: url("./images/forum_read_locked.gif"); }
-.forum_read_subforum { background-image: url("./images/forum_read_subforum.gif"); }
-.forum_unread { background-image: url("./images/forum_unread.gif"); }
-.forum_unread_locked { background-image: url("./images/forum_unread_locked.gif"); }
-.forum_unread_subforum { background-image: url("./images/forum_unread_subforum.gif"); }
-
-.sticky_read { background-image: url("./images/sticky_read.gif"); }
-.sticky_read_mine { background-image: url("./images/sticky_read_mine.gif"); }
-.sticky_read_locked { background-image: url("./images/sticky_read_locked.gif"); }
-.sticky_read_locked_mine { background-image: url("./images/sticky_read_locked_mine.gif"); }
-.sticky_unread { background-image: url("./images/sticky_unread.gif"); }
-.sticky_unread_mine { background-image: url("./images/sticky_unread_mine.gif"); }
-.sticky_unread_locked { background-image: url("./images/sticky_unread_locked.gif"); }
-.sticky_unread_locked_mine { background-image: url("./images/sticky_unread_locked_mine.gif"); }
-
-.topic_moved { background-image: url("./images/topic_moved.gif"); }
-.topic_read { background-image: url("./images/topic_read.gif"); }
-.topic_read_mine { background-image: url("./images/topic_read_mine.gif"); }
-.topic_read_hot { background-image: url("./images/topic_read_hot.gif"); }
-.topic_read_hot_mine { background-image: url("./images/topic_read_hot_mine.gif"); }
-.topic_read_locked { background-image: url("./images/topic_read_locked.gif"); }
-.topic_read_locked_mine { background-image: url("./images/topic_read_locked_mine.gif"); }
-.topic_unread { background-image: url("./images/topic_unread.gif"); }
-.topic_unread_mine { background-image: url("./images/topic_unread_mine.gif"); }
-.topic_unread_hot { background-image: url("./images/topic_unread_hot.gif"); }
-.topic_unread_hot_mine { background-image: url("./images/topic_unread_hot_mine.gif"); }
-.topic_unread_locked { background-image: url("./images/topic_unread_locked.gif"); }
-.topic_unread_locked_mine { background-image: url("./images/topic_unread_locked_mine.gif"); }
-
-.pm_read { background-image: url("./images/topic_read.gif"); }
-.pm_unread { background-image: url("./images/topic_unread.gif"); }
+.global_read { background-image: url("./images/announce_read.gif"); }
+.global_read_mine { background-image: url("./images/announce_read_mine.gif"); }
+.global_read_locked { background-image: url("./images/announce_read_locked.gif"); }
+.global_read_locked_mine { background-image: url("./images/announce_read_locked_mine.gif"); }
+.global_unread { background-image: url("./images/announce_unread.gif"); }
+.global_unread_mine { background-image: url("./images/announce_unread_mine.gif"); }
+.global_unread_locked { background-image: url("./images/announce_unread_locked.gif"); }
+.global_unread_locked_mine { background-image: url("./images/announce_unread_locked_mine.gif"); }
+
+.announce_read { background-image: url("./images/announce_read.gif"); }
+.announce_read_mine { background-image: url("./images/announce_read_mine.gif"); }
+.announce_read_locked { background-image: url("./images/announce_read_locked.gif"); }
+.announce_read_locked_mine { background-image: url("./images/announce_read_locked_mine.gif"); }
+.announce_unread { background-image: url("./images/announce_unread.gif"); }
+.announce_unread_mine { background-image: url("./images/announce_unread_mine.gif"); }
+.announce_unread_locked { background-image: url("./images/announce_unread_locked.gif"); }
+.announce_unread_locked_mine { background-image: url("./images/announce_unread_locked_mine.gif"); }
+
+.forum_link { background-image: url("./images/forum_link.gif"); }
+.forum_read { background-image: url("./images/forum_read.gif"); }
+.forum_read_locked { background-image: url("./images/forum_read_locked.gif"); }
+.forum_read_subforum { background-image: url("./images/forum_read_subforum.gif"); }
+.forum_unread { background-image: url("./images/forum_unread.gif"); }
+.forum_unread_locked { background-image: url("./images/forum_unread_locked.gif"); }
+.forum_unread_subforum { background-image: url("./images/forum_unread_subforum.gif"); }
+
+.sticky_read { background-image: url("./images/sticky_read.gif"); }
+.sticky_read_mine { background-image: url("./images/sticky_read_mine.gif"); }
+.sticky_read_locked { background-image: url("./images/sticky_read_locked.gif"); }
+.sticky_read_locked_mine { background-image: url("./images/sticky_read_locked_mine.gif"); }
+.sticky_unread { background-image: url("./images/sticky_unread.gif"); }
+.sticky_unread_mine { background-image: url("./images/sticky_unread_mine.gif"); }
+.sticky_unread_locked { background-image: url("./images/sticky_unread_locked.gif"); }
+.sticky_unread_locked_mine { background-image: url("./images/sticky_unread_locked_mine.gif"); }
+
+.topic_moved { background-image: url("./images/topic_moved.gif"); }
+.pm_read,
+.topic_read { background-image: url("./images/topic_read.gif"); }
+.topic_read_mine { background-image: url("./images/topic_read_mine.gif"); }
+.topic_read_hot { background-image: url("./images/topic_read_hot.gif"); }
+.topic_read_hot_mine { background-image: url("./images/topic_read_hot_mine.gif"); }
+.topic_read_locked { background-image: url("./images/topic_read_locked.gif"); }
+.topic_read_locked_mine { background-image: url("./images/topic_read_locked_mine.gif"); }
+.pm_unread,
+.topic_unread { background-image: url("./images/topic_unread.gif"); }
+.topic_unread_mine { background-image: url("./images/topic_unread_mine.gif"); }
+.topic_unread_hot { background-image: url("./images/topic_unread_hot.gif"); }
+.topic_unread_hot_mine { background-image: url("./images/topic_unread_hot_mine.gif"); }
+.topic_unread_locked { background-image: url("./images/topic_unread_locked.gif"); }
+.topic_unread_locked_mine { background-image: url("./images/topic_unread_locked_mine.gif"); }
+
/*
--------------------------------------------------------------
@@ -733,7 +753,7 @@ Colours and backgrounds for cp.css
/* Main CP box
----------------------------------------*/
-.panel-container h3, .panel-container hr, #cp-menu hr {
+.panel-container h3, .panel-container hr, .cp-menu hr {
border-color: #A4B3BF;
}
@@ -755,50 +775,46 @@ ul.cplist {
border-bottom-color: #333333;
}
-#cp-main .pm-message {
+.cp-main .pm-message {
border-color: #DBDEE2;
background-color: #FFFFFF;
}
/* CP tabbed menu
----------------------------------------*/
-#tabs .tab > a {
+.tabs .tab > a {
background: #BACCD9;
color: #536482;
}
-#tabs .tab > a:hover {
+.tabs .tab > a:hover {
background: #DDEDFB;
color: #D31141;
}
-#tabs .activetab > a,
-#tabs .activetab > a:hover {
- background: #CADCEB;
- background: -moz-linear-gradient(top, #E2F2FF 0%, #CADCEB 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #E2F2FF), color-stop(100%, #CADCEB));
- background: -webkit-linear-gradient(top, #E2F2FF 0%, #CADCEB 100%);
- background: -o-linear-gradient(top, #E2F2FF 0%, #CADCEB 100%);
- background: -ms-linear-gradient(top, #E2F2FF 0%, #CADCEB 100%);
- background: linear-gradient(to bottom, #E2F2FF 0%, #CADCEB 100%);
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#E2F2FF', endColorstr='#CADCEB', GradientType=0 );
+.tabs .activetab > a,
+.tabs .activetab > a:hover {
+ background-color: #CADCEB; /* Old browsers */ /* FF3.6+ */
+ background-image: -webkit-linear-gradient(top, #E2F2FF 0%, #CADCEB 100%);
+ background-image: linear-gradient(to bottom, #E2F2FF 0%,#CADCEB 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#E2F2FF', endColorstr='#CADCEB',GradientType=0 ); /* IE6-9 */
border-color: #CADCEB;
box-shadow: 0 1px 1px #F2F9FF inset;
color: #333333;
}
-#tabs .activetab > a:hover {
+.tabs .activetab > a:hover {
color: #000000;
}
/* Mini tabbed menu used in MCP
----------------------------------------*/
-#minitabs .tab > a {
+.minitabs .tab > a {
background-color: #E1EBF2;
}
-#minitabs .activetab > a,
-#minitabs .activetab > a:hover {
+.minitabs .activetab > a,
+.minitabs .activetab > a:hover {
background-color: #F9F9F9;
color: #333333;
}
@@ -817,42 +833,34 @@ ul.cplist {
----------------------------------------*/
/* Link styles for the sub-section links */
-#navigation a {
+.navigation a {
color: #333;
- background: #B4C4D1;
- background: -moz-linear-gradient(left, #B4C4D1 50%, #CADCEB 100%);
- background: -webkit-gradient(left top, right top, color-stop(50%, #B4C4D1), color-stop(100%, #CADCEB));
+ background: #CADCEB; /* Old browsers */ /* FF3.6+ */
background: -webkit-linear-gradient(left, #B4C4D1 50%, #CADCEB 100%);
- background: -o-linear-gradient(left, #B4C4D1 50%, #CADCEB 100%);
- background: -ms-linear-gradient(left, #B4C4D1 50%, #CADCEB 100%);
- background: linear-gradient(to right, #B4C4D1 50%, #CADCEB 100%);
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#B4C4D1', endColorstr='#CADCEB', GradientType=1 );
+ background: linear-gradient(to right, #B4C4D1 50%,#CADCEB 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#B4C4D1', endColorstr='#CADCEB',GradientType=1 ); /* IE6-9 */
}
-.rtl #navigation a {
- background: #B4C4D1;
- background: -moz-linear-gradient(left, #CADCEB 0%, #B4C4D1 50%);
- background: -webkit-gradient(left top, right top, color-stop(0%, #CADCEB), color-stop(50%, #B4C4D1));
- background: -webkit-linear-gradient(left, #CADCEB 0%, #B4C4D1 50%);
- background: -o-linear-gradient(left, #CADCEB 0%, #B4C4D1 50%);
- background: -ms-linear-gradient(left, #CADCEB 0%, #B4C4D1 50%);
- background: linear-gradient(to right, #CADCEB 0%, #B4C4D1 50%);
- filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#CADCEB', endColorstr='#B4C4D1', GradientType=1 );
+.rtl .navigation a {
+ background: #B4C4D1; /* Old browsers */ /* FF3.6+ */
+ background: -webkit-linear-gradient(left, #CADCEB 50%, #B4C4D1 100%);
+ background: linear-gradient(to right, #CADCEB 50%,#B4C4D1 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#CADCEB', endColorstr='#B4C4D1',GradientType=1 ); /* IE6-9 */
}
-#navigation a:hover {
+.navigation a:hover {
background: #AABAC6;
color: #BC2A4D;
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-#navigation #active-subsection a {
+.navigation .active-subsection a {
background: #F9F9F9;
color: #D31141;
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}
-#navigation #active-subsection a:hover {
+.navigation .active-subsection a:hover {
color: #D31141;
}
@@ -873,13 +881,13 @@ ul.cplist {
background-color: #F9F9F9;
}
-#cp-main .pm {
+.cp-main .pm {
background-color: #FFFFFF;
}
/* Friends list */
.cp-mini {
- background-color: #eef5f9;
+ background-color: #EEF5F9;
}
dl.mini dt {
@@ -916,12 +924,12 @@ dl.mini dt {
}
/* Avatar gallery */
-#gallery label {
+.gallery label {
background: #FFFFFF;
border-color: #CCC;
}
-#gallery label:hover {
+.gallery label:hover {
background-color: #EEE;
}
@@ -973,15 +981,15 @@ fieldset.quick-login input.inputbox {
/* Posting page styles
----------------------------------------*/
-#message-box textarea {
+.message-box textarea {
color: #333333;
}
-#message-box textarea.drag-n-drop {
+.message-box textarea.drag-n-drop {
outline-color: rgba(102, 102, 102, 0.5);
}
-#message-box textarea.drag-n-drop-highlight {
+.message-box textarea.drag-n-drop-highlight {
outline-color: rgba(17, 163, 234, 0.5);
}
@@ -1007,7 +1015,6 @@ fieldset.quick-login input.inputbox {
.inputbox:focus {
border-color: #11A3EA;
- color: #0F4987;
}
.inputbox:focus:-moz-placeholder {
@@ -1024,8 +1031,10 @@ fieldset.quick-login input.inputbox {
a.button1, input.button1, input.button3, a.button2, input.button2 {
color: #000;
- background-color: #FAFAFA;
- background-image: url("./images/bg_button.gif");
+ background-color: #EFEFEF; /* Old browsers */ /* FF3.6+ */
+ background-image: -webkit-linear-gradient(top, #D2D2D2 0%, #EFEFEF 100%);
+ background-image: linear-gradient(to bottom, #D2D2D2 0%,#EFEFEF 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#D2D2D2', endColorstr='#EFEFEF',GradientType=0 ); /* IE6-9 */
}
a.button1, input.button1 {
@@ -1048,8 +1057,12 @@ a.button1, a.button2 {
/* Hover states */
a.button1:hover, input.button1:hover, a.button2:hover, input.button2:hover, input.button3:hover {
- border-color: #BC2A4D;
- color: #BC2A4D;
+ border-color: #D31141;
+ color: #D31141;
+ background-color: #D2D2D2; /* Old browsers */ /* FF3.6+ */
+ background-image: -webkit-linear-gradient(top, #EFEFEF 0%, #D2D2D2 100%);
+ background-image: linear-gradient(to bottom, #EFEFEF 0%,#D2D2D2 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#EFEFEF', endColorstr='#D2D2D2',GradientType=0 ); /* IE6-9 */
}
/* Focus states */
@@ -1058,10 +1071,6 @@ input.button1:focus, input.button2:focus, input.button3:focus {
color: #0F4987;
}
-input.search {
- background-image: url("./images/icon_textbox_search.gif");
-}
-
input.disabled {
color: #666666;
}
@@ -1072,14 +1081,11 @@ input.disabled {
background-color: #FFFFFF;
border-color: #999999;
}
-.phpbb_alert .alert_close {
- background-image: url("./images/alert_close.png");
-}
-#darken {
+.darken {
background-color: #000000;
}
-#loading_indicator {
+.loading_indicator {
background-color: #000000;
background-image: url("./images/loading.gif");
}
@@ -1104,13 +1110,10 @@ input.disabled {
}
.dropdown-extended .header {
- background: #F1F8FF;
- background: -moz-linear-gradient(top, #F1F8FF 0%, #CADCEB 100%);
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #F1F8FF), color-stop(100%, #CADCEB));
- background: -webkit-linear-gradient(top, #F1F8FF 0%, #CADCEB 100%);
- background: -o-linear-gradient(top, #F1F8FF 0%, #CADCEB 100%);
- background: -ms-linear-gradient(top, #F1F8FF 0%, #CADCEB 100%);
- background: linear-gradient(to bottom, #F1F8FF 0%, #CADCEB 100%);
+ background-color: #F1F8FF; /* Old browsers */ /* FF3.6+ */
+ background-image: -webkit-linear-gradient(top, #F1F8FF 0%, #CADCEB 100%);
+ background-image: linear-gradient(to bottom, #F1F8FF 0%,#CADCEB 100%); /* W3C */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F1F8FF', endColorstr='#CADCEB',GradientType=0 ); /* IE6-9 */
}
.dropdown .pointer {
@@ -1125,17 +1128,9 @@ input.disabled {
border-color: #F1F8FF transparent;
}
-ul.linklist li.responsive-menu a.responsive-menu-link:before {
- border-color: #105289;
-}
-
-ul.linklist li.responsive-menu a.responsive-menu-link:hover:before, ul.linklist li.responsive-menu.visible a.responsive-menu-link:before {
- border-color: #D31141;
-}
-
.dropdown .dropdown-contents {
background: #fff;
- border-color: #b9b9b9;
+ border-color: #B9B9B9;
box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
}
diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css
index df923aa948..a0dc5e043b 100644
--- a/phpBB/styles/prosilver/theme/common.css
+++ b/phpBB/styles/prosilver/theme/common.css
@@ -1,52 +1,3 @@
-/* CSS Reset http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126
----------------------------------------- */
-html, body, div, span, applet, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-a, abbr, acronym, address, big, cite, code,
-del, dfn, em, img, ins, kbd, q, s, samp,
-small, strike, strong, sub, sup, tt, var,
-b, u, i, center,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td,
-article, aside, canvas, details, embed,
-figure, figcaption, footer, header, hgroup,
-menu, nav, output, ruby, section, summary,
-time, mark, audio, video {
- margin: 0;
- padding: 0;
- border: 0;
- font-size: 100%;
- font: inherit;
- vertical-align: baseline;
-}
-/* HTML5 display-role reset for older browsers */
-article, aside, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section {
- display: block;
-}
-body {
- line-height: 1;
-}
-ol, ul {
- list-style: none;
-}
-blockquote, q {
- quotes: none;
-}
-blockquote:before, blockquote:after,
-q:before, q:after {
- content: '';
- content: none;
-}
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-abbr {
- text-decoration: none;
-}
-
/* General Markup Styles
---------------------------------------- */
html {
@@ -182,10 +133,11 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul {
list-style-type: square;
}
+a:hover { text-decoration: underline; }
/* Main blocks
---------------------------------------- */
-#wrap {
+.wrap {
border: 1px solid transparent;
border-radius: 8px;
margin: 0 auto;
@@ -195,21 +147,21 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul {
}
@media only screen and (max-width: 1220px), only screen and (max-device-width: 1220px) {
- #wrap {
+ .wrap {
margin: 0 12px;
}
}
-#page-body {
+.page-body {
margin: 4px 0;
clear: both;
}
-#page-footer {
+.page-footer {
clear: both;
}
-#page-footer h3 {
+.page-footer h3 {
margin-top: 20px;
}
@@ -223,20 +175,25 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul {
text-decoration: none;
}
+.site_logo {
+ display: inline-block;
+ width: 149px;
+ height: 52px;
+}
+
/* Site description and logo */
-#site-description {
+.site-description {
float: left;
width: 65%;
}
-#site-description h1 {
+.site-description h1 {
margin-right: 0;
}
/* Round cornered boxes and backgrounds
---------------------------------------- */
.headerbar {
- background: transparent none repeat-x 0 0;
margin-bottom: 4px;
padding: 5px;
border-radius: 7px;
@@ -248,7 +205,6 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul {
}
.forabg {
- background: transparent none repeat-x 0 0;
margin-bottom: 4px;
padding: 5px;
clear: both;
@@ -256,7 +212,6 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul {
}
.forumbg {
- background: transparent none repeat-x 0 0;
margin-bottom: 4px;
padding: 5px;
clear: both;
@@ -286,6 +241,7 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul {
----------------------------------------*/
.navbar ul.linklist {
padding: 2px 0;
+ list-style-type: none;
}
ul.linklist {
@@ -293,7 +249,7 @@ ul.linklist {
margin: 0;
}
-#cp-main .panel {
+.cp-main .panel {
padding: 5px 10px;
}
@@ -334,28 +290,7 @@ ul.rightside {
ul.linklist li.responsive-menu {
position: relative;
- margin: 0 5px;
-}
-
-ul.linklist li.responsive-menu a.responsive-menu-link {
- display: inline-block;
- margin: 0 5px;
- font-size: 1.455em;
- position: relative;
- width: 16px;
- line-height: 1.2em;
- text-decoration: none;
-}
-
-ul.linklist li.responsive-menu a.responsive-menu-link:before {
- content: '';
- position: absolute;
- left: 0;
- top: 7px;
- height: .125em;
- width: 14px;
- border-bottom: 0.125em solid transparent;
- border-top: 0.375em double transparent;
+ margin: 0 5px 0 0;
}
.hasjs ul.linklist.leftside, .hasjs ul.linklist.rightside {
@@ -412,24 +347,25 @@ ul.linklist.bulletin > li.no-bulletin:before {
vertical-align: top;
}
-.header-avatar:hover {
+a.header-avatar,
+a.header-avatar:hover {
text-decoration: none;
}
-.header-avatar img {
+a.header-avatar img {
margin-bottom: 2px;
max-height: 20px;
vertical-align: middle;
width: auto;
}
-.header-avatar span:after {
- content: '\25BC';
+a.header-avatar span:after {
+ content: '\f0dd';
display: inline-block;
- font-size: 9px;
- float: right;
- padding-left: 2px;
- opacity: 0.7;
+ font: normal normal normal 14px/1 FontAwesome;
+ padding-left: 6px;
+ padding-top: 2px;
+ vertical-align: top;
}
/* Dropdown menu
@@ -451,6 +387,7 @@ ul.linklist.bulletin > li.no-bulletin:before {
}
.dropdown {
+ display: none;
position: absolute;
left: 0;
top: 1.2em;
@@ -511,12 +448,12 @@ ul.linklist.bulletin > li.no-bulletin:before {
.dropdown .pointer {
right: auto;
left: 10px;
- top: 0;
+ top: -1px;
z-index: 3;
}
.dropdown-up .pointer {
- bottom: 0;
+ bottom: -1px;
top: auto;
}
@@ -544,22 +481,72 @@ ul.linklist.bulletin > li.no-bulletin:before {
border-radius: 5px;
padding: 5px;
position: relative;
- min-width: 40px;
max-height: 300px;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
+}
+
+.dropdown-contents a {
+ display: block;
+ padding: 5px;
+}
+
+.jumpbox {
+ margin: 5px 0;
+}
+
+.jumpbox .dropdown li {
+ border-top: 1px solid transparent;
+}
+
+.jumpbox .dropdown-select {
+ margin: 0;
+}
+
+.jumpbox .dropdown-contents {
+ padding: 0;
+ text-decoration: none;
+}
+
+.jumpbox .dropdown-contents li {
+ padding: 0;
+}
+
+.jumpbox .dropdown-contents a {
+ margin-right: 20px;
+ padding: 5px 10px;
+ text-decoration: none;
+ width: 100%;
+}
+
+.jumpbox .spacer {
+ display: inline-block;
+ width: 0px;
+}
+
+.jumpbox .spacer + .spacer {
+ width: 20px;
+}
+
+.dropdown-contents a {
+ display: block;
+ padding: 5px;
+}
+
+.jumpbox .dropdown-select {
+ margin: 0;
+}
+
+.jumpbox .dropdown-contents a {
+ text-decoration: none;
}
.dropdown li {
+ display: list-item;
border-top: 1px dotted transparent;
float: none !important;
line-height: normal !important;
font-size: 1em !important;
list-style: none;
margin: 0;
- padding-top: 4px;
- padding-bottom: 4px;
white-space: nowrap;
text-align: left;
}
@@ -595,7 +582,6 @@ ul.linklist.bulletin > li.no-bulletin:before {
.dropdown li.separator {
border-top: 1px solid transparent;
- margin: 4px 0;
padding: 0;
}
@@ -622,7 +608,6 @@ ul.linklist.bulletin > li.no-bulletin:before {
}
.breadcrumbs .crumb a {
- display: inline-block;
white-space: nowrap;
text-overflow: ellipsis;
vertical-align: bottom;
@@ -645,7 +630,7 @@ table.table1 {
width: 100%;
}
-#ucp-main table.table1 {
+.ucp-main table.table1 {
padding: 2px;
}
@@ -717,7 +702,7 @@ table.info tbody th {
margin: 0 -1px;
}
-#color_palette_placeholder table {
+.color_palette_placeholder table {
border-collapse: separate;
border-spacing: 1px;
}
@@ -812,7 +797,7 @@ fieldset.fields1 dl.pmlist dd.recipients {
/* Action-bars (container for post/reply buttons, pagination, etc.)
---------------------------------------- */
.action-bar {
- font-size: 1.1em;
+ font-size: 11px;
margin: 4px 0;
}
@@ -820,19 +805,32 @@ fieldset.fields1 dl.pmlist dd.recipients {
margin-top: 2em;
}
+.action-bar .button {
+ margin-right: 5px;
+ float: left;
+}
+
+.action-bar .button-search {
+ margin-right: 0;
+}
+
/* Pagination
---------------------------------------- */
.pagination {
float: right;
- margin-top: 3px;
text-align: right;
width: auto;
}
-.action-bar.bottom .pagination {
+.action-bar.bar-bottom .pagination {
margin-top: 0;
}
+.action-bar .pagination .button {
+ margin-right: 0;
+ float: none;
+}
+
.pagination > ul {
display: inline-block;
list-style: none !important;
@@ -848,16 +846,20 @@ fieldset.fields1 dl.pmlist dd.recipients {
}
.pagination li a, .pagination li span {
- border: 1px solid transparent;
border-radius: 2px;
- display: block;
- font-size: 0.9em;
+ padding: 2px 5px;
+}
+
+.pagination li.active span {
+ display: inline-block;
+ font-size: 13px;
font-weight: normal;
- line-height: 1.4em;
- min-width: 10px;
- padding: 3px;
+ font-family: "Open Sans", "Droid Sans", Verdana, Arial, Helvetica;
+ line-height: 1.4;
text-align: center;
- text-decoration: none;
+ white-space: nowrap;
+ vertical-align: middle;
+ border: 1px solid transparent;
}
.pagination li.ellipsis span {
@@ -869,37 +871,23 @@ fieldset.fields1 dl.pmlist dd.recipients {
margin-right: 5px;
}
-.pagination li.page-jump a, .pagination li.next a, .pagination li.previous a {
- background-repeat: no-repeat;
- font-size: 0;
- height: 13px;
- width: 11px;
-}
-
.pagination li.page-jump a {
- background-position: 0 2px;
- width: 24px;
+ padding: 0 8px;
}
-.pagination li.next a {
- background-position: -50px 2px;
+.pagination li.page-jump a i {
+ font-size: 21px;
}
-.pagination li.previous a {
- background-position: -30px 2px;
+.pagination .arrow a {
+ padding: 2px 0;
}
-.pagination li.page-jump a:hover, .pagination .dropdown-visible a.dropdown-trigger, .nojs .pagination .dropdown-container:hover a.dropdown-trigger { background-position: 0 -18px; }
-.pagination li.next a:hover { background-position: -50px -18px; }
-.pagination li.previous a:hover { background-position: -30px -18px; }
-
/* Pagination in viewforum for multipage topics */
.row .pagination {
display: block;
- margin-top: 0;
- padding: 1px 0 1px 15px;
- font-size: 0.9em;
- background: none 0 50% no-repeat;
+ margin-top: 3px;
+ margin-bottom: 3px;
}
.row .pagination > ul {
@@ -907,8 +895,9 @@ fieldset.fields1 dl.pmlist dd.recipients {
}
.row .pagination li a, .row .pagination li span {
- border-radius: 1px;
- padding: 1px;
+ border-radius: 2px;
+ padding: 1px 3px;
+ font-size: 9px;
}
/* jQuery popups
@@ -934,18 +923,9 @@ fieldset.fields1 dl.pmlist dd.recipients {
}
.phpbb_alert .alert_close {
- display: block;
float: right;
- width: 16px;
- height: 16px;
- overflow: hidden;
- text-decoration: none !important;
- background: transparent none 0 0 no-repeat;
- margin-top: -7px;
- margin-right: -31px;
-}
-.phpbb_alert .alert_close:hover {
- background-position: 0 -16px;
+ margin-right: -36px;
+ margin-top: -8px;
}
.phpbb_alert p {
@@ -967,13 +947,13 @@ fieldset.fields1 dl.pmlist dd.recipients {
font-size: 1.1em;
}
-#darkenwrapper {
+.darkenwrapper {
display: none;
position: relative;
z-index: 44;
}
-#darken {
+.darken {
position: fixed;
left: 0;
top: 0;
@@ -983,7 +963,7 @@ fieldset.fields1 dl.pmlist dd.recipients {
z-index: 45;
}
-#loading_indicator {
+.loading_indicator {
background: center center no-repeat;
border-radius: 5px;
display: none;
@@ -1000,18 +980,16 @@ fieldset.fields1 dl.pmlist dd.recipients {
/* Miscellaneous styles
---------------------------------------- */
-#forum-permissions {
- float: right;
- width: auto;
- padding-left: 5px;
- margin-left: 5px;
- margin-top: 10px;
- text-align: right;
-}
-
.copyright {
- padding: 5px;
+ font-size: 10px;
text-align: center;
+ padding: 10px;
+}
+
+.footer-row {
+ font-size: 10px;
+ line-height: 1.8;
+ margin: 0;
}
.small {
@@ -1045,36 +1023,20 @@ div.rules ul, div.rules ol {
p.post-notice {
position: relative;
padding: 5px;
- padding-left: 26px;
min-height: 14px;
margin-bottom: 1em;
}
-p.post-notice:before {
- content: '';
- display: block;
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- width: 28px;
- background: transparent none 50% 50% no-repeat;
- pointer-events: none;
-}
-
form > p.post-notice strong {
line-height: 20px;
}
-#jumpbox {
- margin: 5px 0;
-}
-
.stat-block {
clear: both;
}
-#top {
+.top-anchor {
+ display: block;
position: absolute;
top: -20px;
}
@@ -1093,16 +1055,19 @@ ul.linklist:after,
.action-bar:after,
.notification_text:after,
.tabs-container:after,
-#tabs > ul:after,
-#minitabs > ul:after,
+.tabs > ul:after,
+.minitabs > ul:after,
.postprofile .avatar-container:after {
clear: both;
content: '';
display: block;
}
-.hidden {
- display: none;
+.emoji {
+ min-height: 18px;
+ min-width: 18px;
+ height: 1em;
+ width: 1em;
}
.smilies {
@@ -1183,6 +1148,11 @@ ul.linklist:after,
text-transform: none;
}
+.dropdown-extended .header .header_settings a {
+ display: inline-block;
+ padding: 0 5px;
+}
+
.dropdown-extended .header:after {
content: '';
display: table;
@@ -1284,30 +1254,11 @@ ul.linklist:after,
/* Navbar specific list items
----------------------------------------*/
-#quick-links {
+.linklist .quick-links {
margin: 0 7px 0 0;
}
-#quick-links a.responsive-menu-link {
- display: block;
- font-size: inherit;
- line-height: inherit;
- margin: 0;
- width: auto;
-}
-
-#quick-links a.responsive-menu-link:before {
- font-size: 1.455em;
- line-height: 16.5px;
-}
-
-.compact #quick-links a.responsive-menu-link {
- width: 0;
- overflow: hidden;
- white-space: nowrap;
-}
-
-.compact .icon-notification > a > span, .compact .icon-pm > a > span {
+.linklist.compact .rightside > a > span {
display: none;
}
@@ -1323,6 +1274,10 @@ ul.linklist:after,
width: 50px;
}
+.dropdown .clone.hidden {
+ display: none;
+}
+
.dropdown .clone.hidden + li.separator {
display: none;
}
diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css
index dfb91891fa..807633864c 100644
--- a/phpBB/styles/prosilver/theme/content.css
+++ b/phpBB/styles/prosilver/theme/content.css
@@ -7,10 +7,6 @@ ul.topiclist {
margin: 0;
}
-ul.forums {
- background: transparent none repeat-x 0 0;
-}
-
ul.topiclist li {
display: block;
list-style-type: none;
@@ -22,7 +18,7 @@ ul.topiclist dl {
}
ul.topiclist li.row dl {
- padding: 2px 0;
+ margin: 2px 0;
}
ul.topiclist dt, ul.topiclist dd {
@@ -74,6 +70,11 @@ ul.topiclist dd {
box-sizing: border-box;
}
+ul.topiclist li.row dd {
+ padding: 4px 0 999px 0;
+ margin-bottom: -995px;
+}
+
ul.topiclist dfn {
/* Labels for post/view counts */
position: absolute;
@@ -81,15 +82,6 @@ ul.topiclist dfn {
width: 990px;
}
-ul.topiclist li.row dt a.subforum {
- background-image: none;
- background-position: 0 50%;
- background-repeat: no-repeat;
- position: relative;
- white-space: nowrap;
- padding: 0 0 0 12px;
-}
-
.forum-image {
float: left;
padding-top: 5px;
@@ -133,36 +125,44 @@ li.header dd {
box-sizing: border-box;
}
-li.header dl.icon dt, li.header dl.icon dd {
+li.header dl.row-item dt, li.header dl.row-item dd {
min-height: 0;
}
-li.header dl.icon dt .list-inner {
+li.header dl.row-item dt .list-inner {
/* Tweak for headers alignment when folder icon used */
padding-left: 0;
padding-right: 50px;
}
/* Forum list column styles */
-dl.icon {
+.row .list-inner { padding: 4px 0; }
+
+dl.row-item {
background-position: 10px 50%; /* Position of folder icon */
background-repeat: no-repeat;
+ background-size: 32px;
}
-dl.icon dt {
+dl.row-item dt {
background-repeat: no-repeat;
background-position: 5px 95%; /* Position of topic icon */
+ background-size: 17px;
}
-dl.icon dt .list-inner {
- padding-left: 45px; /* Space for folder icon */
+dl.row-item dt .list-inner {
+ padding-left: 52px; /* Space for folder icon */
}
-dl.icon dt, dl.icon dd {
+dl.row-item dt, dl.row-item dd {
min-height: 35px;
}
-dl a.icon-link { /* topic row icon links */
+dl.row-item dt a {
+ display: inline;
+}
+
+dl a.row-item-link { /* topic row icon links */
display: block;
width: 30px;
height: 30px;
@@ -186,13 +186,13 @@ dd.posts, dd.topics, dd.views {
}
/* List in forum description */
-dl.icon dt ol,
-dl.icon dt ul {
+dl.row-item dt ol,
+dl.row-item dt ul {
list-style-position: inside;
margin-left: 1em;
}
-dl.icon dt li {
+dl.row-item dt li {
display: list-item;
list-style-type: inherit;
}
@@ -286,28 +286,28 @@ dd.option {
/* Topic review panel
----------------------------------------*/
-#review {
+.panel .review {
margin-top: 2em;
}
-#topicreview {
+.topicreview {
padding-right: 5px;
overflow: auto;
height: 300px;
}
-#topicreview .postbody {
+.topicreview .postbody {
width: auto;
float: none;
margin: 0;
height: auto;
}
-#topicreview .post {
+.topicreview .post {
height: auto;
}
-#topicreview h2 {
+.topicreview h2 {
border-bottom-width: 0;
}
@@ -317,7 +317,7 @@ dd.option {
/* MCP Post details
----------------------------------------*/
-#post_details {
+.post_details {
/* This will only work in IE7+, plus the others */
overflow: auto;
max-height: 300px;
@@ -383,8 +383,7 @@ dl.faq dt {
}
.content ul, .content ol {
- margin-bottom: 1em;
- margin-left: 3em;
+ margin: 0.8em 0 0.9em 3em;
}
.posthilit {
@@ -430,8 +429,7 @@ dd .signature {
}
.signature ul, .signature ol {
- margin-bottom: 1em;
- margin-left: 3em;
+ margin: 0.8em 0 0.9em 3em;
}
/* Post noticies */
@@ -457,10 +455,9 @@ ul.searchresults {
----------------------------------------*/
/* Quote block */
blockquote {
- background: transparent none 6px 8px no-repeat;
border: 1px solid transparent;
font-size: 0.95em;
- margin: 0.5em 1px 0 25px;
+ margin: 1em 1px 1em 25px;
overflow: hidden;
padding: 5px;
}
@@ -468,14 +465,13 @@ blockquote {
blockquote blockquote {
/* Nested quotes */
font-size: 1em;
- margin: 0.5em 1px 0 15px;
+ margin: 1em 1px 1em 15px;
}
blockquote cite {
/* Username/source of quoter */
font-style: normal;
font-weight: bold;
- margin-left: 20px;
display: block;
font-size: 0.9em;
}
@@ -484,23 +480,33 @@ blockquote cite cite {
font-size: 1em;
}
-blockquote.uncited {
- padding-top: 25px;
+blockquote cite:before, .uncited:before {
+ padding-right: 5px;
+}
+
+blockquote cite > div {
+ float: right;
+ font-weight: normal;
+}
+
+.postbody .content li blockquote {
+ overflow: inherit;
+ margin-left: 0;
}
/* Code block */
.codebox {
- padding: 3px;
border: 1px solid transparent;
font-size: 1em;
- overflow-x: scroll;
+ margin: 1em 0 1.2em 0;
word-wrap: normal;
}
.codebox p {
text-transform: uppercase;
border-bottom: 1px solid transparent;
- margin-bottom: 3px;
+ margin-bottom: 0;
+ padding: 3px;
font-size: 0.8em !important;
font-weight: bold;
display: block;
@@ -515,16 +521,15 @@ blockquote .codebox {
display: block;
height: auto;
max-height: 200px;
- white-space: normal;
- padding-top: 5px;
+ padding: 5px 3px;
font: 0.9em Monaco, "Andale Mono","Courier New", Courier, monospace;
line-height: 1.3em;
- margin: 2px 0;
}
/* Attachments
----------------------------------------*/
.attachbox {
+ font-size: 13px;
float: left;
width: auto;
max-width: 100%;
@@ -832,7 +837,7 @@ table.fixed-width-table {
/* Show scrollbars for items with overflow on iOS devices
----------------------------------------*/
-.postbody .content::-webkit-scrollbar, #topicreview::-webkit-scrollbar, #post_details::-webkit-scrollbar, .codebox code::-webkit-scrollbar, .attachbox dd::-webkit-scrollbar, .attach-image::-webkit-scrollbar, .dropdown-extended ul::-webkit-scrollbar {
+.postbody .content::-webkit-scrollbar, .topicreview::-webkit-scrollbar, .post_details::-webkit-scrollbar, .codebox code::-webkit-scrollbar, .attachbox dd::-webkit-scrollbar, .attach-image::-webkit-scrollbar, .dropdown-extended ul::-webkit-scrollbar {
width: 8px;
height: 8px;
-webkit-appearance: none;
@@ -840,7 +845,7 @@ table.fixed-width-table {
border-radius: 3px;
}
-.postbody .content::-webkit-scrollbar-thumb, #topicreview::-webkit-scrollbar-thumb, #post_details::-webkit-scrollbar-thumb, .codebox code::-webkit-scrollbar-thumb, .attachbox dd::-webkit-scrollbar-thumb, .attach-image::-webkit-scrollbar-thumb, .dropdown-extended ul::-webkit-scrollbar-thumb {
+.postbody .content::-webkit-scrollbar-thumb, .topicreview::-webkit-scrollbar-thumb, .post_details::-webkit-scrollbar-thumb, .codebox code::-webkit-scrollbar-thumb, .attachbox dd::-webkit-scrollbar-thumb, .attach-image::-webkit-scrollbar-thumb, .dropdown-extended ul::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, .3);
border-radius: 3px;
}
diff --git a/phpBB/styles/prosilver/theme/cp.css b/phpBB/styles/prosilver/theme/cp.css
index 8a223f653f..0041417022 100644
--- a/phpBB/styles/prosilver/theme/cp.css
+++ b/phpBB/styles/prosilver/theme/cp.css
@@ -4,19 +4,19 @@
/* Main CP box
----------------------------------------*/
-#cp-menu {
+.cp-menu {
float:left;
width: 19%;
margin-top: 1em;
margin-bottom: 5px;
}
-#cp-main {
+.cp-main {
float: left;
width: 81%;
}
-#cp-main .content {
+.cp-main .content {
padding: 0;
}
@@ -59,7 +59,7 @@ ul.cplist {
border-bottom: none;
}
-#cp-main .pm-message {
+.cp-main .pm-message {
border: 1px solid transparent;
margin: 10px 0;
width: auto;
@@ -70,7 +70,7 @@ ul.cplist {
padding-bottom: 5px;
}
-#cp-main .postbody h3, #cp-main .box2 h3 {
+.cp-main .postbody h3, .cp-main .box2 h3 {
margin-top: 0;
}
@@ -78,11 +78,11 @@ ul.cplist {
font-size: 1.1em;
}
-#cp-main .buttons {
+.cp-main .buttons {
margin-left: 0;
}
-#cp-main ul.linklist {
+.cp-main ul.linklist {
margin: 0;
}
@@ -98,18 +98,18 @@ ul.cplist {
/* CP tabs shared
----------------------------------------*/
-#tabs, #minitabs {
+.tabs, .minitabs {
line-height: normal;
}
-#tabs > ul, #minitabs > ul {
+.tabs > ul, .minitabs > ul {
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
-#tabs .tab, #minitabs .tab {
+.tabs .tab, .minitabs .tab {
display: block;
float: left;
font-size: 1em;
@@ -117,7 +117,7 @@ ul.cplist {
line-height: 1.4em;
}
-#tabs .tab > a, #minitabs .tab > a {
+.tabs .tab > a, .minitabs .tab > a {
display: block;
padding: 5px 9px;
position: relative;
@@ -128,39 +128,39 @@ ul.cplist {
/* CP tabbed menu
----------------------------------------*/
-#tabs {
+.tabs {
margin: 20px 0 0 7px;
}
-#tabs .tab > a {
+.tabs .tab > a {
border: 1px solid transparent;
border-radius: 4px 4px 0 0;
margin: 1px 1px 0 0;
}
-#tabs .activetab > a {
+.tabs .activetab > a {
margin-top: 0;
padding-bottom: 7px;
}
/* Mini tabbed menu used in MCP
----------------------------------------*/
-#minitabs {
+.minitabs {
float: right;
margin: 15px 7px 0 0;
max-width: 50%;
}
-#minitabs .tab {
+.minitabs .tab {
float: right;
}
-#minitabs .tab > a {
+.minitabs .tab > a {
border-radius: 5px 5px 0 0;
margin-left: 2px;
}
-#minitabs .tab > a:hover {
+.minitabs .tab > a:hover {
text-decoration: none;
}
@@ -190,44 +190,44 @@ ul.cplist {
border-top: 0.375em double transparent;
}
-#tabs .dropdown, #minitabs .dropdown {
+.tabs .dropdown, .minitabs .dropdown {
top: 20px;
margin-right: -2px;
font-size: 1.1em;
font-weight: normal;
}
-#minitabs .dropdown {
+.minitabs .dropdown {
margin-right: -4px;
}
-#tabs .dropdown-up .dropdown, #minitabs .dropdown-up .dropdown {
+.tabs .dropdown-up .dropdown, .minitabs .dropdown-up .dropdown {
bottom: 20px;
top: auto;
}
-#tabs .dropdown li {
+.tabs .dropdown li {
text-align: right;
}
-#minitabs .dropdown li {
+.minitabs .dropdown li {
text-align: left;
}
/* UCP navigation menu
----------------------------------------*/
/* Container for sub-navigation list */
-#navigation {
+.navigation {
width: 100%;
padding-top: 36px;
}
-#navigation ul {
+.navigation ul {
list-style: none;
}
/* Default list state */
-#navigation li {
+.navigation li {
display: inline;
font-weight: bold;
margin: 1px 0;
@@ -235,20 +235,20 @@ ul.cplist {
}
/* Link styles for the sub-section links */
-#navigation a {
+.navigation a {
display: block;
padding: 5px;
margin: 1px 0;
text-decoration: none;
}
-#navigation a:hover {
+.navigation a:hover {
text-decoration: none;
}
/* Preferences pane layout
----------------------------------------*/
-#cp-main h2 {
+.cp-main h2 {
border-bottom: none;
padding: 0;
margin-left: 10px;
@@ -281,10 +281,6 @@ dl.mini dd {
/* PM Styles
----------------------------------------*/
-#pm-menu {
- line-height: 2.5em;
-}
-
/* Defined rules list for PM options */
ol.def-rules {
padding-left: 0;
@@ -304,11 +300,14 @@ ol.def-rules li {
padding: 0 3px;
}
+/* DEPRECATED 3.2.6
.pmlist li.pm_message_reported_colour, .pm_message_reported_colour {
border-left-color: transparent;
border-right-color: transparent;
}
+*/
+.pmlist li.pm_message_reported_colour, .pm_message_reported_colour,
.pmlist li.pm_marked_colour, .pm_marked_colour,
.pmlist li.pm_replied_colour, .pm_replied_colour,
.pmlist li.pm_friend_colour, .pm_friend_colour,
@@ -327,7 +326,7 @@ ol.def-rules li {
}
/* Avatar gallery */
-#gallery label {
+.gallery label {
position: relative;
float: left;
margin: 10px;
@@ -341,35 +340,35 @@ ol.def-rules li {
----------------------------------------*/
@media only screen and (max-width: 900px), only screen and (max-device-width: 900px)
{
- .nojs #tabs a span, .nojs #minitabs a span {
+ .nojs .tabs a span, .nojs .minitabs a span {
max-width: 40px;
overflow: hidden;
text-overflow: ellipsis;
letter-spacing: -.5px;
}
- #cp-menu, #navigation, #cp-main {
+ .cp-menu, .navigation, .cp-main {
float: none;
width: auto;
margin: 0;
}
- #navigation {
+ .navigation {
padding: 0;
margin: 0 auto;
max-width: 320px;
}
- #navigation a {
+ .navigation a {
background-image: none;
}
- #navigation li:first-child a {
+ .navigation li:first-child a {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
- #navigation li:last-child a {
+ .navigation li:last-child a {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
diff --git a/phpBB/styles/prosilver/theme/en/stylesheet.css b/phpBB/styles/prosilver/theme/en/stylesheet.css
index bf4bd31ffc..604b299488 100644
--- a/phpBB/styles/prosilver/theme/en/stylesheet.css
+++ b/phpBB/styles/prosilver/theme/en/stylesheet.css
@@ -1,8 +1,2 @@
/* Online image */
.online { background-image: url("./icon_user_online.gif"); }
-
-.imageset.icon_user_online {
- background-image: url("./icon_user_online.gif");
- padding-left: 58px;
- padding-top: 58px;
-}
diff --git a/phpBB/styles/prosilver/theme/forms.css b/phpBB/styles/prosilver/theme/forms.css
index 235c230ed4..5646a7d6c7 100644
--- a/phpBB/styles/prosilver/theme/forms.css
+++ b/phpBB/styles/prosilver/theme/forms.css
@@ -96,7 +96,7 @@ fieldset.fields1 div {
}
/* Set it back to 0px for the reCaptcha divs: PHPBB3-9587 */
-fieldset.fields1 #recaptcha_widget_div div, fieldset.fields1 .live-search div {
+fieldset.fields1 .live-search div {
margin-bottom: 0;
}
@@ -138,10 +138,16 @@ dd textarea {
}
/* Hover effects */
-#timezone {
+.timezone {
width: 95%;
}
+/* Browser-specific tweaks */
+button::-moz-focus-inner {
+ padding: 0;
+ border: 0
+}
+
/* Quick-login on index page */
fieldset.quick-login {
margin-top: 5px;
@@ -177,6 +183,24 @@ fieldset.display-options a {
margin-top: 3px;
}
+.dropdown fieldset.display-options {
+ font-size: 1em;
+ margin: 0;
+ padding: 0;
+}
+
+.dropdown fieldset.display-options label {
+ display: block;
+ margin: 4px;
+ padding: 0;
+ text-align: right;
+ white-space: nowrap;
+}
+
+.dropdown fieldset.display-options select {
+ min-width: 120px;
+}
+
/* Display actions for ucp and mcp pages */
fieldset.display-actions {
text-align: right;
@@ -214,28 +238,26 @@ fieldset.submit-buttons {
fieldset.submit-buttons input {
vertical-align: middle;
- padding-top: 3px;
- padding-bottom: 3px;
}
/* Posting page styles
----------------------------------------*/
/* Buttons used in the editor */
-#format-buttons {
+.format-buttons {
margin: 15px 0 2px 0;
}
-#format-buttons input, #format-buttons select {
+.format-buttons input, .format-buttons select {
vertical-align: middle;
}
/* Main message box */
-#message-box {
+.message-box {
width: 80%;
}
-#message-box textarea {
+.message-box textarea {
font-family: "Trebuchet MS", Verdana, Helvetica, Arial, sans-serif;
width: 450px;
height: 270px;
@@ -245,20 +267,20 @@ fieldset.submit-buttons input {
resize: vertical;
outline: 3px dashed transparent;
outline-offset: -4px;
- -webkit-transition: all .5s ease;
- -moz-transition: all .5s ease;
- -ms-transition: all .5s ease;
- -o-transition: all .5s ease;
- transition: all .5s ease;
+ -webkit-transition: all .5s ease, height 1ms linear;
+ -moz-transition: all .5s ease, height 1ms linear;
+ -ms-transition: all .5s ease, height 1ms linear;
+ -o-transition: all .5s ease, height 1ms linear;
+ transition: all .5s ease, height 1ms linear;
}
/* Emoticons panel */
-#smiley-box {
+.smiley-box {
width: 18%;
float: right;
}
-#smiley-box img {
+.smiley-box img {
margin: 3px;
}
@@ -316,6 +338,7 @@ a.button1, input.button1, input.button3, a.button2, input.button2 {
padding-bottom: 1px;
font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;
background: transparent none repeat-x top left;
+ line-height: 1.5;
}
a.button1, input.button1 {
@@ -342,18 +365,15 @@ a.button2, input.button2, input.button3 {
}
/* <a> button in the style of the form buttons */
-a.button1, a.button1:link, a.button1:visited, a.button1:active, a.button2, a.button2:link, a.button2:visited, a.button2:active {
+a.button1, a.button2 {
text-decoration: none;
- padding: 2px 8px;
- line-height: 250%;
+ padding: 0 3px;
vertical-align: text-bottom;
- background-position: 0 1px;
}
/* Hover states */
a.button1:hover, input.button1:hover, a.button2:hover, input.button2:hover, input.button3:hover {
border: 1px solid transparent;
- background-position: 0 100%;
}
input.disabled {
@@ -382,26 +402,6 @@ input.button1:focus, input.button2:focus, input.button3:focus {
box-sizing: border-box;
}
-.search-box button {
- float: left;
-}
-
-.search-box button.search-icon {
- border-radius: 0;
- font-size: 0;
- height: 24px;
- margin: 0;
- padding: 3px 5px;
-}
-
-.search-box a.button {
- border-left-width: 0;
- border-radius: 0 4px 4px 0;
- font-size: 0;
- margin: 0;
- padding: 2px 5px 2px 3px;
-}
-
/* Search box (header)
--------------------------------------------- */
.search-header {
@@ -414,16 +414,7 @@ input.button1:focus, input.button2:focus, input.button3:focus {
.search-header .inputbox { border: 0; }
-.search-header button {
- border-top: 0;
- border-bottom: 0;
-}
-
-.search-header a.button {
- border: 0;
- border-left: 1px;
- padding: 3px 5px 3px 4px;
-}
+.navbar .linklist > li.responsive-search { display: none; }
input.search {
background-image: none;
diff --git a/phpBB/styles/prosilver/theme/icons.css b/phpBB/styles/prosilver/theme/icons.css
new file mode 100644
index 0000000000..6643f12d06
--- /dev/null
+++ b/phpBB/styles/prosilver/theme/icons.css
@@ -0,0 +1,96 @@
+/* --------------------------------------------------------------
+ $Icons
+-------------------------------------------------------------- */
+
+/* Global module setup
+--------------------------------*/
+
+/* Renamed version of .fa class for agnostic useage of icon fonts.
+ * Just change the name of the font after the 14/1 to the name of
+ * the font you wish to use.
+ */
+.icon, .button .icon, blockquote cite:before, .uncited:before {
+ display: inline-block;
+ font-weight: normal;
+ font-style: normal;
+ font-variant: normal;
+ font-family: FontAwesome;
+ font-size: 14px;
+ line-height: 1;
+ text-rendering: auto; /* optimizelegibility throws things off #1094 */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon:before { padding-right: 2px; }
+
+.button .icon:before {
+ padding-right: 0;
+}
+
+/* Icon size classes - Default size is 14px, use these for small variations */
+
+.icon.icon-xl {
+ font-size: 20px;
+}
+
+.icon.icon-lg {
+ font-size: 16px;
+}
+
+.icon.icon-md {
+ font-size: 10px;
+}
+
+.icon.icon-sm {
+ font-size: 8px;
+}
+
+/* icon modifiers */
+.icon-tiny {
+ width: 12px;
+ transform: scale(0.65, 0.75);
+ vertical-align: text-bottom;
+ font-size: 16px;
+}
+
+.arrow-left .icon {
+ float: left;
+}
+
+.arrow-left:hover .icon {
+ margin-left: -5px;
+ margin-right: 5px;
+}
+
+.arrow-right .icon {
+ float: right;
+}
+
+.arrow-right:hover .icon {
+ margin-left: 5px;
+ margin-right: -5px;
+}
+
+.post-buttons .dropdown-contents .icon {
+ float: right;
+ margin-left: 5px;
+}
+
+.alert_close .icon:before {
+ padding: 0;
+ border-radius: 50%;
+ width: 11px;
+ display: block;
+ line-height: .9;
+ height: 12px;
+}
+
+blockquote cite:before, .uncited:before {
+ content: '\f10d'; /* Font Awesome quote-left */
+}
+
+.rtl blockquote cite:before, .rtl .uncited:before {
+ content: '\f10e'; /* Font Awesome quote-right */
+}
+
diff --git a/phpBB/styles/prosilver/theme/images/alert_close.png b/phpBB/styles/prosilver/theme/images/alert_close.png
deleted file mode 100644
index 79750a013c..0000000000
--- a/phpBB/styles/prosilver/theme/images/alert_close.png
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_read.gif b/phpBB/styles/prosilver/theme/images/announce_read.gif
index 9457870e6f..a3b3d7b234 100644
--- a/phpBB/styles/prosilver/theme/images/announce_read.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_read.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_read_locked.gif b/phpBB/styles/prosilver/theme/images/announce_read_locked.gif
index 76ead8a02c..0a6cf64341 100644
--- a/phpBB/styles/prosilver/theme/images/announce_read_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_read_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_read_locked_mine.gif b/phpBB/styles/prosilver/theme/images/announce_read_locked_mine.gif
index 2105d21f10..56af0ab071 100644
--- a/phpBB/styles/prosilver/theme/images/announce_read_locked_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_read_locked_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_read_mine.gif b/phpBB/styles/prosilver/theme/images/announce_read_mine.gif
index 2c88cacca0..c333e3b124 100644
--- a/phpBB/styles/prosilver/theme/images/announce_read_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_read_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_unread.gif b/phpBB/styles/prosilver/theme/images/announce_unread.gif
index 33e10b2ccc..9f75cc3e53 100644
--- a/phpBB/styles/prosilver/theme/images/announce_unread.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_unread.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_unread_locked.gif b/phpBB/styles/prosilver/theme/images/announce_unread_locked.gif
index 76dcc6ca71..4ad85bb684 100644
--- a/phpBB/styles/prosilver/theme/images/announce_unread_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_unread_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_unread_locked_mine.gif b/phpBB/styles/prosilver/theme/images/announce_unread_locked_mine.gif
index 53782fc3dc..30db89439e 100644
--- a/phpBB/styles/prosilver/theme/images/announce_unread_locked_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_unread_locked_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/announce_unread_mine.gif b/phpBB/styles/prosilver/theme/images/announce_unread_mine.gif
index bc07df0ce9..3a2cbcac10 100644
--- a/phpBB/styles/prosilver/theme/images/announce_unread_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/announce_unread_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/arrow_down.gif b/phpBB/styles/prosilver/theme/images/arrow_down.gif
deleted file mode 100644
index b7fbf7e276..0000000000
--- a/phpBB/styles/prosilver/theme/images/arrow_down.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/arrow_left.gif b/phpBB/styles/prosilver/theme/images/arrow_left.gif
deleted file mode 100644
index ac92cb4971..0000000000
--- a/phpBB/styles/prosilver/theme/images/arrow_left.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/arrow_right.gif b/phpBB/styles/prosilver/theme/images/arrow_right.gif
deleted file mode 100644
index 3a080ffdfe..0000000000
--- a/phpBB/styles/prosilver/theme/images/arrow_right.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/arrow_up.gif b/phpBB/styles/prosilver/theme/images/arrow_up.gif
deleted file mode 100644
index 0ff5872182..0000000000
--- a/phpBB/styles/prosilver/theme/images/arrow_up.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/bg_button.gif b/phpBB/styles/prosilver/theme/images/bg_button.gif
deleted file mode 100644
index 03172ff5c6..0000000000
--- a/phpBB/styles/prosilver/theme/images/bg_button.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/feed.gif b/phpBB/styles/prosilver/theme/images/feed.gif
deleted file mode 100644
index ff19905874..0000000000
--- a/phpBB/styles/prosilver/theme/images/feed.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/forum_link.gif b/phpBB/styles/prosilver/theme/images/forum_link.gif
index efeaf0a11f..09f8dfa75a 100644
--- a/phpBB/styles/prosilver/theme/images/forum_link.gif
+++ b/phpBB/styles/prosilver/theme/images/forum_link.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/forum_read.gif b/phpBB/styles/prosilver/theme/images/forum_read.gif
index 845618c1a2..891fa20c07 100644
--- a/phpBB/styles/prosilver/theme/images/forum_read.gif
+++ b/phpBB/styles/prosilver/theme/images/forum_read.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/forum_read_locked.gif b/phpBB/styles/prosilver/theme/images/forum_read_locked.gif
index 7afb092a8f..2348240638 100644
--- a/phpBB/styles/prosilver/theme/images/forum_read_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/forum_read_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/forum_read_subforum.gif b/phpBB/styles/prosilver/theme/images/forum_read_subforum.gif
index 7119486539..5b4d30f7ec 100644
--- a/phpBB/styles/prosilver/theme/images/forum_read_subforum.gif
+++ b/phpBB/styles/prosilver/theme/images/forum_read_subforum.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/forum_unread.gif b/phpBB/styles/prosilver/theme/images/forum_unread.gif
index 1a397cb216..e925da82bd 100644
--- a/phpBB/styles/prosilver/theme/images/forum_unread.gif
+++ b/phpBB/styles/prosilver/theme/images/forum_unread.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/forum_unread_locked.gif b/phpBB/styles/prosilver/theme/images/forum_unread_locked.gif
index 34f1d46ad7..5ff59b7421 100644
--- a/phpBB/styles/prosilver/theme/images/forum_unread_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/forum_unread_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/forum_unread_subforum.gif b/phpBB/styles/prosilver/theme/images/forum_unread_subforum.gif
index e955887020..7d6ddb93be 100644
--- a/phpBB/styles/prosilver/theme/images/forum_unread_subforum.gif
+++ b/phpBB/styles/prosilver/theme/images/forum_unread_subforum.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/gradient.gif b/phpBB/styles/prosilver/theme/images/gradient.gif
deleted file mode 100644
index 21dc11f13b..0000000000
--- a/phpBB/styles/prosilver/theme/images/gradient.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_acp.gif b/phpBB/styles/prosilver/theme/images/icon_acp.gif
deleted file mode 100644
index 3afa98ee8f..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_acp.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_back_top.gif b/phpBB/styles/prosilver/theme/images/icon_back_top.gif
deleted file mode 100644
index 4d2b8f3822..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_back_top.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_bookmark.gif b/phpBB/styles/prosilver/theme/images/icon_bookmark.gif
deleted file mode 100644
index 2644293f7d..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_bookmark.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_bump.gif b/phpBB/styles/prosilver/theme/images/icon_bump.gif
deleted file mode 100644
index 014cd9bd15..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_bump.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_contact.png b/phpBB/styles/prosilver/theme/images/icon_contact.png
deleted file mode 100644
index 04e4d9ad17..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_contact.png
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_delete_cookies.gif b/phpBB/styles/prosilver/theme/images/icon_delete_cookies.gif
deleted file mode 100644
index f7665ebff8..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_delete_cookies.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_faq.gif b/phpBB/styles/prosilver/theme/images/icon_faq.gif
deleted file mode 100644
index 4e26460629..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_faq.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_home.gif b/phpBB/styles/prosilver/theme/images/icon_home.gif
deleted file mode 100644
index 8ae9004534..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_home.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_logout.gif b/phpBB/styles/prosilver/theme/images/icon_logout.gif
deleted file mode 100644
index b8ad5c4e5c..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_logout.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_mark.gif b/phpBB/styles/prosilver/theme/images/icon_mark.gif
deleted file mode 100644
index 1a33fc3264..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_mark.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_mcp.gif b/phpBB/styles/prosilver/theme/images/icon_mcp.gif
deleted file mode 100644
index 80de2e53f7..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_mcp.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_members.gif b/phpBB/styles/prosilver/theme/images/icon_members.gif
deleted file mode 100644
index 48e3e5f5f3..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_members.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_notification.gif b/phpBB/styles/prosilver/theme/images/icon_notification.gif
deleted file mode 100644
index 11092f4dce..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_notification.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_pages.gif b/phpBB/styles/prosilver/theme/images/icon_pages.gif
deleted file mode 100644
index 20b2fe9f81..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_pages.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_pm.gif b/phpBB/styles/prosilver/theme/images/icon_pm.gif
deleted file mode 100644
index 103421a26f..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_pm.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_post_target.gif b/phpBB/styles/prosilver/theme/images/icon_post_target.gif
deleted file mode 100644
index a2bc2a2c47..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_post_target.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_post_target_unread.gif b/phpBB/styles/prosilver/theme/images/icon_post_target_unread.gif
deleted file mode 100644
index 65d47bb900..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_post_target_unread.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_print.gif b/phpBB/styles/prosilver/theme/images/icon_print.gif
deleted file mode 100644
index e464e304ea..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_print.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_profile.gif b/phpBB/styles/prosilver/theme/images/icon_profile.gif
deleted file mode 100644
index a0ec098460..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_profile.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_register.gif b/phpBB/styles/prosilver/theme/images/icon_register.gif
deleted file mode 100644
index 9ecf126c4f..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_register.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_search.gif b/phpBB/styles/prosilver/theme/images/icon_search.gif
deleted file mode 100644
index 8492cd308c..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_search.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_sendemail.gif b/phpBB/styles/prosilver/theme/images/icon_sendemail.gif
deleted file mode 100644
index 92a39c8af9..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_sendemail.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_subscribe.gif b/phpBB/styles/prosilver/theme/images/icon_subscribe.gif
deleted file mode 100644
index 5ca18af80a..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_subscribe.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_team.gif b/phpBB/styles/prosilver/theme/images/icon_team.gif
deleted file mode 100644
index 613158257b..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_team.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_textbox_search.gif b/phpBB/styles/prosilver/theme/images/icon_textbox_search.gif
deleted file mode 100644
index b3b51d8425..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_textbox_search.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_topic_attach.gif b/phpBB/styles/prosilver/theme/images/icon_topic_attach.gif
deleted file mode 100644
index 70203124fe..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_topic_attach.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_topic_deleted.png b/phpBB/styles/prosilver/theme/images/icon_topic_deleted.png
deleted file mode 100644
index 494b4fb563..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_topic_deleted.png
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_topic_latest.gif b/phpBB/styles/prosilver/theme/images/icon_topic_latest.gif
deleted file mode 100644
index 815b26927a..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_topic_latest.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_topic_newest.gif b/phpBB/styles/prosilver/theme/images/icon_topic_newest.gif
deleted file mode 100644
index fd6652d957..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_topic_newest.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_topic_poll.gif b/phpBB/styles/prosilver/theme/images/icon_topic_poll.gif
deleted file mode 100644
index 1c80ec87c1..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_topic_poll.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_topic_reported.gif b/phpBB/styles/prosilver/theme/images/icon_topic_reported.gif
deleted file mode 100644
index 006b1e2291..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_topic_reported.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_topic_unapproved.gif b/phpBB/styles/prosilver/theme/images/icon_topic_unapproved.gif
deleted file mode 100644
index 09d8f387a7..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_topic_unapproved.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_ucp.gif b/phpBB/styles/prosilver/theme/images/icon_ucp.gif
deleted file mode 100644
index 2a5fcc3f0c..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_ucp.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icon_unsubscribe.gif b/phpBB/styles/prosilver/theme/images/icon_unsubscribe.gif
deleted file mode 100644
index 27013fc1cb..0000000000
--- a/phpBB/styles/prosilver/theme/images/icon_unsubscribe.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icons_button.png b/phpBB/styles/prosilver/theme/images/icons_button.png
deleted file mode 100644
index 50ac8994de..0000000000
--- a/phpBB/styles/prosilver/theme/images/icons_button.png
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/icons_pagination.png b/phpBB/styles/prosilver/theme/images/icons_pagination.png
deleted file mode 100644
index 872b7308c2..0000000000
--- a/phpBB/styles/prosilver/theme/images/icons_pagination.png
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_read.gif b/phpBB/styles/prosilver/theme/images/sticky_read.gif
index e1af585da5..e8142ddb20 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_read.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_read.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_read_locked.gif b/phpBB/styles/prosilver/theme/images/sticky_read_locked.gif
index 79f581be79..fcd8b85e0b 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_read_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_read_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_read_locked_mine.gif b/phpBB/styles/prosilver/theme/images/sticky_read_locked_mine.gif
index ad056086e5..0a8dc2a6c1 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_read_locked_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_read_locked_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_read_mine.gif b/phpBB/styles/prosilver/theme/images/sticky_read_mine.gif
index 8f5f28fe5e..37c4ed01f6 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_read_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_read_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_unread.gif b/phpBB/styles/prosilver/theme/images/sticky_unread.gif
index d62b3c0f3a..88a212d7c0 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_unread.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_unread.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_unread_locked.gif b/phpBB/styles/prosilver/theme/images/sticky_unread_locked.gif
index 5792b8649a..0241da2ab5 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_unread_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_unread_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_unread_locked_mine.gif b/phpBB/styles/prosilver/theme/images/sticky_unread_locked_mine.gif
index 93495770c8..8d69b447b2 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_unread_locked_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_unread_locked_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/sticky_unread_mine.gif b/phpBB/styles/prosilver/theme/images/sticky_unread_mine.gif
index e201a9f31f..6529102053 100644
--- a/phpBB/styles/prosilver/theme/images/sticky_unread_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/sticky_unread_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/subforum_read.gif b/phpBB/styles/prosilver/theme/images/subforum_read.gif
deleted file mode 100644
index 595595c296..0000000000
--- a/phpBB/styles/prosilver/theme/images/subforum_read.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/subforum_unread.gif b/phpBB/styles/prosilver/theme/images/subforum_unread.gif
deleted file mode 100644
index b2b661dc78..0000000000
--- a/phpBB/styles/prosilver/theme/images/subforum_unread.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_moved.gif b/phpBB/styles/prosilver/theme/images/topic_moved.gif
index 3dafa46ed7..8e9c1f41f6 100644
--- a/phpBB/styles/prosilver/theme/images/topic_moved.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_moved.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_read.gif b/phpBB/styles/prosilver/theme/images/topic_read.gif
index 640d5396f8..5ed739ee9b 100644
--- a/phpBB/styles/prosilver/theme/images/topic_read.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_read.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_read_hot.gif b/phpBB/styles/prosilver/theme/images/topic_read_hot.gif
index dcb6f3bd60..81a42d0a67 100644
--- a/phpBB/styles/prosilver/theme/images/topic_read_hot.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_read_hot.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_read_hot_mine.gif b/phpBB/styles/prosilver/theme/images/topic_read_hot_mine.gif
index 1e5498a9be..b98808cadf 100644
--- a/phpBB/styles/prosilver/theme/images/topic_read_hot_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_read_hot_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_read_locked.gif b/phpBB/styles/prosilver/theme/images/topic_read_locked.gif
index a47affb2f2..61bb1effa2 100644
--- a/phpBB/styles/prosilver/theme/images/topic_read_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_read_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_read_locked_mine.gif b/phpBB/styles/prosilver/theme/images/topic_read_locked_mine.gif
index d6142f0ea7..dbe901919a 100644
--- a/phpBB/styles/prosilver/theme/images/topic_read_locked_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_read_locked_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_read_mine.gif b/phpBB/styles/prosilver/theme/images/topic_read_mine.gif
index 18a1245b93..8fb165c46c 100644
--- a/phpBB/styles/prosilver/theme/images/topic_read_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_read_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_unread.gif b/phpBB/styles/prosilver/theme/images/topic_unread.gif
index 3fa920b6fc..43ea76b4de 100644
--- a/phpBB/styles/prosilver/theme/images/topic_unread.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_unread.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_unread_hot.gif b/phpBB/styles/prosilver/theme/images/topic_unread_hot.gif
index e712f6e827..a45bc4bc19 100644
--- a/phpBB/styles/prosilver/theme/images/topic_unread_hot.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_unread_hot.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_unread_hot_mine.gif b/phpBB/styles/prosilver/theme/images/topic_unread_hot_mine.gif
index fa8b167c64..dc673266be 100644
--- a/phpBB/styles/prosilver/theme/images/topic_unread_hot_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_unread_hot_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_unread_locked.gif b/phpBB/styles/prosilver/theme/images/topic_unread_locked.gif
index 0a9768ba7d..68dd3422d7 100644
--- a/phpBB/styles/prosilver/theme/images/topic_unread_locked.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_unread_locked.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_unread_locked_mine.gif b/phpBB/styles/prosilver/theme/images/topic_unread_locked_mine.gif
index 916b60517e..4f5a36efe9 100644
--- a/phpBB/styles/prosilver/theme/images/topic_unread_locked_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_unread_locked_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/images/topic_unread_mine.gif b/phpBB/styles/prosilver/theme/images/topic_unread_mine.gif
index 4ca8492e74..24e9817ce1 100644
--- a/phpBB/styles/prosilver/theme/images/topic_unread_mine.gif
+++ b/phpBB/styles/prosilver/theme/images/topic_unread_mine.gif
Binary files differ
diff --git a/phpBB/styles/prosilver/theme/imageset.css b/phpBB/styles/prosilver/theme/imageset.css
deleted file mode 100644
index 5cd91348be..0000000000
--- a/phpBB/styles/prosilver/theme/imageset.css
+++ /dev/null
@@ -1,376 +0,0 @@
-/* Former imageset */
-span.imageset {
- display: inline-block !important;
- background: transparent none 0 0 no-repeat;
- margin: 0;
- padding: 0;
- width: 0;
- height: 0;
- overflow: hidden;
-}
-
-/* Global imageset items */
-.imageset.site_logo {
- background-image: url("./images/site_logo.gif");
- padding-left: 149px;
- padding-top: 52px;
-}
-.imageset.forum_link {
- background-image: url("./images/forum_link.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.forum_read {
- background-image: url("./images/forum_read.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.forum_read_locked {
- background-image: url("./images/forum_read_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.forum_read_subforum {
- background-image: url("./images/forum_read_subforum.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.forum_unread {
- background-image: url("./images/forum_unread.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.forum_unread_locked {
- background-image: url("./images/forum_unread_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.forum_unread_subforum {
- background-image: url("./images/forum_unread_subforum.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_moved {
- background-image: url("./images/topic_moved.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_read {
- background-image: url("./images/topic_read.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_read_mine {
- background-image: url("./images/topic_read_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_read_hot {
- background-image: url("./images/topic_read_hot.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_read_hot_mine {
- background-image: url("./images/topic_read_hot_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_read_locked {
- background-image: url("./images/topic_read_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_read_locked_mine {
- background-image: url("./images/topic_read_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_unread {
- background-image: url("./images/topic_unread.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_unread_mine {
- background-image: url("./images/topic_unread_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_unread_hot {
- background-image: url("./images/topic_unread_hot.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_unread_hot_mine {
- background-image: url("./images/topic_unread_hot_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_unread_locked {
- background-image: url("./images/topic_unread_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.topic_unread_locked_mine {
- background-image: url("./images/topic_unread_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_read {
- background-image: url("./images/sticky_read.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_read_mine {
- background-image: url("./images/sticky_read_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_read_locked {
- background-image: url("./images/sticky_read_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_read_locked_mine {
- background-image: url("./images/sticky_read_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_unread {
- background-image: url("./images/sticky_unread.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_unread_mine {
- background-image: url("./images/sticky_unread_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_unread_locked {
- background-image: url("./images/sticky_unread_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.sticky_unread_locked_mine {
- background-image: url("./images/sticky_unread_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_read {
- background-image: url("./images/announce_read.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_read_mine {
- background-image: url("./images/announce_read_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_read_locked {
- background-image: url("./images/announce_read_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_read_locked_mine {
- background-image: url("./images/announce_read_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_unread {
- background-image: url("./images/announce_unread.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_unread_mine {
- background-image: url("./images/announce_unread_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_unread_locked {
- background-image: url("./images/announce_unread_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.announce_unread_locked_mine {
- background-image: url("./images/announce_unread_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_read {
- background-image: url("./images/announce_read.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_read_mine {
- background-image: url("./images/announce_read_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_read_locked {
- background-image: url("./images/announce_read_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_read_locked_mine {
- background-image: url("./images/announce_read_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_unread {
- background-image: url("./images/announce_unread.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_unread_mine {
- background-image: url("./images/announce_unread_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_unread_locked {
- background-image: url("./images/announce_unread_locked.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.global_unread_locked_mine {
- background-image: url("./images/announce_unread_locked_mine.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.subforum_read {
- background-image: url("./images/subforum_read.gif");
- padding-left: 11px;
- padding-top: 9px;
-}
-.imageset.subforum_unread {
- background-image: url("./images/subforum_unread.gif");
- padding-left: 11px;
- padding-top: 9px;
-}
-.imageset.pm_read {
- background-image: url("./images/topic_read.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.pm_unread {
- background-image: url("./images/topic_unread.gif");
- padding-left: 27px;
- padding-top: 27px;
-}
-.imageset.icon_back_top {
- background-image: url("./images/icon_back_top.gif");
- padding-left: 11px;
- padding-top: 11px;
-}
-.imageset.phpbb_aol-icon, .imageset.icon_contact_aim {
- background-image: url("./images/icon_contact_aim.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_contact_email {
- background-image: url("./images/icon_contact_email.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_contact_icq, .imageset.phpbb_icq-icon {
- background-image: url("./images/icon_contact_icq.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_contact_jabber {
- background-image: url("./images/icon_contact_jabber.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.phpbb_wlm-icon, .imageset.icon_contact_msnm {
- background-image: url("./images/icon_contact_msnm.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_contact_www, .imageset.phpbb_website-icon {
- background-image: url("./images/icon_contact_www.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_contact_yahoo, .imageset.phpbb_yahoo-icon {
- background-image: url("./images/icon_contact_yahoo.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_delete {
- background-image: url("./images/icon_post_delete.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_info {
- background-image: url("./images/icon_post_info.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_report {
- background-image: url("./images/icon_post_report.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_target {
- background-image: url("./images/icon_post_target.gif");
- padding-left: 11px;
- padding-top: 9px;
-}
-.imageset.icon_post_target_unread {
- background-image: url("./images/icon_post_target_unread.gif");
- padding-left: 11px;
- padding-top: 9px;
-}
-.imageset.icon_topic_attach {
- background-image: url("./images/icon_topic_attach.gif");
- padding-left: 7px;
- padding-top: 10px;
-}
-.imageset.icon_topic_latest {
- background-image: url("./images/icon_topic_latest.gif");
- padding-left: 11px;
- padding-top: 9px;
-}
-.imageset.icon_topic_newest {
- background-image: url("./images/icon_topic_newest.gif");
- padding-left: 11px;
- padding-top: 9px;
-}
-.imageset.icon_topic_reported {
- background-image: url("./images/icon_topic_reported.gif");
- padding-left: 16px;
- padding-top: 14px;
-}
-.imageset.icon_topic_deleted {
- background-image: url("./images/icon_topic_deleted.png");
- padding-left: 16px;
- padding-top: 14px;
-}
-.imageset.icon_topic_unapproved {
- background-image: url("./images/icon_topic_unapproved.gif");
- padding-left: 16px;
- padding-top: 14px;
-}
-.imageset.icon_topic_poll {
- background-image: url("./images/icon_topic_poll.gif");
- padding-left: 11px;
- padding-top: 10px;
-}
-.imageset.icon_user_warn {
- background-image: url("./images/icon_user_warn.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-
-.imageset.icon_contact {
- background-image: url("./images/icon_contact.png");
- padding-left: 16px;
- padding-top: 12px;
-}
-
-
-/* English images for fallback */
-.imageset.icon_user_online {
- background-image: url("./en/icon_user_online.gif");
- padding-left: 58px;
- padding-top: 58px;
-}
diff --git a/phpBB/styles/prosilver/theme/links.css b/phpBB/styles/prosilver/theme/links.css
index a2f512443c..6a61e9a262 100644
--- a/phpBB/styles/prosilver/theme/links.css
+++ b/phpBB/styles/prosilver/theme/links.css
@@ -6,9 +6,11 @@ a {
direction: ltr;
unicode-bidi: embed;
text-decoration: none;
-}
+ /* we use links inline more often then not so to address several bugs with
+ IE and some other browsers we render all links as inlineblock by default */
+ display: inline-block;
-a:hover { text-decoration: underline; }
+}
/* Coloured usernames */
.username-coloured {
@@ -26,12 +28,6 @@ a:hover { text-decoration: underline; }
text-decoration: underline;
}
-/* Navigation bar links */
-li.breadcrumbs span:first-child > a {
- display: inline-block;
- padding-left: 17px;
-}
-
/* Notification mark read link */
.dropdown-extended a.mark_read {
background-position: center center;
@@ -43,8 +39,6 @@ li.breadcrumbs span:first-child > a {
z-index: 2;
right: 0;
top: 50%;
- width: 30px;
- height: 40px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
@@ -55,9 +49,13 @@ li.breadcrumbs span:first-child > a {
}
.dropdown-extended a.mark_read:hover {
- width: 40px;
+ width: 50px;
}
+.jumpbox-cat-link,
+.jumpbox-forum-link { font-weight: bold; }
+
+
/* Links for forum/topic lists */
a.forumtitle {
font-family: "Trebuchet MS", Helvetica, Arial, Sans-serif;
@@ -75,6 +73,7 @@ a.topictitle {
font-size: 1.2em;
font-weight: bold;
text-decoration: none;
+ display: inline;
}
a.topictitle:hover {
@@ -90,6 +89,17 @@ a.lastsubject:hover {
text-decoration: underline;
}
+.row-item a:hover {
+ text-decoration: none
+}
+
+.row-item .topictitle:hover,
+.row-item .subforum:hover,
+.row-item .username:hover,
+.row-item .username-coloured:hover {
+ text-decoration: underline;
+}
+
/* Post body links */
.postlink {
text-decoration: none;
@@ -126,72 +136,49 @@ a.lastsubject:hover {
text-decoration: underline;
}
+.top {
+ font-size: 12px;
+ text-decoration: none;
+ margin-top: 10px;
+}
+
/* Back to top of page */
.back2top {
clear: both;
- height: 11px;
- text-align: right;
}
-a.top {
- background: none no-repeat top left;
- text-decoration: none;
- width: 11px;
- height: 11px;
- display: block;
+.back2top .top {
float: right;
- overflow: hidden;
- letter-spacing: 1000px;
- text-indent: 11px;
-}
-
-a.top2 {
- background: none no-repeat 0 50%;
- text-decoration: none;
- padding-left: 15px;
+ margin-right: -10px;
+ margin-top: 0;
}
/* Arrow links */
-a.arrow-up { background: none no-repeat left center; }
-a.arrow-down { background: none no-repeat right center; }
-a.arrow-left { background: none no-repeat 3px 60%; }
-a.arrow-right { background: none no-repeat 95% 60%; }
-a.arrow-up {
+.arrow-up {
padding-left: 10px;
text-decoration: none;
border-bottom-width: 0;
}
-a.arrow-up:hover {
- background-position: left top;
+.arrow-up:hover {
+
}
-a.arrow-down {
+.arrow-down {
padding-right: 10px;
}
-a.arrow-down:hover {
- background-position: right bottom;
- text-decoration: none;
-}
+.arrow-down:hover {
-a.arrow-left {
- padding-left: 12px;
}
-a.arrow-left:hover {
+.arrow-left:hover {
text-decoration: none;
- background-position: 0 60%;
-}
-
-a.arrow-right {
- padding-right: 12px;
}
-a.arrow-right:hover {
+.arrow-right:hover {
text-decoration: none;
- background-position: 100% 60%;
}
/* invisible skip link, used for accessibility */
diff --git a/phpBB/styles/prosilver/theme/normalize.css b/phpBB/styles/prosilver/theme/normalize.css
new file mode 100644
index 0000000000..23d84492c8
--- /dev/null
+++ b/phpBB/styles/prosilver/theme/normalize.css
@@ -0,0 +1,424 @@
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS and IE text size adjust after device orientation change,
+ * without disabling user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -ms-text-size-adjust: 100%; /* 2 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+ display: inline-block; /* 1 */
+ vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+ display: none;
+}
+
+/* Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * Improve readability of focused elements when they are also in an
+ * active/hover state.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+ margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+ overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ * Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit; /* 1 */
+ font: inherit; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+ overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+ line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ box-sizing: content-box; /* 2 */
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+ font-weight: bold;
+}
+
+/* Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+td,
+th {
+ padding: 0;
+}
diff --git a/phpBB/styles/prosilver/theme/plupload.css b/phpBB/styles/prosilver/theme/plupload.css
index b17cca5f25..b1f3ae2da8 100644
--- a/phpBB/styles/prosilver/theme/plupload.css
+++ b/phpBB/styles/prosilver/theme/plupload.css
@@ -1,9 +1,13 @@
-#attach-panel-multi {
+.attach-panel-multi {
display: none;
margin-bottom: 1em;
}
-#file-list td {
+.attach-row-tpl {
+ display: none;
+}
+
+.file-list td {
vertical-align: middle;
}
@@ -37,11 +41,11 @@
float: right;
}
-#attach-row-tpl, .nojs .file-inline-bbcode {
+.nojs .file-inline-bbcode {
display: none;
}
-#file-total-progress {
+.file-total-progress {
height: 2px;
display: block;
position: relative;
@@ -55,7 +59,7 @@
width: 50px;
}
-.file-progress-bar, #file-total-progress-bar {
+.file-progress-bar, .file-total-progress-bar {
background-color: green;
display: block;
height: 100%;
diff --git a/phpBB/styles/prosilver/theme/print.css b/phpBB/styles/prosilver/theme/print.css
index 34129c92e8..9445279773 100644
--- a/phpBB/styles/prosilver/theme/print.css
+++ b/phpBB/styles/prosilver/theme/print.css
@@ -19,14 +19,14 @@ a:link { color: #000000; text-decoration: none; }
a:visited { color: #000000; text-decoration: none; }
a:active { color: #000000; text-decoration: none; }
-img, .noprint, #sub-header, #sub-footer, .navbar, .box1, .divider, .signature { display: none; }
+img, .noprint, .navbar, .box1, .divider, .signature { display: none; }
/* Display smilies (Bug #47265) */
.content img {
display: inline;
}
/* Container for the main body */
-#wrap {
+.wrap {
margin: 0 2em;
}
@@ -133,7 +133,18 @@ ol, ul {
/* Misc page elements */
div.spacer { clear: both; }
+code { display: block; }
+
/* Accessibility tweaks: Mozilla.org */
.skip_link { display: none; }
.codebox p { display: none; }
+
+/* stylelint-disable declaration-property-unit-whitelist */
+.emoji {
+ min-height: 18px;
+ min-width: 18px;
+ height: 1em;
+ width: 1em;
+}
+/* stylelint-enable declaration-property-unit-whitelist */
diff --git a/phpBB/styles/prosilver/theme/responsive.css b/phpBB/styles/prosilver/theme/responsive.css
index 8653042a69..ca4054c27f 100644
--- a/phpBB/styles/prosilver/theme/responsive.css
+++ b/phpBB/styles/prosilver/theme/responsive.css
@@ -1,167 +1,110 @@
/* Responsive Design
---------------------------------------- */
-.responsive-hide { display: none !important; }
-.responsive-show { display: block !important; }
-.responsive-show-inline { display: inline !important; }
-.responsive-show-inline-block { display: inline-block !important; }
-
-/* Content wrappers
-----------------------------------------*/
-html {
- height: auto;
-}
-
-body {
- padding: 0;
-}
-
-#wrap {
- border: none;
- border-radius: 0;
- margin: 0;
- min-width: 290px;
- padding: 0 5px;
+@media (max-width: 320px) {
+ select, .inputbox {
+ max-width: 240px;
+ }
}
-/* Common block wrappers
+/* Notifications list
----------------------------------------*/
-.headerbar, .navbar, .forabg, .forumbg, .post, .panel {
- border-radius: 0;
- margin-left: -5px;
- margin-right: -5px;
+@media (max-width: 350px) {
+ .dropdown-extended .dropdown-contents {
+ width: auto;
+ }
}
-#cp-main .forabg, #cp-main .forumdb, #cp-main .post, #cp-main .panel {
- border-radius: 7px;
-}
+@media (max-width: 430px) {
+ .action-bar .search-box .inputbox {
+ width: 120px;
+ }
-/* Logo block
-----------------------------------------*/
-#site-description {
- float: none;
- width: auto;
- text-align: center;
-}
+ .section-viewtopic .search-box .inputbox {
+ width: 57px;
+ }
-.logo {
- /* change display value to inline-block to show logo */
- display: none;
- float: none;
- padding: 10px;
-}
+ .action-bar .search-box .inputbox ::-moz-placeholder {
+ content: "Search...";
+ }
-#site-description h1, #site-description p {
- text-align: inherit;
- float: none;
- margin: 5px;
- line-height: 1.2em;
- overflow: hidden;
- text-overflow: ellipsis;
-}
+ .action-bar .search-box .inputbox :-ms-input-placeholder {
+ content: "Search...";
+ }
-#site-description p, .search-header {
- display: none;
+ .action-bar .search-box .inputbox ::-webkit-input-placeholder {
+ content: "Search...";
+ }
}
-/* Navigation
-----------------------------------------*/
-.headerbar + .navbar {
- margin-top: -5px;
-}
+@media (max-width: 500px) {
+ dd label {
+ white-space: normal;
+ }
-/* Search
-----------------------------------------*/
-.responsive-search { display: block !important; }
-.responsive-search a {
- display: block;
- width: 16px;
- height: 22px;
- text-indent: 99px;
- overflow: hidden;
- background-position: 50% 50%;
- background-repeat: no-repeat;
- text-decoration: none;
-}
+ select, .inputbox {
+ max-width: 260px;
+ }
-/* .topiclist lists
-----------------------------------------*/
-li.header dt {
- text-align: center;
- text-transform: none;
- line-height: 1em;
- font-size: 1.2em;
- padding-bottom: 4px;
-}
+ .captcha-panel dd.captcha {
+ margin-left: 0;
+ }
-ul.topiclist li.header dt, ul.topiclist li.header dt .list-inner {
- margin-right: 0 !important;
- padding-right: 0;
-}
+ .captcha-panel dd.captcha-image img {
+ width: 100%;
+ }
-ul.topiclist li.header dd {
- display: none !important;
-}
+ dl.details dt, dl.details dd {
+ width: auto;
+ float: none;
+ text-align: left;
+ }
-ul.topiclist dt, ul.topiclist dt .list-inner,
-ul.topiclist.missing-column dt, ul.topiclist.missing-column dt .list-inner,
-ul.topiclist.two-long-columns dt, ul.topiclist.two-long-columns dt .list-inner,
-ul.topiclist.two-columns dt, ul.topiclist.two-columns dt .list-inner {
- margin-right: 0;
-}
+ dl.details dd {
+ margin-left: 20px;
+ }
-ul.topiclist dt .list-inner.with-mark {
- padding-right: 34px;
-}
+ p.responsive-center {
+ float: none;
+ text-align: center;
+ margin-bottom: 5px;
+ }
-ul.topiclist dt .list-inner {
- min-height: 28px;
-}
+ .action-bar > div {
+ margin-bottom: 5px;
+ }
-ul.topiclist li.header dt .list-inner {
- min-height: 0;
-}
+ .action-bar > .pagination {
+ float: none;
+ clear: both;
+ padding-bottom: 1px;
+ text-align: center;
+ }
-ul.topiclist dd {
- display: none;
-}
-ul.topiclist dd.mark {
- display: block;
-}
+ .action-bar > .pagination li.page-jump {
+ margin: 0 2px;
+ }
-/* Forums and topics lists
-----------------------------------------*/
-ul.topiclist.forums dt {
- margin-right: -250px;
-}
-ul.topiclist.forums dt .list-inner {
- margin-right: 250px;
-}
+ p.jumpbox-return {
+ display: none;
+ }
-ul.topiclist.forums dd.lastpost {
- display: block;
-}
+ .display-options > label:nth-child(1) {
+ display: block;
+ margin-bottom: 5px;
+ }
-ul.topiclist dd.mark {
- display: block;
- position: absolute;
- right: 5px;
- top: 0;
- margin: 0;
- width: auto;
- min-width: 0;
- text-align: left;
-}
+ .attach-controls {
+ margin-top: 5px;
+ width: 100%;
+ }
-ul.topiclist.forums dd.topics dfn, ul.topiclist.topics dd.posts dfn {
- position: relative;
- left: 0;
- width: auto;
- display: inline;
- font-weight: normal;
+ .quick-links .dropdown-trigger span {
+ display: none;
+ }
}
-@media only screen and (max-width: 550px), only screen and (max-device-width: 550px) {
+@media (max-width: 550px) {
ul.topiclist.forums dt {
margin-right: 0;
}
@@ -175,400 +118,466 @@ ul.topiclist.forums dd.topics dfn, ul.topiclist.topics dd.posts dfn {
}
}
-li.row .responsive-show strong {
- font-weight: bold;
- color: inherit;
-}
+@media (max-width: 700px) {
+ .responsive-hide { display: none !important; }
+ .responsive-show { display: block !important; }
+ .responsive-show-inline { display: inline !important; }
+ .responsive-show-inline-block { display: inline-block !important; }
-ul.topiclist li.row dt a.subforum {
- display: inline-block;
- vertical-align: bottom;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 100px;
-}
+ /* Content wrappers
+ ----------------------------------------*/
+ html {
+ height: auto;
+ }
-/* Notifications list
-----------------------------------------*/
-@media only screen and (max-width: 350px), only screen and (max-device-width: 350px) {
- .dropdown-extended .dropdown-contents {
+ body {
+ padding: 0;
+ }
+
+ .wrap {
+ border: none;
+ border-radius: 0;
+ margin: 0;
+ min-width: 290px;
+ padding: 0 5px;
+ }
+
+ /* Common block wrappers
+ ----------------------------------------*/
+ .headerbar, .navbar, .forabg, .forumbg, .post, .panel {
+ border-radius: 0;
+ margin-left: -5px;
+ margin-right: -5px;
+ }
+
+ .cp-main .forabg, .cp-main .forumdb, .cp-main .post, .cp-main .panel {
+ border-radius: 7px;
+ }
+
+ /* Logo block
+ ----------------------------------------*/
+ .site-description {
+ float: none;
width: auto;
+ text-align: center;
}
-}
-/* Pagination
-----------------------------------------*/
-.pagination > ul {
- margin: 5px 0 0;
-}
+ .logo {
+ /* change display value to inline-block to show logo */
+ display: none;
+ float: none;
+ padding: 10px;
+ }
-.row .pagination .ellipsis + li {
- display: none !important;
-}
+ .site-description h1, .site-description p {
+ text-align: inherit;
+ float: none;
+ margin: 5px;
+ line-height: 1.2em;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
-/* Responsive tables
-----------------------------------------*/
-table.responsive, table.responsive tbody, table.responsive tr, table.responsive td {
- display: block;
-}
+ .site-description p, .search-header {
+ display: none;
+ }
-table.responsive thead, table.responsive th {
- display: none;
-}
+ /* Navigation
+ ----------------------------------------*/
+ .headerbar + .navbar {
+ margin-top: -5px;
+ }
-table.responsive.show-header thead, table.responsive.show-header th:first-child {
- display: block;
- width: auto !important;
- text-align: left !important;
-}
+ /* Search
+ ----------------------------------------*/
+ .responsive-search { display: block !important; }
-table.responsive.show-header th:first-child span.rank-img {
- display: none;
-}
+ /* .topiclist lists
+ ----------------------------------------*/
+ li.header dt {
+ text-align: center;
+ text-transform: none;
+ line-height: 1em;
+ font-size: 1.2em;
+ padding-bottom: 4px;
+ }
-table.responsive tr {
- margin: 2px 0;
-}
+ ul.topiclist li.header dt, ul.topiclist li.header dt .list-inner {
+ margin-right: 0 !important;
+ padding-right: 0;
+ }
-table.responsive td {
- width: auto !important;
- text-align: left !important;
- padding: 4px;
-}
+ ul.topiclist li.header dd {
+ display: none !important;
+ }
-table.responsive td.empty {
- display: none !important;
-}
+ ul.topiclist dt, ul.topiclist dt .list-inner,
+ ul.topiclist.missing-column dt, ul.topiclist.missing-column dt .list-inner,
+ ul.topiclist.two-long-columns dt, ul.topiclist.two-long-columns dt .list-inner,
+ ul.topiclist.two-columns dt, ul.topiclist.two-columns dt .list-inner {
+ margin-right: 0;
+ }
-table.responsive td > dfn {
- display: inline-block !important;
-}
+ ul.topiclist dt .list-inner.with-mark {
+ padding-right: 34px;
+ }
-table.responsive td > dfn:after {
- content: ':';
- padding-right: 5px;
-}
+ ul.topiclist dt .list-inner {
+ min-height: 28px;
+ }
-table.responsive span.rank-img {
- float: none;
- padding-right: 5px;
-}
+ ul.topiclist li.header dt .list-inner {
+ min-height: 0;
+ }
-table.responsive#memberlist td:first-child input[type="checkbox"] {
- float: right;
-}
+ ul.topiclist dd {
+ display: none;
+ }
+ ul.topiclist dd.mark {
+ display: block;
+ }
-/* Forms
-----------------------------------------*/
-fieldset dt, fieldset.fields1 dt, fieldset.fields2 dt {
- width: auto;
- float: none;
-}
+ /* Forums and topics lists
+ ----------------------------------------*/
+ ul.topiclist.forums dt {
+ margin-right: -250px;
+ }
-fieldset dd, fieldset.fields1 dd, fieldset.fields2 dd {
- margin-left: 20px;
-}
+ ul.topiclist dd.mark {
+ display: block;
+ position: absolute;
+ right: 5px;
+ top: 0;
+ margin: 0;
+ width: auto;
+ min-width: 0;
+ text-align: left;
+ }
-textarea, dd textarea, #message-box textarea {
- width: 100%;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
+ ul.topiclist.forums dd.topics dfn, ul.topiclist.topics dd.posts dfn {
+ position: relative;
+ left: 0;
+ width: auto;
+ display: inline;
+ font-weight: normal;
+ }
-dl.pmlist dt {
- width: auto !important;
- margin-bottom: 5px;
-}
+ li.row .responsive-show strong {
+ font-weight: bold;
+ color: inherit;
+ }
-dl.pmlist dd {
- display: inline-block;
- margin-left: 0 !important;
-}
+ ul.topiclist li.row dt a.subforum {
+ vertical-align: bottom;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100px;
+ }
-dl.pmlist dd:first-of-type {
- padding-left: 20px;
-}
+ /* Pagination
+ ----------------------------------------*/
+ .pagination > ul {
+ margin: 5px 0 0;
+ }
-#smiley-box, #message-box {
- float: none;
- width: auto;
-}
+ .row .pagination .ellipsis + li {
+ display: none !important;
+ }
-#smiley-box {
- margin-top: 5px;
-}
+ /* Responsive tables
+ ----------------------------------------*/
+ table.responsive, table.responsive tbody, table.responsive tr, table.responsive td {
+ display: block;
+ }
-.bbcode-status {
- display: none;
-}
+ table.responsive thead, table.responsive th {
+ display: none;
+ }
-.colour-palette, .colour-palette tbody, .colour-palette tr {
- display: block;
-}
+ table.responsive.show-header thead, table.responsive.show-header th:first-child {
+ display: block;
+ width: auto !important;
+ text-align: left !important;
+ }
-.colour-palette td {
- display: inline-block;
- margin-right: 2px;
-}
+ table.responsive.show-header th:first-child span.rank-img {
+ display: none;
+ }
-.horizontal-palette td:nth-child(2n), .vertical-palette tr:nth-child(2n) {
- display: none;
-}
+ table.responsive tr {
+ margin: 2px 0;
+ }
-.colour-palette a {
- display: inline-block !important;
-}
+ table.responsive td {
+ width: auto !important;
+ text-align: left !important;
+ padding: 4px;
+ }
-fieldset.quick-login label {
- display: block;
- margin-bottom: 5px;
- white-space: normal;
-}
+ table.responsive td.empty {
+ display: none !important;
+ }
-fieldset.quick-login label > span {
- display: inline-block;
- min-width: 100px;
-}
+ table.responsive td > dfn {
+ display: inline-block !important;
+ }
-fieldset.quick-login input.inputbox {
- width: 85%;
- max-width: 300px;
- margin-left: 20px;
-}
+ table.responsive td > dfn:after {
+ content: ':';
+ padding-right: 5px;
+ }
-fieldset.quick-login label[for="autologin"] {
- display: inline-block;
- text-align: right;
- min-width: 50%;
-}
+ table.responsive span.rank-img {
+ float: none;
+ padding-right: 5px;
+ }
-@media only screen and (max-width: 500px), only screen and (max-device-width: 500px) {
- dd label {
- white-space: normal;
+ table.responsive.memberlist td:first-child input[type="checkbox"] {
+ float: right;
}
- select, .inputbox {
- max-width: 260px;
+ /* Forms
+ ----------------------------------------*/
+ fieldset dt, fieldset.fields1 dt, fieldset.fields2 dt {
+ width: auto;
+ float: none;
}
- .captcha-panel dd.captcha {
- margin-left: 0;
+ fieldset dd, fieldset.fields1 dd, fieldset.fields2 dd {
+ margin-left: 0px;
}
- .captcha-panel dd.captcha-image img {
+ textarea, dd textarea, .message-box textarea {
width: 100%;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
- #recaptcha_challenge_image,
- #recaptcha_response_field,
- .recaptchatable #recaptcha_image {
- width: 100% !important;
- height: auto !important;
+ dl.pmlist dt {
+ width: auto !important;
+ margin-bottom: 5px;
+ }
+
+ dl.pmlist dd {
+ display: inline-block;
+ margin-left: 0 !important;
+ }
+
+ dl.pmlist dd:first-of-type {
+ padding-left: 20px;
+ }
+
+ .smiley-box, .message-box {
+ float: none;
+ width: auto;
}
- .recaptchatable tr td:last-child {
+ .smiley-box {
+ margin-top: 5px;
+ }
+
+ .bbcode-status {
display: none;
}
- .captcha-panel .recaptcha-responsive {
- display: inline-block !important;
- margin-top: 10px;
- vertical-align: middle;
+ .colour-palette, .colour-palette tbody, .colour-palette tr {
+ display: block;
}
-}
-@media only screen and (max-width: 430px), only screen and (max-device-width: 430px) {
- .section-viewtopic .search-box .inputbox {
- width: 110px;
+ .colour-palette td {
+ display: inline-block;
+ margin-right: 2px;
}
-}
-@media only screen and (max-width: 320px), only screen and (max-device-width: 320px) {
- select, .inputbox {
- max-width: 240px;
+ .horizontal-palette td:nth-child(2n), .vertical-palette tr:nth-child(2n) {
+ display: none;
}
-}
-/* User profile
-----------------------------------------*/
-.column1, .column2, .left-box.profile-details {
- float: none;
- width: auto;
-}
+ fieldset.quick-login label {
+ display: block;
+ margin-bottom: 5px;
+ white-space: normal;
+ }
-@media only screen and (max-width: 500px), only screen and (max-device-width: 500px) {
- dl.details dt, dl.details dd {
- width: auto;
- float: none;
- text-align: left;
+ fieldset.quick-login label > span {
+ display: inline-block;
+ min-width: 100px;
}
- dl.details dd {
+ fieldset.quick-login input.inputbox {
+ width: 85%;
+ max-width: 300px;
margin-left: 20px;
}
-}
-/* Polls
-----------------------------------------*/
-fieldset.polls dt {
- width: 90%;
-}
+ fieldset.quick-login label[for="autologin"] {
+ display: inline-block;
+ text-align: right;
+ min-width: 50%;
+ }
-fieldset.polls dd.resultbar {
- padding-left: 20px;
-}
+ /* User profile
+ ----------------------------------------*/
+ .column1, .column2, .left-box.profile-details {
+ float: none;
+ width: auto;
+ clear: both;
+ }
-fieldset.polls dd.poll_option_percent {
- width: 20%;
-}
+ /* Polls
+ ----------------------------------------*/
+ fieldset.polls dt {
+ width: 90%;
+ }
-fieldset.polls dd.resultbar, fieldset.polls dd.poll_option_percent {
- margin-top: 5px;
-}
+ fieldset.polls dd.resultbar {
+ padding-left: 20px;
+ }
-/* Post
-----------------------------------------*/
-.postbody {
- position: inherit;
-}
+ fieldset.polls dd.poll_option_percent {
+ width: 20%;
+ }
-.postprofile, .postbody, .search .postbody {
- display: block;
- width: auto;
- float: none;
- padding: 0;
- min-height: 0;
-}
+ fieldset.polls dd.resultbar, fieldset.polls dd.poll_option_percent {
+ margin-top: 5px;
+ }
-.post .postprofile {
- width: auto;
- border-width: 0 0 1px 0;
- padding-bottom: 5px;
- margin: 0;
- margin-bottom: 5px;
- min-height: 40px;
- overflow: hidden;
-}
+ /* Post
+ ----------------------------------------*/
+ .postbody {
+ position: inherit;
+ }
-.postprofile dd {
- display: none;
-}
+ .postprofile, .postbody, .search .postbody {
+ display: block;
+ width: auto;
+ float: none;
+ padding: 0;
+ min-height: 0;
+ }
-.postprofile dt, .postprofile dd.profile-rank, .search .postprofile dd {
- display: block;
- margin: 0;
-}
+ .post .postprofile {
+ width: auto;
+ border-width: 0 0 1px 0;
+ padding-bottom: 5px;
+ margin: 0;
+ margin-bottom: 5px;
+ min-height: 40px;
+ overflow: hidden;
+ }
-.postprofile .has-avatar .avatar-container {
- margin: 0;
- overflow: inherit;
-}
+ .postprofile dd {
+ display: none;
+ }
-.postprofile .avatar-container:after {
- clear: none;
-}
+ .postprofile dt, .postprofile dd.profile-rank, .search .postprofile dd {
+ display: block;
+ margin: 0;
+ }
-.postprofile .avatar {
- margin-right: 5px;
-}
+ .postprofile .has-avatar .avatar-container {
+ margin: 0;
+ overflow: inherit;
+ }
-.postprofile .avatar img {
- width: auto !important;
- height: auto !important;
- max-height: 32px;
-}
+ .postprofile .avatar-container:after {
+ clear: none;
+ }
-.has-profile .postbody h3 {
- margin-left: 0 !important;
- margin-right: 0 !important;
-}
+ .postprofile .avatar {
+ margin-right: 5px;
+ }
-.has-profile .post-buttons {
- right: 20px;
- top: 15px;
-}
+ .postprofile .avatar img {
+ width: auto !important;
+ height: auto !important;
+ max-height: 32px;
+ }
-.online {
- background-size: 40px;
-}
+ .has-profile .postbody h3 {
+ margin-left: 0 !important;
+ margin-right: 0 !important;
+ }
-/* Misc stuff
-----------------------------------------*/
-h2 {
- margin-top: .5em;
-}
+ .has-profile .post-buttons {
+ right: 30px;
+ top: 15px;
+ }
-p {
- margin-bottom: .5em;
- overflow: hidden;
-}
+ .online {
+ background-size: 40px;
+ }
-p.rightside {
- margin-bottom: 0;
-}
+ /* Misc stuff
+ ----------------------------------------*/
+ h2 {
+ margin-top: .5em;
+ }
-fieldset.display-options label {
- display: block;
- clear: both;
- margin-bottom: 5px;
-}
+ p {
+ margin-bottom: .5em;
+ overflow: hidden;
+ }
-dl.mini dd.pm-legend {
- float: left;
- min-width: 200px;
-}
+ p.rightside {
+ margin-bottom: 0;
+ }
-#topicreview {
- margin: 0 -5px;
- padding: 0 5px;
-}
+ fieldset.display-options label {
+ display: block;
+ clear: both;
+ margin-bottom: 5px;
+ }
-fieldset.display-actions {
- white-space: normal;
+ dl.mini dd.pm-legend {
+ float: left;
+ min-width: 200px;
+ }
+
+ .topicreview {
+ margin: 0 -5px;
+ padding: 0 5px;
+ }
+
+ fieldset.display-actions {
+ white-space: normal;
+ }
+
+ .phpbb_alert {
+ width: auto;
+ margin: 0 5px;
+ }
+
+ .attach-comment dfn {
+ width: 100%;
+ }
}
-.phpbb_alert {
- width: auto;
- margin: 0 5px;
+@media (min-width: 700px) {
+ .postbody { width: 70%; }
}
-.attach-comment dfn {
- width: 100%;
+@media (min-width: 850px) {
+ .postbody { width: 76%; }
}
-@media only screen and (max-width: 500px), only screen and (max-device-width: 500px) {
- p.responsive-center {
- float: none;
- text-align: center;
- margin-bottom: 5px;
- }
+@media (max-width: 850px) {
+ .postprofile { width: 28%; }
- .action-bar > div {
- margin-bottom: 5px;
- }
- .action-bar > .pagination {
- float: none;
- clear: both;
- padding-bottom: 1px;
- text-align: center;
- }
+}
- .action-bar > .pagination li.page-jump {
- margin: 0 2px;
- }
+@media (min-width: 701px) and (max-width: 950px) {
- p.jumpbox-return {
- display: none;
+ ul.topiclist dt {
+ margin-right: -410px;
}
- .display-options > label:nth-child(1) {
- display: block;
- margin-bottom: 5px;
+ ul.topiclist dt .list-inner {
+ margin-right: 410px;
}
- .attach-controls {
- margin-top: 5px;
- width: 100%;
+ dd.posts, dd.topics, dd.views {
+ width: 80px;
}
}
diff --git a/phpBB/styles/prosilver/theme/stylesheet.css b/phpBB/styles/prosilver/theme/stylesheet.css
index 77c7c88b07..45eb5b6fc9 100644
--- a/phpBB/styles/prosilver/theme/stylesheet.css
+++ b/phpBB/styles/prosilver/theme/stylesheet.css
@@ -1,17 +1,21 @@
/* phpBB3 Style Sheet
--------------------------------------------------------------
- Style name: prosilver (the default phpBB 3.1.x style)
- Based on style:
+ Style name: prosilver (the default phpBB 3.2.x style)
+ Based on style:
Original author: Tom Beddard ( http://www.subblue.com/ )
Modified by: phpBB Limited ( https://www.phpbb.com/ )
--------------------------------------------------------------
*/
-@import url("common.css");
-@import url("links.css");
-@import url("content.css");
-@import url("buttons.css");
-@import url("cp.css");
-@import url("forms.css");
-@import url("colours.css");
-@import url("imageset.css");
+@import url("normalize.css?v=3.2");
+@import url("base.css?v=3.2");
+@import url("utilities.css?v=3.2");
+@import url("common.css?v=3.2");
+@import url("links.css?v=3.2");
+@import url("content.css?v=3.2");
+@import url("buttons.css?v=3.2");
+@import url("cp.css?v=3.2");
+@import url("forms.css?v=3.2");
+@import url("icons.css?v=3.2");
+@import url("colours.css?v=3.2");
+@import url("responsive.css?v=3.2");
diff --git a/phpBB/styles/prosilver/theme/tweaks.css b/phpBB/styles/prosilver/theme/tweaks.css
index d2dad9e299..ba82551f85 100644
--- a/phpBB/styles/prosilver/theme/tweaks.css
+++ b/phpBB/styles/prosilver/theme/tweaks.css
@@ -27,3 +27,15 @@ dd label input { vertical-align: text-bottom\9; }
.search-header, .search-header .inputbox, .search-header a.button {
border-radius: 0;
}
+
+.headerbar, .forumbg {
+ background-image: url("./images/bg_header.gif");
+}
+
+.forabg {
+ background-image: url("./images/bg_list.gif");
+}
+
+.tabs .tab > a {
+ border-radius: 0;
+}
diff --git a/phpBB/styles/prosilver/theme/utilities.css b/phpBB/styles/prosilver/theme/utilities.css
new file mode 100644
index 0000000000..cbb8127d1c
--- /dev/null
+++ b/phpBB/styles/prosilver/theme/utilities.css
@@ -0,0 +1,66 @@
+/* --------------------------------------------------------------
+ $Utilities
+-------------------------------------------------------------- */
+
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ margin: -1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ border: 0;
+}
+
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ clip: auto;
+}
+
+.clearfix:before,
+.clearfix:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after {
+ content: " ";
+ display: table;
+}
+.clearfix:after,
+.container:after,
+.container-fluid:after,
+.row:after { clear: both }
+
+.center-block {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.pull-right { float: right !important }
+.pull-left { float: left !important }
+.hide { display: none !important }
+.show { display: block !important }
+.invisible { visibility: hidden }
+
+.text-hide {
+ font: 0/0 a;
+ color: transparent;
+ text-shadow: none;
+ background-color: transparent;
+ border: 0;
+}
+
+.hidden {
+ display: none ;
+}
+
+.affix { position: fixed }
diff --git a/phpBB/styles/subsilver2/style.cfg b/phpBB/styles/subsilver2/style.cfg
deleted file mode 100644
index 65d846402d..0000000000
--- a/phpBB/styles/subsilver2/style.cfg
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# phpBB Style Configuration File
-#
-# This file is part of the phpBB Forum Software package.
-#
-# @copyright (c) phpBB Limited <https://www.phpbb.com>
-# @license GNU General Public License, version 2 (GPL-2.0)
-#
-# For full copyright and license information, please see
-# the docs/CREDITS.txt file.
-#
-# At the left is the name, please do not change this
-# At the right the value is entered
-#
-# Values get trimmed, if you want to add a space in front or at the end of
-# the value, then enclose the value with single or double quotes.
-# Single and double quotes do not need to be escaped.
-#
-#
-
-# General Information about this style
-name = subsilver2
-copyright = © 2005 phpBB Limited
-style_version = 3.1.11
-phpbb_version = 3.1.11
-
-# Defining a different template bitfield
-# template_bitfield = lNg=
-
-# Parent style
-# Set value to empty or to this style's name if this style does not have a parent style
-parent = subsilver2
diff --git a/phpBB/styles/subsilver2/template/attachment.html b/phpBB/styles/subsilver2/template/attachment.html
deleted file mode 100644
index 65a28aead4..0000000000
--- a/phpBB/styles/subsilver2/template/attachment.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!-- EVENT attachment_file_before -->
-
-<!-- BEGIN _file -->
-
- <!-- IF _file.S_DENIED -->
- <span class="genmed">[{_file.DENIED_MESSAGE}]</span><br />
- <!-- ELSE -->
- <!-- EVENT attachment_file_prepend -->
-
- <!-- IF _file.COMMENT -->
- <span class="gensmall"><b>{L_FILE_COMMENT}{L_COLON}</b> {_file.COMMENT}</span><br />
- <!-- ENDIF -->
-
- <!-- IF _file.S_THUMBNAIL -->
- <a href="{_file.U_DOWNLOAD_LINK}"><img src="{_file.THUMB_IMAGE}" class="postimage" alt="{_file.DOWNLOAD_NAME}" /></a><br />
- <span class="gensmall">{_file.DOWNLOAD_NAME} [ {_file.FILESIZE} {_file.SIZE_LANG} | {_file.L_DOWNLOAD_COUNT} ]</span>
- <!-- ENDIF -->
-
- <!-- IF _file.S_IMAGE -->
- <img src="{_file.U_INLINE_LINK}" class="postimage" alt="{_file.DOWNLOAD_NAME}" /><br />
- <span class="gensmall">{_file.DOWNLOAD_NAME} [ {_file.FILESIZE} {_file.SIZE_LANG} | {_file.L_DOWNLOAD_COUNT} ]</span>
- <!-- ENDIF -->
-
- <!-- IF _file.S_FILE -->
- <span class="genmed">
- <!-- IF _file.UPLOAD_ICON -->{_file.UPLOAD_ICON} <!-- ENDIF -->
- <a href="{_file.U_DOWNLOAD_LINK}">{_file.DOWNLOAD_NAME}</a> [{_file.FILESIZE} {_file.SIZE_LANG}]
- </span><br />
- <span class="gensmall">{_file.L_DOWNLOAD_COUNT}</span>
- <!-- ENDIF -->
-
- <!-- IF _file.S_WM_FILE -->
- <!-- method used here from http://alistapart.com/articles/byebyeembed / autosizing seems to not work always, this will not fix -->
- <object width="320" height="285" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" id="wmstream_{_file.ATTACH_ID}">
- <param name="url" value="{_file.U_DOWNLOAD_LINK}" />
- <param name="showcontrols" value="1" />
- <param name="showdisplay" value="0" />
- <param name="showstatusbar" value="0" />
- <param name="autosize" value="1" />
- <param name="autostart" value="0" />
- <param name="visible" value="1" />
- <param name="animationstart" value="0" />
- <param name="loop" value="0" />
- <param name="src" value="{_file.U_DOWNLOAD_LINK}" />
- <!--[if !IE]>-->
- <object width="320" height="285" type="video/x-ms-wmv" data="{_file.U_DOWNLOAD_LINK}">
- <param name="src" value="{_file.U_DOWNLOAD_LINK}" />
- <param name="controller" value="1" />
- <param name="showcontrols" value="1" />
- <param name="showdisplay" value="0" />
- <param name="showstatusbar" value="0" />
- <param name="autosize" value="1" />
- <param name="autostart" value="0" />
- <param name="visible" value="1" />
- <param name="animationstart" value="0" />
- <param name="loop" value="0" />
- </object>
- <!--<![endif]-->
- </object>
-
- <!-- ELSEIF _file.S_FLASH_FILE -->
- <object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{_file.WIDTH}" height="{_file.HEIGHT}">
- <param name="movie" value="{_file.U_VIEW_LINK}" />
- <param name="play" value="true" />
- <param name="loop" value="true" />
- <param name="quality" value="high" />
- <param name="allowScriptAccess" value="never" />
- <param name="allowNetworking" value="internal" />
- <embed src="{_file.U_VIEW_LINK}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{_file.WIDTH}" height="{_file.HEIGHT}" play="true" loop="true" quality="high" allowscriptaccess="never" allownetworking="internal"></embed>
- </object>
- <!-- ELSEIF _file.S_QUICKTIME_FILE -->
- <object id="qtstream_{_file.ATTACH_ID}" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0" width="320" height="285">
- <param name="src" value="{_file.U_DOWNLOAD_LINK}">
- <param name="controller" value="true">
- <param name="autoplay" value="false" />
- <param name="type" value="video/quicktime">
- <embed name="qtstream_{_file.ATTACH_ID}" src="{_file.U_DOWNLOAD_LINK}" pluginspage="http://www.apple.com/quicktime/download/" enablejavascript="true" controller="true" width="320" height="285" type="video/quicktime" autoplay="false"></embed>
- </object>
- <!-- ELSEIF _file.S_RM_FILE -->
- <object id="rmstream_{_file.ATTACH_ID}" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" width="200" height="50">
- <param name="src" value="{_file.U_DOWNLOAD_LINK}">
- <param name="autostart" value="false">
- <param name="controls" value="ImageWindow">
- <param name="console" value="ctrls_{_file.ATTACH_ID}">
- <param name="prefetch" value="false">
- <embed name="rmstream_{_file.ATTACH_ID}" type="audio/x-pn-realaudio-plugin" src="{_file.U_DOWNLOAD_LINK}" width="0" height="0" autostart="false" controls="ImageWindow" console="ctrls_{_file.ATTACH_ID}" prefetch="false"></embed>
- </object>
- <br />
- <object id="ctrls_{_file.ATTACH_ID}" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" width="0" height="36">
- <param name="controls" value="ControlPanel">
- <param name="console" value="ctrls_{_file.ATTACH_ID}">
- <embed name="ctrls_{_file.ATTACH_ID}" type="audio/x-pn-realaudio-plugin" width="200" height="36" controls="ControlPanel" console="ctrls_{_file.ATTACH_ID}"></embed>
- </object>
-
- <script type="text/javascript">
- // <![CDATA[
- if (document.rmstream_{_file.ATTACH_ID}.GetClipWidth)
- {
- while (!document.rmstream_{_file.ATTACH_ID}.GetClipWidth())
- {
- }
-
- var width = document.rmstream_{_file.ATTACH_ID}.GetClipWidth();
- var height = document.rmstream_{_file.ATTACH_ID}.GetClipHeight();
-
- document.rmstream_{_file.ATTACH_ID}.width = width;
- document.rmstream_{_file.ATTACH_ID}.height = height;
- document.ctrls_{_file.ATTACH_ID}.width = width;
- }
- // ]]>
- </script>
- <!-- ENDIF -->
-
- <!-- IF _file.S_WM_FILE or _file.S_RM_FILE or _file.S_FLASH_FILE or _file.S_QUICKTIME_FILE -->
- <br />
- <!-- IF _file.S_QUICKTIME_FILE --><a href="#" onclick="play_qt_file(document.qtstream_{_file.ATTACH_ID}); return false;">[ {L_PLAY_QUICKTIME_FILE} ]</a> <!-- ENDIF -->
- <span class="gensmall"><a href="{_file.U_DOWNLOAD_LINK}">{_file.DOWNLOAD_NAME}</a> [ {_file.FILESIZE} {_file.SIZE_LANG} | {_file.L_DOWNLOAD_COUNT} ]</span>
- <!-- ENDIF -->
-
- <!-- EVENT attachment_file_append -->
- <br />
- <!-- ENDIF -->
-
-<!-- END _file -->
-<!-- EVENT attachment_file_after -->
diff --git a/phpBB/styles/subsilver2/template/bbcode.html b/phpBB/styles/subsilver2/template/bbcode.html
deleted file mode 100644
index 9ee5acec34..0000000000
--- a/phpBB/styles/subsilver2/template/bbcode.html
+++ /dev/null
@@ -1,69 +0,0 @@
-<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open -->
-<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default -->
-<!-- BEGIN ulist_close --></ul><!-- END ulist_close -->
-
-<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open -->
-<!-- BEGIN olist_close --></ol><!-- END olist_close -->
-
-<!-- BEGIN listitem --><li><!-- END listitem -->
-<!-- BEGIN listitem_close --></li><!-- END listitem_close -->
-
-<!-- BEGIN quote_username_open -->
-<div class="quotetitle">{USERNAME} {L_WROTE}{L_COLON}</div><div class="quotecontent">
-<!-- END quote_username_open -->
-
-<!-- BEGIN quote_open -->
-<div class="quotetitle"><b>{L_QUOTE}{L_COLON}</b></div><div class="quotecontent">
-<!-- END quote_open -->
-
-<!-- BEGIN quote_close -->
-</div>
-<!-- END quote_close -->
-
-<!-- BEGIN code_open -->
-<div class="codetitle"><b>{L_CODE}{L_COLON}</b></div><pre class="codecontent">
-<!-- END code_open -->
-
-<!-- BEGIN code_close -->
-</pre>
-<!-- END code_close -->
-
-<!-- BEGIN inline_attachment_open -->
-<div class="attachtitle">{L_ATTACHMENT}{L_COLON}</div><div class="attachcontent">
-<!-- END inline_attachment_open -->
-
-<!-- BEGIN inline_attachment_close -->
-</div>
-<!-- END inline_attachment_close -->
-
-
-<!-- BEGIN b_open --><strong><!-- END b_open -->
-<!-- BEGIN b_close --></strong><!-- END b_close -->
-
-<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open -->
-<!-- BEGIN u_close --></span><!-- END u_close -->
-
-<!-- BEGIN i_open --><em><!-- END i_open -->
-<!-- BEGIN i_close --></em><!-- END i_close -->
-
-<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color -->
-
-<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: normal">{TEXT}</span><!-- END size -->
-
-<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
-
-<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
-
-<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email -->
-
-<!-- BEGIN flash -->
- <object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}">
- <param name="movie" value="{URL}" />
- <param name="play" value="false" />
- <param name="loop" value="false" />
- <param name="quality" value="high" />
- <param name="allowScriptAccess" value="never" />
- <param name="allowNetworking" value="internal" />
- <embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed>
- </object>
-<!-- END flash -->
diff --git a/phpBB/styles/subsilver2/template/breadcrumbs.html b/phpBB/styles/subsilver2/template/breadcrumbs.html
deleted file mode 100644
index 36983a5d88..0000000000
--- a/phpBB/styles/subsilver2/template/breadcrumbs.html
+++ /dev/null
@@ -1,14 +0,0 @@
- <!-- IF $S_MICRODATA --><!-- DEFINE $MICRODATA = ' itemtype="http://data-vocabulary.org/Breadcrumb" itemscope=""' --><!-- ELSE --><!-- DEFINE $MICRODATA = '' --><!-- ENDIF -->
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0" style="margin-top: 5px;">
- <tr>
- <td class="row1">
- <!-- EVENT overall_header_breadcrumbs_before -->
- <p class="breadcrumbs"><!-- IF U_SITE_HOME --><span{$MICRODATA}><a href="{U_SITE_HOME}" data-navbar-reference="home" itemprop="url"><span itemprop="title">{L_SITE_HOME}</span></a></span> <strong>&#187;</strong> <!-- ENDIF --><!-- IF $OVERALL_HEADER_BREADCRUMBS --><!-- EVENT overall_header_breadcrumb_prepend --><!-- ELSE --><!-- EVENT overall_footer_breadcrumb_prepend --><!-- ENDIF --><span{$MICRODATA}><a href="{U_INDEX}" data-navbar-reference="index" itemprop="url"><span itemprop="title">{L_INDEX}</span></a></span><!-- BEGIN navlinks --><!-- EVENT overall_header_navlink_prepend --> &#187; <span{$MICRODATA}<!-- IF navlinks.MICRODATA --> {navlinks.MICRODATA}<!-- ENDIF -->><a href="{navlinks.U_VIEW_FORUM}" itemprop="url"><span itemprop="title">{navlinks.FORUM_NAME}</span></a></span><!-- EVENT overall_header_navlink_append --><!-- END navlinks -->
- <!-- IF $OVERALL_HEADER_BREADCRUMBS --><!-- EVENT overall_header_breadcrumb_append --><!-- ELSE --><!-- EVENT overall_footer_breadcrumb_append --><!-- ENDIF --></p>
- <!-- EVENT overall_header_breadcrumbs_after -->
- <!-- EVENT overall_footer_timezone_before -->
- <p class="datetime">{S_TIMEZONE}</p>
- <!-- EVENT overall_footer_timezone_after -->
- </td>
- </tr>
- </table>
diff --git a/phpBB/styles/subsilver2/template/captcha_default.html b/phpBB/styles/subsilver2/template/captcha_default.html
deleted file mode 100644
index 1be25403ce..0000000000
--- a/phpBB/styles/subsilver2/template/captcha_default.html
+++ /dev/null
@@ -1,17 +0,0 @@
- <tr>
- <th colspan="2" valign="middle">{L_CONFIRM_CODE}</th>
- </tr>
- <!-- IF S_TYPE == 1 -->
- <tr>
- <td class="row3" colspan="2"><span class="gensmall">{L_CONFIRM_EXPLAIN}</span></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="row1" colspan="2" align="center"><img src="{CONFIRM_IMAGE_LINK}" alt="{L_CONFIRM_CODE}" />
- <input type="hidden" name="confirm_id" id="confirm_id" value="{CONFIRM_ID}" /></td>
- </tr>
- <tr>
- <td class="row1"><b class="genmed">{L_CONFIRM_CODE}{L_COLON}</b><br /><span class="gensmall">{L_CONFIRM_CODE_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="confirm_code" size="8" maxlength="8"<!-- IF $CAPTCHA_TAB_INDEX --> tabindex="{$CAPTCHA_TAB_INDEX}"<!-- ENDIF --> />
- <!-- IF S_CONFIRM_REFRESH --><input type="submit" name="refresh_vc" id="refresh_vc" class="btnlite" value="{L_VC_REFRESH}" /><!-- ENDIF --></td>
- </tr>
diff --git a/phpBB/styles/subsilver2/template/captcha_qa.html b/phpBB/styles/subsilver2/template/captcha_qa.html
deleted file mode 100644
index 90a6492400..0000000000
--- a/phpBB/styles/subsilver2/template/captcha_qa.html
+++ /dev/null
@@ -1,8 +0,0 @@
- <tr>
- <th colspan="2" valign="middle">{L_CONFIRM_QUESTION}</th>
- </tr>
- <tr>
- <td class="row1"><b class="genmed">{QA_CONFIRM_QUESTION}{L_COLON}</b><br /><span class="gensmall">{L_CONFIRM_QUESTION_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="qa_answer" size="80"<!-- IF $CAPTCHA_TAB_INDEX --> tabindex="{$CAPTCHA_TAB_INDEX}"<!-- ENDIF --> />
- <input type="hidden" name="qa_confirm_id" id="confirm_id" value="{QA_CONFIRM_ID}" /></td>
- </tr>
diff --git a/phpBB/styles/subsilver2/template/captcha_recaptcha.html b/phpBB/styles/subsilver2/template/captcha_recaptcha.html
deleted file mode 100644
index 0d116b361f..0000000000
--- a/phpBB/styles/subsilver2/template/captcha_recaptcha.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!-- IF S_RECAPTCHA_AVAILABLE -->
- <tr>
- <th colspan="2" valign="middle">{L_CONFIRM_CODE}</th>
- </tr>
- <tr>
- <td class="row1"><b class="genmed">{L_CONFIRM_CODE}{L_COLON}</b><br /><span class="gensmall">{L_RECAPTCHA_EXPLAIN}</span></td>
- <td class="row2">
- <script type="text/javascript">
- // <![CDATA[
- var RecaptchaOptions = {
- lang : '{LA_RECAPTCHA_LANG}',
- theme : 'clean',
- tabindex : <!-- IF $CAPTCHA_TAB_INDEX -->{$CAPTCHA_TAB_INDEX}<!-- ELSE -->10<!-- ENDIF -->
- };
- // ]]>
- </script>
- <script type="text/javascript" src="{RECAPTCHA_SERVER}/challenge?k={RECAPTCHA_PUBKEY}{RECAPTCHA_ERRORGET}" ></script>
- <script type="text/javascript">
- // <![CDATA[
- <!-- IF S_CONTENT_DIRECTION eq 'rtl' -->
- document.getElementById('recaptcha_table').style.direction = 'ltr';
- <!-- ENDIF -->
- // ]]>
- </script>
-
- <noscript>
- <iframe src="{RECAPTCHA_SERVER}/noscript?k={RECAPTCHA_PUBKEY}{RECAPTCHA_ERRORGET}" height="300" width="500" frameborder="0"></iframe><br />
- <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
- <input type="hidden" name="recaptcha_response_field" value="manual_challenge" />
- </noscript>
- </td>
- </tr>
-
-<!-- ELSE -->
-{L_RECAPTCHA_NOT_AVAILABLE}
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/confirm_body.html b/phpBB/styles/subsilver2/template/confirm_body.html
deleted file mode 100644
index 1712017c38..0000000000
--- a/phpBB/styles/subsilver2/template/confirm_body.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div id="pagecontent">
-
- <form name="confirm" action="{S_CONFIRM_ACTION}" method="post">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{MESSAGE_TITLE}</th>
- </tr>
- <tr>
- <td class="row1" align="center"><br /><p class="gen">{MESSAGE_TEXT}</p><br />{S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="btnlite" />&nbsp;&nbsp;<input type="submit" name="cancel" value="{L_NO}" class="btnlite" /></td>
- </tr>
- </table>
-
- </form>
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/confirm_delete_body.html b/phpBB/styles/subsilver2/template/confirm_delete_body.html
deleted file mode 100644
index 44aec9b60a..0000000000
--- a/phpBB/styles/subsilver2/template/confirm_delete_body.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div id="pagecontent">
-
- <form name="confirm" action="{S_CONFIRM_ACTION}" method="post">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{MESSAGE_TITLE}</th>
- </tr>
- <tr>
- <td class="row1" align="center">
- <br />
- <p class="gen">{MESSAGE_TEXT}</p>
- <br />
-
- <!-- IF not S_SHADOW_TOPICS -->
- <table border="0" width="90%" cellspacing="2" cellpadding="1">
- <!-- IF not S_SOFTDELETED and S_ALLOWED_DELETE and S_ALLOWED_SOFTDELETE -->
- <tr>
- <td class="row1" width="22%"><b class="gen">{L_DELETE_PERMANENTLY}{L_COLON}</b></td>
- <td class="row1" width="78%">
- <input id="delete_permanent" name="delete_permanent" type="checkbox" value="1" {S_CHECKED_PERMANENT} />
- <!-- IF S_TOPIC_MODE -->{L_DELETE_TOPIC_PERMANENTLY}<!-- ELSE -->{L_DELETE_POST_PERMANENTLY}<!-- ENDIF -->
- </td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="row1" valign="top"><span class="gen"><b>{L_DELETE_REASON}{L_COLON}</b></span><br /><span class="gensmall">{L_DELETE_REASON_EXPLAIN}</span></td>
- <td class="row1"><input type="text" name="delete_reason" value="" class="inputbox autowidth" maxlength="120" size="45" /></td>
- </tr>
- </table>
- <br />
- <!-- ENDIF -->
-
- {S_HIDDEN_FIELDS}
- <input type="submit" name="confirm" value="{L_YES}" class="btnmain" />&nbsp;&nbsp;
- <input type="submit" name="cancel" value="{L_NO}" class="btnlite" />
- </td>
- </tr>
- </table>
-
- </form>
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/faq_body.html b/phpBB/styles/subsilver2/template/faq_body.html
deleted file mode 100644
index b3c41e932a..0000000000
--- a/phpBB/styles/subsilver2/template/faq_body.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<a name="faqtop" class="anchor"></a>
-
-<div id="pagecontent">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_FAQ_TITLE}</th>
- </tr>
- <tr>
- <td class="row1">
- <!-- BEGIN faq_block -->
- <span class="gen"><b>{faq_block.BLOCK_TITLE}</b></span><br />
- <!-- BEGIN faq_row -->
- <span class="gen"><a href="#f{faq_block.S_ROW_COUNT}r{faq_block.faq_row.S_ROW_COUNT}">{faq_block.faq_row.FAQ_QUESTION}</a></span><br />
- <!-- END faq_row -->
- <br />
- <!-- END faq_block -->
- </td>
- </tr>
- <tr>
- <td class="cat">&nbsp;</td>
- </tr>
- </table>
-
- <br clear="all" />
-
- <!-- BEGIN faq_block -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat" align="center"><h4>{faq_block.BLOCK_TITLE}</h4></td>
- </tr>
- <!-- BEGIN faq_row -->
- <tr>
- <!-- IF faq_block.faq_row.S_ROW_COUNT is even -->
- <td class="row1" valign="top">
- <!-- ELSE -->
- <td class="row2" valign="top">
- <!-- ENDIF -->
- <div class="postbody"><a name="f{faq_block.S_ROW_COUNT}r{faq_block.faq_row.S_ROW_COUNT}" class="anchor"></a><b>&#187; {faq_block.faq_row.FAQ_QUESTION}</b></div>
- <div class="postbody">{faq_block.faq_row.FAQ_ANSWER}</div>
- <p class="gensmall"><a href="#faqtop">{L_BACK_TO_TOP}</a></p>
- </td>
- </tr>
- <tr>
- <td class="spacer" height="1"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
- </tr>
- <!-- END faq_row -->
- </table>
-
- <br clear="all" />
- <!-- END faq_block -->
-
-</div>
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/forumlist_body.html b/phpBB/styles/subsilver2/template/forumlist_body.html
deleted file mode 100644
index 6b7f884aaa..0000000000
--- a/phpBB/styles/subsilver2/template/forumlist_body.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<table class="tablebg" cellspacing="1" width="100%">
-<tr>
- <td class="cat" colspan="5" align="{S_CONTENT_FLOW_END}"><!-- IF not S_IS_BOT and U_MARK_FORUMS --><a class="nav" href="{U_MARK_FORUMS}">{L_MARK_FORUMS_READ}</a><!-- ENDIF -->&nbsp;</td>
-</tr>
-<tr>
- <th colspan="2">&nbsp;{L_FORUM}&nbsp;</th>
- <th width="50">&nbsp;{L_TOPICS}&nbsp;</th>
- <th width="50">&nbsp;{L_POSTS}&nbsp;</th>
- <th>&nbsp;{L_LAST_POST}&nbsp;</th>
-</tr>
-<!-- BEGIN forumrow -->
- <!-- EVENT forumlist_body_category_header_before -->
- <!-- IF forumrow.S_IS_CAT -->
- <tr>
- <td class="cat" colspan="2"><h4><a href="{forumrow.U_VIEWFORUM}">{forumrow.FORUM_NAME}</a></h4></td>
- <td class="catdiv" colspan="3">&nbsp;</td>
- </tr>
- <!-- EVENT forumlist_body_category_header_after -->
- <!-- ELSEIF forumrow.S_IS_LINK -->
- <tr>
- <td class="row1" width="50" align="center">{forumrow.FORUM_FOLDER_IMG}</td>
- <td class="row1">
- <!-- IF forumrow.FORUM_IMAGE -->
- <div style="float: {S_CONTENT_FLOW_BEGIN}; margin-{S_CONTENT_FLOW_END}{L_COLON} 5px;">{forumrow.FORUM_IMAGE}</div>
- <!-- ENDIF -->
- <a class="forumlink" href="{forumrow.U_VIEWFORUM}">{forumrow.FORUM_NAME}</a>
- <p class="forumdesc">{forumrow.FORUM_DESC}</p>
- </td>
- <!-- IF forumrow.CLICKS -->
- <td class="row2" colspan="3" align="center"><span class="genmed">{L_REDIRECTS}{L_COLON} {forumrow.CLICKS}</span></td>
- <!-- ELSE -->
- <td class="row2" colspan="3" align="center">&nbsp;</td>
- <!-- ENDIF -->
- </tr>
- <!-- ELSE -->
- <!-- IF forumrow.S_NO_CAT -->
- <tr>
- <td class="cat" colspan="2"><h4>{L_FORUM}</h4></td>
- <td class="catdiv" colspan="3">&nbsp;</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT forumlist_body_forum_row_before -->
- <tr>
- <!-- EVENT forumlist_body_forum_row_prepend -->
- <td class="row1" width="50" align="center">{forumrow.FORUM_FOLDER_IMG}</td>
- <td class="row1" width="100%">
- <!-- IF forumrow.FORUM_IMAGE -->
- <div style="float: {S_CONTENT_FLOW_BEGIN}; margin-{S_CONTENT_FLOW_END}{L_COLON} 5px;">{forumrow.FORUM_IMAGE}</div>
- <!-- ENDIF -->
- <a class="forumlink" href="{forumrow.U_VIEWFORUM}">{forumrow.FORUM_NAME}</a>
- <p class="forumdesc">{forumrow.FORUM_DESC}</p>
- <!-- IF forumrow.MODERATORS -->
- <p class="forumdesc"><strong>{forumrow.L_MODERATOR_STR}{L_COLON}</strong> {forumrow.MODERATORS}</p>
- <!-- ENDIF -->
- <!-- IF .forumrow.subforum and forumrow.S_LIST_SUBFORUMS -->
- <!-- EVENT forumlist_body_subforums_before -->
- <p class="forumdesc"><strong>{forumrow.L_SUBFORUM_STR}{L_COLON}</strong>
- <!-- BEGIN subforum -->
- <!-- EVENT forumlist_body_subforum_link_prepend --><a href="{forumrow.subforum.U_SUBFORUM}" class="subforum<!-- IF forumrow.subforum.S_UNREAD --> unread<!-- ELSE --> read<!-- ENDIF -->" title="<!-- IF forumrow.subforum.S_UNREAD -->{L_UNREAD_POSTS}<!-- ELSE -->{L_NO_UNREAD_POSTS}<!-- ENDIF -->">{forumrow.subforum.SUBFORUM_NAME}</a><!-- IF not forumrow.subforum.S_LAST_ROW -->{L_COMMA_SEPARATOR}<!-- ENDIF --><!-- EVENT forumlist_body_subforum_link_append -->
- <!-- END subforum -->
- </p>
- <!-- EVENT forumlist_body_subforums_after -->
- <!-- ENDIF -->
- </td>
- <td class="row2" align="center"><p class="topicdetails">{forumrow.TOPICS}</p></td>
- <td class="row2" align="center"><p class="topicdetails">{forumrow.POSTS}</p></td>
- <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>&nbsp;
- <!-- ELSEIF forumrow.U_UNAPPROVED_POSTS -->
- <a href="{forumrow.U_UNAPPROVED_POSTS}" class="imageset">{UNAPPROVED_POST_IMG}</a>&nbsp;
- <!-- ENDIF -->
- {forumrow.LAST_POST_TIME}
- </p>
- <p class="topicdetails">{forumrow.LAST_POSTER_FULL}
- <!-- IF not S_IS_BOT --><a href="{forumrow.U_LAST_POST}" class="imageset">{LAST_POST_IMG}</a><!-- ENDIF -->
- </p>
- <!-- ELSE -->
- <p class="topicdetails">{L_NO_POSTS}</p>
- <!-- ENDIF -->
- </td>
- <!-- EVENT forumlist_body_forum_row_append -->
- </tr>
- <!-- EVENT forumlist_body_forum_row_after -->
- <!-- ENDIF -->
- <!-- EVENT forumlist_body_last_row_after -->
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="5" align="center"><p class="gensmall">{L_NO_FORUMS}</p></td>
- </tr>
-<!-- END forumrow -->
-</table>
diff --git a/phpBB/styles/subsilver2/template/index.htm b/phpBB/styles/subsilver2/template/index.htm
deleted file mode 100644
index a1356823e2..0000000000
--- a/phpBB/styles/subsilver2/template/index.htm
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-<head>
-<title>subSilver created by subBlue Design</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-</head>
-
-<body bgcolor="#FFFFFF" text="#000000">
-
-<table width="100%" height="100%" cellspacing="0" cellpadding="0" border="0">
- <tr>
- <td align="center" valign="middle"><a href="http://www.subblue.com/" target="_new"><img src="images/created_by.jpg" width="400" height="300" alt="Created by subBlue Design" /></a></td>
- </tr>
-</table>
-
-</body>
-</html> \ No newline at end of file
diff --git a/phpBB/styles/subsilver2/template/index_body.html b/phpBB/styles/subsilver2/template/index_body.html
deleted file mode 100644
index de1523b11c..0000000000
--- a/phpBB/styles/subsilver2/template/index_body.html
+++ /dev/null
@@ -1,144 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- EVENT index_body_markforums_before -->
-
-<!-- IF U_MCP or U_ACP -->
- <div id="pageheader">
- <p class="linkmcp">[&nbsp;<!-- IF U_ACP --><a href="{U_ACP}">{L_ACP}</a><!-- IF U_MCP -->&nbsp;|&nbsp;<!-- ENDIF --><!-- ENDIF --><!-- IF U_MCP --><a href="{U_MCP}">{L_MCP}</a><!-- ENDIF -->&nbsp;]</p>
- </div>
-
- <br clear="all" /><br />
-<!-- ENDIF -->
-
-<!-- EVENT index_body_markforums_after -->
-
-<!-- INCLUDE forumlist_body.html -->
-
-<!-- EVENT index_body_forumlist_body_after -->
-
-<!-- IF not S_IS_BOT or U_TEAM -->
-<span class="gensmall">
- <!-- IF not S_IS_BOT --><a href="{U_DELETE_COOKIES}">{L_DELETE_COOKIES}</a><!-- ENDIF -->
- <!-- IF not S_IS_BOT and U_TEAM --> | <!-- ENDIF -->
- <!-- EVENT overall_footer_teamlink_before -->
- <!-- IF U_TEAM --><a href="{U_TEAM}">{L_THE_TEAM}</a><!-- ENDIF -->
- <!-- IF U_CONTACT_US -->
- <!-- IF U_TEAM --> | <!-- ENDIF -->
- <a href="{U_CONTACT_US}">{L_CONTACT_US}</a>
- <!-- ENDIF -->
- <!-- EVENT overall_footer_teamlink_after -->
-</span>
-<!-- ENDIF -->
-<br />
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<!-- EVENT index_body_stat_blocks_before -->
-
-<!-- IF S_DISPLAY_ONLINE_LIST -->
- <br clear="all" />
-
- <table class="tablebg stat-block online-list" width="100%" cellspacing="1">
- <tr>
- <td class="cat" colspan="2"><!-- IF U_VIEWONLINE --><h4><a href="{U_VIEWONLINE}">{L_WHO_IS_ONLINE}</a></h4><!-- ELSE --><h4>{L_WHO_IS_ONLINE}</h4><!-- ENDIF --></td>
- </tr>
- <tr>
- <!-- IF LEGEND -->
- <td class="row1" rowspan="2" align="center" valign="middle"><img src="{T_THEME_PATH}/images/whosonline.gif" alt="{L_WHO_IS_ONLINE}" /></td>
- <!-- ELSE -->
- <td class="row1" align="center" valign="middle"><img src="{T_THEME_PATH}/images/whosonline.gif" alt="{L_WHO_IS_ONLINE}" /></td>
- <!-- ENDIF -->
- <td class="row1" width="100%">
- <span class="genmed">
- <!-- EVENT index_body_block_online_prepend -->
- {TOTAL_USERS_ONLINE} ({L_ONLINE_EXPLAIN})<br />{RECORD_USERS}<br /><br />{LOGGED_IN_USER_LIST}
- <!-- EVENT index_body_block_online_append -->
- </span>
- </td>
- </tr>
- <!-- IF LEGEND -->
- <tr>
- <td class="row1"><b class="gensmall">{L_LEGEND} :: {LEGEND}</b></td>
- </tr>
- <!-- ENDIF -->
- </table>
-<!-- ENDIF -->
-
-<!-- EVENT index_body_birthday_block_before -->
-
-<!-- IF S_DISPLAY_BIRTHDAY_LIST -->
- <br clear="all" />
-
- <table class="tablebg stat-block birthday-list" width="100%" cellspacing="1">
- <tr>
- <td class="cat" colspan="2"><h4>{L_BIRTHDAYS}</h4></td>
- </tr>
- <tr>
- <td class="row1" align="center" valign="middle"><img src="{T_THEME_PATH}/images/whosonline.gif" alt="{L_BIRTHDAYS}" /></td>
- <td class="row1" width="100%">
- <p class="genmed">
- <!-- EVENT index_body_block_birthday_prepend -->
- <!-- IF .birthdays -->{L_CONGRATULATIONS}{L_COLON} <b><!-- BEGIN birthdays -->{birthdays.USERNAME}<!-- IF birthdays.AGE !== '' --> ({birthdays.AGE})<!-- ENDIF --><!-- IF not birthdays.S_LAST_ROW -->, <!-- ENDIF --><!-- END birthdays --></b><!-- ELSE -->{L_NO_BIRTHDAYS}<!-- ENDIF -->
- <!-- EVENT index_body_block_birthday_append -->
- </p>
- </td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-<br clear="all" />
-
-<table class="tablebg stat-block statistics" width="100%" cellspacing="1">
-<tr>
- <td class="cat" colspan="2"><h4>{L_STATISTICS}</h4></td>
-</tr>
-<tr>
- <td class="row1"><img src="{T_THEME_PATH}/images/whosonline.gif" alt="{L_STATISTICS}" /></td>
- <td class="row1" width="100%" valign="middle">
- <p class="genmed">
- <!-- EVENT index_body_block_stats_prepend -->
- {TOTAL_POSTS} | {TOTAL_TOPICS} | {TOTAL_USERS} | {NEWEST_USER}
- <!-- EVENT index_body_block_stats_append -->
- </p>
- </td>
-</tr>
-</table>
-
-<!-- EVENT index_body_stat_blocks_after -->
-
-<!-- IF not S_USER_LOGGED_IN and not S_IS_BOT -->
- <br clear="all" />
-
- <form method="post" action="{S_LOGIN_ACTION}">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat"><h4><a href="{U_LOGIN_LOGOUT}">{L_LOGIN_LOGOUT}</a></h4></td>
- </tr>
- <tr>
- <td class="row1" align="center"><span class="genmed">{L_USERNAME}{L_COLON}</span> <input class="post" type="text" name="username" size="10" />&nbsp; <span class="genmed">{L_PASSWORD}{L_COLON}</span> <input class="post" type="password" name="password" size="10" autocomplete="off" />&nbsp; <!-- IF U_SEND_PASSWORD --><a href="{U_SEND_PASSWORD}">{L_FORGOT_PASS}</a>&nbsp; <!-- ENDIF --> <!-- IF S_AUTOLOGIN_ENABLED --> <span class="gensmall">{L_LOG_ME_IN}</span> <input type="checkbox" class="radio" name="autologin" /><!-- ENDIF -->&nbsp; <input type="submit" class="btnmain" name="login" value="{L_LOGIN}" /></td>
- </tr>
- </table>
- {S_LOGIN_REDIRECT}
- {S_FORM_TOKEN}
- </form>
-<!-- ENDIF -->
-
-<br clear="all" />
-
-<table class="legend">
-<tr>
- <td width="20" align="center">{FORUM_UNREAD_IMG}</td>
- <td><span class="gensmall">{L_UNREAD_POSTS}</span></td>
- <td>&nbsp;&nbsp;</td>
- <td width="20" align="center">{FORUM_IMG}</td>
- <td><span class="gensmall">{L_NO_UNREAD_POSTS}</span></td>
- <td>&nbsp;&nbsp;</td>
- <td width="20" align="center">{FORUM_LOCKED_IMG}</td>
- <td><span class="gensmall">{L_FORUM_LOCKED}</span></td>
-</tr>
-</table>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/jumpbox.html b/phpBB/styles/subsilver2/template/jumpbox.html
deleted file mode 100644
index e0603c6a6e..0000000000
--- a/phpBB/styles/subsilver2/template/jumpbox.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-<!-- IF S_DISPLAY_JUMPBOX -->
- <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">{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>&nbsp;<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 -->
- <option value="{jumpbox_forums.FORUM_ID}"{jumpbox_forums.SELECTED}><!-- BEGIN level -->&nbsp; &nbsp;<!-- END level -->{jumpbox_forums.FORUM_NAME}</option>
- <!-- END jumpbox_forums -->
-
- </select>&nbsp;<input class="btnlite" type="submit" value="{L_GO}" /></td>
- </tr>
- </table>
-
- </form>
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/login_body.html b/phpBB/styles/subsilver2/template/login_body.html
deleted file mode 100644
index 1067f3738d..0000000000
--- a/phpBB/styles/subsilver2/template/login_body.html
+++ /dev/null
@@ -1,111 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<form action="{S_LOGIN_ACTION}" method="post">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <!-- IF not S_ADMIN_AUTH -->
- <th colspan="2">{L_LOGIN}</th>
- <!-- ELSE -->
- <th>{LOGIN_EXPLAIN}</th>
- <!-- ENDIF -->
-</tr>
-<!-- IF LOGIN_EXPLAIN && not S_ADMIN_AUTH -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall">{LOGIN_EXPLAIN}</span></td>
- </tr>
-<!-- ENDIF -->
-<tr><!-- IF not S_ADMIN_AUTH and S_REGISTER_ENABLED -->
- <td class="row1" width="50%">
- <p class="genmed">{L_LOGIN_INFO}</p>
-
- <p class="genmed" align="center">
- <a href="{U_TERMS_USE}">{L_TERMS_USE}</a> | <a href="{U_PRIVACY}">{L_PRIVACY}</a>
- </p>
- </td>
- <!-- ENDIF -->
- <td <!-- IF not S_ADMIN_AUTH -->class="row2"<!-- ELSE -->class="row1"<!-- ENDIF -->>
-
- <table align="center" cellspacing="1" cellpadding="4" style="width: 100%;">
- <!-- IF LOGIN_ERROR -->
- <tr>
- <td class="gensmall" colspan="2" align="center"><span class="error">{LOGIN_ERROR}</span></td>
- </tr>
- <!-- ENDIF -->
-
- <tr>
- <td valign="top" <!-- IF S_ADMIN_AUTH -->style="width: 50%; text-align: {S_CONTENT_FLOW_END};"<!-- ENDIF -->><b class="gensmall">{L_USERNAME}{L_COLON}</b></td>
- <td><input class="post" type="text" name="{USERNAME_CREDENTIAL}" size="25" value="{USERNAME}" tabindex="1" />
- <!-- IF not S_ADMIN_AUTH and S_REGISTER_ENABLED -->
- <br /><a class="gensmall" href="{U_REGISTER}">{L_REGISTER}</a>
- <!-- ENDIF -->
- </td>
- </tr>
- <tr>
- <td valign="top" <!-- IF S_ADMIN_AUTH -->style="width: 50%; text-align: {S_CONTENT_FLOW_END};"<!-- ENDIF -->><b class="gensmall">{L_PASSWORD}{L_COLON}</b></td>
- <td>
- <input class="post" type="password" name="{PASSWORD_CREDENTIAL}" size="25" tabindex="2" autocomplete="off" />
- <!-- IF U_SEND_PASSWORD --><br /><a class="gensmall" href="{U_SEND_PASSWORD}">{L_FORGOT_PASS}</a><!-- ENDIF -->
- <!-- IF U_RESEND_ACTIVATION and not S_ADMIN_AUTH --><br /><a class="gensmall" href="{U_RESEND_ACTIVATION}">{L_RESEND_ACTIVATION}</a><!-- ENDIF -->
- </td>
- </tr>
- <!-- IF S_DISPLAY_FULL_LOGIN -->
- <!-- IF S_AUTOLOGIN_ENABLED -->
- <tr>
- <td>&nbsp;</td>
- <td><input type="checkbox" class="radio" name="autologin" tabindex="3" /> <span class="gensmall">{L_LOG_ME_IN}</span></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td>&nbsp;</td>
- <td><input type="checkbox" class="radio" name="viewonline" tabindex="4" /> <span class="gensmall">{L_HIDE_ME}</span></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF not S_ADMIN_AUTH and PROVIDER_TEMPLATE_FILE -->
- <!-- INCLUDE {PROVIDER_TEMPLATE_FILE} -->
- <!-- ENDIF -->
- </table>
- </td>
-</tr>
-
-<!-- IF CAPTCHA_TEMPLATE and S_CONFIRM_CODE -->
-</table>
-<table class="tablebg" width="100%" cellspacing="1">
- <!-- DEFINE $CAPTCHA_TAB_INDEX = 4 -->
- <!-- INCLUDE {CAPTCHA_TEMPLATE} -->
-<!-- ENDIF -->
-
-{S_LOGIN_REDIRECT}
-<tr>
- <td class="cat" <!-- IF not S_ADMIN_AUTH or S_CONFIRM_CODE -->colspan="2"<!-- ENDIF --> align="center">{S_HIDDEN_FIELDS}<input type="submit" name="login" class="btnmain" value="{L_LOGIN}" tabindex="5" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<script type="text/javascript">
-// <![CDATA[
- (function()
- {
- var elements = document.getElementsByName("<!-- IF S_ADMIN_AUTH -->{PASSWORD_CREDENTIAL}<!-- ELSE -->{USERNAME_CREDENTIAL}<!-- ENDIF -->");
- for (var i = 0; i < elements.length; ++i)
- {
- if (elements[i].tagName.toLowerCase() == 'input')
- {
- elements[i].focus();
- break;
- }
- }
- })();
-// ]]>
-</script>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/login_body_oauth.html b/phpBB/styles/subsilver2/template/login_body_oauth.html
deleted file mode 100644
index 6f374fa4f2..0000000000
--- a/phpBB/styles/subsilver2/template/login_body_oauth.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- BEGIN oauth -->
- <tr>
- <td>
- <a href="{oauth.REDIRECT_URL}">{oauth.SERVICE_NAME}</a>
- </td>
- </tr>
-<!-- END oauth -->
diff --git a/phpBB/styles/subsilver2/template/login_forum.html b/phpBB/styles/subsilver2/template/login_forum.html
deleted file mode 100644
index 2cda9f3452..0000000000
--- a/phpBB/styles/subsilver2/template/login_forum.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- IF FORUM_NAME -->
- <div id="pageheader">
- <h2><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a></h2>
- </div>
-
- <br clear="all" /><br />
-<!-- ENDIF -->
-
-<div id="pagecontent">
-
- <form name="login_forum" method="post" action="{S_LOGIN_ACTION}">
-
- <table class="tablebg" width="100%" cellspacing="1" align="center">
- <tr>
- <th>{L_LOGIN}</th>
- </tr>
- <tr>
- <td class="row3" align="center"><span class="gensmall">{L_LOGIN_FORUM}</span></td>
- </tr>
- <tr>
- <td class="row1" align="center">
-
- <table cellspacing="1" cellpadding="4" border="0">
- <!-- IF LOGIN_ERROR -->
- <tr>
- <td class="gensmall" colspan="2" align="center"><span class="error">{LOGIN_ERROR}</span></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="gensmall"><b>{L_PASSWORD}{L_COLON}</b></td>
- <td><input class="post" type="password" name="password" size="25" tabindex="2" autocomplete="off" /></td>
- </tr>
- </table>
- </td>
- </tr>
- <tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input type="submit" name="login" class="btnmain" value="{L_LOGIN}" tabindex="3" /></td>
- </tr>
- </table>
- {S_FORM_TOKEN}
- {S_LOGIN_REDIRECT}
- </form>
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_approve.html b/phpBB/styles/subsilver2/template/mcp_approve.html
deleted file mode 100644
index 8c2ef0806b..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_approve.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div id="pagecontent">
-
- <form name="confirm" action="{S_CONFIRM_ACTION}" method="post">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{MESSAGE_TITLE}</th>
- </tr>
- <tr>
- <td class="row1" align="center">
- <!-- IF ADDITIONAL_MSG -->
- <span class="gen error">{ADDITIONAL_MSG}</span><br />
- <!-- ENDIF -->
- <!-- IF S_NOTIFY_POSTER -->
- <input type="checkbox" class="radio" name="notify_poster" checked="checked" /><span class="gen"><!-- IF S_APPROVE -->{L_NOTIFY_POSTER_APPROVAL}<!-- ELSE -->{L_NOTIFY_POSTER_DISAPPROVAL}<!-- ENDIF --></span><br />
- <!-- ENDIF -->
- <!-- IF not S_APPROVE and not S_RESTORE and .reason -->
- <br />
- <table border="0" width="90%" cellspacing="2" cellpadding="1">
- <tr>
- <td class="row1" width="22%"><b class="gen">{L_DISAPPROVE_REASON}{L_COLON}</b></td>
- <td class="row1" width="78%"><select name="reason_id"><!-- BEGIN reason --><option value="{reason.ID}"<!-- IF reason.S_SELECTED --> selected="selected"<!-- ENDIF -->>{reason.DESCRIPTION}</option><!-- END reason --></select></td>
- </tr>
- <tr>
- <td class="row1" valign="top"><span class="gen"><b>{L_MORE_INFO}{L_COLON}</b></span><br /><span class="gensmall">{L_CAN_LEAVE_BLANK}</span></td>
- <td class="row1"><textarea class="post" style="width:500px" name="reason" rows="10" cols="40">{REASON}</textarea></td>
- </tr>
- </table>
- <br />
- <!-- ENDIF -->
- <br />{S_HIDDEN_FIELDS}<span class="gen">{MESSAGE_TEXT}</span><br /><br />
- <input type="submit" name="confirm" value="{YES_VALUE}" class="btnmain" />&nbsp;&nbsp;<input type="submit" name="cancel" value="{L_NO}" class="btnlite" /></span>
- </td>
- </tr>
- </table>
- {S_FORM_TOKEN}
- </form>
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_ban.html b/phpBB/styles/subsilver2/template/mcp_ban.html
deleted file mode 100644
index cc24d21d73..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_ban.html
+++ /dev/null
@@ -1,120 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<script type="text/javascript">
-// <![CDATA[
-
- var ban_length = new Array();
- ban_length[-1] = '';
- var ban_reason = new Array();
- ban_reason[-1] = '';
- var ban_give_reason = new Array();
- ban_give_reason[-1] = '';
-
- <!-- BEGIN bans -->
- ban_length['{bans.BAN_ID}'] = '{bans.A_LENGTH}';
- <!-- IF bans.A_REASON -->
- ban_reason['{bans.BAN_ID}'] = '{bans.A_REASON}';
- <!-- ENDIF -->
- <!-- IF bans.A_GIVE_REASON -->
- ban_give_reason['{bans.BAN_ID}'] = '{bans.A_GIVE_REASON}';
- <!-- ENDIF -->
- <!-- END bans -->
-
- function display_details(option)
- {
- document.getElementById('mcp_ban').unbanlength.value = ban_length[option];
- if (option in ban_reason) {
- document.getElementById('mcp_ban').unbanreason.value = ban_reason[option];
- } else {
- document.getElementById('mcp_ban').unbanreason.value = '';
- }
- if (option in ban_give_reason) {
- document.getElementById('mcp_ban').unbangivereason.value = ban_give_reason[option];
- } else {
- document.getElementById('mcp_ban').unbangivereason.value = '';
- }
- }
-
-// ]]>
-</script>
-
-<form id="mcp_ban" method="post" action="{U_ACTION}">
-
-<table width="100%" class="tablebg" cellspacing="1" cellpadding="4" border="0">
-<tr>
- <th colspan="2" nowrap="nowrap">{L_TITLE}</th>
-</tr>
-<tr>
- <td class="row3" colspan="2">{L_EXPLAIN}</td>
-</tr>
-<!-- EVENT mcp_ban_fields_before -->
-<tr>
- <td class="row1" width="45%" valign="top"><b>{L_BAN_CELL}{L_COLON}</b></td>
- <td class="row2">
- <textarea name="ban" id="ban" cols="40" rows="3" class="post">{USERNAMES}</textarea>
- <!-- IF S_USERNAME_BAN --><br />[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]<!-- ENDIF -->
- </td>
-</tr>
-<tr>
- <td class="row1" valign="top"><b>{L_BAN_LENGTH}{L_COLON}</b></td>
- <td class="row2"><select name="banlength">{S_BAN_END_OPTIONS}</select><br /><input type="text" name="banlengthother" class="post" /> {L_YEAR_MONTH_DAY}</td>
-</tr>
-<tr>
- <td class="row1" valign="top"><b>{L_BAN_EXCLUDE}{L_COLON}</b><br /><span class="gensmall">{L_BAN_EXCLUDE_EXPLAIN}</span></td>
- <td class="row2"><input type="radio" class="radio" name="banexclude" value="1" /> {L_YES} &nbsp; <input type="radio" class="radio" name="banexclude" value="0" checked="checked" /> {L_NO}</td>
-</tr>
-<tr>
- <td class="row1" valign="top"><b>{L_BAN_REASON}{L_COLON}</b></td>
- <td class="row2"><input name="banreason" type="text" class="post" maxlength="255" /></td>
-</tr>
-<tr>
- <td class="row1" valign="top"><b>{L_BAN_GIVE_REASON}{L_COLON}</b></td>
- <td class="row2"><input name="bangivereason" type="text" class="post" maxlength="255" /></td>
-</tr>
-<!-- EVENT mcp_ban_fields_after -->
-<tr>
- <td class="cat" colspan="2" align="center"><input type="submit" name="bansubmit" value="{L_SUBMIT}" class="btnmain" />&nbsp; <input type="reset" value="{L_RESET}" class="btnlite" />&nbsp;</td>
-</tr>
-</table>
-
-<br /><br />
-
-<table width="100%" class="tablebg" cellspacing="1" cellpadding="4" border="0">
-<tr>
- <th colspan="2" nowrap="nowrap">{L_UNBAN_TITLE}</th>
-</tr>
-<tr>
- <td class="row3" colspan="2">{L_UNBAN_EXPLAIN}</td>
-</tr>
-<!-- IF S_BANNED_OPTIONS -->
- <!-- EVENT mcp_ban_unban_before -->
- <tr>
- <td class="row1" valign="top" width="45%"><b>{L_BAN_CELL}{L_COLON}</b></td>
- <td class="row2"><select name="unban[]" multiple="multiple" size="10" style="width: 50%" onchange="if (this.selectedIndex > -1) display_details(this.options[this.selectedIndex].value); else display_details(-1);">{BANNED_OPTIONS}</select></td>
- </tr>
- <tr>
- <td class="row1" valign="top"><b>{L_BAN_LENGTH}{L_COLON}</b></td>
- <td class="row2"><input style="border: 0; width: 100%" type="text" name="unbanlength" readonly="readonly" /></td>
- </tr>
- <tr>
- <td class="row1" valign="top"><b>{L_BAN_REASON}{L_COLON}</b></td>
- <td class="row2"><textarea style="border: 0; width: 100%" name="unbanreason" readonly="readonly" rows="5" cols="80">&nbsp;</textarea></td>
- </tr>
- <tr>
- <td class="row1" valign="top"><b>{L_BAN_GIVE_REASON}{L_COLON}</b></td>
- <td class="row2"><textarea style="border: 0; width: 100%" name="unbangivereason" readonly="readonly" rows="5" cols="80">&nbsp;</textarea></td>
- </tr>
- <!-- EVENT mcp_ban_unban_after -->
- <tr>
- <td class="cat" colspan="2" align="center"><input type="submit" name="unbansubmit" value="{L_SUBMIT}" class="btnmain" />&nbsp; <input type="reset" value="{L_RESET}" class="btnlite" />&nbsp;</td>
- </tr>
-<!-- ELSE -->
- <tr>
- <td class="row1" colspan="2"><b>{L_NO_BAN_CELL}</b></td>
- </tr>
-<!-- ENDIF -->
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_footer.html b/phpBB/styles/subsilver2/template/mcp_footer.html
deleted file mode 100644
index 280920b148..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_footer.html
+++ /dev/null
@@ -1,27 +0,0 @@
-
- </td>
- </tr>
- </table>
-
- <!-- IF .pagination -->
- <table width="80%" align="{S_CONTENT_FLOW_END}" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ <!-- IF TOTAL_TOPICS -->{TOTAL_TOPICS}<!-- ELSEIF TOTAL_POSTS -->{TOTAL_POSTS}<!-- ELSE -->{TOTAL}<!-- ENDIF --> ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
- <br />
- <!-- ENDIF -->
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_forum.html b/phpBB/styles/subsilver2/template/mcp_forum.html
deleted file mode 100644
index 12447b2b1e..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_forum.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<!-- IF S_MERGE_SELECT --><div style="float: {S_CONTENT_FLOW_END};"><!-- INCLUDE jumpbox.html --></div><!-- ENDIF -->
-
-<!-- IF U_VIEW_FORUM_LOGS --><a href="{U_VIEW_FORUM_LOGS}">{L_VIEW_FORUM_LOGS}</a><!-- ENDIF -->
-
-<!-- IF S_MERGE_SELECT --><br clear="{S_CONTENT_FLOW_END}" /><!-- ENDIF -->
-
-<form method="post" id="mcp" action="{S_MCP_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <td class="cat" colspan="6" align="center"><span class="gensmall">{L_DISPLAY_TOPICS}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" name="sort" value="{L_GO}" /></td>
-</tr>
-<tr>
- <th width="4%" nowrap="nowrap">&nbsp;</th>
- <th nowrap="nowrap">&nbsp;{L_TOPICS}&nbsp;</th>
- <th width="8%" nowrap="nowrap">&nbsp;{L_REPLIES}&nbsp;</th>
- <th width="17%" nowrap="nowrap">&nbsp;{L_LAST_POST}&nbsp;</th>
- <th width="5%" nowrap="nowrap">&nbsp;{L_MARK}&nbsp;</th>
-</tr>
-<!-- BEGIN topicrow -->
- <tr>
- <td class="row1" width="25" align="center">{topicrow.TOPIC_FOLDER_IMG}</td>
- <!-- IF S_TOPIC_ICONS -->
- <!-- td class="row1" width="25" align="center">{topicrow.TOPIC_ICON_IMG}</td -->
- <!-- ENDIF -->
- <td class="row1">
- <!-- EVENT topiclist_row_prepend -->
- <!-- IF topicrow.S_SELECT_TOPIC -->
- <span class="genmed">[ <a href="{topicrow.U_SELECT_TOPIC}">{L_SELECT_MERGE}</a> ]&nbsp;</span>
- <!-- ENDIF -->
- <p class="topictitle">{NEWEST_POST_IMG} {topicrow.ATTACH_ICON_IMG} <!-- EVENT mcp_forum_topic_title_before --><a href="{topicrow.U_VIEW_TOPIC}">{topicrow.TOPIC_TITLE}</a><!-- EVENT mcp_forum_topic_title_after -->
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED -->
- <a href="{topicrow.U_MCP_QUEUE}" class="imageset">{topicrow.UNAPPROVED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_DELETED or topicrow.S_POSTS_DELETED -->
- <a href="{topicrow.U_MCP_QUEUE}" class="imageset">{topicrow.DELETED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED and topicrow.U_MCP_REPORT -->
- <a href="{topicrow.U_MCP_REPORT}" class="imageset">{REPORTED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF topicrow.S_MOVED_TOPIC and S_CAN_DELETE -->
- [ <a href="{topicrow.U_DELETE_TOPIC}">{L_DELETE_SHADOW_TOPIC}</a> ]&nbsp;
- <!-- ENDIF -->
- <!-- EVENT topiclist_row_topic_title_after -->
- </p>
- <!-- EVENT topiclist_row_append -->
- </td>
- <td class="row1" width="50" align="center"><p class="topicdetails">{topicrow.REPLIES}</p></td>
- <td class="row1" width="120" align="center"><p class="topicdetails">{topicrow.LAST_POST_TIME}</p></td>
- <td class="row2" align="center">
- <!-- IF not topicrow.S_MOVED_TOPIC and not S_MERGE_SELECT --><input type="checkbox" class="radio" name="topic_id_list[]" value="{topicrow.TOPIC_ID}"<!-- IF topicrow.S_TOPIC_CHECKED --> checked="checked"<!-- ENDIF --> /><!-- ELSE -->&nbsp;<!-- ENDIF -->
- </td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="8" align="center"><p class="gen">{L_NO_TOPICS}</p></td>
- </tr>
-<!-- END topicrow -->
-<!-- EVENT mcp_forum_actions_before -->
-<!-- IF not S_MERGE_SELECT -->
-<tr>
- <td class="cat" colspan="6" align="{S_CONTENT_FLOW_END}">
- <select name="action">
- <option value="" selected="selected">{L_SELECT_ACTION}</option>
- <!-- IF S_CAN_DELETE --><option value="delete_topic">{L_DELETE}</option><!-- ENDIF -->
- <!-- IF S_CAN_RESTORE --><option value="restore_topic">{L_RESTORE}</option><!-- ENDIF -->
- <!-- IF S_CAN_MERGE --><option value="merge_topics">{L_MERGE}</option><!-- ENDIF -->
- <!-- IF S_CAN_MOVE --><option value="move">{L_MOVE}</option><!-- ENDIF -->
- <!-- IF S_CAN_FORK --><option value="fork">{L_FORK}</option><!-- ENDIF -->
- <!-- IF S_CAN_LOCK --><option value="lock">{L_LOCK}</option><option value="unlock">{L_UNLOCK}</option><!-- ENDIF -->
- <!-- IF S_CAN_SYNC --><option value="resync">{L_RESYNC}</option><!-- ENDIF -->
- <!-- IF S_CAN_MAKE_NORMAL --><option value="make_normal">{L_MAKE_NORMAL}</option><!-- ENDIF -->
- <!-- IF S_CAN_MAKE_STICKY --><option value="make_sticky">{L_MAKE_STICKY}</option><!-- ENDIF -->
- <!-- IF S_CAN_MAKE_ANNOUNCE -->
- <option value="make_announce">{L_MAKE_ANNOUNCE}</option>
- <option value="make_global">{L_MAKE_GLOBAL}</option>
- <!-- ENDIF -->
- <!-- EVENT mcp_forum_actions_append -->
- </select>
- <input class="btnmain" type="submit" value="{L_SUBMIT}" />
- </td>
-</tr>
-<!-- ENDIF -->
-<!-- EVENT mcp_forum_actions_after -->
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<!-- IF not S_MERGE_SELECT -->
-<table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
-<tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="gensmall"><a href="#" onclick="marklist('mcp', 'topic_id_list', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('mcp', 'topic_id_list', false); return false;">{L_UNMARK_ALL}</a></b></td>
-</tr>
-</table>
-<!-- ENDIF -->
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_front.html b/phpBB/styles/subsilver2/template/mcp_front.html
deleted file mode 100644
index 55adb3b550..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_front.html
+++ /dev/null
@@ -1,147 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<!-- EVENT mcp_front_latest_unapproved_before -->
-
-<!-- IF S_SHOW_UNAPPROVED -->
- <form name="mcp_queue" method="post" action="{S_MCP_QUEUE_ACTION}">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3" colspan="6" align="center"><b class="gen">{L_LATEST_UNAPPROVED}</b></td>
- </tr>
- <tr>
- <th>&nbsp;{L_FORUM}&nbsp;</th>
- <th>&nbsp;{L_TOPIC}&nbsp;</th>
- <th>&nbsp;{L_SUBJECT}&nbsp;</th>
- <th>&nbsp;{L_AUTHOR}&nbsp;</th>
- <th>&nbsp;{L_POST_TIME}&nbsp;</th>
- <th width="5%">&nbsp;{L_SELECT}&nbsp;</th>
- </tr>
- <!-- BEGIN unapproved -->
- <tr>
- <td class="row1" width="15%" valign="top"><span class="gen"><!-- IF unapproved.U_FORUM --><a href="{unapproved.U_FORUM}">{unapproved.FORUM_NAME}</a><!-- ELSE -->{unapproved.FORUM_NAME}<!-- ENDIF --></span><!-- IF unapproved.U_MCP_FORUM --><br /><span class="gensmall">[ <a href="{unapproved.U_MCP_FORUM}">{L_MODERATE}</a> ]</span><!-- ENDIF --></td>
- <td class="row2" valign="top"><span class="gen"><a href="{unapproved.U_TOPIC}">{unapproved.TOPIC_TITLE}</a></span><br /><span class="gensmall">[ <a href="{unapproved.U_MCP_TOPIC}">{L_MODERATE}</a> ]</span></td>
- <td class="row1" valign="top">{unapproved.ATTACH_ICON_IMG} <span class="gen">{unapproved.SUBJECT}</span><br /><span class="gensmall">[ <a href="{unapproved.U_POST_DETAILS}">{L_VIEW_DETAILS}</a> ]</span></td>
- <td class="row2" align="center" width="15%" nowrap="nowrap" valign="top"><span class="gen">{unapproved.AUTHOR_FULL}</span></td>
- <td class="row1" align="center" width="15%" nowrap="nowrap" valign="top"><span class="gensmall">{unapproved.POST_TIME}</span></td>
- <td class="row2" align="center"><input type="checkbox" class="radio" name="post_id_list[]" value="{unapproved.POST_ID}" /></td>
- </tr>
- <!-- END unapproved -->
- <tr>
- <td class="row3" colspan="6"><span class="gensmall">{L_UNAPPROVED_TOTAL}</span></td>
- </tr>
- <tr>
- <td class="cat" colspan="6" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="action[approve]" value="{L_APPROVE}" />&nbsp;&nbsp;<input class="btnlite" type="submit" name="action[disapprove]" value="{L_DISAPPROVE}" /></td>
- </tr>
- </table>
- {S_FORM_TOKEN}
- </form>
-
- <table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
- <tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="gensmall"><a href="#" onclick="marklist('mcp_queue', '', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('mcp_queue', '', false); return false;">{L_UNMARK_ALL}</a></b></td>
- </tr>
- </table>
-
- <br clear="all" /><br />
-<!-- ENDIF -->
-
-<!-- EVENT mcp_front_latest_reported_before -->
-
-<!-- IF S_SHOW_REPORTS -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3" colspan="5" align="center"><b class="gen">{L_LATEST_REPORTED}</b></td>
- </tr>
- <tr>
- <th>&nbsp;{L_FORUM}&nbsp;</th>
- <th>&nbsp;{L_TOPIC}&nbsp;</th>
- <th>&nbsp;{L_SUBJECT}&nbsp;</th>
- <th>&nbsp;{L_REPORTER}&nbsp;</th>
- <th>&nbsp;{L_REPORT_TIME}&nbsp;</th>
- </tr>
- <!-- BEGIN report -->
- <tr>
- <td class="row1" width="15%" valign="top"><span class="gen"><!-- IF report.U_FORUM --><a href="{report.U_FORUM}">{report.FORUM_NAME}</a><!-- ELSE -->{report.FORUM_NAME}<!-- ENDIF --></span><!-- IF report.U_MCP_FORUM --><br /><span class="gensmall">[ <a href="{report.U_MCP_FORUM}">{L_MODERATE}</a> ]</span><!-- ENDIF --></td>
- <td class="row2" valign="top"><span class="gen"><a href="{report.U_TOPIC}">{report.TOPIC_TITLE}</a></span><br /><span class="gensmall">[ <a href="{report.U_MCP_TOPIC}">{L_MODERATE}</a> ]</span></td>
- <td class="row1" valign="top">{report.ATTACH_ICON_IMG} <span class="gen">{report.SUBJECT}</span><br /><span class="gensmall">[ <a href="{report.U_POST_DETAILS}">{L_VIEW_DETAILS}</a> ]</span></td>
- <td class="row2" align="center" width="15%" nowrap="nowrap" valign="top"><span class="gen">{report.REPORTER_FULL}</span></td>
- <td class="row1" align="center" width="15%" nowrap="nowrap" valign="top"><span class="gensmall">{report.REPORT_TIME}</span></td>
- </tr>
- <!-- END report -->
- <tr>
- <td class="row3" colspan="5"><span class="gensmall">{L_REPORTS_TOTAL}</span></td>
- </tr>
- </table>
-
- <br clear="all" /><br />
-<!-- ENDIF -->
-
-<!-- EVENT mcp_front_latest_reported_pms_before -->
-
-<!-- IF S_SHOW_PM_REPORTS -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3" colspan="6" align="center"><b class="gen">{L_LATEST_REPORTED_PMS}</b></td>
- </tr>
- <tr>
- <th>&nbsp;{L_PM_SUBJECT}&nbsp;</th>
- <th>&nbsp;{L_PM_FROM}&nbsp;</th>
- <th>&nbsp;{L_TO} &amp; {L_BCC}&nbsp;</th>
- <th>&nbsp;{L_SENT_AT}&nbsp;</th>
- <th>&nbsp;{L_REPORTER}&nbsp;</th>
- <th>&nbsp;{L_REPORT_TIME}&nbsp;</th>
- </tr>
- <!-- BEGIN pm_report -->
- <tr>
- <td class="row1" valign="top">{pm_report.ATTACH_ICON_IMG} <span class="gen">{pm_report.PM_SUBJECT}</span><br /><span class="gensmall">[ <a href="{pm_report.U_PM_DETAILS}">{L_VIEW_DETAILS}</a> ]</span></td>
- <td class="row2" align="center" width="15%" nowrap="nowrap" valign="top"><span class="gen">{pm_report.PM_AUTHOR_FULL}</span></td>
- <td class="row1" align="center" width="15%" nowrap="nowrap" valign="top"><span class="gen">{pm_report.RECIPIENTS}</span></td>
- <td class="row2" align="center" width="10%" nowrap="nowrap" valign="top"><span class="gensmall">{pm_report.PM_TIME}</span></td>
- <td class="row1" align="center" width="15%" nowrap="nowrap" valign="top"><span class="gen">{pm_report.REPORTER_FULL}</span></td>
- <td class="row2" align="center" width="10%" nowrap="nowrap" valign="top"><span class="gensmall">{pm_report.REPORT_TIME}</span></td>
- </tr>
- <!-- END pm_report -->
- <tr>
- <td class="row3" colspan="6"><span class="gensmall">{L_PM_REPORTS_TOTAL}</span></td>
- </tr>
- </table>
-
- <br clear="all" /><br />
-<!-- ENDIF -->
-
-<!-- EVENT mcp_front_latest_logs_before -->
-
-<!-- IF S_SHOW_LOGS -->
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="4" border="0" align="{S_CONTENT_FLOW_END}">
- <tr>
- <td class="row3" colspan="5" align="center"><b class="gen">{L_LATEST_LOGS}</b></td>
- </tr>
- <tr>
- <th width="15%" nowrap="nowrap">{L_USERNAME}</th>
- <th width="12%" nowrap="nowrap">{L_IP}</th>
- <th width="45%" nowrap="nowrap">{L_ACTION}</th>
- <th nowrap="nowrap"></th>
- <th width="18%" nowrap="nowrap">{L_TIME}</th>
- </tr>
- <!-- BEGIN log -->
- <tr>
- <td class="row1" nowrap="nowrap"><span class="gen">{log.USERNAME}</span></td>
- <td class="row1" align="center" nowrap="nowrap"><span class="gen">{log.IP}</span></td>
- <td class="row1"><span class="genmed">{log.ACTION}</span></td>
- <td class="row1" align="center" nowrap="nowrap"><span class="gensmall"><!-- IF log.U_VIEW_TOPIC --><a href="{log.U_VIEW_TOPIC}">{L_VIEW_TOPIC}</a><!-- IF log.U_VIEWLOGS --> | <!-- ENDIF --><!-- ENDIF --><!-- IF log.U_VIEWLOGS --><a href="{log.U_VIEWLOGS}">{L_VIEW_TOPIC_LOGS}</a><!-- ENDIF --></span></td>
- <td class="row1" align="center" nowrap="nowrap"><span class="gensmall">{log.TIME}</span></td>
- </tr>
- <!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="5" align="center"><span class="gen">{L_NO_ENTRIES}</span></td>
- </tr>
- <!-- END log -->
- </table>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-<!-- EVENT mcp_front_latest_logs_after -->
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_header.html b/phpBB/styles/subsilver2/template/mcp_header.html
deleted file mode 100644
index 7144750ed4..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_header.html
+++ /dev/null
@@ -1,60 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div id="pageheader">
- <!-- IF U_MCP -->
- <p class="linkmcp">
- [<!-- IF U_ACP -->&nbsp;<a href="{U_ACP}">{L_ACP}</a>&nbsp;|<!-- ENDIF -->&nbsp;<a href="{U_MCP}">{L_MCP}</a><!-- IF U_MCP_FORUM -->&nbsp;|&nbsp;<a href="{U_MCP_FORUM}">{L_MODERATE_FORUM}</a><!-- ENDIF --><!-- IF U_MCP_TOPIC -->&nbsp;|&nbsp;<a href="{U_MCP_TOPIC}">{L_MODERATE_TOPIC}</a><!-- ENDIF --><!-- IF U_MCP_POST -->&nbsp;|&nbsp;<a href="{U_MCP_POST}">{L_MODERATE_POST}</a><!-- ENDIF -->&nbsp;]
- </p>
- <!-- ENDIF -->
-
- <!-- IF TOPIC_TITLE or FORUM_NAME -->
- <h2><!-- IF TOPIC_TITLE --><a class="titles" href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a><!-- ELSE --><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a><!-- ENDIF --></h2>
- <!-- ENDIF -->
-</div>
-
-<br clear="all" />
-
-<div id="pagecontent">
-
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr>
- <td width="20%" valign="top">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_OPTIONS}</th>
- </tr>
- <!-- BEGIN l_block1 -->
- <tr>
- <!-- IF l_block1.S_SELECTED -->
- <td class="row1"><b class="nav">{l_block1.L_TITLE}</b>
-
- <ul class="nav" style="margin: 0; padding: 0; list-style-type: none; line-height: 175%;">
- <!-- BEGIN l_block2 -->
- <li>&#187; <!-- IF l_block1.l_block2.S_SELECTED --><b>{l_block1.l_block2.L_TITLE}</b><!-- ELSE --><a href="{l_block1.l_block2.U_TITLE}">{l_block1.l_block2.L_TITLE}</a><!-- ENDIF --></li>
- <!-- END l_block2 -->
- </ul>
- <!-- ELSE -->
- <td class="row2" nowrap="nowrap" onmouseover="this.className='row1'" onmouseout="this.className='row2'" onclick="location.href=this.firstChild.href;"><a class="nav" href="{l_block1.U_TITLE}">{l_block1.L_TITLE}</a>
- <!-- ENDIF -->
- </td>
- </tr>
- <!-- END l_block1 -->
- </table>
-
- </td>
- <td><img src="images/spacer.gif" width="4" alt="" /></td>
- <td width="80%" valign="top">
-
- <!-- IF MESSAGE -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_MESSAGE}</th>
- </tr>
- <tr>
- <td class="row1" align="center"><br /><span class="gen">{MESSAGE}<br /><br /><!-- BEGIN return_links -->{return_links.MESSAGE_LINK}<br /><br /><!-- END return_links --></span></td>
- </tr>
- </table>
-
- <br />
- <!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/mcp_logs.html b/phpBB/styles/subsilver2/template/mcp_logs.html
deleted file mode 100644
index 64f2a6a64d..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_logs.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form method="post" name="mcp" action="{U_POST_ACTION}">
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th>{L_USERNAME}</th>
- <th>{L_IP}</th>
- <th>{L_TIME}</th>
- <th>{L_ACTION}</th>
- <!-- IF S_CLEAR_ALLOWED --><th>{L_MARK}</th><!-- ENDIF -->
-</tr>
-<!-- IF S_LOGS -->
-
- <!-- BEGIN log -->
- <!-- IF log.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td class="genmed">{log.USERNAME}</td>
- <td class="genmed" style="text-align: center;">{log.IP}</td>
- <td class="genmed" style="text-align: center;">{log.DATE}</td>
- <td class="genmed">{log.ACTION}<br />{log.DATA}</td>
- <!-- IF S_CLEAR_ALLOWED --><td width="5%" align="center"><input type="checkbox" class="radio" name="mark[]" value="{log.ID}" /></td><!-- ENDIF -->
- </tr>
- <!-- END log -->
- <tr align="center">
- <td class="row3" colspan="<!-- IF S_CLEAR_ALLOWED -->5<!-- ELSE -->4<!-- ENDIF -->"><span class="gensmall">{L_SEARCH_KEYWORDS}{L_COLON}</span> <input type="text" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="btnlite" name="filter" value="{L_SEARCH}" /></td>
- </tr>
- <tr align="center">
- <td class="row3" colspan="<!-- IF S_CLEAR_ALLOWED -->5<!-- ELSE -->4<!-- ENDIF -->"><span class="gensmall">{L_DISPLAY_LOG}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" value="{L_GO}" name="sort" /></td>
- </tr>
- <!-- IF S_CLEAR_ALLOWED -->
- <tr>
- <td class="cat" colspan="5" align="center"><input class="btnlite" type="submit" name="action[del_all]" value="{L_DELETE_ALL}" />&nbsp; <input class="btnlite" type="submit" name="action[del_marked]" value="{L_DELETE_MARKED}" /></td>
- </tr>
- <!-- ENDIF -->
-<!-- ELSE -->
- <tr>
- <td class="row1" colspan="<!-- IF S_CLEAR_ALLOWED -->5<!-- ELSE -->4<!-- ENDIF -->" align="center"><span class="gen">{L_NO_ENTRIES}</span></td>
- </tr>
-<!-- ENDIF -->
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_message.html b/phpBB/styles/subsilver2/template/mcp_message.html
deleted file mode 100644
index 5699dd54af..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_message.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1" cellpadding="4" border="0" align="center">
-<tr>
- <th><b>{MESSAGE_TITLE}</b></th>
-</tr>
-<tr>
- <td class="row1" align="center"><br /><span class="gen">{MESSAGE_TEXT}</span><br /><br /></td>
-</tr>
-</table>
-
-<br clear="all" />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_move.html b/phpBB/styles/subsilver2/template/mcp_move.html
deleted file mode 100644
index 429fee7e38..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_move.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- EVENT mcp_move_before -->
-
-<div id="pagecontent">
-
- <form name="confirm" action="{S_CONFIRM_ACTION}" method="post">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{MESSAGE_TITLE}</th>
- </tr>
- <tr>
- <td class="row1" align="center">
- <!-- IF ADDITIONAL_MSG -->
- <span class="gen error">{ADDITIONAL_MSG}</span><br />
- <!-- ENDIF -->
- <!-- IF S_FORUM_SELECT -->
- <span class="gen"><br />{L_SELECT_DESTINATION_FORUM}&nbsp;&nbsp;</span>
- <select name="to_forum_id">{S_FORUM_SELECT}</select><br />
- <!-- IF S_CAN_LEAVE_SHADOW -->
- <input type="checkbox" class="radio" name="move_leave_shadow" /><span class="gen">{L_LEAVE_SHADOW}</span><br />
- <!-- ENDIF -->
- <!-- IF S_CAN_LOCK_TOPIC -->
- <input type="checkbox" class="radio" name="move_lock_topics" /><span class="gen">{L_LOCK_TOPIC}</span><br />
- <!-- ENDIF -->
- <br />{S_HIDDEN_FIELDS}<span class="gen">{MESSAGE_TEXT}</span><br /><br />
- <input type="submit" name="confirm" value="{YES_VALUE}" class="btnmain" />&nbsp;&nbsp;<input type="submit" name="cancel" value="{L_NO}" class="btnlite" />
- <!-- ELSE -->
- <span class="gen">{L_NO_DESTINATION_FORUM}</span><br /><br />
- {S_HIDDEN_FIELDS}
- <input type="submit" name="cancel" value="{L_CANCEL}" class="btnlite" />
- <!-- ENDIF -->
- </td>
- </tr>
- </table>
- {S_FORM_TOKEN}
- </form>
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_notes_front.html b/phpBB/styles/subsilver2/template/mcp_notes_front.html
deleted file mode 100644
index e2e14e0150..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_notes_front.html
+++ /dev/null
@@ -1,22 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form method="post" name="mcp" action="{U_POST_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1" cellpadding="4" border="0" align="center">
-<tr>
- <th colspan="2"align="center">{L_SELECT_USER}</th>
-</tr>
-<tr>
- <td class="row1" width="40%"><b class="gen">{L_FIND_USERNAME}{L_COLON} </b><br /><span class="gensmall">[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</span></td>
- <td class="row2"><input type="text" class="post" name="username" size="20" /></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center"><input type="submit" name="submituser" value="{L_SUBMIT}" class="btnmain" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_notes_user.html b/phpBB/styles/subsilver2/template/mcp_notes_user.html
deleted file mode 100644
index 4bd8de6862..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_notes_user.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form method="post" name="mcp" action="{U_POST_ACTION}">
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th colspan="2" align="center">{USERNAME}</th>
-</tr>
-<tr>
- <td class="row1" align="center">
- <table cellspacing="1" cellpadding="2" border="0">
- <tr>
- <td class="gen" align="center"><b>{USERNAME_FULL}</b></td>
- </tr>
- <!-- IF RANK_TITLE -->
- <tr>
- <td class="postdetails" align="center">{RANK_TITLE}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF RANK_IMG -->
- <tr>
- <td align="center">{RANK_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td align="center"><!-- IF AVATAR_IMG -->{AVATAR_IMG}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF --></td>
- </tr>
- </table>
- </td>
- <td class="row1">
- <table width="100%" cellspacing="1" cellpadding="2" border="0">
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{L_JOINED}{L_COLON} </td>
- <td width="100%"><b class="gen">{JOINED}</b></td>
- </tr>
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_TOTAL_POSTS}{L_COLON} </td>
- <td><b class="gen">{POSTS}</b></td>
- </tr>
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_WARNINGS}{L_COLON} </td>
- <td><b class="gen">{WARNINGS}</b></td>
- </tr>
- </table>
- </td>
-</tr>
-</table>
-
-<br />
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th colspan="5" align="center">{L_FEEDBACK}</th>
-</tr>
-<!-- IF S_USER_NOTES -->
-
- <tr align="center">
- <td colspan="5" class="row3"><span class="gensmall">{L_SEARCH_KEYWORDS}{L_COLON}</span> <input type="text" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="btnlite" name="filter" value="{L_SEARCH}" /></td>
- </tr>
- <tr align="center">
- <td colspan="5" class="row3"><span class="gensmall">{L_DISPLAY_LOG}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}{L_COLON}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" value="{L_GO}" name="sort" /></td>
- </tr>
- <tr>
- <th>{L_REPORT_BY}</th>
- <th>{L_IP}</th>
- <th>{L_TIME}</th>
- <th>{L_ACTION}</th>
- <th><!-- IF S_CLEAR_ALLOWED -->{L_MARK}<!-- ENDIF --></th>
- </tr>
-
- <!-- BEGIN usernotes -->
- <!-- IF usernotes.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td class="gen">{usernotes.REPORT_BY}</td>
- <td style="text-align: center;">{usernotes.IP}</td>
- <td style="text-align: center;">{usernotes.REPORT_AT}</td>
- <td class="gen">
- {usernotes.ACTION}
- <!-- IF usernotes.DATA --><br />&#187; <span class="gensmall">[ {usernotes.DATA} ]</span><!-- ENDIF -->
- </td>
- <td style="text-align: center;"><!-- IF S_CLEAR_ALLOWED --><input type="checkbox" class="radio" name="marknote[]" value="{usernotes.ID}" /><!-- ENDIF --></td>
- </tr>
- <!-- END usernotes -->
-
- <!-- IF S_CLEAR_ALLOWED -->
- <tr>
- <td class="cat" colspan="5" align="center"><input class="btnlite" type="submit" name="action[del_all]" value="{L_DELETE_ALL}" />&nbsp; <input class="btnlite" type="submit" name="action[del_marked]" value="{L_DELETE_MARKED}" /></td>
- </tr>
- <!-- ENDIF -->
-
-<!-- ELSE -->
- <tr>
- <td class="row1" colspan="2" align="center"><span class="gen">{L_NO_FEEDBACK}</span></td>
- </tr>
-<!-- ENDIF -->
-</table>
-
-<br clear="all" />
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th colspan="2" align="center">{L_ADD_FEEDBACK}</th>
-</tr>
-<tr>
- <td class="row3" align="center" colspan="2"><span class="genmed">{L_ADD_FEEDBACK_EXPLAIN}</span></td>
-</tr>
-<tr>
- <td colspan="2" class="row1" align="center"><textarea name="usernote" rows="10" cols="76"></textarea></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center"><input class="btnmain" type="submit" name="action[add_feedback]" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" /></td>
-</tr>
-</table>
-
-<table width="100%" cellspacing="0" cellpadding="0">
-<tr>
- <td class="pagination">{PAGE_NUMBER} [ {TOTAL_REPORTS} ]</td>
- <td align="{S_CONTENT_FLOW_END}"><span class="pagination"><!-- INCLUDE pagination.html --></span></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_post.html b/phpBB/styles/subsilver2/template/mcp_post.html
deleted file mode 100644
index 1a29df94b0..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_post.html
+++ /dev/null
@@ -1,214 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<!-- IF S_MCP_REPORT -->
- <form method="post" name="mcp_report" action="{S_CLOSE_ACTION}">
-
- <table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
- <tr>
- <th colspan="2" align="center"><!-- IF S_PM -->{L_PM_REPORT_DETAILS}<!-- ELSE -->{L_REPORT_DETAILS}<!-- ENDIF --></th>
- </tr>
- <tr>
- <td class="row1"><b class="gen">{L_REPORT_REASON}{L_COLON} </b></td>
- <td class="row2"><span class="gen">{REPORT_REASON_TITLE} &raquo; {REPORT_REASON_DESCRIPTION}</span></td>
- </tr>
- <tr>
- <td class="row1" width="20%"><b class="gen">{L_REPORTER}{L_COLON} </b></td>
- <td class="row2" width="80%"><span class="gen"<!-- IF REPORTER_COLOUR --> style="font-weight: bold; color: {REPORTER_COLOUR};"<!-- ENDIF -->>{REPORTER_NAME}</span> &nbsp; <span class="gen">[ <!-- IF U_VIEW_REPORTER_PROFILE --><a href="{U_VIEW_REPORTER_PROFILE}">{L_READ_PROFILE}</a><!-- ENDIF --><!-- IF S_USER_NOTES --><!-- IF U_VIEW_REPORTER_PROFILE --> | <!-- ENDIF --><a href="{U_MCP_REPORTER_NOTES}">{L_VIEW_NOTES}</a> | <a href="{U_MCP_WARN_REPORTER}">{L_WARN_USER}</a><!-- ENDIF --> ]</span></td>
- </tr>
- <tr>
- <td class="row1"><b class="gen">{L_REPORTED}{L_COLON} </b></td>
- <td class="row2"><span class="postdetails">{REPORT_DATE}</span></td>
- </tr>
- <!-- IF REPORT_TEXT -->
- <tr>
- <th colspan="2" align="center">{L_MORE_INFO}</th>
- </tr>
- <tr>
- <td class="row1" colspan="2"><div class="gen" style="overflow: auto; width: 100%; height: 80pt; border: 1px;">{REPORT_TEXT}</div></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="cat" align="center" colspan="2"><!-- IF not S_REPORT_CLOSED --><input class="btnmain" type="submit" value="{L_CLOSE_REPORT}" name="action[close]" /><!-- ELSE -->{L_REPORT_CLOSED}<!-- ENDIF --> &nbsp; <input class="btnlite" type="submit" value="{L_DELETE_REPORT}" name="action[delete]" /></td>
- </tr>
- </table>
-
- <input type="hidden" name="report_id_list[]" value="{REPORT_ID}" />
- {S_FORM_TOKEN}
- </form>
-
- <br clear="all"/>
-<!-- ENDIF -->
-
-<!-- IF S_MCP_QUEUE --><form method="post" name="mcp_approve" action="{U_APPROVE_ACTION}"><!-- ELSE --><form method="post" name="mcp_report_details" action="{S_CLOSE_ACTION}"><!-- ENDIF -->
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th colspan="2" align="center"><!-- IF S_PM -->{L_PM}<!-- ELSE -->{L_POST_DETAILS}<!-- ENDIF --></th>
-</tr>
-<tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall"><!-- IF S_MCP_QUEUE -->{RETURN_QUEUE} | {RETURN_TOPIC_SIMPLE} | {RETURN_POST}<!-- ELSEIF S_MCP_REPORT -->{RETURN_REPORTS}<!-- IF not S_PM --> | <a href="{U_VIEW_POST}">{L_VIEW_POST}</a> | <a href="{U_VIEW_TOPIC}">{L_VIEW_TOPIC}</a> | <a href="{U_VIEW_FORUM}">{L_VIEW_FORUM}</a><!-- ENDIF --><!-- ELSE -->{RETURN_TOPIC}<!-- ENDIF --></span></td>
-</tr>
-<tr>
- <td class="row1"><b class="gen"><!-- IF S_PM -->{L_PM_SUBJECT}<!-- ELSE -->{L_POST_SUBJECT}<!-- ENDIF -->{L_COLON} </b></td>
- <td class="row2">
- <span class="gen">{POST_SUBJECT}</span>
- <!-- IF S_POST_UNAPPROVED --><span class="postapprove">{UNAPPROVED_IMG} <a href="{U_MCP_APPROVE}">{L_POST_UNAPPROVED}</a></span> <!-- ENDIF -->
- <!-- IF S_POST_DELETED --><span class="postapprove">{DELETED_IMG} <a href="{U_MCP_APPROVE}">{L_POST_DELETED}</a></span> <!-- ENDIF -->
- <!-- IF S_POST_REPORTED and not S_MCP_REPORT --><span class="postreported">{REPORTED_IMG} <a href="{U_MCP_REPORT}">{L_POST_REPORTED}</a></span><!-- ENDIF -->
- </td>
-</tr>
-<tr>
- <td class="row1" width="20%"><b class="gen"><!-- IF S_PM -->{L_PM_FROM}<!-- ELSE -->{L_POSTER}<!-- ENDIF -->{L_COLON} </b></td>
- <td class="row2" width="80%"><span class="gen"<!-- IF POST_AUTHOR_COLOUR --> style="font-weight: bold; color: {POST_AUTHOR_COLOUR}"<!-- ENDIF -->>{POST_AUTHOR}</span><span class="gen"> &nbsp; [ <!-- IF U_POST_AUTHOR --><a href="{U_POST_AUTHOR}">{L_READ_PROFILE}</a><!-- ENDIF --><!-- IF S_USER_NOTES --><!-- IF U_POST_AUTHOR --> | <!-- ENDIF --><a href="{U_MCP_USER_NOTES}">{L_VIEW_NOTES}</a> <!-- IF U_MCP_WARN_USER -->| <a href="{U_MCP_WARN_USER}">{L_WARN_USER}</a><!-- ENDIF --><!-- ENDIF --> ]</span></td>
-</tr>
-<!-- IF S_CAN_VIEWIP -->
- <tr>
- <td class="row1"><b class="gen"><!-- IF S_PM -->{L_THIS_PM_IP}<!-- ELSE -->{L_THIS_POST_IP}<!-- ENDIF -->{L_COLON} </b></td>
- <td class="row2"><span class="gen">
- <!-- IF U_WHOIS -->
- <a href="{U_WHOIS}"><!-- IF POST_IPADDR -->{POST_IPADDR}<!-- ELSE -->{POST_IP}<!-- ENDIF --></a> (<!-- IF POST_IPADDR -->{POST_IP}<!-- ELSE --><a href="{U_LOOKUP_IP}">{L_LOOKUP_IP}</a><!-- ENDIF -->)
- <!-- ELSE -->
- <!-- IF POST_IPADDR -->{POST_IPADDR} ({POST_IP})<!-- ELSE -->{POST_IP}<!-- IF U_LOOKUP_IP --> (<a href="{U_LOOKUP_IP}">{L_LOOKUP_IP}</a>)<!-- ENDIF --><!-- ENDIF -->
- <!-- ENDIF -->
- </span></td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td class="row1"><b class="gen"><!-- IF S_PM -->{L_SENT_AT}<!-- ELSE -->{L_POSTED}<!-- ENDIF -->{L_COLON} </b></td>
- <td class="row2"><span class="postdetails">{POST_DATE}</span></td>
-</tr>
-<!-- IF S_TO_RECIPIENT -->
- <tr>
- <td class="row1" nowrap="nowrap" width="150"><b class="gen">{L_TO}{L_COLON}</b></td>
- <td class="row2 gen">
- <!-- BEGIN to_recipient -->
- <!-- IF to_recipient.IS_GROUP --><span class="sep"><a href="{to_recipient.U_VIEW}">{to_recipient.NAME}</a></span><!-- ELSE -->{to_recipient.NAME_FULL}&nbsp;<!-- ENDIF -->
- <!-- END to_recipient -->
- </td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_BCC_RECIPIENT -->
- <tr>
- <td class="row1" nowrap="nowrap" width="150"><b class="gen">{L_BCC}{L_COLON}</b></td>
- <td class="row2 gen">
- <!-- BEGIN bcc_recipient -->
- <!-- IF bcc_recipient.IS_GROUP --><span class="sep"><a href="{bcc_recipient.U_VIEW}">{bcc_recipient.NAME}</a></span><!-- ELSE -->{bcc_recipient.NAME_FULL}&nbsp;<!-- ENDIF -->
- <!-- END bcc_recipient -->
- </td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <th colspan="2" align="center">{L_PREVIEW}</th>
-</tr>
-<tr>
- <td class="row1" colspan="2">
- <!-- IF U_EDIT --><div class="gen" style="float: {S_CONTENT_FLOW_END};"><a href="{U_EDIT}" class="imageset">{EDIT_IMG}</a></div><!-- ENDIF -->
-
- <div class="postbody">{POST_PREVIEW}</div>
-
- <!-- IF S_HAS_ATTACHMENTS -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <!-- IF attachment.S_ROW_COUNT is even --><td class="row2"><!-- ELSE --><td class="row1"><!-- ENDIF -->{attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
-
- </td>
-</tr>
-<!-- IF S_POST_UNAPPROVED and S_MCP_QUEUE -->
- <tr>
- <td class="cat" align="center" colspan="2"><input class="btnmain" type="submit" value="{L_APPROVE}" name="action[approve]" /> &nbsp; <input class="btnlite" type="submit" value="{L_DISAPPROVE}" name="action[disapprove]" /></td>
- </tr>
- <input type="hidden" name="post_id_list[]" value="{POST_ID}" />
-<!-- ENDIF -->
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<!-- IF S_MCP_QUEUE -->
- <br clear="all" />
-
- <!-- IF S_TOPIC_REVIEW --><!-- INCLUDE posting_topic_review.html --><!-- ENDIF -->
-<!-- ELSEIF S_MCP_REPORT -->
- <br clear="all" />
-
- <!-- IF S_TOPIC_REVIEW --><!-- INCLUDE posting_topic_review.html --><!-- ENDIF -->
-<!-- ELSE -->
- <!-- IF S_CAN_LOCK_POST or S_CAN_DELETE_POST or S_CAN_CHGPOSTER or S_MCP_POST_ADDITIONAL_OPTS -->
- <br /><a name="mod" class="anchor"></a>
-
- <table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
- <tr>
- <th colspan="2" align="center">{L_MOD_OPTIONS}</th>
- </tr>
- <!-- IF S_CAN_CHGPOSTER -->
- <tr>
- <td class="row1" valign="top"><b class="gen">{L_CHANGE_POSTER}</b></td>
- <td class="row2"><form method="post" name="mcp_chgposter" action="{U_POST_ACTION}"><input class="post" type="text" name="username" value="" /> <input class="btnmain" type="submit" value="{L_CONFIRM}" name="action[chgposter]" /><br /><span class="gensmall">[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</span><!-- IF S_USER_SELECT --><br /><select name="u">{S_USER_SELECT}</select> <input type="submit" class="btnmain" name="action[chgposter_ip]" value="{L_CONFIRM}" /><!-- ENDIF -->{S_FORM_TOKEN}</form></td>
- </tr>
- <!-- ENDIF -->
-
- <!-- EVENT mcp_post_additional_options -->
-
- <!-- IF S_CAN_LOCK_POST or S_CAN_DELETE_POST -->
- <tr>
- <td class="row1" valign="top"><b class="gen">{L_MOD_OPTIONS}</b></td>
- <td class="row2"><form method="post" name="mcp" action="{U_MCP_ACTION}"><select name="action"><!-- IF S_CAN_LOCK_POST --><!-- IF S_POST_LOCKED --><option value="unlock_post">{L_UNLOCK_POST} [{L_UNLOCK_POST_EXPLAIN}]</option><!-- ELSE --><option value="lock_post">{L_LOCK_POST} [{L_LOCK_POST_EXPLAIN}]</option><!-- ENDIF --><!-- ENDIF --><!-- IF S_CAN_DELETE_POST --><option value="delete_post">{L_DELETE_POST}</option><!-- ENDIF --></select> <input class="btnmain" type="submit" value="{L_SUBMIT}" /> {S_FORM_TOKEN}</form></td>
- </tr>
- <!-- ENDIF -->
- </table>
- <!-- ENDIF -->
-
- <!-- IF S_CAN_VIEWIP -->
- <br /><a name="ip" class="anchor"></a>
-
- <table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
- <tr>
- <th colspan="2" align="center">{L_IP_INFO}</th>
- </tr>
- <tr>
- <td colspan="2" class="cat"><b class="gen">{L_OTHER_USERS}</b></td>
- </tr>
- <!-- BEGIN userrow -->
- <!-- IF userrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td><span class="gen"><!-- IF userrow.U_PROFILE --><a href="{userrow.U_PROFILE}">{userrow.USERNAME}</a><!-- ELSE -->{userrow.USERNAME}<!-- ENDIF --> [ {userrow.NUM_POSTS} {userrow.L_POST_S} ]</span></td>
- <td align="center"><a href="{userrow.U_SEARCHPOSTS}" class="imageset">{SEARCH_IMG}</a></td>
- </tr>
- <!-- BEGINELSE -->
- <tr class="row1">
- <td colspan="2" align="center"><span class="gen">{L_NO_MATCHES_FOUND}</span></td>
- </tr>
- <!-- END userrow -->
- <tr>
- <td class="cat"><b class="gen">{L_IPS_POSTED_FROM}</b></td>
- <td class="cat" width="10%" nowrap="nowrap"><!-- IF U_LOOKUP_ALL --><span class="gen">[ <a href="{U_LOOKUP_ALL}">{L_LOOKUP_ALL}</a> ]</span><!-- ENDIF --></td>
- </tr>
- <!-- BEGIN iprow -->
- <!-- IF iprow.S_ROW_COUNT is even -->
- <tr class="row1">
- <!-- ELSE -->
- <tr class="row2">
- <!-- ENDIF -->
- <td><span class="gen"><!-- IF iprow.HOSTNAME --><a href="{iprow.U_WHOIS}">{iprow.HOSTNAME}</a> ({iprow.IP})<!-- ELSE --><a href="{iprow.U_WHOIS}">{iprow.IP}</a><!-- ENDIF --> [ {iprow.NUM_POSTS} {iprow.L_POST_S} ]</span></td>
- <td align="center"><!-- IF iprow.U_LOOKUP_IP --><span class="gen">[ <a href="{iprow.U_LOOKUP_IP}">{L_LOOKUP_IP}</a> ]</span><!-- ENDIF --></td>
- </tr>
- <!-- BEGINELSE -->
- <tr class="row1">
- <td colspan="2" align="center"><span class="gen">{L_NO_MATCHES_FOUND}</span></td>
- </tr>
- <!-- END iprow -->
- </table>
- <!-- ENDIF -->
-
-<!-- ENDIF -->
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_queue.html b/phpBB/styles/subsilver2/template/mcp_queue.html
deleted file mode 100644
index 7ca659b5da..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_queue.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form name="mcp" id="mcp" method="post" action="{S_MCP_ACTION}">
-
-<table width="100%" class="tablebg" cellspacing="1" cellpadding="4" border="0">
-<tr>
- <th colspan="4" nowrap="nowrap">{L_DISPLAY_OPTIONS}</th>
-</tr>
-<tr>
- <td colspan="4" class="cat" align="center"><span class="gensmall">{L_DISPLAY_ITEMS}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<span class="gensmall">{L_FORUM}</span> <select name="f">{S_FORUM_OPTIONS}</select> &nbsp; <!-- IF TOPIC_ID --><input type="checkbox" class="radio" name="t" value="{TOPIC_ID}" checked="checked" />&nbsp; <b>{L_ONLY_TOPIC}</b> &nbsp; <!-- ENDIF --><input class="btnlite" type="submit" name="sort" value="{L_GO}" /></td>
-</tr>
-<tr>
- <th>&nbsp;<!-- IF S_TOPICS -->{L_TOPIC}<!-- ELSE -->{L_POST}<!-- ENDIF -->&nbsp;</th>
- <th>&nbsp;{L_AUTHOR}&nbsp;</th>
- <th>&nbsp;{L_POST_TIME}&nbsp;</th>
- <th width="5%">&nbsp;{L_SELECT}&nbsp;</th>
-</tr>
-<!-- BEGIN postrow -->
-
- <!-- IF postrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td style="padding: 4px;"><p class="topictitle">{postrow.ATTACH_ICON_IMG} <a href="{postrow.U_VIEWPOST}">{postrow.POST_SUBJECT}</a></p>
- <span class="gensmall"><!-- IF postrow.U_VIEWFORUM -->{L_FORUM}{L_COLON} <a href="{postrow.U_VIEWFORUM}">{postrow.FORUM_NAME}</a><!-- ELSE -->{postrow.FORUM_NAME}<!-- ENDIF --></span></td>
- <td style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top" nowrap="nowrap"><span class="gen">{postrow.POST_AUTHOR_FULL}</span><br />
- <span class="gensmall">[ <a href="{postrow.U_VIEW_DETAILS}">{L_VIEW_DETAILS}</a> ]</span></td>
- <td class="postdetails" style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top" nowrap="nowrap">{postrow.POST_TIME}</td>
- <td align="center">
- <!-- IF S_TOPICS -->
- <input type="checkbox" class="radio" name="topic_id_list[]" value="{postrow.TOPIC_ID}" />
- <!-- ELSE -->
- <input type="checkbox" class="radio" name="post_id_list[]" value="{postrow.POST_ID}" />
- <!-- ENDIF -->
- </td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="4" height="30" align="center" valign="middle">
- <span class="gen">
- <!-- IF S_RESTORE -->
- <!-- IF S_TOPICS -->{L_NO_TOPICS_DELETED}<!-- ELSE -->{L_NO_POSTS_DELETED}<!-- ENDIF -->
- <!-- ELSE -->
- <!-- IF S_TOPICS -->{L_NO_TOPICS_QUEUE}<!-- ELSE -->{L_NO_POSTS_QUEUE}<!-- ENDIF -->
- <!-- ENDIF -->
- </span>
- </td>
- </tr>
-<!-- END postrow -->
-<tr>
- <td class="cat" colspan="4" align="center">
- <!-- IF S_RESTORE -->
- <input class="btnlite" type="submit" name="action[delete]" value="{L_DELETE}" />&nbsp;&nbsp;
- <input class="btnmain" type="submit" name="action[restore]" value="{L_RESTORE}" />
- <!-- ELSE -->
- <input class="btnmain" type="submit" name="action[approve]" value="{L_APPROVE}" />&nbsp;&nbsp;
- <input class="btnlite" type="submit" name="action[disapprove]" value="{L_DISAPPROVE}" />
- <!-- ENDIF -->
- </td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
-<tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">
- <b class="gensmall">
- <!-- IF S_TOPICS -->
- <a href="#" onclick="marklist('mcp', 'topic_id_list', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('mcp', 'topic_id_list', false); return false;">{L_UNMARK_ALL}</a>
- <!-- ELSE -->
- <a href="#" onclick="marklist('mcp', 'post_id_list', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('mcp', 'post_id_list', false); return false;">{L_UNMARK_ALL}</a>
- <!-- ENDIF -->
- </b>
- </td>
-</tr>
-</table>
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_reports.html b/phpBB/styles/subsilver2/template/mcp_reports.html
deleted file mode 100644
index 158f9c2603..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_reports.html
+++ /dev/null
@@ -1,67 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form name="mcp" id="mcp" method="post" action="{S_MCP_ACTION}">
-
-<table width="100%" class="tablebg" cellspacing="1" cellpadding="4" border="0">
-<tr>
- <th colspan="5" nowrap="nowrap">{L_DISPLAY_OPTIONS}</th>
-</tr>
-<tr>
- <td colspan="5" class="cat" align="center"><span class="gensmall">{L_DISPLAY_POSTS}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}<!-- IF not S_PM -->&nbsp;<span class="gensmall">{L_FORUM}</span> <select name="f">{S_FORUM_OPTIONS}</select> &nbsp; <!-- IF TOPIC_ID --><input type="checkbox" class="radio" name="t" value="{TOPIC_ID}" checked="checked" />&nbsp; <b>{L_ONLY_TOPIC}</b> &nbsp; <!-- ENDIF --><!-- ENDIF --><input class="btnlite" type="submit" name="sort" value="{L_GO}" /></td>
-</tr>
-<tr>
- <!-- IF S_PM -->
- <th>&nbsp;{L_PM}&nbsp;</th>
- <th>&nbsp;{L_TO} &amp; {L_BCC}&nbsp;</th>
- <!-- ELSE -->
- <th>&nbsp;{L_POST}&nbsp;</th>
- <th>&nbsp;{L_AUTHOR}&nbsp;</th>
- <!-- ENDIF -->
- <th>&nbsp;{L_REPORTER}&nbsp;</th>
- <th>&nbsp;{L_REPORT_TIME}&nbsp;</th>
- <th width="5%">&nbsp;{L_SELECT}&nbsp;</th>
-</tr>
-<!-- BEGIN postrow -->
-
- <!-- IF postrow.S_ROW_ is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <!-- IF S_PM -->
- <td style="padding: 4px;"><p class="topictitle">{postrow.ATTACH_ICON_IMG} <a href="{postrow.U_VIEW_DETAILS}">{postrow.PM_SUBJECT}</a></p>
- <span class="gensmall">{L_PM_FROM}{L_COLON} {postrow.PM_AUTHOR_FULL}</span></td>
- <td style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><span class="gen">{postrow.RECIPIENTS}</span><br />
- <span class="gensmall">{L_SENT_AT}{L_COLON} {postrow.PM_TIME}</span></td>
- <!-- ELSE -->
- <td style="padding: 4px;"><p class="topictitle">{postrow.ATTACH_ICON_IMG} <a href="{postrow.U_VIEWPOST}">{postrow.POST_SUBJECT}</a></p>
- <span class="gensmall"><!-- IF postrow.U_VIEWFORUM -->{L_FORUM}{L_COLON} <a href="{postrow.U_VIEWFORUM}">{postrow.FORUM_NAME}</a><!-- ELSE -->{postrow.FORUM_NAME}<!-- ENDIF --></span></td>
- <td style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top" nowrap="nowrap"><span class="gen">{postrow.POST_AUTHOR_FULL}</span><br />
- <span class="gensmall">{postrow.POST_TIME}</span></td>
- <!-- ENDIF -->
- <td style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top" nowrap="nowrap"><span class="gen">{postrow.REPORTER_FULL}</span></td>
- <td style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top" nowrap="nowrap"><span class="gen">{postrow.REPORT_TIME}</span><br />
- <span class="gensmall">[ <a href="{postrow.U_VIEW_DETAILS}">{L_VIEW_DETAILS}</a> ]</span></td>
- <td align="center"><input type="checkbox" class="radio" name="report_id_list[]" value="{postrow.REPORT_ID}" /></td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="5" height="30" align="center" valign="middle"><span class="gen">{L_NO_POSTS}</span></td>
- </tr>
-<!-- END postrow -->
-<tr>
- <td class="cat" colspan="5" align="center">
- <!-- IF S_CLOSED -->
- <input class="btnmain" type="submit" value="{L_DELETE_REPORTS}" name="action[delete]" />
- <!-- ELSE -->
- <input class="btnmain" type="submit" name="action[close]" value="{L_CLOSE_REPORTS}" /> &nbsp; <input class="btnlite" type="submit" value="{L_DELETE_REPORTS}" name="action[delete]" />
- <!-- ENDIF -->
- </td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
-<tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="gensmall"><a href="#" onclick="marklist('mcp', '', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('mcp', '', false); return false;">{L_UNMARK_ALL}</a></b></td>
-</tr>
-</table>
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_topic.html b/phpBB/styles/subsilver2/template/mcp_topic.html
deleted file mode 100644
index eee7fa95ea..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_topic.html
+++ /dev/null
@@ -1,158 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form name="mcp" id="mcp" method="post" action="{S_MCP_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<!-- IF S_CAN_SPLIT -->
- <tr>
- <th colspan="3" nowrap="nowrap">{L_SPLIT_TOPIC}</th>
- </tr>
- <tr>
- <td class="row2" colspan="3" align="center"><span class="gensmall">{L_SPLIT_TOPIC_EXPLAIN}</span></td>
- </tr>
- <!-- EVENT mcp_topic_options_before -->
- <tr>
- <td class="row1" nowrap="nowrap"><span class="gen">{L_SPLIT_SUBJECT}</span></td>
- <td class="row2" colspan="2"><input class="post" style="width: 350px" type="text" size="35" maxlength="124" name="subject" value="{SPLIT_SUBJECT}" /></td>
- </tr>
- <!-- EVENT mcp_topic_options_after -->
- <tr>
- <td class="row1" nowrap="nowrap"><span class="gen">{L_SPLIT_FORUM}</span></td>
- <td class="row2" colspan="2"><select name="to_forum_id">{S_FORUM_SELECT}</select></td>
- </tr>
-
- <!-- IF S_SHOW_TOPIC_ICONS -->
- <tr>
- <td class="row1"><span class="gen">{L_TOPIC_ICON}</span></td>
- <td class="row2" colspan="2">
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr>
- <td><span class="genmed nowrap"><input type="radio" class="radio" name="icon" value="0"<!-- IF not S_TOPIC_ICON --> checked="checked"<!-- ENDIF --> />{L_NO_TOPIC_ICON}</span> <!-- BEGIN topic_icon --><span class="nowrap"><input type="radio" class="radio" name="icon" value="{topic_icon.ICON_ID}"<!-- IF topic_icon.S_CHECKED --> checked="checked"<!-- ENDIF --> /><img src="{topic_icon.ICON_IMG}" width="{topic_icon.ICON_WIDTH}" height="{topic_icon.ICON_HEIGHT}" alt="" title="" hspace="2" vspace="2" /></span> <!-- END topic_icon --></td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- ENDIF -->
-<!-- ENDIF -->
-
-<!-- IF S_CAN_MERGE -->
- <tr>
- <th colspan="3" nowrap="nowrap">{L_MERGE_POSTS}</th>
- </tr>
- <tr>
- <td class="row2" colspan="3" align="center"><span class="gensmall">{L_MERGE_TOPIC_EXPLAIN}</span></td>
- </tr>
- <tr>
- <td class="row1" nowrap="nowrap"><span class="gen">{L_MERGE_TOPIC_ID}</span></td>
- <td class="row2" colspan="2"><input class="post" type="number" min="0" max="9999999999" name="to_topic_id" value="{TO_TOPIC_ID}" /> <a href="{U_SELECT_TOPIC}">{L_SELECT_TOPIC}</a></td>
- </tr>
- <!-- IF TO_TOPIC_INFO -->
- <tr>
- <td class="row3" colspan="3" align="center"><b class="gen">{TO_TOPIC_INFO}</b></td>
- </tr>
- <!-- ENDIF -->
-<!-- ENDIF -->
-<tr>
- <th colspan="3" nowrap="nowrap">{L_DISPLAY_OPTIONS}</th>
-</tr>
-<tr>
- <td class="row1" nowrap="nowrap"><span class="gen">{L_POSTS_PER_PAGE}</span><br /><span class="gensmall">{L_POSTS_PER_PAGE_EXPLAIN}</span></td>
- <td class="row2" colspan="2"><input class="post" type="number" min="0" max="999999" name="posts_per_page" value="{POSTS_PER_PAGE}" /></td>
-</tr>
-<tr>
- <td class="cat" colspan="3" align="center"><span class="gensmall">{L_DISPLAY_POSTS}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" name="sort" value="{L_GO}" /></td>
-</tr>
-<tr>
- <th nowrap="nowrap" colspan="3">{L_TOPIC_REVIEW}{L_COLON} <!-- EVENT mcp_topic_topic_title_before -->{TOPIC_TITLE}<!-- EVENT mcp_topic_topic_title_after --></th>
-</tr>
-<tr>
- <td class="row3" colspan="3" align="center"><span class="gensmall">{RETURN_TOPIC}</span></td>
-</tr>
-<!-- BEGIN postrow -->
-
- <!-- IF postrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td align="center"><b class="postauthor">{postrow.POST_AUTHOR_FULL}</b></td>
- <td width="100%">
- <!-- EVENT mcp_topic_postrow_post_details_before -->
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr style="vertical-align: top;">
- <td class="gensmall" nowrap="nowrap">&nbsp;<b>{L_POST_SUBJECT}{L_COLON}</b>&nbsp;</td>
- <td class="gensmall" width="100%">{postrow.POST_SUBJECT}</td>
- </tr>
- </table>
- <!-- EVENT mcp_topic_postrow_post_details_after -->
- </td>
- <td width="5%" align="center"><a href="{postrow.U_POST_DETAILS}" class="imageset">{INFO_IMG}</a></td>
- </tr>
-
- <!-- IF postrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td width="100%" valign="top" colspan="2">
- <table width="100%" cellspacing="0" cellpadding="2" border="0">
- <tr>
- <td valign="top">
- <div class="postbody">{postrow.MESSAGE}</div>
- <!-- IF postrow.S_HAS_ATTACHMENTS -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <!-- IF postrow.attachment.S_ROW_COUNT is even --><td class="row2"><!-- ELSE --><td class="row1"><!-- ENDIF -->{postrow.attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
-
- </td>
- </tr>
- <tr>
- <td valign="bottom">
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr valign="middle">
- <td width="100%">
- <!-- IF postrow.S_POST_UNAPPROVED and postrow.U_MCP_APPROVE --><span class="postapprove">{UNAPPROVED_IMG} <a href="{postrow.U_MCP_APPROVE}">{L_POST_UNAPPROVED}</a></span><br /><!-- ENDIF -->
- <!-- IF postrow.S_POST_DELETED and postrow.U_MCP_APPROVE --><span class="postapprove">{DELETED_IMG} <a href="{postrow.U_MCP_APPROVE}">{L_POST_DELETED}</a></span><br /><!-- ENDIF -->
- <!-- IF postrow.S_POST_REPORTED and postrow.U_MCP_REPORT --><span class="postreported">{REPORTED_IMG} <a href="{postrow.U_MCP_REPORT}">{L_POST_REPORTED}</a></span><!-- ENDIF -->
- </td>
- <td width="10" nowrap="nowrap">{postrow.MINI_POST_IMG}</td>
- <td class="gensmall" nowrap="nowrap"><b>{L_POSTED}{L_COLON}</b> {postrow.POST_DATE}</td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
- <td width="5%" align="center"><input type="checkbox" class="radio" name="post_id_list[]" value="{postrow.POST_ID}"<!-- IF postrow.S_CHECKED --> checked="checked"<!-- ENDIF --> /></td>
- </tr>
- <tr>
- <td class="row3" colspan="3" height="1"><img src="images/spacer.gif" width="1" height="1" alt="" /></td>
- </tr>
-<!-- END postrow -->
-<tr>
- <td class="cat" colspan="3" align="center"><select name="action"><option value="" selected="selected">{L_SELECT_ACTION}</option>
- <!-- IF S_CAN_APPROVE --><option value="approve">{L_APPROVE_POSTS}</option><!-- ENDIF -->
- <!-- IF S_CAN_LOCK --><option value="lock_post">{L_LOCK_POST_POSTS} [ {L_LOCK_POST_EXPLAIN} ]</option><option value="unlock_post">{L_UNLOCK_POST_POSTS}</option><!-- ENDIF -->
- <!-- IF S_CAN_DELETE --><option value="delete_post">{L_DELETE_POSTS}</option><!-- ENDIF -->
- <!-- IF S_CAN_RESTORE --><option value="restore">{L_RESTORE_POSTS}</option><!-- ENDIF -->
- <!-- IF S_CAN_MERGE --><option value="merge_posts"<!-- IF ACTION eq 'merge' --> selected="selected"<!-- ENDIF -->>{L_MERGE_POSTS}</option><!-- ENDIF -->
- <!-- IF S_CAN_SPLIT --><option value="split_all"<!-- IF ACTION eq 'split' --> selected="selected"<!-- ENDIF -->>{L_SPLIT_POSTS}</option><option value="split_beyond">{L_SPLIT_AFTER}</option><!-- ENDIF -->
- <!-- IF S_CAN_SYNC --><option value="resync">{L_RESYNC}</option><!-- ENDIF -->
- </select>&nbsp;<input class="btnmain" type="submit" name="mcp_topic_submit" value="{L_SUBMIT}" /></td>
-</tr>
-</table>
-{S_HIDDEN_FIELDS}
-{S_FORM_TOKEN}
-</form>
-
-<table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
-<tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="gensmall"><a href="#" onclick="marklist('mcp', '', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('mcp', '', false); return false;">{L_UNMARK_ALL}</a></b></td>
-</tr>
-</table>
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_warn_front.html b/phpBB/styles/subsilver2/template/mcp_warn_front.html
deleted file mode 100644
index f6daec9cc5..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_warn_front.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form method="post" name="mcp" action="{U_POST_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1" border="0" align="center">
-<tr>
- <th colspan="2"align="center">{L_SELECT_USER}</th>
-</tr>
-<tr>
- <td class="row1" width="40%"><b class="gen">{L_FIND_USERNAME}{L_COLON} </b><br /><span class="gensmall">[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</span></td>
- <td class="row2"><input type="text" class="post" name="username" size="20" /></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center"><input type="submit" name="submituser" value="{L_SUBMIT}" class="btnmain" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" /><br />
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <td class="row3" colspan="4" align="center"><b class="gen">{L_MOST_WARNINGS}</b></td>
-</tr>
-<tr>
- <th>&nbsp;{L_USERNAME}&nbsp;</th>
- <th>&nbsp;{L_WARNINGS}&nbsp;</th>
- <th>&nbsp;{L_LATEST_WARNING_TIME}&nbsp;</th>
- <th>&nbsp;</th>
-</tr>
-<!-- BEGIN highest -->
- <tr>
- <td class="row1" width="15%" valign="top"><span class="gen">{highest.USERNAME_FULL}</span></td>
- <td class="row2" width="15%" valign="top"><span class="gen">{highest.WARNINGS}</span></td>
- <td class="row1" width="15%" valign="top"><span class="gen">{highest.WARNING_TIME}</span></td>
- <td class="row2" width="15%" valign="top"><span class="gen"><a href="{highest.U_NOTES}">{L_VIEW_NOTES}</a></span></td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="4" align="center"><span class="gen">{L_NO_WARNINGS}</span></td>
- </tr>
-<!-- END highest -->
-</table>
-
-<br clear="all" /><br />
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <td class="row3" colspan="4" align="center"><b class="gen">{L_LATEST_WARNINGS}</b></td>
-</tr>
-<tr>
- <th>&nbsp;{L_USERNAME}&nbsp;</th>
- <th>&nbsp;{L_TIME}&nbsp;</th>
- <th>&nbsp;{L_TOTAL_WARNINGS}&nbsp;</th>
- <th>&nbsp;</th>
-</tr>
-<!-- BEGIN latest -->
- <tr>
- <td class="row1" width="15%" valign="top"><span class="gen">{latest.USERNAME_FULL}</span></td>
- <td class="row2" width="15%" valign="top"><span class="gen">{latest.WARNING_TIME}</span></td>
- <td class="row1" width="15%" valign="top"><span class="gen">{latest.WARNINGS}</span></td>
- <td class="row2" width="15%" valign="top"><span class="gen"><a href="{latest.U_NOTES}">{L_VIEW_NOTES}</a></span></td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="4" align="center"><span class="gen">{L_NO_WARNINGS}</span></td>
- </tr>
-<!-- END latest -->
-</table>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_warn_list.html b/phpBB/styles/subsilver2/template/mcp_warn_list.html
deleted file mode 100644
index 6e263b6403..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_warn_list.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<form method="post" name="mcp" action="{U_POST_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <td class="row3" colspan="4" align="center"><b class="gen">{L_WARNED_USERS}</b></td>
-</tr>
-<tr>
- <th>&nbsp;{L_USERNAME}&nbsp;</th>
- <th>&nbsp;{L_WARNINGS}&nbsp;</th>
- <th>&nbsp;{L_LATEST_WARNING_TIME}&nbsp;</th>
- <th>&nbsp;</th>
-</tr>
-<!-- BEGIN user -->
- <tr>
- <td class="row1" width="15%" valign="top"><span class="gen">{user.USERNAME_FULL}</span></td>
- <td class="row2" width="15%" valign="top"><span class="gen">{user.WARNINGS}</span></td>
- <td class="row1" width="15%" valign="top"><span class="gen">{user.WARNING_TIME}</span></td>
- <td class="row2" width="15%" valign="top"><span class="gen"><a href="{user.U_NOTES}">{L_VIEW_NOTES}</a></span></td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="4" align="center"><span class="gen">{L_NO_WARNINGS}</span></td>
- </tr>
-<!-- END user -->
-<tr align="center">
- <td class="row3" colspan="4"><span class="gensmall">{L_DISPLAY_POSTS}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" value="{L_GO}" name="sort" /></td>
-</tr>
-</table>
-
-<table width="100%" cellspacing="0" cellpadding="0">
-<tr>
- <td class="pagination">{PAGE_NUMBER} [ {TOTAL_USERS} ]</td>
- <td align="{S_CONTENT_FLOW_END}"><span class="pagination"><!-- INCLUDE pagination.html --></span></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_warn_post.html b/phpBB/styles/subsilver2/template/mcp_warn_post.html
deleted file mode 100644
index 68715eff2d..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_warn_post.html
+++ /dev/null
@@ -1,67 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th colspan="2" align="center">{L_POST}</th>
-</tr>
-<tr>
- <td class="row1" align="center">
- <table cellspacing="1" cellpadding="2" border="0">
- <tr>
- <td class="gen" align="center"><!-- IF USER_COLOR --><b style="color: #{USER_COLOR}"><!-- ELSE --><b><!-- ENDIF -->{USERNAME}</b></td>
- </tr>
- <!-- IF RANK_TITLE -->
- <tr>
- <td class="postdetails" align="center">{RANK_TITLE}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF RANK_IMG -->
- <tr>
- <td align="center">{RANK_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td align="center"><!-- IF AVATAR_IMG -->{AVATAR_IMG}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF --></td>
- </tr>
- </table>
- </td>
- <td class="row1">
- <span class="gen">{POST}</span>
- </td>
-</tr>
-</table>
-
-<br clear="all" /><br />
-
-<form method="post" name="mcp" action="{U_POST_ACTION}">
-
-<!-- EVENT mcp_warn_post_add_warning_field_before -->
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th align="center">{L_ADD_WARNING}</th>
-</tr>
-<tr>
- <td class="row3" align="center"><span class="genmed">{L_ADD_WARNING_EXPLAIN}</span></td>
-</tr>
-<tr>
- <td class="row1" align="center"><textarea name="warning" rows="10" cols="76">{L_WARNING_POST_DEFAULT}</textarea></td>
-</tr>
-<!-- IF S_CAN_NOTIFY -->
-<tr>
- <td class="row1" align="center"><input type="checkbox" class="radio" name="notify_user" checked="checked" /><span class="genmed">{L_NOTIFY_USER_WARN}</span></td>
-</tr>
-<!-- ENDIF -->
-<tr>
- <td class="cat" align="center"><input class="btnmain" type="submit" name="action[add_warning]" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" /></td>
-</tr>
-</table>
-
-<!-- EVENT mcp_warn_post_add_warning_field_after -->
-
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_warn_user.html b/phpBB/styles/subsilver2/template/mcp_warn_user.html
deleted file mode 100644
index 20b57c6837..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_warn_user.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th colspan="2" align="center">{USERNAME}</th>
-</tr>
-<tr>
- <td class="row1" align="center">
- <table cellspacing="1" cellpadding="2" border="0">
- <tr>
- <td class="gen" align="center"><b>{USERNAME_FULL}</b></td>
- </tr>
- <!-- IF RANK_TITLE -->
- <tr>
- <td class="postdetails" align="center">{RANK_TITLE}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF RANK_IMG -->
- <tr>
- <td align="center">{RANK_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td align="center"><!-- IF AVATAR_IMG -->{AVATAR_IMG}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF --></td>
- </tr>
- </table>
- </td>
- <td class="row1">
- <table width="100%" cellspacing="1" cellpadding="2" border="0">
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{L_JOINED}{L_COLON} </td>
- <td width="100%"><b class="gen">{JOINED}</b></td>
- </tr>
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_TOTAL_POSTS}{L_COLON} </td>
- <td><b class="gen">{POSTS}</b></td>
- </tr>
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_WARNINGS}{L_COLON} </td>
- <td><b class="gen">{WARNINGS}</b></td>
- </tr>
- </table>
- </td>
-</tr>
-</table>
-
-<br clear="all" /><br />
-
-<form method="post" name="mcp" action="{U_POST_ACTION}">
-
-<!-- EVENT mcp_warn_user_add_warning_field_before -->
-
-<table width="100%" cellpadding="3" cellspacing="1" border="0" class="tablebg">
-<tr>
- <th align="center">{L_ADD_WARNING}</th>
-</tr>
-<tr>
- <td class="row3" align="center"><span class="genmed">{L_ADD_WARNING_EXPLAIN}</span></td>
-</tr>
-<tr>
- <td class="row1" align="center"><textarea name="warning" rows="10" cols="76"></textarea></td>
-</tr>
-<!-- IF S_CAN_NOTIFY -->
-<tr>
- <td class="row1" align="center"><input type="checkbox" class="radio" name="notify_user" checked="checked" /><span class="genmed">{L_NOTIFY_USER_WARN}</span></td>
-</tr>
-<!-- ENDIF -->
-<tr>
- <td class="cat" align="center"><input class="btnmain" type="submit" name="action[add_warning]" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" /></td>
-</tr>
-</table>
-
-<!-- EVENT mcp_warn_user_add_warning_field_after -->
-
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/mcp_whois.html b/phpBB/styles/subsilver2/template/mcp_whois.html
deleted file mode 100644
index 3e3b983059..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_whois.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!-- INCLUDE mcp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th>{L_WHOIS}</th>
-</tr>
-<tr>
- <td class="row3" align="center"><span class="gensmall">{RETURN_POST}</span></td>
-</tr>
-<tr>
- <td class="row1"><pre>{WHOIS}</pre></td>
-</tr>
-</table>
-
-<!-- INCLUDE mcp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/memberlist_body.html b/phpBB/styles/subsilver2/template/memberlist_body.html
deleted file mode 100644
index 9044896bca..0000000000
--- a/phpBB/styles/subsilver2/template/memberlist_body.html
+++ /dev/null
@@ -1,117 +0,0 @@
-<!-- IF S_IN_SEARCH_POPUP -->
- <!-- INCLUDE simple_header.html -->
-<!-- ELSE -->
- <!-- INCLUDE overall_header.html -->
-<!-- ENDIF -->
-
-<!-- IF S_SEARCH_USER -->
- <!-- INCLUDE memberlist_search.html -->
-<!-- ENDIF -->
-
-<!-- IF S_SHOW_GROUP --><!-- INCLUDE memberlist_group.html --><!-- ENDIF -->
-
-<!-- IF not S_SHOW_GROUP -->
- <form method="post" name="charsearch" action="{S_MODE_ACTION}">
- <table width="100%" cellspacing="1">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}"><span class="genmed">{L_USERNAME_BEGINS_WITH}{L_COLON} </span>
- <select name="first_char" onchange="this.form.submit();">
- <!-- BEGIN first_char -->
- <option value="{first_char.VALUE}"<!-- IF first_char.S_SELECTED --> selected="selected"<!-- ENDIF -->>{first_char.DESC}</option>
- <!-- END first_char -->
- </select>&nbsp;<input type="submit" name="char" value="{L_DISPLAY}" class="btnlite" /></td>
- <!-- IF U_FIND_MEMBER and not S_SEARCH_USER -->
- <td class="genmed" align="{S_CONTENT_FLOW_END}"><a href="{U_FIND_MEMBER}">{L_FIND_USERNAME}</a></td>
- <!-- ELSEIF S_SEARCH_USER and U_HIDE_FIND_MEMBER and not S_IN_SEARCH_POPUP -->
- <td class="genmed" align="{S_CONTENT_FLOW_END}"><a href="{U_HIDE_FIND_MEMBER}">{L_HIDE_MEMBER_SEARCH}</a></td>
- <!-- ENDIF -->
- </tr>
- </table>
- {S_FORM_TOKEN}
- </form>
-<!-- ENDIF -->
-
-<!-- IF S_IN_SEARCH_POPUP -->
- <form method="post" name="results" action="{S_MODE_ACTION}" onsubmit="insert_marked(this.user);return false">
-<!-- ELSE -->
- <form method="post" action="{S_MODE_ACTION}">
-<!-- ENDIF -->
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th nowrap="nowrap">#</th>
- <th nowrap="nowrap" width="36%" align="{S_CONTENT_FLOW_BEGIN}"><a href="{U_SORT_USERNAME}">{L_USERNAME}</a></th>
- <th nowrap="nowrap" width="15%"><a href="{U_SORT_JOINED}">{L_JOINED}</a></th>
- <th nowrap="nowrap" width="10%"><a href="{U_SORT_POSTS}">{L_POSTS}</a></th>
- <th nowrap="nowrap" width="15%"><a href="{U_SORT_RANK}">{L_RANK}</a></th>
- <th nowrap="nowrap" width="11%"><a href="{U_SORT_EMAIL}">{L_EMAIL}</a></th>
- <!-- IF S_IN_SEARCH_POPUP and not S_SELECT_SINGLE --><th width="2%" nowrap="nowrap">{L_MARK}</th><!-- ENDIF -->
-</tr>
-<!-- BEGIN memberrow -->
-
- <!-- IF S_SHOW_GROUP -->
- <!-- IF memberrow.S_FIRST_ROW and memberrow.S_GROUP_LEADER -->
- <tr class="row3">
- <td colspan="7"><b class="gensmall">{L_GROUP_LEADER}</b></td>
- </tr>
- <!-- ELSEIF not memberrow.S_GROUP_LEADER and not $S_MEMBER_HEADER -->
- <tr class="row3">
- <td colspan="7"><b class="gensmall">{L_GROUP_MEMBERS}</b></td>
- </tr>
- <!-- DEFINE $S_MEMBER_HEADER = 1 -->
- <!-- ENDIF -->
- <!-- ENDIF -->
-
- <!-- IF memberrow.S_ROW_COUNT is even --><tr class="row2"><!-- ELSE --> <tr class="row1"><!-- ENDIF -->
-
- <td class="gen" align="center">&nbsp;{memberrow.ROW_NUMBER}&nbsp;</td>
- <td class="genmed" align="{S_CONTENT_FLOW_BEGIN}"><!-- EVENT memberlist_body_username_prepend -->{memberrow.USERNAME_FULL}<!-- IF memberrow.S_INACTIVE --> <em>({L_INACTIVE})</em><!-- ENDIF --><!-- EVENT memberlist_body_username_append --><!-- IF S_SELECT_SINGLE --> [&nbsp;<a href="#" onclick="insert_single('{memberrow.A_USERNAME}'); return false;">{L_SELECT}</a>&nbsp;]<!-- ENDIF --></td>
- <td class="genmed" align="center" nowrap="nowrap">&nbsp;{memberrow.JOINED}&nbsp;</td>
- <td class="gen" align="center">{memberrow.POSTS}</td>
- <td class="gen" align="center"><!-- EVENT memberlist_body_rank_prepend --><!-- IF memberrow.RANK_IMG -->{memberrow.RANK_IMG}<!-- ELSE -->{memberrow.RANK_TITLE}<!-- ENDIF --><!-- EVENT memberlist_body_rank_append --></td>
- <td class="gen" align="center">&nbsp;<!-- IF memberrow.U_EMAIL --><a href="{memberrow.U_EMAIL}" class="imageset">{EMAIL_IMG}</a><!-- ENDIF -->&nbsp;</td>
- <!-- IF memberrow.S_PROFILE_FIELD1 -->
- <!-- Use a construct like this to include admin defined profile fields. Replace FIELD1 with the name of your field. -->
- <td class="gen" align="center">&nbsp;{memberrow.PROFILE_FIELD1_VALUE}</td>
- <!-- ENDIF -->
- <!-- IF S_IN_SEARCH_POPUP and not S_SELECT_SINGLE --><td align="center"><input type="checkbox" class="radio" name="user" value="{memberrow.USERNAME}" /></td><!-- ENDIF -->
- </tr>
-
-<!-- BEGINELSE -->
-
- <tr>
- <td class="row1" colspan="<!-- IF S_IN_SEARCH_POPUP -->8<!-- ELSE -->7<!-- ENDIF -->" align="center">
- <span class="gen"><!-- IF S_SHOW_GROUP -->{L_NO_GROUP_MEMBERS}<!-- ELSE -->{L_NO_MEMBERS}<!-- ENDIF --></span>
- </td>
- </tr>
-
-<!-- END memberrow -->
-
-<tr>
- <td class="cat" colspan="<!-- IF S_IN_SEARCH_POPUP -->8<!-- ELSE -->7<!-- ENDIF -->" align="center"><!-- IF S_IN_SEARCH_POPUP and not S_SELECT_SINGLE --><input class="btnlite" type="submit" value="{L_SELECT_MARKED}" /><!-- ELSE --><span class="gensmall">{L_SELECT_SORT_METHOD}{L_COLON}</span>&nbsp;<select name="sk">{S_MODE_SELECT}</select>&nbsp; <span class="gensmall">{L_ORDER}</span>&nbsp;<select name="sd">{S_ORDER_SELECT}</select>&nbsp; <input type="submit" name="submit" value="{L_SUBMIT}" class="btnlite" /><!-- ENDIF --></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-
-</form>
-
-<table width="100%" cellspacing="0" cellpadding="0">
-<tr>
- <td class="pagination">{PAGE_NUMBER} [ {TOTAL_USERS} ]</td>
- <td align="{S_CONTENT_FLOW_END}"><!-- IF S_IN_SEARCH_POPUP and not S_SELECT_SINGLE --><b class="nav"><a href="#" onclick="marklist('results', 'user', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('results', 'user', false); return false;">{L_UNMARK_ALL}</a></b><br /><!-- ENDIF --><span class="pagination"><!-- INCLUDE pagination.html --></span></td>
-</tr>
-</table>
-
-
-
-<!-- IF S_IN_SEARCH_POPUP -->
- <!-- INCLUDE simple_footer.html -->
-<!-- ELSE -->
- <br clear="all" />
-
- <!-- INCLUDE breadcrumbs.html -->
-
- <br clear="all" />
-
- <div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
- <!-- INCLUDE overall_footer.html -->
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/memberlist_email.html b/phpBB/styles/subsilver2/template/memberlist_email.html
deleted file mode 100644
index 04f36b2244..0000000000
--- a/phpBB/styles/subsilver2/template/memberlist_email.html
+++ /dev/null
@@ -1,107 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- EVENT memberlist_email_before -->
-
-<div id="pagecontent">
-
- <form action="{S_POST_ACTION}" method="post" name="postform">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <!-- IF S_CONTACT_ADMIN-->
- <th colspan="2">{L_CONTACT_ADMIN}</th>
- <!-- ELSEIF S_SEND_USER -->
- <th colspan="2">{L_SEND_EMAIL_USER}</th>
- <!-- ELSE -->
- <th colspan="2">{L_EMAIL_TOPIC}</th>
- <!-- ENDIF -->
- </tr>
- <!-- IF ERROR_MESSAGE -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="error">{ERROR_MESSAGE}</span></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF CONTACT_INFO -->
- <tr>
- <td class="row1" colspan="2">{CONTACT_INFO}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_SEND_USER -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_RECIPIENT}</b></td>
- <td class="row2" width="65%"><b class="genmed">{USERNAME}</b></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_SUBJECT}</b></td>
- <td class="row2"><input class="post" type="text" name="subject" size="50" tabindex="2" value="{SUBJECT}" /></td>
- </tr>
- <!-- ELSEIF S_CONTACT_ADMIN-->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_RECIPIENT}</b></td>
- <td class="row2" width="65%"><b class="genmed">{L_ADMINISTRATOR}</b></td>
- </tr>
- <!-- IF not S_IS_REGISTERED -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_SENDER_EMAIL_ADDRESS}</b></td>
- <td class="row2"><input class="post" type="text" name="email" size="50" maxlength="100" value="{EMAIL}" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_SENDER_NAME}</b></td>
- <td class="row2"><input class="post" type="text" name="name" size="50" value="{NAME}" /></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_SUBJECT}</b></td>
- <td class="row2"><input class="post" type="text" name="subject" size="50" tabindex="2" value="{SUBJECT}" /></td>
- </tr>
- <!-- ELSE -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_EMAIL_ADDRESS}</b></td>
- <td class="row2"><input class="post" type="email" name="email" size="50" maxlength="100" value="{EMAIL}" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_REAL_NAME}</b></td>
- <td class="row2"><input class="post" type="text" name="name" size="50" value="{NAME}" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_DEST_LANG}</b><br /><span class="gensmall">{L_DEST_LANG_EXPLAIN}</span></td>
- <td class="row2"><select name="lang">{S_LANG_OPTIONS}</select></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="row1" valign="top"><b class="genmed">{L_MESSAGE_BODY}</b><br /><span class="gensmall">{L_EMAIL_BODY_EXPLAIN}</span></td>
- <td class="row2"><textarea class="post" name="message" rows="15" cols="76" tabindex="3">{MESSAGE}</textarea></td>
- </tr>
- <!-- IF S_REGISTERED_USER -->
- <tr>
- <td class="row1" valign="top"><span class="gen"><b>{L_OPTIONS}</b></span></td>
- <td class="row2">
- <table cellspacing="0" cellpadding="1" border="0">
- <tr>
- <td><input type="checkbox" class="radio" name="cc_sender" value="1" checked="checked" /></td>
- <td class="gen">{L_CC_SENDER}</td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="cat" colspan="2" align="center"><input type="submit" tabindex="6" name="submit" class="btnmain" value="{L_SEND_EMAIL}" /></td>
- </tr>
- </table>
-
- {S_FORM_TOKEN}
-
- </form>
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div style="float: {S_CONTENT_FLOW_END};"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/memberlist_group.html b/phpBB/styles/subsilver2/template/memberlist_group.html
deleted file mode 100644
index ff8c96c120..0000000000
--- a/phpBB/styles/subsilver2/template/memberlist_group.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="3">{L_GROUP_INFORMATION}</th>
-</tr>
-<tr>
- <td class="row1" width="20%"><b class="genmed">{L_GROUP_NAME}{L_COLON}</b></td>
- <td class="row2"><b class="gen"<!-- IF GROUP_COLOR --> style="color:#{GROUP_COLOR}"<!-- ENDIF -->>{GROUP_NAME}</b> <!-- IF U_MANAGE --><a href="{U_MANAGE}">{L_MANAGE_GROUP}</a><!-- ENDIF --></td>
-<!-- IF AVATAR_IMG or RANK_IMG or GROUP_RANK or U_PM -->
- <td class="row1" width="33%" rowspan="2" align="center"><!-- IF AVATAR_IMG -->{AVATAR_IMG}<br /><!-- ENDIF --><!-- IF RANK_IMG -->{RANK_IMG}<!-- ENDIF --><!-- IF GROUP_RANK --><span class="gensmall">{GROUP_RANK}</span><br /><br /><!-- ENDIF --><!-- IF U_PM --><a href="{U_PM}" class="imageset">{PM_IMG}</a><!-- ENDIF --></td>
-<!-- ENDIF -->
-</tr>
-<tr>
- <td class="row1" width="20%"><b class="genmed">{L_GROUP_DESC}{L_COLON}</b></td>
- <td class="row2"><span class="gen">{GROUP_DESC}</span><p class="forumdesc">{GROUP_TYPE}</p></td>
-</tr>
-</table>
diff --git a/phpBB/styles/subsilver2/template/memberlist_im.html b/phpBB/styles/subsilver2/template/memberlist_im.html
deleted file mode 100644
index ecd9aca86f..0000000000
--- a/phpBB/styles/subsilver2/template/memberlist_im.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- INCLUDE simple_header.html -->
-
-<br clear="all" />
-
-<form method="post" action="{S_IM_ACTION}">
- <table class="tablebg" width="95%" cellspacing="1" cellpadding="4" border="0" align="center">
- <tr>
- <th colspan="2">{L_SEND_IM}</th>
- </tr>
- <!-- IF S_SENT_JABBER -->
- <tr>
- <td class="row1" colspan="2" align="center"><span class="gen">{L_IM_SENT_JABBER}</span></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="row3" colspan="2"><span class="gensmall">{L_SEND_IM_EXPLAIN}</span></td>
- </tr>
- <tr>
- <td class="row1"><b class="genmed">{L_IM_RECIPIENT}{L_COLON} </b></td>
- <td class="row2"><span class="gen"><b>{USERNAME}</b><!-- IF S_NO_SEND_JABBER --> [ {IM_CONTACT} ]<!-- ENDIF --></span> <!-- IF PRESENCE_IMG -->{PRESENCE_IMG}<!-- ENDIF --></td>
- </tr>
-
- <!-- IF S_SEND_JABBER -->
- <tr>
- <td class="row1"><b class="genmed">{L_IM_MESSAGE}{L_COLON} </b></td>
- <td class="row2"><textarea class="post" name="message" rows="5" cols="45"></textarea></td>
- </tr>
- <tr>
- <td class="cat" colspan="2" align="center"><input class="btnmain" name="submit" type="submit" value="{L_IM_SEND}" /></td>
- </tr>
- <!-- ELSEIF S_NO_SEND_JABBER -->
- <tr>
- <td class="row1" colspan="2"><span class="genmed">{L_IM_NO_JABBER}</span></td>
- </tr>
- <!-- ENDIF -->
-
- </table>
-{S_FORM_TOKEN}
-</form>
-
-<a class="nav" href="#" onclick="window.close(); return false;">{L_CLOSE_WINDOW}</a>
-
-<!-- INCLUDE simple_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/memberlist_search.html b/phpBB/styles/subsilver2/template/memberlist_search.html
deleted file mode 100644
index 5a4c430cd2..0000000000
--- a/phpBB/styles/subsilver2/template/memberlist_search.html
+++ /dev/null
@@ -1,129 +0,0 @@
-<!-- You should retain this javascript in your own template! -->
-
-<!-- IF S_IN_SEARCH_POPUP -->
- <script type="text/javascript">
- // <![CDATA[
- function insert_user(user)
- {
- opener.document.forms['{S_FORM_NAME}'].{S_FIELD_NAME}.value = ( opener.document.forms['{S_FORM_NAME}'].{S_FIELD_NAME}.value.length && opener.document.forms['{S_FORM_NAME}'].{S_FIELD_NAME}.type == "textarea" ) ? opener.document.forms['{S_FORM_NAME}'].{S_FIELD_NAME}.value + "\n" + user : user;
- }
-
- function insert_marked(users)
- {
- if (typeof(users.length) == "undefined")
- {
- if (users.checked)
- {
- insert_user(users.value);
- }
- }
- else if (users.length > 0)
- {
- for (i = 0; i < users.length; i++)
- {
- if (users[i].checked)
- {
- insert_user(users[i].value);
- }
- }
- }
-
- self.close();
- }
-
- function insert_single(user)
- {
- opener.document.forms['{S_FORM_NAME}'].{S_FIELD_NAME}.value = user;
- self.close();
- }
-
- /**
- * Mark/unmark checklist
- * id = ID of parent container, name = name prefix, state = state [true/false]
- */
- function marklist(id, name, state)
- {
- var parent = document.getElementById(id) || document[id];
-
- if (!parent)
- {
- return;
- }
-
- var rb = parent.getElementsByTagName('input');
-
- for (var r = 0; r < rb.length; r++)
- {
- if (rb[r].name.substr(0, name.length) == name && rb[r].disabled !== true)
- {
- rb[r].checked = state;
- }
- }
- }
- // ]]>
- </script>
-<!-- ENDIF -->
-
-<form method="post" action="{S_MODE_ACTION}" name="search">
-
-<!-- EVENT memberlist_search_fields_before -->
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="4">{L_FIND_USERNAME}</th>
-</tr>
-<tr>
- <td class="row3" colspan="4"><span class="gensmall">{L_FIND_USERNAME_EXPLAIN}</span></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_USERNAME}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" name="username" value="{USERNAME}" /></td>
- <!-- IF S_EMAIL_SEARCH_ALLOWED -->
- <td class="row1"><b class="genmed">{L_EMAIL}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="email" name="email" value="{EMAIL}" /></td>
- <!-- ELSE -->
- <td colspan="2" class="row1">&nbsp;</td>
- <!-- ENDIF -->
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_JOINED}{L_COLON}</b></td>
- <td class="row2"><select name="joined_select">{S_JOINED_TIME_OPTIONS}</select> <input class="post" type="text" name="joined" value="{JOINED}" /></td>
- <td class="row1"><b class="genmed">{L_POSTS}{L_COLON}</b></td>
- <td class="row2"><select name="count_select">{S_COUNT_OPTIONS}</select> <input class="post" type="number" min="0" name="count" value="{COUNT}" /></td>
-</tr>
-<!-- IF S_VIEWONLINE -->
-<tr>
- <td class="row1"><b class="genmed">{L_LAST_ACTIVE}{L_COLON}</b></td>
- <td class="row2"><select name="active_select">{S_ACTIVE_TIME_OPTIONS}</select> <input class="post" type="text" name="active" value="{ACTIVE}" /></td>
- <!-- IF S_IP_SEARCH_ALLOWED -->
- <td class="row1"><b class="genmed">{L_POST_IP}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" name="ip" value="{IP}" /></td>
- <!-- ELSE -->
- <td colspan="2" class="row1">&nbsp;</td>
- <!-- ENDIF -->
-</tr>
-<!-- ENDIF -->
-<tr>
- <td class="row1"><b class="genmed">{L_GROUP}{L_COLON}</b></td>
- <td class="row2" nowrap="nowrap"><select name="search_group_id">{S_GROUP_SELECT}</select></td>
- <!-- IF S_JABBER_ENABLED -->
- <td class="row1"><b class="genmed">{L_JABBER}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" name="jabber" value="{JABBER}" /></td>
- <!-- ELSE -->
- <td colspan="2" class="row1">&nbsp;</td>
- <!-- ENDIF -->
-</tr>
-<!-- EVENT memberlist_search_sorting_options_before -->
-<tr>
- <td class="row1"><b class="genmed">{L_SORT_BY}{L_COLON}</b></td>
- <td class="row2" nowrap="nowrap"><select name="sk">{S_SORT_OPTIONS}</select> <select name="sd">{S_ORDER_SELECT}</select>&nbsp;</td>
- <td colspan="2" class="row1">&nbsp;</td>
-</tr>
-<tr>
- <td class="cat" colspan="4" align="center"><input class="btnmain" type="submit" name="submit" value="{L_SEARCH}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" /></td>
-</tr>
-</table>
-<!-- EVENT memberlist_search_fields_after -->
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" />
diff --git a/phpBB/styles/subsilver2/template/memberlist_team.html b/phpBB/styles/subsilver2/template/memberlist_team.html
deleted file mode 100644
index 75fade184c..0000000000
--- a/phpBB/styles/subsilver2/template/memberlist_team.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<form method="post" action="{S_MODE_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th nowrap="nowrap" width="20%">{L_USERNAME}</th>
- <!-- IF S_DISPLAY_MODERATOR_FORUMS --><th nowrap="nowrap" width="25%">{L_FORUMS}</th><!-- ENDIF -->
- <th nowrap="nowrap" width="20%">{L_PRIMARY_GROUP}</th>
- <th nowrap="nowrap" width="15%">{L_RANK}</th>
- <th nowrap="nowrap" width="11%">{L_SEND_MESSAGE}</th>
-</tr>
-<!-- BEGIN group -->
-<tr class="row3">
- <td colspan="5"><b class="gensmall"><!-- IF group.U_GROUP --><a href="{group.U_GROUP}">{group.GROUP_NAME}</a><!-- ELSE -->{group.GROUP_NAME}<!-- ENDIF --></b></td>
-</tr>
-<!-- BEGIN user -->
- <!-- IF group.user.S_ROW_COUNT is even --><tr class="row2"><!-- ELSE --><tr class="row1"><!-- ENDIF -->
-
- <td class="gen" align="center"><!-- EVENT memberlist_team_username_prepend --><strong>{group.user.USERNAME_FULL}</strong><!-- IF group.user.S_INACTIVE --> <em>({L_INACTIVE})</em><!-- ENDIF --><!-- EVENT memberlist_team_username_append --></td>
- <!-- IF S_DISPLAY_MODERATOR_FORUMS --><td class="gensmall" align="center"><!-- IF group.user.FORUM_OPTIONS --><select style="width: 100%;">{group.user.FORUMS}</select><!-- ELSEIF group.user.FORUMS -->{group.user.FORUMS}<!-- ELSE -->-<!-- ENDIF --></td><!-- ENDIF -->
- <td class="gensmall" align="center" nowrap="nowrap">&nbsp;
- <!-- IF group.user.U_GROUP -->
- <a<!-- IF group.user.GROUP_COLOR --> style="font-weight: bold; color:#{group.user.GROUP_COLOR}"<!-- ENDIF --> href="{group.user.U_GROUP}">{group.user.GROUP_NAME}</a>
- <!-- ELSE -->
- {group.user.GROUP_NAME}
- <!-- ENDIF -->
- &nbsp;</td>
- <td class="gen" align="center"><!-- IF group.user.RANK_IMG -->{group.user.RANK_IMG}<!-- ELSE -->{group.user.RANK_TITLE}<!-- ENDIF --></td>
- <td class="gen" align="center">&nbsp;<!-- IF group.user.U_PM --><a href="{group.user.U_PM}" class="imageset">{PM_IMG}</a><!-- ENDIF -->&nbsp;</td>
-</tr>
-<!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="5" align="center"><span class="gen">{L_NO_MEMBERS}</span></td>
- </tr>
-<!-- END user -->
-<!-- END group -->
-</table>
-
-</form>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div style="float: {S_CONTENT_FLOW_END};"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/memberlist_view.html b/phpBB/styles/subsilver2/template/memberlist_view.html
deleted file mode 100644
index 731d2c8bca..0000000000
--- a/phpBB/styles/subsilver2/template/memberlist_view.html
+++ /dev/null
@@ -1,207 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div id="pagecontent">
-
- <!-- EVENT memberlist_view_content_prepend -->
-
- <form method="post" action="{S_PROFILE_ACTION}">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="2" nowrap="nowrap">{L_VIEWING_PROFILE}</th>
- </tr>
- <tr>
- <td class="cat" width="40%" align="center"><h4>{L_USER_PRESENCE}</h4></td>
- <td class="cat" width="60%" align="center"><h4>{L_USER_FORUM}</h4></td>
- </tr>
- <tr>
- <td class="row1" align="center">
-
- <table cellspacing="1" cellpadding="2" border="0">
- <!-- IF S_USER_INACTIVE -->
- <tr>
- <td align="center"><b class="gen inactive">{L_USER_IS_INACTIVE}</b><br />{L_INACTIVE_REASON}{L_COLON} {USER_INACTIVE_REASON}<br /><br /></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td align="center"><!-- IF USER_COLOR --><b class="gen" style="color: {USER_COLOR}"><!-- ELSE --><b class="gen"><!-- ENDIF -->{USERNAME}</b><!-- IF U_USER_BAN --><span class="genmed"> [ <a href="{U_USER_BAN}">{L_USER_BAN}</a> ]</span><!-- ENDIF --><!-- IF U_USER_ADMIN --><span class="genmed"> [ <a href="{U_USER_ADMIN}">{L_USER_ADMIN}</a> ]</span><!-- ENDIF --></td>
- </tr>
- <!-- EVENT memberlist_view_rank_before -->
- <!-- IF RANK_TITLE -->
- <tr>
- <td class="postdetails" align="center">{RANK_TITLE}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF RANK_IMG -->
- <tr>
- <td align="center">{RANK_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT memberlist_view_rank_after -->
- <!-- IF AVATAR_IMG -->
- <tr>
- <td align="center">{AVATAR_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF ONLINE_IMG -->
- <tr>
- <td align="center">{ONLINE_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF U_SWITCH_PERMISSIONS -->
- <tr>
- <td class="genmed" align="center">[ <a href="{U_SWITCH_PERMISSIONS}">{L_USE_PERMISSIONS}</a> ]</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT memberlist_view_zebra_before -->
- <!-- IF S_USER_LOGGED_IN and S_ZEBRA -->
- <tr>
- <td class="genmed" align="center">[
- <!-- IF U_REMOVE_FRIEND -->
- <a href="{U_REMOVE_FRIEND}">{L_REMOVE_FRIEND}</a>
- <!-- ELSEIF U_REMOVE_FOE -->
- <a href="{U_REMOVE_FOE}">{L_REMOVE_FOE}</a>
- <!-- ELSE -->
- <!-- IF U_ADD_FRIEND --><a href="{U_ADD_FRIEND}">{L_ADD_FRIEND}</a><!-- ENDIF --><!-- IF U_ADD_FOE --><!-- IF U_ADD_FRIEND --> | <!-- ENDIF --><a href="{U_ADD_FOE}">{L_ADD_FOE}</a><!-- ENDIF -->
- <!-- ENDIF -->
- ]</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT memberlist_view_zebra_after -->
- </table>
- </td>
- <td class="row1">
- <table width="100%" cellspacing="1" cellpadding="2" border="0">
- <!-- EVENT memberlist_view_user_statistics_before -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{L_JOINED}{L_COLON} </td>
- <td width="100%"><b class="gen">{JOINED}</b></td>
- </tr>
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{L_LAST_ACTIVE}{L_COLON} </td>
- <td width="100%"><b class="gen">{LAST_ACTIVE}</b></td>
- </tr>
- <!-- IF S_WARNINGS -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_WARNINGS}{L_COLON} </td>
- <td width="100%"><b class="gen">{WARNINGS}</b><!-- IF U_NOTES or U_WARN --><br /><span class="genmed"> [ <!-- IF U_NOTES --><a href="{U_NOTES}">{L_VIEW_NOTES}</a><!-- ENDIF --> <!-- IF U_WARN --><!-- IF U_NOTES --> | <!-- ENDIF --><a href="{U_WARN}">{L_WARN_USER}</a><!-- ENDIF --> ]</span><!-- ENDIF --></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_TOTAL_POSTS}{L_COLON} </td>
- <td><b class="gen">{POSTS}</b><span class="genmed"><!-- IF POSTS_PCT --><br />[{POSTS_PCT} / {POSTS_DAY}]<!-- ENDIF -->
- <!-- IF POSTS_IN_QUEUE and U_MCP_QUEUE --><br />[<a href="{U_MCP_QUEUE}">{L_POSTS_IN_QUEUE}</a>]<!-- ELSEIF POSTS_IN_QUEUE --><br />[{L_POSTS_IN_QUEUE}]<!-- ENDIF -->
- <!-- IF S_DISPLAY_SEARCH --><br /><a href="{U_SEARCH_USER}">{L_SEARCH_USER_POSTS}</a><!-- ENDIF --></span></td>
- </tr>
- <!-- IF S_SHOW_ACTIVITY -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_ACTIVE_IN_FORUM}{L_COLON} </td>
- <td><!-- IF ACTIVE_FORUM != '' --><b><a class="gen" href="{U_ACTIVE_FORUM}">{ACTIVE_FORUM}</a></b><br /><span class="genmed">[ {ACTIVE_FORUM_POSTS} / {ACTIVE_FORUM_PCT} ]</span><!-- ELSE --><span class="gen">-</span><!-- ENDIF --></td>
- </tr>
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap">{L_ACTIVE_IN_TOPIC}{L_COLON} </td>
- <td><!-- IF ACTIVE_TOPIC != '' --><b><a class="gen" href="{U_ACTIVE_TOPIC}">{ACTIVE_TOPIC}</a></b><br /><span class="genmed">[ {ACTIVE_TOPIC_POSTS} / {ACTIVE_TOPIC_PCT} ]</span><!-- ELSE --><span class="gen">-</span><!-- ENDIF --></td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT memberlist_view_user_statistics_after -->
- </table>
- </td>
- </tr>
- <tr>
- <td class="cat" align="center"><h4>{L_CONTACT}</h4></td>
- <td class="cat" align="center"><h4>{L_ABOUT_USER}</h4></td>
- </tr>
- <!-- EVENT memberlist_view_contact_before -->
- <tr>
- <td class="row1">
- <table width="100%" cellspacing="1" cellpadding="2" border="0">
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{L_EMAIL_ADDRESS}{L_COLON} </td>
- <td width="100%"><!-- IF U_EMAIL --><a href="{U_EMAIL}" class="imageset">{EMAIL_IMG}</a><!-- ENDIF --></td>
- </tr>
- <!-- IF U_PM -->
- <tr>
- <td class="gen" nowrap="nowrap" align="{S_CONTENT_FLOW_END}">{L_PM}{L_COLON} </td>
- <td><a href="{U_PM}" class="imageset">{PM_IMG}</a></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_JABBER_ENABLED -->
- <tr>
- <td class="gen" nowrap="nowrap" align="{S_CONTENT_FLOW_END}">{L_JABBER}{L_COLON} </td>
- <td><!-- IF U_JABBER --><a href="{U_JABBER}" onclick="popup(this.href, 550, 320); return false" class="imageset">{JABBER_IMG}</a><!-- ELSEIF USER_JABBER -->{USER_JABBER_IMG}<!-- ENDIF --></td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT memberlist_view_contact_custom_fields_before -->
- <!-- BEGIN custom_fields -->
- <!-- IF custom_fields.S_PROFILE_CONTACT -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{custom_fields.PROFILE_FIELD_NAME}{L_COLON} </td>
- <!-- IF custom_fields.PROFILE_FIELD_CONTACT -->
- <td><a href="{custom_fields.PROFILE_FIELD_CONTACT}"><span class="imageset {custom_fields.PROFILE_FIELD_IDENT}-icon">{custom_fields.PROFILE_FIELD_DESC}</span></a></td>
- <!-- ELSE -->
- <td><b class="genmed">{custom_fields.PROFILE_FIELD_VALUE}</b></td>
- <!-- ENDIF -->
- </tr>
- <!-- ENDIF -->
- <!-- END custom_fields -->
- <!-- EVENT memberlist_view_contact_custom_fields_after -->
- </table>
- </td>
- <td class="row1">
- <table cellspacing="1" cellpadding="2" border="0">
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{L_USERGROUPS}{L_COLON} </td>
- <td><select name="g">{S_GROUP_OPTIONS}</select> <input class="btnlite" type="submit" name="submit" value="{L_GO}" /></td>
- </tr>
- <!-- IF AGE !== '' -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{L_AGE}{L_COLON} </td>
- <td><b class="genmed">{AGE}</b></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_PROFILE_FIELD1 -->
- <!-- Use a construct like this to include admin defined profile fields. Replace FIELD1 with the name of your field. -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{PROFILE_FIELD1_NAME}{L_COLON} </td>
- <td><b class="genmed">{PROFILE_FIELD1_VALUE}</b></td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT memberlist_view_non_contact_custom_fields_before -->
- <!-- BEGIN custom_fields -->
- <!-- IF not custom_fields.S_PROFILE_CONTACT -->
- <tr>
- <td class="gen" align="{S_CONTENT_FLOW_END}" nowrap="nowrap">{custom_fields.PROFILE_FIELD_NAME}{L_COLON} </td>
- <td><b class="genmed">{custom_fields.PROFILE_FIELD_VALUE}</b></td>
- </tr>
- <!-- ENDIF -->
- <!-- END custom_fields -->
- <!-- EVENT memberlist_view_non_contact_custom_fields_after -->
- </table>
- </td>
- </tr>
- <!-- EVENT memberlist_view_contact_after -->
- <!-- IF SIGNATURE -->
- <tr>
- <td class="cat" colspan="2" align="center"><h4>{L_SIGNATURE}</h4></td>
- </tr>
- <tr>
- <td class="row1" colspan="2"><div class="postbody" style="padding: 10px;">{SIGNATURE}</div></td>
- </tr>
- <!-- ENDIF -->
- </table>
-
- </form>
-
- <!-- EVENT memberlist_view_content_append -->
-
-</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div style="float: {S_CONTENT_FLOW_END};"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/message_body.html b/phpBB/styles/subsilver2/template/message_body.html
deleted file mode 100644
index b9b502a57f..0000000000
--- a/phpBB/styles/subsilver2/template/message_body.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th>{MESSAGE_TITLE}</th>
-</tr>
-<tr>
- <td class="row1" align="center"><br /><p class="gen">{MESSAGE_TEXT}</p><br /></td>
-</tr>
-</table>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/overall_footer.html b/phpBB/styles/subsilver2/template/overall_footer.html
deleted file mode 100644
index 176110c58d..0000000000
--- a/phpBB/styles/subsilver2/template/overall_footer.html
+++ /dev/null
@@ -1,29 +0,0 @@
- <!-- EVENT overall_footer_content_after -->
-
- <!-- IF not S_IS_BOT -->{RUN_CRON_TASK}<!-- ENDIF -->
-</div>
-
-<!-- EVENT overall_footer_page_body_after -->
-
-<div id="wrapfooter">
- <!-- IF U_ACP --><span class="gensmall">[ <a href="{U_ACP}">{L_ACP}</a> ]</span><br /><br /><!-- ENDIF -->
- <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>
-
-<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
-<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF -->
-<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
-
-<!-- EVENT overall_footer_after -->
-
-{$SCRIPTS}
-
-<!-- EVENT overall_footer_body_after -->
-
-</body>
-</html>
diff --git a/phpBB/styles/subsilver2/template/overall_header.html b/phpBB/styles/subsilver2/template/overall_header.html
deleted file mode 100644
index ae3d48215e..0000000000
--- a/phpBB/styles/subsilver2/template/overall_header.html
+++ /dev/null
@@ -1,262 +0,0 @@
-<!DOCTYPE html>
-<html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">
-<head>
-<meta charset="utf-8" />
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-{META}
-<title><!-- IF UNREAD_NOTIFICATIONS_COUNT -->({UNREAD_NOTIFICATIONS_COUNT}) <!-- ENDIF --><!-- IF not S_VIEWTOPIC and not S_VIEWFORUM -->{SITENAME} - <!-- ENDIF --><!-- IF S_IN_MCP -->{L_MCP} - <!-- ELSEIF S_IN_UCP -->{L_UCP} - <!-- ENDIF -->{PAGE_TITLE}<!-- IF S_VIEWTOPIC or S_VIEWFORUM --> - {SITENAME}<!-- ENDIF --></title>
-
-<!-- IF S_ENABLE_FEEDS -->
- <!-- IF S_ENABLE_FEEDS_OVERALL --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {SITENAME}" href="{U_FEED}" /><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_NEWS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_NEWS}" href="{U_FEED}?mode=news" /><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_FORUMS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_ALL_FORUMS}" href="{U_FEED}?mode=forums" /><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_TOPICS --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_TOPICS_NEW}" href="{U_FEED}?mode=topics" /><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_TOPICS_ACTIVE --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FEED_TOPICS_ACTIVE}" href="{U_FEED}?mode=topics_active" /><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_FORUM and S_FORUM_ID --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_FORUM} - {FORUM_NAME}" href="{U_FEED}?f={S_FORUM_ID}" /><!-- ENDIF -->
- <!-- IF S_ENABLE_FEEDS_TOPIC and S_TOPIC_ID --><link rel="alternate" type="application/atom+xml" title="{L_FEED} - {L_TOPIC} - {TOPIC_TITLE}" href="{U_FEED}?f={S_FORUM_ID}&amp;t={S_TOPIC_ID}" /><!-- ENDIF -->
- <!-- EVENT overall_header_feeds -->
-<!-- ENDIF -->
-
-<!-- IF U_CANONICAL -->
- <link rel="canonical" href="{U_CANONICAL}" />
-<!-- ENDIF -->
-
-<link rel="stylesheet" href="{T_STYLESHEET_LINK}" type="text/css" />
-<link rel="stylesheet" href="{T_STYLESHEET_LANG_LINK}" type="text/css" />
-
-<script type="text/javascript">
-// <![CDATA[
-
-function popup(url, width, height, name)
-{
- if (!name)
- {
- name = '_popup';
- }
-
- window.open(url.replace(/&amp;/g, '&'), name, 'height=' + height + ',resizable=yes,scrollbars=yes,width=' + width);
- return false;
-}
-
-function jumpto()
-{
- var page = prompt('{LA_JUMP_PAGE}{L_COLON}', '{CURRENT_PAGE}');
- var per_page = '{PER_PAGE}';
- var base_url = '{BASE_URL|e('js')}';
-
- if (page !== null && !isNaN(page) && page == Math.floor(page) && page > 0)
- {
- if (base_url.indexOf('?') == -1)
- {
- document.location.href = base_url + '?start=' + ((page - 1) * per_page);
- }
- else
- {
- document.location.href = base_url.replace(/&amp;/g, '&') + '&start=' + ((page - 1) * per_page);
- }
- }
-}
-
-/**
-* Find a member
-*/
-function find_username(url)
-{
- popup(url, 760, 570, '_usersearch');
- return false;
-}
-
-/**
-* Mark/unmark checklist
-* id = ID of parent container, name = name prefix, state = state [true/false]
-*/
-function marklist(id, name, state)
-{
- var parent = document.getElementById(id) || document[id];
-
- if (!parent)
- {
- return;
- }
-
- var rb = parent.getElementsByTagName('input');
-
- for (var r = 0; r < rb.length; r++)
- {
- if (rb[r].name.substr(0, name.length) == name && rb[r].disabled !== true)
- {
- rb[r].checked = state;
- }
- }
-}
-
-<!-- IF ._file -->
-
- /**
- * Play quicktime file by determining it's width/height
- * from the displayed rectangle area
- *
- * Only defined if there is a file block present.
- */
- function play_qt_file(obj)
- {
- var rectangle = obj.GetRectangle();
-
- if (rectangle)
- {
- rectangle = rectangle.split(',')
- var x1 = parseInt(rectangle[0]);
- var x2 = parseInt(rectangle[2]);
- var y1 = parseInt(rectangle[1]);
- var y2 = parseInt(rectangle[3]);
-
- var width = (x1 < 0) ? (x1 * -1) + x2 : x2 - x1;
- var height = (y1 < 0) ? (y1 * -1) + y2 : y2 - y1;
- }
- else
- {
- var width = 200;
- var height = 0;
- }
-
- obj.width = width;
- obj.height = height + 16;
-
- obj.SetControllerVisible(true);
-
- obj.Play();
- }
-<!-- ENDIF -->
-
-// ]]>
-</script>
-
-<!-- EVENT overall_header_head_append -->
-
-{$STYLESHEETS}
-
-<!-- EVENT overall_header_stylesheets_after -->
-
-</head>
-<body class="{S_CONTENT_DIRECTION} {BODY_CLASS}">
-
-<!-- EVENT overall_header_body_before -->
-
-<a name="top" class="anchor"></a>
-
-<div id="wrapheader">
-
- <div id="logodesc">
- <table width="100%" cellspacing="0">
- <tr>
- <td><a href="<!-- IF U_SITE_HOME -->{U_SITE_HOME}<!-- ELSE -->{U_INDEX}<!-- ENDIF -->" class="imageset">{SITE_LOGO_IMG}</a></td>
- <td width="100%" align="center"><h1>{SITENAME}</h1><span class="gen">{SITE_DESCRIPTION}</span></td>
- </tr>
- </table>
- </div>
- <!-- EVENT overall_header_navbar_before -->
- <div id="menubar">
- <table width="100%" cellspacing="0">
- <tr>
- <td class="genmed dropdown-container">
- <!-- IF S_NOTIFICATIONS_DISPLAY and not S_IS_BOT and S_USER_LOGGED_IN -->
- <a href="{U_VIEW_ALL_NOTIFICATIONS}" id="notification_list_button" class="dropdown-trigger">
- <img src="{T_THEME_PATH}/images/icon_mini_notification.gif" width="12" height="13" alt="*" />
- {L_NOTIFICATIONS} [<strong>{NOTIFICATIONS_COUNT}</strong>]
- </a>&nbsp;
- <div id="notification_list" class="notification_list dropdown">
- <div class="row1 header">
- {L_NOTIFICATIONS}
- <span class="header_settings"><a href="{U_NOTIFICATION_SETTINGS}">{L_SETTINGS}</a></span>
- </div>
-
- <div class="notification_scroll">
- <table class="tablebg" cellspacing="1">
- <!-- BEGIN notifications -->
- <tr class="row<!-- IF notifications.UNREAD -->2<!-- ELSE -->1<!-- ENDIF -->">
- <td width="50">
- <!-- IF notifications.AVATAR -->{notifications.AVATAR}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF -->
- </td>
- <td valign="top">
- <div class="notification_title">
- <!-- IF notifications.URL --><a href="<!-- IF notifications.UNREAD -->{notifications.U_MARK_READ}<!-- ELSE -->{notifications.URL}<!-- ENDIF -->"><!-- ENDIF -->
- {notifications.FORMATTED_TITLE}
- <!-- IF notifications.URL --></a><!-- ENDIF -->
-
- <!-- IF notifications.REFERENCE --><br /><span class="notification-reference">{notifications.REFERENCE}</span><!-- ENDIF -->
- <!-- IF notifications.FORUM --><br /><span class="notification-forum">{notifications.FORUM}</span><!-- ENDIF -->
- <!-- IF notifications.REASON --><br /><span class="notification-reason">{notifications.REASON}</span><!-- ENDIF -->
- <br /><span class="notification-time">{notifications.TIME}</span>
- <!-- IF not notifications.URL and notifications.UNREAD -->
- <br /><a href="{notifications.U_MARK_READ}">{L_MARK_READ}</a>
- <!-- ENDIF -->
- </div>
- </td>
- </tr>
- <!-- END notifications -->
- </table>
- </div>
-
- <div class="row1 footer">
- <a href="{U_VIEW_ALL_NOTIFICATIONS}"><span>{L_SEE_ALL}</span></a>
- </div>
- </div>
- <!-- ENDIF -->
- <!-- IF not S_IS_BOT -->
- <!-- IF S_USER_LOGGED_IN -->
- <!-- IF S_DISPLAY_PM --> &nbsp;<a href="{U_PRIVATEMSGS}"><img src="{T_THEME_PATH}/images/icon_mini_message.gif" width="12" height="13" alt="*" /> {L_PRIVATE_MESSAGES} [<strong>{PRIVATE_MESSAGE_COUNT}</strong>]</a><!-- ENDIF -->
- <!-- ELSEIF S_REGISTER_ENABLED and not (S_SHOW_COPPA or S_REGISTRATION) --> &nbsp;<a href="{U_REGISTER}"><img src="{T_THEME_PATH}/images/icon_mini_register.gif" width="12" height="13" alt="*" /> {L_REGISTER}</a>
- <!-- ENDIF -->
- <!-- ENDIF -->
- <!-- IF not S_IS_BOT --> &nbsp;<a href="{U_LOGIN_LOGOUT}"><img src="{T_THEME_PATH}/images/icon_mini_login.gif" width="12" height="13" alt="*" /> {L_LOGIN_LOGOUT}</a>&nbsp;<!-- ENDIF -->
- <!-- IF U_RESTORE_PERMISSIONS --> &nbsp;<a href="{U_RESTORE_PERMISSIONS}"><img src="{T_THEME_PATH}/images/icon_mini_login.gif" width="12" height="13" alt="*" /> {L_RESTORE_PERMISSIONS}</a><!-- ENDIF -->
- <!-- IF S_BOARD_DISABLED and S_USER_LOGGED_IN --> &nbsp;<span class="error">{L_BOARD_DISABLED}</span><!-- ENDIF -->
- </td>
- <td class="genmed" align="{S_CONTENT_FLOW_END}">
- <!-- EVENT overall_header_navigation_prepend -->
- <a href="{U_FAQ}" rel="help"><img src="{T_THEME_PATH}/images/icon_mini_faq.gif" width="12" height="13" alt="*" /> {L_FAQ}</a>
- <!-- IF S_DISPLAY_SEARCH -->&nbsp; &nbsp;<a href="{U_SEARCH}"><img src="{T_THEME_PATH}/images/icon_mini_search.gif" width="12" height="13" alt="*" /> {L_SEARCH}</a><!-- ENDIF -->
- <!-- IF not S_IS_BOT -->
- <!-- IF S_DISPLAY_MEMBERLIST -->&nbsp; &nbsp;<a href="{U_MEMBERLIST}"><img src="{T_THEME_PATH}/images/icon_mini_members.gif" width="12" height="13" alt="*" /> {L_MEMBERLIST}</a><!-- ENDIF -->
- <!-- IF S_USER_LOGGED_IN -->&nbsp; &nbsp;<a href="{U_PROFILE}"><img src="{T_THEME_PATH}/images/icon_mini_profile.gif" width="12" height="13" alt="*" /> {L_PROFILE}</a><!-- ENDIF -->
- <!-- ENDIF -->
- <!-- EVENT overall_header_navigation_append -->
- </td>
- </tr>
- </table>
- </div>
-
- <div id="datebar">
- <table width="100%" cellspacing="0">
- <tr>
- <td class="gensmall"><!-- IF S_USER_LOGGED_IN -->{LAST_VISIT_DATE}<!-- ENDIF --></td>
- <td class="gensmall" align="{S_CONTENT_FLOW_END}">{CURRENT_TIME}<br /></td>
- </tr>
- </table>
- </div>
-
-</div>
-
-<!-- EVENT overall_header_page_body_before -->
-
-<div id="wrapcentre">
-
- <!-- IF S_DISPLAY_SEARCH -->
- <p class="searchbar">
- <span style="float: {S_CONTENT_FLOW_BEGIN};"><a href="{U_SEARCH_UNANSWERED}">{L_SEARCH_UNANSWERED}</a> | <a href="{U_SEARCH_ACTIVE_TOPICS}">{L_SEARCH_ACTIVE_TOPICS}</a></span>
- <!-- IF S_USER_LOGGED_IN or S_LOAD_UNREADS -->
- <span style="float: {S_CONTENT_FLOW_END};"><!-- IF S_LOAD_UNREADS --><a href="{U_SEARCH_UNREAD}">{L_SEARCH_UNREAD}</a><!-- IF S_USER_LOGGED_IN --> | <!-- ENDIF --><!-- ENDIF --><!-- IF S_USER_LOGGED_IN --><a href="{U_SEARCH_NEW}">{L_SEARCH_NEW}</a> | <a href="{U_SEARCH_SELF}">{L_SEARCH_SELF}</a><!-- ENDIF --></span>
- <!-- ENDIF -->
- </p>
- <!-- ENDIF -->
-
- <br style="clear: both;" />
-
- <!-- DEFINE $S_MICRODATA = 1 -->
- <!-- DEFINE $OVERALL_HEADER_BREADCRUMBS = 1 -->
- <!-- INCLUDE breadcrumbs.html -->
- <!-- UNDEFINE $OVERALL_HEADER_BREADCRUMBS -->
- <!-- DEFINE $S_MICRODATA = 0 -->
-
- <br />
- <!-- EVENT overall_header_content_before -->
diff --git a/phpBB/styles/subsilver2/template/pagination.html b/phpBB/styles/subsilver2/template/pagination.html
deleted file mode 100644
index b1c1d0e6c9..0000000000
--- a/phpBB/styles/subsilver2/template/pagination.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!-- IF .pagination -->
- <!-- IF BASE_URL --><b><a href="#" onclick="jumpto(); return false;" title="{L_JUMP_TO_PAGE_CLICK}">{L_GOTO_PAGE}</a></b><!-- ENDIF -->
- <!-- BEGIN pagination -->
- <!-- IF pagination.S_IS_PREV --><a href="{pagination.PAGE_URL}">{L_PREVIOUS}</a>
- <!-- ELSEIF pagination.S_IS_CURRENT --><strong>{pagination.PAGE_NUMBER}</strong>
- <!-- ELSEIF pagination.S_IS_ELLIPSIS --> {L_ELLIPSIS}
- <!-- ELSEIF pagination.S_IS_NEXT --><a href="{pagination.PAGE_URL}">{L_NEXT}</a>
- <!-- ELSE --><a href="{pagination.PAGE_URL}">{pagination.PAGE_NUMBER}</a>
- <!-- ENDIF -->
- <!-- END pagination -->
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/posting_attach_body.html b/phpBB/styles/subsilver2/template/posting_attach_body.html
deleted file mode 100644
index 67b3aaf3ea..0000000000
--- a/phpBB/styles/subsilver2/template/posting_attach_body.html
+++ /dev/null
@@ -1,83 +0,0 @@
-<tr>
- <th colspan="2">
- <script type="text/javascript">
- // <![CDATA[
- /**
- * Show upload progress bar
- */
- function popup_progress_bar()
- {
- close_waitscreen = 0;
- // no scrollbars
- popup('{UA_PROGRESS_BAR}', 400, 200, '_upload');
- }
- // ]]>
- </script>
-
- <!-- IF S_CLOSE_PROGRESS_WINDOW -->
- <script type="text/javascript">
- // <![CDATA[
- close_waitscreen = 1;
- // ]]>
- </script>
- <!-- ENDIF -->
-
- {L_ADD_ATTACHMENT}
- </th>
-</tr>
-<tr>
- <td class="row3" colspan="2"><span class="gensmall">{L_ADD_ATTACHMENT_EXPLAIN}</span></td>
-</tr>
-
-<tr>
- <td class="row1"><b class="genmed">{L_FILENAME}</b></td>
- <td class="row2"><input type="file" name="fileupload" maxlength="{FILESIZE}" value="" class="btnfile" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_FILE_COMMENT}</b></td>
- <td class="row2">
- <table border="0" cellspacing="0" cellpadding="2">
- <tr>
- <td><textarea class="post" name="filecomment" rows="3" cols="35">{FILE_COMMENT}</textarea>&nbsp;</td>
- <td valign="top">
- <table border="0" cellspacing="4" cellpadding="0">
- <tr>
- <td><input class="btnlite" type="submit" style="width:150px" name="add_file" value="{L_ADD_FILE}" onclick="popup_progress_bar();" /></td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
-</tr>
-
-<!-- IF S_HAS_ATTACHMENTS -->
- <tr>
- <th colspan="2">{L_POSTED_ATTACHMENTS}</th>
- </tr>
-
- <!-- BEGIN attach_row -->
- <tr>
- <td class="row1"><b class="genmed">{L_FILENAME}</b></td>
- <td class="row2"><a class="genmed" href="{attach_row.U_VIEW_ATTACHMENT}" target="_blank">{attach_row.FILENAME}</a></td>
- </tr>
- <tr>
- <td class="row1"><b class="genmed">{L_FILE_COMMENT}</b></td>
- <td class="row2">{attach_row.S_HIDDEN}
- <table border="0" cellspacing="0" cellpadding="2">
- <tr>
- <td><textarea class="post" name="comment_list[{attach_row.ASSOC_INDEX}]" rows="3" cols="35" wrap="virtual">{attach_row.FILE_COMMENT}</textarea>&nbsp;</td>
- <td valign="top">
- <table border="0" cellspacing="4" cellpadding="0">
- <tr>
- <td><input class="btnlite" type="submit" style="width:150px" name="delete_file[{attach_row.ASSOC_INDEX}]" value="{L_DELETE_FILE}" /></td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- END attach_row -->
-
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/posting_body.html b/phpBB/styles/subsilver2/template/posting_body.html
deleted file mode 100644
index 95f817e838..0000000000
--- a/phpBB/styles/subsilver2/template/posting_body.html
+++ /dev/null
@@ -1,434 +0,0 @@
-<!-- IF S_PRIVMSGS -->
- <!-- INCLUDE ucp_header.html -->
-<!-- ELSE -->
- <!-- INCLUDE overall_header.html -->
-<!-- ENDIF -->
-
-<!-- IF S_FORUM_RULES -->
- <div class="forumrules<!-- IF U_FORUM_RULES --> rules-link<!-- ENDIF -->">
- <!-- IF U_FORUM_RULES -->
- <h3>{L_FORUM_RULES}</h3><br />
- <a href="{U_FORUM_RULES}"><b>{L_FORUM_RULES_LINK}</b></a>
- <!-- ELSE -->
- <h3>{L_FORUM_RULES}</h3><br />
- {FORUM_RULES}
- <!-- ENDIF -->
- </div>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-<!-- IF not S_PRIVMSGS -->
- <div id="pageheader">
- <h2><!-- IF TOPIC_TITLE --><!-- EVENT posting_topic_title_before --><a class="titles" href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a><!-- EVENT posting_topic_title_after --><!-- ELSE --><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a><!-- ENDIF --></h2>
-
- <!-- IF MODERATORS -->
- <p class="moderators">{L_MODERATORS}{L_COLON} {MODERATORS}</p>
- <!-- ENDIF -->
- <!-- IF U_MCP or U_ACP -->
- <p class="linkmcp">[&nbsp;<!-- IF U_ACP --><a href="{U_ACP}">{L_ACP}</a><!-- IF U_MCP -->&nbsp;|&nbsp;<!-- ENDIF --><!-- ENDIF --><!-- IF U_MCP --><a href="{U_MCP}">{L_MCP}</a><!-- ENDIF -->&nbsp;]</p>
- <!-- ENDIF -->
- </div>
-
- <br clear="all" /><br />
-<!-- ENDIF -->
-
-<!-- IF not S_SHOW_PM_BOX -->
- <form action="{S_POST_ACTION}" method="post" name="postform"{S_FORM_ENCTYPE}>
-<!-- ENDIF -->
-
-<!-- IF S_DRAFT_LOADED -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th align="center">{L_INFORMATION}</th>
- </tr>
- <tr>
- <td class="row1" align="center"><span class="gen"><!-- IF S_PRIVMSGS -->{L_DRAFT_LOADED_PM}<!-- ELSE -->{L_DRAFT_LOADED}<!-- ENDIF --></span></td>
- </tr>
- </table>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-<!-- IF S_SHOW_DRAFTS -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="3" align="center">{L_LOAD_DRAFT}</th>
- </tr>
- <tr>
- <td class="row1" colspan="3" align="center"><span class="gen">{L_LOAD_DRAFT_EXPLAIN}</span></td>
- </tr>
- <tr>
- <th>{L_SAVE_DATE}</th>
- <th>{L_DRAFT_TITLE}</th>
- <th>{L_OPTIONS}</th>
- </tr>
- <!-- BEGIN draftrow -->
-
- <!-- IF draftrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td class="postdetails" style="padding: 4px;">{draftrow.DATE}</td>
- <td style="padding: 4px;"><b class="gen">{draftrow.DRAFT_SUBJECT}</b>
- <!-- IF draftrow.S_LINK_TOPIC --><br /><span class="gensmall">{L_TOPIC}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a></span>
- <!-- ELSEIF draftrow.S_LINK_FORUM --><br /><span class="gensmall">{L_FORUM}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a></span>
- <!-- ELSEIF draftrow.S_LINK_PM --><br /><span class="gensmall">{L_PRIVATE_MESSAGE}</span>
- <!-- ELSE --><br /><span class="gensmall">{L_NO_TOPIC_FORUM}</span><!-- ENDIF -->
- </td>
- <td style="padding: 4px;" align="center"><span class="gen"><a href="{draftrow.U_INSERT}">{L_LOAD_DRAFT}</a></span></td>
- </tr>
- <!-- END draftrow -->
- </table>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-
-<!-- IF S_POST_REVIEW --><!-- INCLUDE posting_review.html --><!-- ENDIF -->
-<!-- IF S_DISPLAY_PREVIEW --><!-- INCLUDE posting_preview.html --><!-- ENDIF -->
-
-
-<!-- IF not S_PRIVMSGS and S_UNGLOBALISE -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_MOVE}</th>
- </tr>
- <tr>
- <td class="spacer" colspan="2"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
- </tr>
- <tr>
- <td class="row2" align="center"><span class="gen">{L_UNGLOBALISE_EXPLAIN}<br /><br />{L_SELECT_DESTINATION_FORUM}&nbsp;&nbsp;</span><select name="to_forum_id">{S_FORUM_SELECT}</select><br /><br /><input class="btnmain" type="submit" name="post" value="{L_CONFIRM}" />&nbsp;&nbsp; <input class="btnlite" type="submit" name="cancel_unglobalise" value="{L_CANCEL}" /></td>
- </tr>
- </table>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2"><b>{L_POST_A}</b></th>
-</tr>
-
-<!-- IF ERROR -->
- <tr>
- <td class="row2" colspan="2" align="center"><span class="genmed error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_SHOW_TOPIC_ICONS or S_SHOW_PM_ICONS -->
- <tr>
- <td class="row1"><b class="genmed">{L_ICON}{L_COLON}</b></td>
- <td class="row2">
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr>
- <td><input type="radio" class="radio" name="icon" value="0"{S_NO_ICON_CHECKED} tabindex="1" /><span class="genmed"><!-- IF S_SHOW_TOPIC_ICONS -->{L_NO_TOPIC_ICON}<!-- ELSE -->{L_NO_PM_ICON}<!-- ENDIF --></span> <!-- BEGIN topic_icon --><span style="white-space: nowrap;"><input type="radio" class="radio" name="icon" value="{topic_icon.ICON_ID}"{topic_icon.S_ICON_CHECKED} tabindex="1" /><img src="{topic_icon.ICON_IMG}" width="{topic_icon.ICON_WIDTH}" height="{topic_icon.ICON_HEIGHT}" alt="{topic_icon.ICON_NAME}" title="" hspace="2" vspace="2" /></span> <!-- END topic_icon --></td>
- </tr>
- </table>
- </td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF not S_PRIVMSGS and S_DISPLAY_USERNAME -->
- <tr>
- <td class="row1"><b class="genmed">{L_USERNAME}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" tabindex="1" name="username" size="25" value="{USERNAME}" /></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_PRIVMSGS -->
- <tr>
- <td class="row1"><b class="genmed">{L_TO}{L_COLON}</b></td>
- <td class="row2">
- {S_HIDDEN_ADDRESS_FIELD}
- <!-- BEGIN to_recipient -->
- <span style="display: block; float: {S_CONTENT_FLOW_BEGIN};" class="nowrap genmed"><strong>
- <!-- IF to_recipient.IS_GROUP --><a href="{to_recipient.U_VIEW}"><span class="sep">{to_recipient.NAME}</span></a><!-- ELSE -->{to_recipient.NAME_FULL}<!-- ENDIF --></strong>&nbsp;<!-- IF not S_EDIT_POST --><input class="post" type="submit" name="remove_{to_recipient.TYPE}[{to_recipient.UG_ID}]" value="{L_REMOVE}" />&nbsp;<!-- ENDIF -->
- </span>
- <!-- BEGINELSE -->
- <span class="genmed">{L_NO_TO_RECIPIENT}</span>
- <!-- END to_recipient -->
- </td>
- </tr>
- <!-- IF S_ALLOW_MASS_PM -->
- <tr>
- <td class="row1"><b class="genmed">{L_BCC}{L_COLON}</b></td>
- <td class="row2">
- <!-- BEGIN bcc_recipient -->
- <span class="genmed nowrap"><strong>
- <!-- IF bcc_recipient.IS_GROUP --><a href="{bcc_recipient.U_VIEW}"><span class="sep">{bcc_recipient.NAME}</span></a><!-- ELSE -->{bcc_recipient.NAME_FULL}<!-- ENDIF --></strong>&nbsp;<!-- IF not S_EDIT_POST --><input class="post" type="submit" name="remove_{bcc_recipient.TYPE}[{bcc_recipient.UG_ID}]" value="{L_REMOVE}" />&nbsp;<!-- ENDIF -->
- </span>
- <!-- BEGINELSE -->
- <span class="genmed">{L_NO_BCC_RECIPIENT}</span>
- <!-- END bcc_recipient -->
- </td>
- </tr>
- <!-- ENDIF -->
-<!-- ENDIF -->
-<!-- EVENT posting_editor_subject_before -->
-<tr>
- <td class="row1" width="22%"><b class="genmed">{L_SUBJECT}{L_COLON}</b></td>
- <td class="row2" width="78%">
- <!-- EVENT posting_editor_subject_prepend -->
- <input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="<!-- IF S_NEW_MESSAGE -->120<!-- ELSE -->124<!-- ENDIF -->" tabindex="2" value="{SUBJECT}" />
- <!-- EVENT posting_editor_subject_append -->
- </td>
-</tr>
-<!-- EVENT posting_editor_subject_after -->
-<tr>
- <td class="row1" valign="top"><b class="genmed">{L_MESSAGE_BODY}{L_COLON}</b><br /><span class="gensmall">{L_MESSAGE_BODY_EXPLAIN}&nbsp;</span><br /><br />
- <!-- EVENT posting_editor_smilies_before -->
- <!-- IF S_SMILIES_ALLOWED -->
- <table width="100%" cellspacing="5" cellpadding="0" border="0" align="center">
- <tr>
- <td class="gensmall" align="center"><b>{L_SMILIES}</b></td>
- </tr>
- <tr>
- <td align="center">
- <!-- BEGIN smiley -->
- <a href="#" onclick="insert_text('{smiley.A_SMILEY_CODE}', true); return false;" style="line-height: 20px;"><img src="{smiley.SMILEY_IMG}" width="{smiley.SMILEY_WIDTH}" height="{smiley.SMILEY_HEIGHT}" alt="{smiley.SMILEY_CODE}" title="{smiley.SMILEY_DESC}" hspace="2" vspace="2" /></a>
- <!-- END smiley -->
- </td>
- </tr>
-
- <!-- IF S_SHOW_SMILEY_LINK -->
- <tr>
- <td align="center"><a class="nav" href="{U_MORE_SMILIES}" onclick="popup(this.href, 300, 350, '_phpbbsmilies'); return false;">{L_MORE_SMILIES}</a></td>
- </tr>
- <!-- ENDIF -->
-
- </table>
- <!-- ENDIF -->
- <!-- EVENT posting_editor_smilies_after -->
- </td>
- <td class="row2" valign="top">
- <script type="text/javascript">
- // <![CDATA[
- var form_name = 'postform';
- var text_name = 'message';
- // ]]>
- </script>
-
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <!-- INCLUDE posting_buttons.html -->
- <!-- EVENT posting_editor_message_before -->
- <tr>
- <td valign="top" style="width: 100%;"><textarea name="message" rows="15" cols="76" tabindex="3" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" onfocus="initInsertions();" style="width: 700px; height: 270px; min-width: 98%; max-width: 98%;">{MESSAGE}</textarea></td>
- <!-- IF S_BBCODE_ALLOWED -->
- <td width="80" align="center" valign="top" id="color_palette_placeholder" data-orientation="v" data-width="11" data-height="10" data-bbcode="true">
- </td>
- <!-- ENDIF -->
- </tr>
- <!-- EVENT posting_editor_message_after -->
- </table>
- </td>
-</tr>
-
-<!-- IF S_INLINE_ATTACHMENT_OPTIONS -->
- <tr>
- <td class="row1"><b class="genmed">{L_ATTACHMENTS}{L_COLON}</b></td>
- <td class="row2"><select name="attachments">{S_INLINE_ATTACHMENT_OPTIONS}</select>&nbsp;<input type="button" class="btnbbcode" accesskey="a" value="{L_PLACE_INLINE}" name="attachinline" onclick="attach_form = document.forms[form_name].elements['attachments']; attachInline(attach_form.value, attach_form.options[attach_form.selectedIndex].text);" onmouseover="helpline('a')" onmouseout="helpline('tip')" />
- </td>
- </tr>
-<!-- ENDIF -->
-
-<tr>
- <td class="row1" valign="top"><b class="genmed">{L_OPTIONS}{L_COLON}</b><br />
- <table cellspacing="2" cellpadding="0" border="0">
- <tr>
- <td class="gensmall">{BBCODE_STATUS}</td>
- </tr>
- <!-- IF S_BBCODE_ALLOWED -->
- <tr>
- <td class="gensmall">{IMG_STATUS}</td>
- </tr>
- <tr>
- <td class="gensmall">{FLASH_STATUS}</td>
- </tr>
- <tr>
- <td class="gensmall">{URL_STATUS}</td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <td class="gensmall">{SMILIES_STATUS}</td>
- </tr>
- </table>
- </td>
- <!-- EVENT posting_editor_bbcode_status_after -->
- <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>
- <td class="gen">{L_DISABLE_BBCODE}</td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF S_SMILIES_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="disable_smilies"{S_SMILIES_CHECKED} /></td>
- <td class="gen">{L_DISABLE_SMILIES}</td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF S_LINKS_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="disable_magic_url"{S_MAGIC_URL_CHECKED} /></td>
- <td class="gen">{L_DISABLE_MAGIC_URL}</td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF S_SIG_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="attach_sig"{S_SIGNATURE_CHECKED} /></td>
- <td class="gen">{L_ATTACH_SIG}</td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF S_NOTIFY_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="notify"{S_NOTIFY_CHECKED} /></td>
- <td class="gen">{L_NOTIFY_REPLY}</td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF not S_PRIVMSGS -->
- <!-- IF S_LOCK_TOPIC_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="lock_topic"{S_LOCK_TOPIC_CHECKED} /></td>
- <td class="gen">{L_LOCK_TOPIC}</td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF S_LOCK_POST_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="lock_post"{S_LOCK_POST_CHECKED} /></td>
- <td class="gen">{L_LOCK_POST} [{L_LOCK_POST_EXPLAIN}]</td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF S_TYPE_TOGGLE -->
- <tr>
- <td></td>
- <td class="gen"><!-- IF S_EDIT_POST -->{L_CHANGE_TOPIC_TO}<!-- ELSE -->{L_POST_TOPIC_AS}<!-- ENDIF -->{L_COLON} <!-- BEGIN topic_type --><input type="radio" class="radio" name="topic_type" value="{topic_type.VALUE}"{topic_type.S_CHECKED} />{topic_type.L_TOPIC_TYPE}&nbsp;&nbsp;<!-- END topic_type --></td>
- </tr>
- <!-- ENDIF -->
- <!-- ENDIF -->
- </table>
- </td>
-</tr>
-
-<!-- IF S_SOFTDELETE_ALLOWED or S_DELETE_ALLOWED -->
- <tr>
- <td class="row1" valign="top"><b class="genmed">{L_DELETE_POST}{L_COLON}</b></td>
- <td class="row2">
- <table cellpadding="1">
- <tr>
- <td><input type="checkbox" class="radio" name="delete" /></td>
- <td class="gen">{L_DELETE_POST_WARN}</td>
- </tr>
- <!-- IF S_SOFTDELETE_ALLOWED and S_DELETE_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="delete_permanent" /></td>
- <td class="gen">{L_DELETE_POST_PERMANENTLY}</td>
- </tr>
- <!-- ENDIF -->
- </table>
- </td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_TOPIC_TYPE_ANNOUNCE or S_TOPIC_TYPE_STICKY -->
- <tr>
- <td class="row1"><b class="genmed">{L_STICK_TOPIC_FOR}{L_COLON}</b><br /><span class="gensmall">{L_STICKY_ANNOUNCE_TIME_LIMIT}</span></td>
- <td class="row2"><input class="post" type="number" min="0" max="999" name="topic_time_limit" value="{TOPIC_TIME_LIMIT}" />&nbsp;<b class="gen">{L_DAYS}</b> <span class="gensmall">{L_STICK_TOPIC_FOR_EXPLAIN}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_EDIT_REASON -->
- <tr>
- <td class="row1" valign="top"><b class="genmed">{L_EDIT_REASON}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" name="edit_reason" size="50" value="{EDIT_REASON}" /></td>
- </tr>
-<!-- ENDIF -->
-
- <!-- IF CAPTCHA_TEMPLATE and S_CONFIRM_CODE -->
- <!-- DEFINE $CAPTCHA_TAB_INDEX = 4 -->
- <!-- INCLUDE {CAPTCHA_TEMPLATE} -->
- <!-- ENDIF -->
-
-
-<!-- IF S_SHOW_ATTACH_BOX or S_SHOW_POLL_BOX -->
- <tr>
- <td class="cat" colspan="2" align="center">
- <input class="btnlite" type="submit" tabindex="5" name="preview" value="{L_PREVIEW}" />
- &nbsp; <input class="btnmain" type="submit" accesskey="s" tabindex="6" name="post" value="{L_SUBMIT}" />
- <!-- IF S_SAVE_ALLOWED -->&nbsp; <input class="btnlite" type="submit" accesskey="k" tabindex="7" name="save" value="{L_SAVE_DRAFT}" /><!-- ENDIF -->
- <!-- IF S_HAS_DRAFTS -->&nbsp; <input class="btnlite" type="submit" accesskey="d" tabindex="8" name="load" value="{L_LOAD_DRAFT}" /><!-- ENDIF -->
- &nbsp; <input class="btnlite" type="submit" accesskey="c" tabindex="9" name="cancel" value="{L_CANCEL}" />
- </td>
- </tr>
-
- <!-- IF S_SHOW_ATTACH_BOX --><!-- INCLUDE posting_attach_body.html --><!-- ENDIF -->
-
- <!-- IF S_SHOW_POLL_BOX -->
- <!-- INCLUDE posting_poll_body.html -->
- <!-- ELSEIF S_POLL_DELETE -->
- <tr>
- <td class="row1"><span class="genmed"><b>{L_POLL_DELETE}{L_COLON}</b></span></td>
- <td class="row2"><input type="checkbox" class="radio" name="poll_delete" /></td>
- </tr>
- <!-- ENDIF -->
-<!-- ENDIF -->
-
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}
- <input class="btnlite" type="submit" tabindex="10" name="preview" value="{L_PREVIEW}" />
- &nbsp; <input class="btnmain" type="submit" accesskey="s" tabindex="11" name="post" value="{L_SUBMIT}" />
- <!-- EVENT posting_editor_submit_buttons -->
- <!-- IF not S_SHOW_ATTACH_BOX and not S_SHOW_POLL_BOX -->
- <!-- IF S_SAVE_ALLOWED -->&nbsp; <input class="btnlite" type="submit" accesskey="k" tabindex="12" name="save" value="{L_SAVE_DRAFT}" /><!-- ENDIF -->
- <!-- IF S_HAS_DRAFTS -->&nbsp; <input class="btnlite" type="submit" accesskey="d" tabindex="13" name="load" value="{L_LOAD_DRAFT}" /><!-- ENDIF -->
- <!-- ENDIF -->
- &nbsp; <input class="btnlite" type="submit" accesskey="c" tabindex="14" name="cancel" value="{L_CANCEL}" />
- </td>
-</tr>
-</table>
-<!-- IF not S_PRIVMSGS -->
- {S_FORM_TOKEN}
- </form>
-<!-- ENDIF -->
-<br clear="all" />
-
-<!-- IF S_DISPLAY_REVIEW --><!-- INCLUDE posting_topic_review.html --><!-- ENDIF -->
-<!-- IF S_DISPLAY_HISTORY --><!-- INCLUDE ucp_pm_history.html --><!-- ENDIF -->
-
-<!-- IF S_PRIVMSGS -->
- <!-- INCLUDE ucp_footer.html -->
-<!-- ELSE -->
-
- <!-- INCLUDE breadcrumbs.html -->
-
-
- <!-- IF S_DISPLAY_ONLINE_LIST -->
- <br clear="all" />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat"><h4>{L_WHO_IS_ONLINE}</h4></td>
- </tr>
- <tr>
- <td class="row1"><span class="gensmall">{LOGGED_IN_USER_LIST}</span></td>
- </tr>
- </table>
- <!-- ENDIF -->
-
- <br clear="all" />
-
- <table width="100%" cellspacing="1">
- <tr>
- <td align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></td>
- </tr>
- </table>
-
- <!-- INCLUDE overall_footer.html -->
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/posting_buttons.html b/phpBB/styles/subsilver2/template/posting_buttons.html
deleted file mode 100644
index 516cd0922b..0000000000
--- a/phpBB/styles/subsilver2/template/posting_buttons.html
+++ /dev/null
@@ -1,91 +0,0 @@
-<tr valign="middle" align="{S_CONTENT_FLOW_BEGIN}">
- <td colspan="2">
- <script type="text/javascript">
- // <![CDATA[
-
- // Define the bbCode tags
- var bbcode = new Array();
- var bbtags = new Array('[b]','[/b]','[i]','[/i]','[u]','[/u]','[quote]','[/quote]','[code]','[/code]','[list]','[/list]','[list=]','[/list]','[img]','[/img]','[url]','[/url]','[flash=]', '[/flash]','[size=]','[/size]'<!-- BEGIN custom_tags -->, {custom_tags.BBCODE_NAME}<!-- END custom_tags -->);
- var imageTag = false;
-
- // Helpline messages
- var help_line = {
- b: '{LA_BBCODE_B_HELP}',
- i: '{LA_BBCODE_I_HELP}',
- u: '{LA_BBCODE_U_HELP}',
- q: '{LA_BBCODE_Q_HELP}',
- c: '{LA_BBCODE_C_HELP}',
- l: '{LA_BBCODE_L_HELP}',
- e: '{LA_BBCODE_LISTITEM_HELP}',
- o: '{LA_BBCODE_O_HELP}',
- p: '{LA_BBCODE_P_HELP}',
- w: '{LA_BBCODE_W_HELP}',
- a: '{LA_BBCODE_A_HELP}',
- s: '{LA_BBCODE_S_HELP}',
- f: '{LA_BBCODE_F_HELP}',
- y: '{LA_BBCODE_Y_HELP}',
- d: '{LA_BBCODE_D_HELP}',
- tip: '{L_STYLES_TIP}'
- <!-- BEGIN custom_tags -->
- ,cb_{custom_tags.BBCODE_ID}: '{custom_tags.A_BBCODE_HELPLINE}'
- <!-- END custom_tags -->
- }
-
- // ]]>
- </script>
- <!-- INCLUDEJS {T_ASSETS_PATH}/javascript/editor.js -->
-
-<!-- IF S_BBCODE_ALLOWED -->
- <!-- EVENT posting_editor_buttons_before -->
- <div id="core-bbcode-buttons">
- <input type="button" class="btnbbcode bbcode-b" accesskey="b" name="addbbcode0" value=" B " style="font-weight:bold; width: 30px;" onclick="bbstyle(0)" onmouseover="helpline('b')" onmouseout="helpline('tip')" />
- <input type="button" class="btnbbcode bbcode-i" accesskey="i" name="addbbcode2" value=" i " style="font-style:italic; width: 30px;" onclick="bbstyle(2)" onmouseover="helpline('i')" onmouseout="helpline('tip')" />
- <input type="button" class="btnbbcode bbcode-u" accesskey="u" name="addbbcode4" value=" u " style="text-decoration: underline; width: 30px;" onclick="bbstyle(4)" onmouseover="helpline('u')" onmouseout="helpline('tip')" />
- <!-- IF S_BBCODE_QUOTE -->
- <input type="button" class="btnbbcode bbcode-quote" accesskey="q" name="addbbcode6" value="Quote" style="width: 50px" onclick="bbstyle(6)" onmouseover="helpline('q')" onmouseout="helpline('tip')" />
- <!-- ENDIF -->
- <input type="button" class="btnbbcode bbcode-code" accesskey="c" name="addbbcode8" value="Code" style="width: 40px" onclick="bbstyle(8)" onmouseover="helpline('c')" onmouseout="helpline('tip')" />
- <input type="button" class="btnbbcode bbcode-list" accesskey="l" name="addbbcode10" value="List" style="width: 40px" onclick="bbstyle(10)" onmouseover="helpline('l')" onmouseout="helpline('tip')" />
- <input type="button" class="btnbbcode bbcode-list-" accesskey="o" name="addbbcode12" value="List=" style="width: 40px" onclick="bbstyle(12)" onmouseover="helpline('o')" onmouseout="helpline('tip')" />
- <input type="button" class="btnbbcode bbcode-asterisk" accesskey="y" name="addlistitem" value="[*]" style="width: 40px" onclick="bbstyle(-1)" onmouseover="helpline('e')" onmouseout="helpline('tip')" />
- <!-- IF S_BBCODE_IMG -->
- <input type="button" class="btnbbcode bbcode-img" accesskey="p" name="addbbcode14" value="Img" style="width: 40px" onclick="bbstyle(14)" onmouseover="helpline('p')" onmouseout="helpline('tip')" />
- <!-- ENDIF -->
- <!-- IF S_LINKS_ALLOWED -->
- <input type="button" class="btnbbcode bbcode-url" accesskey="w" name="addbbcode16" value="URL" style="text-decoration: underline; width: 40px" onclick="bbstyle(16)" onmouseover="helpline('w')" onmouseout="helpline('tip')" />
- <!-- ENDIF -->
- <!-- IF S_BBCODE_FLASH -->
- <input type="button" class="btnbbcode bbcode-flash" accesskey="d" name="addbbcode18" value="Flash" onclick="bbstyle(18)" onmouseover="helpline('d')" onmouseout="helpline('tip')" />
- <!-- ENDIF -->
- <span class="genmed nowrap">{L_FONT_SIZE}{L_COLON} <select class="gensmall bbcode-size" name="addbbcode20" onchange="bbfontstyle('[size=' + this.form.addbbcode20.options[this.form.addbbcode20.selectedIndex].value + ']', '[/size]');this.form.addbbcode20.selectedIndex = 2;" onmouseover="helpline('f')" onmouseout="helpline('tip')">
- <option value="50">{L_FONT_TINY}</option>
- <option value="85">{L_FONT_SMALL}</option>
- <option value="100" selected="selected">{L_FONT_NORMAL}</option>
- <!-- IF not MAX_FONT_SIZE or MAX_FONT_SIZE >= 150 -->
- <option value="150">{L_FONT_LARGE}</option>
- <!-- IF not MAX_FONT_SIZE or MAX_FONT_SIZE >= 200 -->
- <option value="200">{L_FONT_HUGE}</option>
- <!-- ENDIF -->
- <!-- ENDIF -->
- </select></span>
- </div>
- <!-- EVENT posting_editor_buttons_custom_tags_before -->
- <!-- IF .custom_tags -->
- <div id="custom-bbcode-buttons">
- <!-- BEGIN custom_tags -->
- <input type="button" class="btnbbcode bbcode-{custom_tags.BBCODE_TAG_CLEAN}" name="addbbcode{custom_tags.BBCODE_ID}" value="{custom_tags.BBCODE_TAG}" onclick="bbstyle({custom_tags.BBCODE_ID})"<!-- IF custom_tags.BBCODE_HELPLINE !== '' --> onmouseover="helpline('cb_{custom_tags.BBCODE_ID}')" onmouseout="helpline('tip')"<!-- ENDIF --> />
- <!-- END custom_tags -->
- </div>
- <!-- ENDIF -->
- <!-- EVENT posting_editor_buttons_after -->
-<!-- ENDIF -->
- </td>
-</tr>
-<!-- IF S_BBCODE_ALLOWED -->
-<tr>
- <td<!-- IF $S_SIGNATURE or S_EDIT_DRAFT --> colspan="2"<!-- ENDIF -->><input type="text" readonly="readonly" name="helpbox" style="width:100%" class="helpline" value="{L_STYLES_TIP}" /></td>
- <!-- IF not $S_SIGNATURE and not S_EDIT_DRAFT -->
- <td class="genmed" align="center">{L_FONT_COLOR}</td>
- <!-- ENDIF -->
-</tr>
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/posting_poll_body.html b/phpBB/styles/subsilver2/template/posting_poll_body.html
deleted file mode 100644
index a18f319c1c..0000000000
--- a/phpBB/styles/subsilver2/template/posting_poll_body.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-<tr>
- <th colspan="2">{L_ADD_POLL}</th>
-</tr>
-<tr>
- <td class="row3" colspan="2"><span class="gensmall">{L_ADD_POLL_EXPLAIN}</span></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_POLL_QUESTION}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" name="poll_title" size="50" maxlength="255" value="{POLL_TITLE}" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_POLL_OPTIONS}{L_COLON}</b><br /><span class="gensmall">{L_POLL_OPTIONS_EXPLAIN}</span></td>
- <td class="row2"><textarea style="width:450px" name="poll_option_text" rows="5" cols="35">{POLL_OPTIONS}</textarea></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_POLL_MAX_OPTIONS}{L_COLON}</b><br /><span class="gensmall">{L_POLL_MAX_OPTIONS_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="number" min="0" max="999" name="poll_max_options" value="{POLL_MAX_OPTIONS}" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_POLL_FOR}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="number" min="0" max="999" name="poll_length" value="{POLL_LENGTH}" />&nbsp;<b class="gen">{L_DAYS}</b> <span class="gensmall">{L_POLL_FOR_EXPLAIN}</span></td>
-</tr>
-<!-- IF S_POLL_VOTE_CHANGE -->
- <tr>
- <td class="row1"><b class="genmed">{L_POLL_VOTE_CHANGE}{L_COLON}</b><br /><span class="gensmall">{L_POLL_VOTE_CHANGE_EXPLAIN}</span></td>
- <td class="row2"><input type="checkbox" class="radio" name="poll_vote_change"{VOTE_CHANGE_CHECKED} /></td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT posting_poll_body_options_after -->
-
-<!-- IF S_POLL_DELETE -->
- <tr>
- <td class="row1"><b class="genmed">{L_POLL_DELETE}{L_COLON}</b></td>
- <td class="row2"><input type="checkbox" class="radio" name="poll_delete"<!-- IF S_POLL_DELETE_CHECKED --> checked="checked"<!-- ENDIF --> /></td>
- </tr>
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/posting_preview.html b/phpBB/styles/subsilver2/template/posting_preview.html
deleted file mode 100644
index c451e4c871..0000000000
--- a/phpBB/styles/subsilver2/template/posting_preview.html
+++ /dev/null
@@ -1,71 +0,0 @@
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th>{L_PREVIEW}</th>
-</tr>
-<tr>
- <td class="row1">{MINI_POST_IMG}<span class="postdetails">{L_POSTED}{L_COLON} {POST_DATE} &nbsp;&nbsp;&nbsp; {L_POST_SUBJECT}{L_COLON} {PREVIEW_SUBJECT}</span></td>
-</tr>
-<!-- IF S_HAS_POLL_OPTIONS -->
- <tr>
- <td class="row2" colspan="2" align="center"><br clear="all" />
- <table cellspacing="0" cellpadding="4" border="0" align="center">
- <tr>
- <td align="center"><span class="gen"><b>{POLL_QUESTION}</b></span><br /><span class="gensmall">{L_POLL_LENGTH}</span></td>
- </tr>
- <tr>
- <td align="center">
- <table cellspacing="0" cellpadding="2" border="0">
- <!-- BEGIN poll_option -->
- <tr>
- <td>
- <!-- IF S_IS_MULTI_CHOICE -->
- <input type="checkbox" class="radio" name="vote_id" value="" />
- <!-- ELSE -->
- <input type="radio" class="radio" name="vote_id" value="" />
- <!-- ENDIF -->
- </td>
- <td><span class="gen">{poll_option.POLL_OPTION_CAPTION}</span></td>
- </tr>
- <!-- END poll_option -->
- </table>
- </td>
- </tr>
- <tr>
- <td align="center"><span class="gensmall">{L_MAX_VOTES}</span></td>
- </tr>
- </table>
- </td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT posting_preview_poll_after -->
-<tr>
- <td class="row1">
- <table width="100%" border="0" cellspacing="0" cellpadding="0">
- <tr>
- <td><div class="postbody">{PREVIEW_MESSAGE}</div>
- <!-- IF .attachment -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <td class="row2">{attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
- <!-- IF PREVIEW_SIGNATURE --><span class="postbody"><br />_________________<br />{PREVIEW_SIGNATURE}</span><!-- ENDIF --></td>
- </tr>
- </table>
- </td>
-</tr>
-<tr>
- <td class="spacer"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
-</tr>
-</table>
-
-<br clear="all" />
diff --git a/phpBB/styles/subsilver2/template/posting_progress_bar.html b/phpBB/styles/subsilver2/template/posting_progress_bar.html
deleted file mode 100644
index f9decc506b..0000000000
--- a/phpBB/styles/subsilver2/template/posting_progress_bar.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!-- INCLUDE simple_header.html -->
-<script type="text/javascript">
-// <![CDATA[
- /**
- * Close upload popup
- */
- function close_popup()
- {
- if (opener != null)
- {
- if (opener.close_waitscreen != null)
- {
- if (opener.close_waitscreen == 1)
- {
- opener.close_waitscreen = 0;
- self.close();
- return 0;
- }
- }
- }
- setTimeout("close_popup()", 1000);
- return 0;
- }
-// ]]>
-</script>
-
-<table width="100%" border="0" cellspacing="0" cellpadding="10">
-<tr>
- <td>
- <table width="100%" border="0" cellspacing="1" cellpadding="4">
- <tr>
- <td valign="top" class="row1" align="center"><br /><span class="genmed">{L_UPLOAD_IN_PROGRESS}</span><br /><br /><div style="align:center">{PROGRESS_BAR}</div><br /><br /><span class="genmed"><a href="#" onclick="window.close(); return false;">{L_CLOSE_WINDOW}</a></span><br /><br /></td>
- </tr>
- </table>
- </td>
-</tr>
-</table>
-
-<script type="text/javascript">
-// <![CDATA[
- close_popup();
-// ]]>
-</script>
-<!-- INCLUDE simple_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/posting_review.html b/phpBB/styles/subsilver2/template/posting_review.html
deleted file mode 100644
index c118499564..0000000000
--- a/phpBB/styles/subsilver2/template/posting_review.html
+++ /dev/null
@@ -1,99 +0,0 @@
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th align="center">{L_POST_REVIEW}</th>
-</tr>
-<tr>
- <td class="row1" align="center"><span class="gen">{L_POST_REVIEW_EXPLAIN}</span></td>
-</tr>
-<tr>
- <td class="spacer"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
-</tr>
-<tr>
- <td class="row1">
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th width="22%">{L_AUTHOR}</th>
- <th>{L_MESSAGE}</th>
- </tr>
- <!-- BEGIN post_review_row -->
-
- <!-- IF post_review_row.S_ROW_COUNT is even --> <tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <!-- IF post_review_row.S_IGNORE_POST -->
- <td colspan="2">{post_review_row.L_IGNORE_POST}</td>
- <!-- ELSE -->
-
- <td rowspan="2" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><a id="pr{post_review_row.POST_ID}" class="anchor"></a>
- <table width="150" cellspacing="0" cellpadding="4" border="0">
- <tr>
- <td align="center"><b class="postauthor">{post_review_row.POST_AUTHOR_FULL}</b></td>
- </tr>
- </table>
- </td>
- <td width="100%">
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr>
- <td>&nbsp;</td>
- <td class="gensmall" valign="middle" nowrap="nowrap"><b>{L_POST_SUBJECT}{L_COLON}</b>&nbsp;</td>
- <td class="gensmall" width="100%" valign="middle">{post_review_row.POST_SUBJECT}</td>
- <td>&nbsp;</td>
- </tr>
- </table>
- </td>
- </tr>
-
- <!-- IF post_review_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td valign="top">
- <table width="100%" cellspacing="0">
- <tr>
- <td valign="top">
- <table width="100%" cellspacing="0" cellpadding="2">
- <tr>
- <td><div class="postbody">{post_review_row.MESSAGE}</div>
-
- <!-- IF post_review_row.S_HAS_ATTACHMENTS -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <!-- IF post_review_row.attachment.S_ROW_COUNT is even --><td class="row2"><!-- ELSE --><td class="row1"><!-- ENDIF -->{post_review_row.attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
-
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <tr>
- <td>
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr valign="middle">
- <td width="100%">&nbsp;</td>
- <td width="10" nowrap="nowrap"><!-- IF S_IS_BOT -->{post_review_row.MINI_POST_IMG}<!-- ELSE --><a href="{post_review_row.U_MINI_POST}" class="imageset">{post_review_row.MINI_POST_IMG}</a><!-- ENDIF --></td>
- <td class="gensmall" nowrap="nowrap"><b>{L_POSTED}{L_COLON}</b> {post_review_row.POST_DATE}</td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
- <!-- ENDIF -->
- </tr>
- <tr>
- <td class="spacer" colspan="2" height="1"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
- </tr>
- <!-- END post_review_row -->
- </table>
- </td>
-</tr>
-</table>
-
-<br clear="all" />
diff --git a/phpBB/styles/subsilver2/template/posting_smilies.html b/phpBB/styles/subsilver2/template/posting_smilies.html
deleted file mode 100644
index 7087414fa8..0000000000
--- a/phpBB/styles/subsilver2/template/posting_smilies.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!-- INCLUDE simple_header.html -->
-
-<script type="text/javascript">
-// <![CDATA[
- var form_name = opener.form_name;
- var text_name = opener.text_name;
-// ]]>
-</script>
-<!-- INCLUDEJS {T_ASSETS_PATH}/javascript/editor.js -->
-
-<table width="100%" cellspacing="1" cellpadding="4" border="0">
-<tr>
- <td>
- <table class="tablebg" width="95%" cellspacing="1" cellpadding="4" border="0">
- <tr>
- <th>{L_SMILIES}</th>
- </tr>
- <tr>
- <td class="row1" align="center" valign="middle"><!-- BEGIN smiley --> <a href="#" onclick="initInsertions(); insert_text('{smiley.A_SMILEY_CODE}', true, true); return false;"><img src="{smiley.SMILEY_IMG}" width="{smiley.SMILEY_WIDTH}" height="{smiley.SMILEY_HEIGHT}" alt="{smiley.SMILEY_CODE}" title="{smiley.SMILEY_DESC}" hspace="2" vspace="2" /></a> <!-- END smiley --><br />
- <!-- IF .pagination -->
- <b><a href="#" onclick="jumpto(); return false;" title="{L_JUMP_TO_PAGE_CLICK}">{L_GOTO_PAGE}</a>
- <!-- BEGIN pagination -->
- <!-- IF pagination.S_IS_PREV --><a href="{pagination.PAGE_URL}">{pagination.PAGE_NUMBER}</a>
- <!-- ELSEIF pagination.S_IS_CURRENT --><strong>{pagination.PAGE_NUMBER}</strong>
- <!-- ELSEIF pagination.S_IS_ELLIPSIS --> {L_ELLIPSIS}
- <!-- ELSEIF pagination.S_IS_NEXT --><a href="{pagination.PAGE_URL}">{pagination.PAGE_NUMBER}</a>
- <!-- ELSE --><a href="{pagination.PAGE_URL}">{pagination.PAGE_NUMBER}</a>
- <!-- ENDIF -->
- <!-- END pagination -->
- <br />
- <!-- ENDIF -->
- <a class="nav" href="#" onclick="window.close(); return false;">{L_CLOSE_WINDOW}</a></td>
- </tr>
- </table>
- </td>
-</tr>
-</table>
-<!-- INCLUDE simple_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/posting_topic_review.html b/phpBB/styles/subsilver2/template/posting_topic_review.html
deleted file mode 100644
index 46329e19fa..0000000000
--- a/phpBB/styles/subsilver2/template/posting_topic_review.html
+++ /dev/null
@@ -1,112 +0,0 @@
-<script type="text/javascript">
-// <![CDATA[
- bbcodeEnabled = {S_BBCODE_ALLOWED};
-// ]]>
-</script>
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th align="center">{L_TOPIC_REVIEW} - {TOPIC_TITLE}</th>
-</tr>
-<tr>
- <td class="row1"><div style="overflow: auto; width: 100%; height: 300px;">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th width="22%">{L_AUTHOR}</th>
- <th>{L_MESSAGE}</th>
- </tr>
- <!-- BEGIN topic_review_row -->
-
- <!-- EVENT posting_topic_review_row_post_details_before -->
- <!-- IF topic_review_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <!-- IF topic_review_row.S_IGNORE_POST -->
- <td colspan="2">{topic_review_row.L_IGNORE_POST}</td>
- <!-- ELSE -->
- <td rowspan="2" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><a id="pr{topic_review_row.POST_ID}" class="anchor"></a>
- <table width="150" cellspacing="0">
- <tr>
- <td align="center"><b class="postauthor"<!-- IF topic_review_row.POST_AUTHOR_COLOUR --> style="color: {topic_review_row.POST_AUTHOR_COLOUR}"<!-- ENDIF -->>{topic_review_row.POST_AUTHOR}</b></td>
- </tr>
- </table>
- </td>
- <td width="100%">
- <table width="100%" cellspacing="0">
- <tr>
- <td>&nbsp;</td>
- <td class="gensmall" valign="middle" nowrap="nowrap"><b>{L_POST_SUBJECT}{L_COLON}</b>&nbsp;</td>
- <td class="gensmall" width="100%" valign="middle">{topic_review_row.POST_SUBJECT}</td>
- <td valign="top" nowrap="nowrap">&nbsp;<!-- IF topic_review_row.POSTER_QUOTE and topic_review_row.DECODED_MESSAGE --><a href="#" onclick="addquote({topic_review_row.POST_ID},'{topic_review_row.POSTER_QUOTE}', '{LA_WROTE}'); return false;" class="imageset">{QUOTE_IMG}</a><!-- ENDIF --></td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- EVENT posting_topic_review_row_post_details_after -->
-
- <!-- IF topic_review_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td valign="top">
- <table width="100%" cellspacing="0">
- <tr>
- <td valign="top">
- <table width="100%" cellspacing="0" cellpadding="2">
- <tr>
- <td>
- <!-- IF topic_review_row.POST_ID == REPORTED_POST_ID -->
- <table width="100%" cellspacing="0">
- <tr>
- <span class="postreported">{REPORTED_IMG}</span>
- </tr>
- </table>
- <!-- ENDIF -->
- <div class="postbody">{topic_review_row.MESSAGE}</div>
-
- <!-- IF topic_review_row.S_HAS_ATTACHMENTS -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <!-- IF topic_review_row.attachment.S_ROW_COUNT is even --><td class="row2"><!-- ELSE --><td class="row1"><!-- ENDIF -->{topic_review_row.attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
-
- <!-- IF topic_review_row.POSTER_QUOTE and topic_review_row.DECODED_MESSAGE -->
- <div id="message_{topic_review_row.POST_ID}" style="display: none;">{topic_review_row.DECODED_MESSAGE}</div>
- <!-- ENDIF -->
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <tr>
- <td>
- <table width="100%" cellspacing="0">
- <tr valign="middle">
- <td width="100%" align="{S_CONTENT_FLOW_BEGIN}"><span class="gensmall"><!-- IF topic_review_row.U_MCP_DETAILS -->[ <a href="{topic_review_row.U_MCP_DETAILS}">{L_POST_DETAILS}</a> ]<!-- ENDIF --></span></td>
- <td width="10" nowrap="nowrap"><!-- IF S_IS_BOT -->{topic_review_row.MINI_POST_IMG}<!-- ELSE --><a href="{topic_review_row.U_MINI_POST}" class="imageset">{topic_review_row.MINI_POST_IMG}</a><!-- ENDIF --></td>
- <td class="gensmall" nowrap="nowrap"><b>{L_POSTED}{L_COLON}</b> {topic_review_row.POST_DATE}</td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
- <!-- ENDIF -->
- </tr>
- <tr>
- <td class="spacer" colspan="2"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
- </tr>
- <!-- END topic_review_row -->
- </table>
- </div></td>
-</tr>
-</table>
-
-<br clear="all" />
diff --git a/phpBB/styles/subsilver2/template/profilefields/bool.html b/phpBB/styles/subsilver2/template/profilefields/bool.html
deleted file mode 100644
index f57bd4e4da..0000000000
--- a/phpBB/styles/subsilver2/template/profilefields/bool.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- BEGIN bool -->
- <!-- IF bool.FIELD_LENGTH eq 1 -->
- <!-- BEGIN options --><input type="radio" class="radio" name="{bool.FIELD_IDENT}" value="{bool.options.OPTION_ID}"{bool.options.CHECKED} /><span class="genmed">{bool.options.VALUE}</span>&nbsp; &nbsp;<!-- END options -->
- <!-- ELSE -->
- <input type="checkbox" class="radio" name="{bool.FIELD_IDENT}" value="1"<!-- IF bool.FIELD_VALUE eq 1 --> checked="checked"<!-- ENDIF --> />
- <!-- ENDIF -->
-<!-- END bool -->
diff --git a/phpBB/styles/subsilver2/template/profilefields/date.html b/phpBB/styles/subsilver2/template/profilefields/date.html
deleted file mode 100644
index e2da2463a5..0000000000
--- a/phpBB/styles/subsilver2/template/profilefields/date.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!-- BEGIN date -->
-<span class="genmed">{L_DAY}{L_COLON}</span> <select name="{date.FIELD_IDENT}_day">{date.S_DAY_OPTIONS}</select>
-<span class="genmed">{L_MONTH}{L_COLON}</span> <select name="{date.FIELD_IDENT}_month">{date.S_MONTH_OPTIONS}</select>
-<span class="genmed">{L_YEAR}{L_COLON}</span> <select name="{date.FIELD_IDENT}_year">{date.S_YEAR_OPTIONS}</select>
-<!-- END date -->
diff --git a/phpBB/styles/subsilver2/template/profilefields/dropdown.html b/phpBB/styles/subsilver2/template/profilefields/dropdown.html
deleted file mode 100644
index 16242da895..0000000000
--- a/phpBB/styles/subsilver2/template/profilefields/dropdown.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!-- BEGIN dropdown -->
-<select name="{dropdown.FIELD_IDENT}">
- <!-- BEGIN options --><option value="{dropdown.options.OPTION_ID}"{dropdown.options.SELECTED}>{dropdown.options.VALUE}</option><!-- END options -->
-</select>
-<!-- END dropdown -->
diff --git a/phpBB/styles/subsilver2/template/profilefields/int.html b/phpBB/styles/subsilver2/template/profilefields/int.html
deleted file mode 100644
index 067921e320..0000000000
--- a/phpBB/styles/subsilver2/template/profilefields/int.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<!-- BEGIN int -->
- <input type="number" min="{int.FIELD_MINLEN}" max="{int.FIELD_MAXLEN}" class="post" name="{int.FIELD_IDENT}" size="{int.FIELD_LENGTH}" value="{int.FIELD_VALUE}" />
-<!-- END int -->
diff --git a/phpBB/styles/subsilver2/template/profilefields/string.html b/phpBB/styles/subsilver2/template/profilefields/string.html
deleted file mode 100644
index 5a98562e2a..0000000000
--- a/phpBB/styles/subsilver2/template/profilefields/string.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<!-- BEGIN string -->
- <input type="text" class="post" name="{string.FIELD_IDENT}" size="{string.FIELD_LENGTH}" maxlength="{string.FIELD_MAXLEN}" value="{string.FIELD_VALUE}" />
-<!-- END string -->
diff --git a/phpBB/styles/subsilver2/template/profilefields/text.html b/phpBB/styles/subsilver2/template/profilefields/text.html
deleted file mode 100644
index df2474ad3e..0000000000
--- a/phpBB/styles/subsilver2/template/profilefields/text.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<!-- BEGIN text -->
-<textarea name="{text.FIELD_IDENT}" rows="{text.FIELD_ROWS}" cols="{text.FIELD_COLS}">{text.FIELD_VALUE}</textarea>
-<!-- END text -->
diff --git a/phpBB/styles/subsilver2/template/profilefields/url.html b/phpBB/styles/subsilver2/template/profilefields/url.html
deleted file mode 100644
index 42805aa98d..0000000000
--- a/phpBB/styles/subsilver2/template/profilefields/url.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<!-- BEGIN url -->
- <input type="url" class="post" name="{url.FIELD_IDENT}" id="{url.FIELD_IDENT}" size="{url.FIELD_LENGTH}" maxlength="{url.FIELD_MAXLEN}" value="{url.FIELD_VALUE}" />
-<!-- END url -->
diff --git a/phpBB/styles/subsilver2/template/quickreply_editor.html b/phpBB/styles/subsilver2/template/quickreply_editor.html
deleted file mode 100644
index a7614e841f..0000000000
--- a/phpBB/styles/subsilver2/template/quickreply_editor.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<form method="post" action="{U_QR_ACTION}">
-<!-- EVENT quickreply_editor_panel_before -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th align="center" colspan="2">{L_QUICKREPLY}</th>
- </tr>
- <!-- EVENT quickreply_editor_subject_before -->
- <tr>
- <td class="row1" width="22%"><b class="genmed">{L_SUBJECT}{L_COLON}</b></td>
- <td class="row2" width="78%"><input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="124" tabindex="2" value="{SUBJECT}" /></td>
- </tr>
- <!-- EVENT quickreply_editor_message_before -->
- <tr>
- <td class="row1" width="22%"><b class="genmed">{L_MESSAGE}{L_COLON}</b></td>
- <td class="row2" valign="top" align="left" width="78%"><textarea name="message" rows="7" cols="76" tabindex="3" style="width: 700px; height: 130px; min-width: 98%; max-width: 98%;"></textarea> </td>
- </tr>
- <!-- EVENT quickreply_editor_message_after -->
- <tr>
- <td class="cat" colspan="2" align="center">
- <input class="btnlite" type="submit" accesskey="f" tabindex="6" name="preview" value="{L_FULL_EDITOR}" />&nbsp;
- <input class="btnmain" type="submit" accesskey="s" tabindex="7" name="post" value="{L_SUBMIT}" />
-
- {S_FORM_TOKEN}
- {QR_HIDDEN_FIELDS}
- </td>
- </tr>
- </table>
-<!-- EVENT quickreply_editor_panel_after -->
-</form>
-<br clear="all" />
diff --git a/phpBB/styles/subsilver2/template/report_body.html b/phpBB/styles/subsilver2/template/report_body.html
deleted file mode 100644
index 906a957ef4..0000000000
--- a/phpBB/styles/subsilver2/template/report_body.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<form method="post" id="report" action="{S_REPORT_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2"><!-- IF S_REPORT_POST -->{L_REPORT_POST}<!-- ELSE -->{L_REPORT_MESSAGE}<!-- ENDIF --></th>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="genmed error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td class="row3" colspan="2"><span class="gensmall"><!-- IF S_REPORT_POST -->{L_REPORT_POST_EXPLAIN}<!-- ELSE -->{L_REPORT_MESSAGE_EXPLAIN}<!-- ENDIF --></span></td>
-</tr>
-<tr>
- <td class="row1" width="22%"><b class="gen">{L_REASON}{L_COLON}</b></td>
- <td class="row2" width="78%"><select name="reason_id">
- <!-- BEGIN reason --><option value="{reason.ID}"<!-- IF reason.S_SELECTED --> selected="selected"<!-- ENDIF -->>{reason.TITLE} &raquo; {reason.DESCRIPTION}</option><!-- END reason -->
- </select></td>
-</tr>
-<!-- IF S_CAN_NOTIFY -->
- <tr>
- <td class="row1"><span class="gen"><b>{L_REPORT_NOTIFY}{L_COLON}</b></span><br /><span class="gensmall">{L_REPORT_NOTIFY_EXPLAIN}</span></td>
- <td class="row2"><span class="gen"><input type="radio" class="radio" name="notify" value="1"<!-- IF S_NOTIFY --> checked="checked"<!-- ENDIF --> />&nbsp; {L_YES} &nbsp;<input type="radio" class="radio" name="notify" value="0"<!-- IF not S_NOTIFY --> checked="checked"<!-- ENDIF --> />&nbsp; {L_NO}</span></td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td class="row1" valign="top"><span class="gen"><b>{L_MORE_INFO}{L_COLON}</b></span><br /><span class="gensmall">{L_CAN_LEAVE_BLANK}</span></td>
- <td class="row2"><textarea class="post" name="report_text" rows="10" cols="50">{REPORT_TEXT}</textarea></td>
-</tr>
-<!-- IF CAPTCHA_TEMPLATE -->
- <!-- INCLUDE {CAPTCHA_TEMPLATE} -->
-<!-- ENDIF -->
-<tr>
- <td class="cat" colspan="2" align="center"><input type="submit" name="submit" class="btnmain" value="{L_SUBMIT}" />&nbsp;<input type="submit" name="cancel" class="btnlite" value="{L_CANCEL}" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<div style="float: {S_CONTENT_FLOW_END};"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/search_body.html b/phpBB/styles/subsilver2/template/search_body.html
deleted file mode 100644
index 84ea73ea30..0000000000
--- a/phpBB/styles/subsilver2/template/search_body.html
+++ /dev/null
@@ -1,110 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div id="pagecontent">
-
- <!-- EVENT search_body_form_before -->
- <form method="get" action="{S_SEARCH_ACTION}">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <!-- DEFINE $COLSPAN = 4 -->
- <!-- EVENT search_body_search_query_before -->
- <tr>
- <th colspan="{$COLSPAN}">{L_SEARCH_QUERY}</th>
- </tr>
- <!-- EVENT search_body_search_query_prepend -->
- <tr>
- <td class="row1" colspan="2" width="50%"><b class="genmed">{L_SEARCH_KEYWORDS}{L_COLON} </b><br /><span class="gensmall">{L_SEARCH_KEYWORDS_EXPLAIN}</span></td>
- <td class="row2" colspan="2" valign="top"><input type="text" style="width: 300px" class="post" name="keywords" size="30" /><br /><input type="radio" class="radio" name="terms" value="all" checked="checked" /> <span class="genmed">{L_SEARCH_ALL_TERMS}</span><br /><input type="radio" class="radio" name="terms" value="any" /> <span class="genmed">{L_SEARCH_ANY_TERMS}</span></td>
- </tr>
- <tr>
- <td class="row1" colspan="2"><b class="genmed">{L_SEARCH_AUTHOR}{L_COLON}</b><br /><span class="gensmall">{L_SEARCH_AUTHOR_EXPLAIN}</span></td>
- <td class="row2" colspan="2" valign="middle"><input type="text" style="width: 300px" class="post" name="author" size="30" /></td>
- </tr>
- <tr>
- <td class="row1" colspan="2"><b class="genmed">{L_SEARCH_FORUMS}{L_COLON} </b><br /><span class="gensmall">{L_SEARCH_FORUMS_EXPLAIN}</span></td>
- <td class="row2" colspan="2"><select name="fid[]" multiple="multiple" size="5">{S_FORUM_OPTIONS}</select></td>
- </tr>
- <!-- EVENT search_body_search_query_append -->
- <!-- EVENT search_body_search_query_after -->
- <!-- EVENT search_body_search_options_before -->
- <tr>
- <th colspan="{$COLSPAN}">{L_SEARCH_OPTIONS}</th>
- </tr>
- <!-- EVENT search_body_search_options_prepend -->
- <tr>
- <td class="row1" width="25%" nowrap="nowrap"><b class="genmed">{L_SEARCH_SUBFORUMS}{L_COLON} </b></td>
- <td class="row2" width="25%" nowrap="nowrap"><input type="radio" class="radio" name="sc" value="1" checked="checked" /> <span class="genmed">{L_YES}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="sc" value="0" /> <span class="genmed">{L_NO}</span></td>
- <td class="row1" width="25%" nowrap="nowrap"><b class="genmed">{L_SEARCH_WITHIN}{L_COLON} </b></td>
- <td class="row2" width="25%" nowrap="nowrap"><input type="radio" class="radio" name="sf" value="all" checked="checked" /> <span class="genmed">{L_SEARCH_TITLE_MSG}</span><br /><input type="radio" class="radio" name="sf" value="msgonly" /> <span class="genmed">{L_SEARCH_MSG_ONLY}</span> <br /><input type="radio" class="radio" name="sf" value="titleonly" /> <span class="genmed">{L_SEARCH_TITLE_ONLY}</span> <br /><input type="radio" class="radio" name="sf" value="firstpost" /> <span class="genmed">{L_SEARCH_FIRST_POST}</span></td>
- </tr>
- <!-- EVENT search_body_search_options_append -->
- <!-- EVENT search_body_search_display_options_prepend -->
- <tr>
- <td class="row1"><b class="genmed">{L_RESULT_SORT}{L_COLON} </b></td>
- <td class="row2" nowrap="nowrap">{S_SELECT_SORT_KEY}<br /><input type="radio" class="radio" name="sd" value="a" /> <span class="genmed">{L_SORT_ASCENDING}</span><br /><input type="radio" class="radio" name="sd" value="d" checked="checked" /> <span class="genmed">{L_SORT_DESCENDING}</span></td>
- <td class="row1" nowrap="nowrap"><b class="genmed">{L_DISPLAY_RESULTS}{L_COLON} </b></td>
- <td class="row2" nowrap="nowrap"><input type="radio" class="radio" name="sr" value="posts" checked="checked" /> <span class="genmed">{L_POSTS}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="sr" value="topics" /> <span class="genmed">{L_TOPICS}</span></td>
- </tr>
- <tr>
- <td class="row1" width="25%"><b class="genmed">{L_RESULT_DAYS}{L_COLON} </b></td>
- <td class="row2" width="25%" nowrap="nowrap">{S_SELECT_SORT_DAYS}</td>
- <td class="row1" nowrap="nowrap"><b class="genmed">{L_RETURN_FIRST}{L_COLON} </b></td>
- <td class="row2" nowrap="nowrap"><select name="ch">{S_CHARACTER_OPTIONS}</select> <span class="genmed">{L_POST_CHARACTERS}</span></td>
- </tr>
- <!-- EVENT search_body_search_display_options_append -->
- <!-- EVENT search_body_search_options_after -->
- <tr>
- <td class="cat" colspan="{$COLSPAN}" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" name="submit" type="submit" value="{L_SEARCH}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" /></td>
- </tr>
- </table>
-
- </form>
- <!-- EVENT search_body_form_after -->
-
- <br clear="all" />
-
- <!-- EVENT search_body_recent_search_before -->
- <!-- IF .recentsearch -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="2">{L_RECENT_SEARCHES}</th>
- </tr>
- <!-- BEGIN recentsearch -->
- <!-- IF recentsearch.S_ROW_COUNT is even --><tr class="row2"><!-- ELSE --><tr class="row1"><!-- ENDIF -->
-
- <td class="genmed" style="padding: 4px;" width="70%"><a href="{recentsearch.U_KEYWORDS}">{recentsearch.KEYWORDS}</a></td>
- <td class="genmed" style="padding: 4px;" width="30%" align="center">{recentsearch.TIME}</td>
- </tr>
- <!-- END recentsearch -->
- </table>
-
- <br clear="all" />
- <!-- ENDIF -->
- <!-- EVENT search_body_recent_search_after -->
-
- </div>
-
- <!-- INCLUDE breadcrumbs.html -->
-
- <br clear="all" />
-
- <div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<script type="text/javascript">
-// <![CDATA[
- (function()
- {
- var elements = document.getElementsByName("keywords");
- for (var i = 0; i < elements.length; ++i)
- {
- if (elements[i].tagName.toLowerCase() == 'input')
- {
- elements[i].focus();
- break;
- }
- }
- })();
-// ]]>
-</script>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/search_results.html b/phpBB/styles/subsilver2/template/search_results.html
deleted file mode 100644
index 1ba8af7fe2..0000000000
--- a/phpBB/styles/subsilver2/template/search_results.html
+++ /dev/null
@@ -1,165 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- EVENT search_results_header_before -->
-
-<form method="post" action="{S_SEARCH_ACTION}">
-
-<table width="100%" cellspacing="1">
-<tr>
- <td colspan="2"><span class="titles"><!-- IF SEARCH_TITLE -->{SEARCH_TITLE}<!-- ELSE -->{SEARCH_MATCHES}<!-- ENDIF --></span><br /></td>
-</tr>
-<tr>
- <td class="genmed"><!-- IF SEARCH_TOPIC -->{L_SEARCHED_TOPIC}{L_COLON} <a href="{U_SEARCH_TOPIC}"><b>{SEARCH_TOPIC}</b></a><br /><!-- ENDIF --><!-- IF SEARCH_WORDS -->{L_SEARCHED_FOR}{L_COLON} <a href="{U_SEARCH_WORDS}"><b>{SEARCH_WORDS}</b></a><!-- ENDIF --><!-- IF IGNORED_WORDS --> {L_IGNORED_TERMS}{L_COLON} <b>{IGNORED_WORDS}</b><!-- ENDIF --></td>
- <td align="{S_CONTENT_FLOW_END}"><!-- EVENT search_results_searchbox_after --><!-- IF SEARCH_IN_RESULTS --><span class="genmed">{L_SEARCH_IN_RESULTS}{L_COLON} </span><input class="post" type="text" name="add_keywords" value="" /> <input class="btnlite" type="submit" name="submit" value="{L_GO}" /><!-- ENDIF --></td>
-</tr>
-</table>
-
-<!-- EVENT search_results_header_after -->
-
-<br clear="all" />
-
-<!-- IF S_SHOW_TOPICS -->
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th width="4%" nowrap="nowrap">&nbsp;</th>
- <th colspan="2" nowrap="nowrap">&nbsp;{L_TOPICS}&nbsp;</th>
- <th nowrap="nowrap">&nbsp;{L_AUTHOR}&nbsp;</th>
- <th nowrap="nowrap">&nbsp;{L_REPLIES}&nbsp;</th>
- <th nowrap="nowrap">&nbsp;{L_VIEWS}&nbsp;</th>
- <th nowrap="nowrap">&nbsp;{L_LAST_POST}&nbsp;</th>
- </tr>
- <!-- BEGIN searchresults -->
- <!-- EVENT search_results_topic_before -->
- <tr valign="middle">
- <td class="row1" width="25" align="center">{searchresults.TOPIC_FOLDER_IMG}</td>
- <td class="row1" width="25" align="center">
- <!-- IF searchresults.TOPIC_ICON_IMG -->
- <img src="{T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}" width="{searchresults.TOPIC_ICON_IMG_WIDTH}" height="{searchresults.TOPIC_ICON_IMG_HEIGHT}" alt="" title="" />
- <!-- ENDIF -->
- </td>
- <td class="row1">
- <!-- EVENT topiclist_row_prepend -->
- <!-- IF searchresults.S_UNREAD_TOPIC --><a href="{searchresults.U_NEWEST_POST}" class="imageset">{NEWEST_POST_IMG}</a><!-- ENDIF -->
- {searchresults.ATTACH_ICON_IMG} <a href="{searchresults.U_VIEW_TOPIC}" class="topictitle">{searchresults.TOPIC_TITLE}</a>
- <!-- IF searchresults.S_TOPIC_UNAPPROVED or searchresults.S_POSTS_UNAPPROVED -->
- <a href="{searchresults.U_MCP_QUEUE}" class="imageset">{searchresults.UNAPPROVED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF searchresults.S_TOPIC_DELETED -->
- <a href="{searchresults.U_MCP_QUEUE}" class="imageset">{DELETED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF searchresults.S_TOPIC_REPORTED -->
- <a href="{searchresults.U_MCP_REPORT}" class="imageset">{REPORTED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- EVENT topiclist_row_topic_title_after -->
- <!-- IF .searchresults.pagination -->
- <p class="gensmall"> [ {GOTO_PAGE_IMG}{L_GOTO_PAGE}{L_COLON}
- <!-- BEGIN pagination -->
- <!-- IF searchresults.pagination.S_IS_PREV -->
- <!-- ELSEIF searchresults.pagination.S_IS_CURRENT --><strong>{searchresults.pagination.PAGE_NUMBER}</strong>
- <!-- ELSEIF searchresults.pagination.S_IS_ELLIPSIS --> {L_ELLIPSIS}
- <!-- ELSEIF searchresults.pagination.S_IS_NEXT -->
- <!-- ELSE --><a href="{searchresults.pagination.PAGE_URL}">{searchresults.pagination.PAGE_NUMBER}</a>
- <!-- ENDIF -->
- <!-- END pagination -->
- ] </p>
- <!-- ENDIF -->
- <p class="gensmall">{L_IN} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a></p>
- <!-- EVENT topiclist_row_append -->
- </td>
- <td class="row2" width="100" align="center"><p class="topicauthor">{searchresults.TOPIC_AUTHOR_FULL}</p></td>
- <td class="row1" width="50" align="center"><p class="topicdetails">{searchresults.TOPIC_REPLIES}</p></td>
- <td class="row2" width="50" align="center"><p class="topicdetails">{searchresults.TOPIC_VIEWS}</p></td>
- <td class="row1" width="120" align="center">
- <p class="topicdetails">{searchresults.LAST_POST_TIME}</p>
- <p class="topicdetails">{searchresults.LAST_POST_AUTHOR_FULL}
- <a href="{searchresults.U_LAST_POST}" class="imageset">{LAST_POST_IMG}</a>
- </p>
- </td>
- </tr>
- <!-- EVENT search_results_topic_after -->
- <!-- BEGINELSE -->
- <tr valign="middle">
- <td colspan="7" class="row3" align="center">{L_NO_SEARCH_RESULTS}</td>
- </tr>
- <!-- END searchresults -->
- <tr>
- <td class="cat" colspan="7" valign="middle" align="center"><!-- IF S_SELECT_SORT_DAYS or S_SELECT_SORT_KEY --><span class="gensmall">{L_DISPLAY_POSTS}{L_COLON}</span> {S_SELECT_SORT_DAYS}<!-- IF S_SELECT_SORT_KEY -->&nbsp;<span class="gensmall">{L_SORT_BY}{L_COLON}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}<!-- ENDIF -->&nbsp;<input class="btnlite" type="submit" value="{L_GO}" name="sort" /><!-- ENDIF --></td>
- </tr>
- </table>
-
-<!-- ELSE -->
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th width="150" nowrap="nowrap">{L_AUTHOR}</th>
- <th width="100%" nowrap="nowrap">{L_MESSAGE}</th>
- </tr>
-
- <!-- BEGIN searchresults -->
- <tr class="row2">
- <!-- EVENT search_results_post_before -->
- <!-- IF searchresults.S_IGNORE_POST -->
- <td class="gensmall" colspan="2" height="25" align="center">{searchresults.L_IGNORE_POST}</td>
- <!-- ELSE -->
- <td colspan="2" height="25"><p class="topictitle"><a name="p{searchresults.POST_ID}" id="p{searchresults.POST_ID}" class="anchor"></a>&nbsp;{L_FORUM}{L_COLON} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a> &nbsp; {L_TOPIC}{L_COLON} <a href="{searchresults.U_VIEW_TOPIC}">{searchresults.TOPIC_TITLE}</a> </p></td>
- </tr>
- <tr class="row1">
- <td width="150" align="center" valign="middle"><b class="postauthor">{searchresults.POST_AUTHOR_FULL}</b></td>
- <td height="25">
- <table width="100%" cellspacing="0" cellpadding="0" border="0">
- <tr>
- <td class="gensmall">
- <div style="float: {S_CONTENT_FLOW_BEGIN};">
- <!-- IF searchresults.POST_SUBJECT neq "" -->
- &nbsp;<b>{L_POST_SUBJECT}{L_COLON}</b> <a href="{searchresults.U_VIEW_POST}">{searchresults.POST_SUBJECT}</a>
- <!-- ELSE -->
- [ <a href="{searchresults.U_VIEW_POST}">{L_JUMP_TO_POST}</a> ]
- <!-- ENDIF -->
- </div>
- <div style="float: {S_CONTENT_FLOW_END};"><b>{L_POSTED}{L_COLON}</b> {searchresults.POST_DATE}&nbsp;</div>
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <tr class="row1">
- <td width="150" align="center" valign="top"><br /><span class="postdetails">{L_REPLIES}{L_COLON} <b>{searchresults.TOPIC_REPLIES}</b><br />{L_VIEWS}{L_COLON} <b>{searchresults.TOPIC_VIEWS}</b></span><br /><br /></td>
- <td valign="top">
- <table width="100%" cellspacing="5">
- <tr>
- <td class="postbody">{searchresults.MESSAGE}</td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT search_results_post_after -->
- <tr>
- <td class="spacer" colspan="2"><img src="images/spacer.gif" height="1" alt="" /></td>
- </tr>
- <!-- BEGINELSE -->
- <tr valign="middle">
- <td colspan="2" class="row3" align="center">{L_NO_SEARCH_RESULTS}</td>
- </tr>
- <!-- END searchresults -->
- <tr>
- <td class="cat" colspan="2" align="center"><!-- IF S_SELECT_SORT_KEY --><span class="gensmall">{L_SORT_BY}{L_COLON}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" name="sort" value="{L_GO}" /><!-- ENDIF --></td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-</form>
-
-<div class="gensmall" style="float: {S_CONTENT_FLOW_BEGIN};"><span class="nav">{PAGE_NUMBER}</span> [ {SEARCH_MATCHES} ]</div>
-<div class="nav" style="float: {S_CONTENT_FLOW_END};"><!-- INCLUDE pagination.html --></div>
-
-<br clear="all" /><br />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/searchbox.html b/phpBB/styles/subsilver2/template/searchbox.html
deleted file mode 100644
index 49de299ea2..0000000000
--- a/phpBB/styles/subsilver2/template/searchbox.html
+++ /dev/null
@@ -1 +0,0 @@
-<form method="get" name="search" action="{S_SEARCHBOX_ACTION}"><span class="gensmall">{L_SEARCH_FOR}{L_COLON}</span> <input class="post" type="text" name="keywords" size="20" /> <input class="btnlite" type="submit" value="{L_GO}" />{S_SEARCH_LOCAL_HIDDEN_FIELDS}</form>
diff --git a/phpBB/styles/subsilver2/template/simple_footer.html b/phpBB/styles/subsilver2/template/simple_footer.html
deleted file mode 100644
index d69c56fb8c..0000000000
--- a/phpBB/styles/subsilver2/template/simple_footer.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-</div>
-
-<div id="wrapfooter">
- <span class="copyright">{CREDIT_LINE}</span>
-</div>
-
-<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
-<!-- IF S_ALLOW_CDN --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.min.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF -->
-
-<!-- EVENT simple_footer_after -->
-
-{$SCRIPTS}
-</body>
-</html>
diff --git a/phpBB/styles/subsilver2/template/simple_header.html b/phpBB/styles/subsilver2/template/simple_header.html
deleted file mode 100644
index 2beeac2548..0000000000
--- a/phpBB/styles/subsilver2/template/simple_header.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">
-<head>
-<meta charset="utf-8" />
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-{META}
-<title>{SITENAME} &bull; <!-- IF S_IN_MCP -->{L_MCP} &bull; <!-- ELSEIF S_IN_UCP -->{L_UCP} &bull; <!-- ENDIF -->{PAGE_TITLE}</title>
-
-<link rel="stylesheet" href="{T_STYLESHEET_LINK}" type="text/css" />
-<link rel="stylesheet" href="{T_STYLESHEET_LANG_LINK}" type="text/css" />
-
-<!-- EVENT simple_header_head_append -->
-
-{$STYLESHEETS}
-
-<!-- EVENT simple_header_stylesheets_after -->
-
-</head>
-
-<body class="{S_CONTENT_DIRECTION} {BODY_CLASS}">
-<!-- EVENT simple_header_body_before -->
-<a name="top" class="anchor"></a>
-<div id="wrapcentre">
diff --git a/phpBB/styles/subsilver2/template/timezone.js b/phpBB/styles/subsilver2/template/timezone.js
deleted file mode 100644
index c5829c0bb1..0000000000
--- a/phpBB/styles/subsilver2/template/timezone.js
+++ /dev/null
@@ -1,21 +0,0 @@
-(function($) { // Avoid conflicts with other libraries
-
-"use strict";
-
-$('#tz_date').change(function() {
- phpbb.timezoneSwitchDate(false);
-});
-
-$('#tz_select_date_suggest').click(function(){
- phpbb.timezonePreselectSelect(true);
-});
-
-$(document).ready(
- phpbb.timezoneEnableDateSelection
-);
-
-$(document).ready(
- phpbb.timezonePreselectSelect($('#tz_select_date_suggest').attr('timezone-preselect') == 'true')
-);
-
-})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/styles/subsilver2/template/timezone_option.html b/phpBB/styles/subsilver2/template/timezone_option.html
deleted file mode 100644
index 3fc7467d16..0000000000
--- a/phpBB/styles/subsilver2/template/timezone_option.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_BOARD_TIMEZONE}{L_COLON}</b></td>
- <td class="row2">
- <!-- IF .timezone_date -->
- <div id="tz_select_date" style="display: none;">
- <select name="tz_date" id="tz_date" class="autowidth tz_select">
- <option value="">{L_SELECT_CURRENT_TIME}</option>
- <!-- BEGIN timezone_date -->
- <option value="{timezone_date.VALUE}"<!-- IF timezone_date.SELECTED --> selected="selected"<!-- ENDIF -->>{timezone_date.TITLE}</option>
- <!-- END timezone_date -->
- </select><br />
- <input type="button" id="tz_select_date_suggest" class="btnlite" style="display: none;" timezone-preselect="<!-- IF S_TZ_PRESELECT -->true<!-- ELSE -->false<!-- ENDIF -->" data-l-suggestion="{L_TIMEZONE_DATE_SUGGESTION}" value="{L_TIMEZONE_DATE_SUGGESTION}" />
- </div>
- <!-- ENDIF -->
- <select name="tz" id="timezone" class="autowidth tz_select">
- <option value="">{L_SELECT_TIMEZONE}</option>
- <!-- BEGIN timezone_select -->
- <optgroup label="{timezone_select.LABEL}" data-tz-value="{timezone_select.VALUE}">
- <!-- BEGIN timezone_options -->
- <option title="{timezone_select.timezone_options.TITLE}" value="{timezone_select.timezone_options.VALUE}"<!-- IF timezone_select.timezone_options.SELECTED --> selected="selected"<!-- ENDIF -->>{timezone_select.timezone_options.LABEL}</option>
- <!-- END timezone_options -->
- </optgroup>
- <!-- END timezone_select -->
- </select>
-
- <!-- INCLUDEJS timezone.js -->
- </td>
-</tr>
diff --git a/phpBB/styles/subsilver2/template/ucp_agreement.html b/phpBB/styles/subsilver2/template/ucp_agreement.html
deleted file mode 100644
index fca7eb2368..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_agreement.html
+++ /dev/null
@@ -1,87 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- IF S_SHOW_COPPA or S_REGISTRATION -->
-
-<!-- IF S_LANG_OPTIONS -->
-<script type="text/javascript">
-// <![CDATA[
- /**
- * Change language
- */
- function change_language(lang_iso)
- {
- document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}';
- document.forms['register'].change_lang.value = lang_iso;
- document.forms['register'].submit();
- }
-
-// ]]>
-</script>
-
- <form method="post" action="{S_UCP_ACTION}" id="register">
- <table width="100%" cellspacing="0">
- <tr>
- <td class="gensmall" align="{S_CONTENT_FLOW_END}">{L_LANGUAGE}{L_COLON} <select name="lang" id="lang" onchange="change_language(this.value); return false;" title="{L_LANGUAGE}">{S_LANG_OPTIONS}</select></td>
- </tr>
- </table>
- {S_HIDDEN_FIELDS}
- </form>
-<!-- ENDIF -->
-
- <form method="post" action="{S_UCP_ACTION}">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th height="25">{SITENAME} - {L_REGISTRATION}</th>
- </tr>
- <tr>
- <td class="row1" align="center">
- <table width="90%" cellspacing="2" cellpadding="2" border="0" align="center">
- <tr>
- <!-- IF S_SHOW_COPPA -->
- <td class="gen" align="center"><br />{L_COPPA_BIRTHDAY}<br /><br /><a href="{U_COPPA_NO}">{L_COPPA_NO}</a> :: <a href="{U_COPPA_YES}">{L_COPPA_YES}</a><br /><br /></td>
- <!-- ELSE -->
- <td>
- <!-- EVENT ucp_agreement_terms_before -->
- <span class="genmed"><br />{L_TERMS_OF_USE}<br /><br /></span>
- <!-- EVENT ucp_agreement_terms_after -->
- <div align="center">
- <input class="btnlite" type="submit" id="agreed" name="agreed" value="{L_AGREE}" /><br /><br />
- <input class="btnlite" type="submit" name="not_agreed" value="{L_NOT_AGREE}" />
- </div>
- </td>
- <!-- ENDIF -->
- </tr>
- </table>
- </td>
- </tr>
- </table>
- {S_HIDDEN_FIELDS}
- {S_FORM_TOKEN}
- </form>
-
-<!-- ELSEIF S_AGREEMENT -->
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th height="25">{SITENAME} - {AGREEMENT_TITLE}</th>
- </tr>
- <tr>
- <td class="row1" align="center">
- <table width="90%" cellspacing="2" cellpadding="2" border="0" align="center">
- <tr>
- <td>
- <span class="genmed"><br />{AGREEMENT_TEXT}<br /><br /></span>
- <div align="center">
- <a href="{U_BACK}">{L_BACK}</a>
- </div>
- </td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
-
-<!-- ENDIF -->
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_attachments.html b/phpBB/styles/subsilver2/template/ucp_attachments.html
deleted file mode 100644
index c513f933c0..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_attachments.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<!-- IF S_ATTACHMENT_ROWS -->
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th nowrap="nowrap">#</th>
- <th nowrap="nowrap" width="15%"><a href="{U_SORT_FILENAME}">{L_FILENAME}</a></th>
- <th nowrap="nowrap" width="5%"><a href="{U_SORT_POST_TIME}">{L_POST_TIME}</a></th>
- <th nowrap="nowrap" width="5%"><a href="{U_SORT_FILESIZE}">{L_FILESIZE}</a></th>
- <th nowrap="nowrap" width="5%"><a href="{U_SORT_DOWNLOADS}">{L_DOWNLOADS}</a></th>
- <th width="2%" nowrap="nowrap">{L_DELETE}</th>
- </tr>
- <!-- IF TOTAL_ATTACHMENTS -->
- <tr>
- <td class="row3" colspan="6">
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ {NUM_ATTACHMENTS} ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- ENDIF -->
- <!-- BEGIN attachrow -->
- <!-- IF attachrow.S_ROW_COUNT is even --><tr class="row2"><!-- ELSE --><tr class="row1"><!-- ENDIF -->
-
- <td class="genmed" style="padding: 4px;" align="center" width="2%">&nbsp;{attachrow.ROW_NUMBER}&nbsp;</td>
- <td style="padding: 4px;"><a class="gen" href="{attachrow.U_VIEW_ATTACHMENT}">{attachrow.FILENAME}</a><br /><span class="gensmall"><!-- IF attachrow.S_IN_MESSAGE --><b>{L_PM}{L_COLON} </b><!-- ELSE --><b>{L_TOPIC}{L_COLON} </b><!-- ENDIF --><a href="{attachrow.U_VIEW_TOPIC}">{attachrow.TOPIC_TITLE}</a></span></td>
- <td class="gensmall" style="padding: 4px;" align="center" valign="middle" nowrap="nowrap">&nbsp;{attachrow.POST_TIME}&nbsp;</td>
- <td class="genmed" style="padding: 4px;" align="center" valign="middle" nowrap="nowrap">{attachrow.SIZE}</td>
- <td class="genmed" style="padding: 4px;" align="center">{attachrow.DOWNLOAD_COUNT}</td>
- <td style="padding: 4px;" align="center" valign="middle"><input type="checkbox" class="radio" name="attachment[{attachrow.ATTACH_ID}]" value="1" /></td>
- </tr>
- <!-- END attachrow -->
- <tr>
- <td class="cat" colspan="6"><div style="float: {S_CONTENT_FLOW_BEGIN};"><span class="gensmall">{L_SORT_BY}{L_COLON} </span><select name="sk">{S_SORT_OPTIONS}</select> <select name="sd">{S_ORDER_SELECT}</select>&nbsp;<input class="btnlite" type="submit" name="sort" value="{L_SORT}" /></div><div style="float: {S_CONTENT_FLOW_END};"><input class="btnlite" type="submit" name="delete" value="{L_DELETE_MARKED}" />&nbsp;</div></td>
- </tr>
- </table>
-
- <div style="float: {S_CONTENT_FLOW_END};"><b class="gensmall"><a href="#" onclick="marklist('ucp', 'attachment', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('ucp', 'attachment', false); return false;">{L_UNMARK_ALL}</a></b></div>
-
-<!-- ELSE -->
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_TITLE}</th>
- </tr>
- <tr class="row1">
- <td align="center"><b class="genmed">{L_UCP_NO_ATTACHMENTS}</b></td>
- </tr>
- </table>
-
-<!-- ENDIF -->
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_auth_link.html b/phpBB/styles/subsilver2/template/ucp_auth_link.html
deleted file mode 100644
index 75e3133fcf..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_auth_link.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="4">{L_UCP_AUTH_LINK_TITLE}</th>
- </tr>
-
- <!-- IF ERROR -->
- <tr>
- <td class="row1" colspan="2" align="center"><span class="genmed error">{ERROR}</span></td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF PROVIDER_TEMPLATE_FILE -->
- <!-- INCLUDE {PROVIDER_TEMPLATE_FILE} -->
- <!-- ENDIF -->
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_auth_link_oauth.html b/phpBB/styles/subsilver2/template/ucp_auth_link_oauth.html
deleted file mode 100644
index 80564d207b..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_auth_link_oauth.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!-- BEGIN oauth -->
- <tr>
- <th>{oauth.SERVICE_NAME}</th>
- </tr>
-
- <tr>
- <td class="row1">
- <form id="ucp" method="post" action="{S_UCP_ACTION}">
- <table>
- <!-- IF oauth.UNIQUE_ID -->
- <tr>
- <td class="row1">{L_UCP_AUTH_LINK_ID}{L_COLON}</td>
- <td class="row1">{oauth.UNIQUE_ID}</td>
- </tr>
- <tr>
- <td class="row1">&nbsp;</td>
- <td class="row1"><input type="submit" name="submit" tabindex="6" value="{L_UCP_AUTH_LINK_UNLINK}" class="button1" /></td>
- </tr>
- <!-- ELSE -->
- <tr>
- <td class="row1">{L_UCP_AUTH_LINK_ASK}</td>
- </tr>
- <tr>
- <td class="row1"><input type="submit" name="submit" tabindex="6" value="{L_UCP_AUTH_LINK_LINK}" class="button1" /></td>
- </tr>
- <!-- ENDIF -->
- </table>
- {oauth.HIDDEN_FIELDS}
- {S_HIDDEN_FIELDS}
- {S_FORM_TOKEN}
- </form>
- </td>
- </tr>
-<!-- END oauth -->
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html
deleted file mode 100644
index 9fb3f0e754..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_GRAVATAR_AVATAR_EMAIL}{L_COLON}</b><br /><span class="gensmall">{L_GRAVATAR_AVATAR_EMAIL_EXPLAIN}</span></td>
- <td class="row2"><input type="text" name="avatar_gravatar_email" id="avatar_gravatar_email" value="{AVATAR_GRAVATAR_EMAIL}" class="inputbox" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_GRAVATAR_AVATAR_SIZE}{L_COLON}</b><br /><span class="gensmall">{L_GRAVATAR_AVATAR_SIZE_EXPLAIN}</span></td>
- <td class="row2">
- <input type="number" name="avatar_gravatar_width" id="avatar_gravatar_width" min="{AVATAR_MIN_WIDTH}" max="{AVATAR_MAX_WIDTH}" value="{AVATAR_GRAVATAR_WIDTH}" class="inputbox autowidth" /> {L_PIXEL} &times;&nbsp;
- <input type="number" name="avatar_gravatar_height" id="avatar_gravatar_height" min="{AVATAR_MIN_HEIGHT}" max="{AVATAR_MAX_HEIGHT}" value="{AVATAR_GRAVATAR_HEIGHT}" class="inputbox autowidth" /> {L_PIXEL}
- </td>
- </tr>
-</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_local.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_local.html
deleted file mode 100644
index 921126ba22..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_avatar_options_local.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<table class="tablebg" width="100%" cellspacing="1">
- <!-- IF .avatar_local_cats -->
- <tr>
- <td class="cat" colspan="2" align="center" valign="middle"><span class="genmed">{L_AVATAR_CATEGORY}{L_COLON} </span><select name="avatar_local_cat" id="category">
- <!-- BEGIN avatar_local_cats -->
- <option value="{avatar_local_cats.NAME}"<!-- IF avatar_local_cats.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_local_cats.NAME}</option>
- <!-- END avatar_local_cats -->
- </select>&nbsp; <input class="btnlite" tabindex="0" type="submit" value="{L_GO}" name="avatar_local_go" />
- </td>
- </tr>
- <tr>
- <td class="row1" colspan="2" align="center">
- <table cellspacing="1" cellpadding="4" border="0">
- <!-- BEGIN avatar_local_row -->
- <tr>
- <!-- BEGIN avatar_local_col -->
- <td class="row1" align="center" id="av-{avatar_local_row.S_ROW_COUNT}-{avatar_local_row.avatar_local_col.S_ROW_COUNT}"><img src="{avatar_local_row.avatar_local_col.AVATAR_IMAGE}" alt="{avatar_local_row.avatar_local_col.AVATAR_NAME}" title="{avatar_local_row.avatar_local_col.AVATAR_NAME}" /></td>
- <!-- END avatar_local_col -->
- </tr>
- <tr>
- <!-- BEGIN avatar_local_option -->
- <td class="row2" align="center"><input type="radio" class="radio" name="avatar_local_file"
- id="av-{avatar_local_row.S_ROW_COUNT}-{avatar_local_row.avatar_local_col.S_ROW_COUNT}"
- value="{avatar_local_row.avatar_local_option.S_OPTIONS_AVATAR}"
- <!-- IF avatar_local_row.avatar_local_option.CHECKED --> checked="checked"<!-- ENDIF --> />
- </td>
- <!-- END avatar_local_option -->
- </tr>
- <!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="2">{L_NO_AVATAR_CATEGORY}</td>
- </tr>
- <!-- END avatar_local_row -->
- </table>
- </td>
- </tr>
- <!-- ELSE -->
- <tr>
- <td class="row1" colspan="2"><strong>{L_NO_AVATARS}</strong></td>
- </tr>
- <!-- ENDIF -->
-</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html
deleted file mode 100644
index 309b3f9836..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_LINK_REMOTE_AVATAR}{L_COLON} </b><br /><span class="gensmall">{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="avatar_remote_url" size="40" value="{AVATAR_REMOTE_URL}" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_LINK_REMOTE_SIZE}{L_COLON} </b><br /><span class="gensmall">{L_LINK_REMOTE_SIZE_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="number" name="avatar_remote_width" min="{AVATAR_MIN_WIDTH}" max="{AVATAR_MAX_WIDTH}" value="{AVATAR_REMOTE_WIDTH}" /> <span class="gen">{L_PIXEL} &times; </span> <input class="post" type="number" name="avatar_remote_height" min="{AVATAR_MIN_HEIGHT}" max="{AVATAR_MAX_HEIGHT}" value="{AVATAR_REMOTE_HEIGHT}" /> <span class="gen">{L_PIXEL}</span></td>
- </tr>
-</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html
deleted file mode 100644
index 6b813baeaa..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_UPLOAD_AVATAR_FILE}{L_COLON} </b></td>
- <td class="row2"><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_SIZE}" /><input class="post" type="file" name="avatar_upload_file" /></td>
- </tr>
-<!-- IF S_UPLOAD_AVATAR_URL -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_UPLOAD_AVATAR_URL}{L_COLON} </b><br /><span class="gensmall">{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="avatar_upload_url" size="40" value="" /></td>
- </tr>
-<!-- ENDIF -->
-</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_footer.html b/phpBB/styles/subsilver2/template/ucp_footer.html
deleted file mode 100644
index 57adb2da97..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_footer.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
- <!-- IF not S_PRIVMSGS or S_SHOW_DRAFTS --> {S_FORM_TOKEN}</form><!-- ENDIF --></td>
-</tr>
-</table>
-<!-- IF (S_SHOW_PM_BOX or S_EDIT_POST) and S_POST_ACTION -->{S_FORM_TOKEN}</form><!-- ENDIF -->
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_groups_manage.html b/phpBB/styles/subsilver2/template/ucp_groups_manage.html
deleted file mode 100644
index 09d59c8ec0..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_groups_manage.html
+++ /dev/null
@@ -1,229 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<!-- IF S_EDIT -->
-
- <!-- IF S_ERROR -->
- <div class="errorbox">
- <h3>{L_WARNING}</h3>
- <p>{ERROR_MSG}</p>
- </div>
- <!-- ENDIF -->
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="2">{L_USERGROUPS}</th>
- </tr>
- <tr>
- <td class="row1" colspan="2"><span class="genmed">{L_GROUPS_EXPLAIN}</span></td>
- </tr>
-
- <tr>
- <th colspan="2">{L_GROUP_DETAILS}</th>
- </tr>
- <tr>
- <td class="row1" width="35%"><label<!-- IF not S_SPECIAL_GROUP --> for="group_name"<!-- ENDIF -->>{L_GROUP_NAME}{L_COLON}</label></td>
- <td class="row2"><!-- IF S_SPECIAL_GROUP --><b<!-- IF GROUP_COLOUR --> style="color: #{GROUP_COLOUR};"<!-- ENDIF -->>{GROUP_NAME}</b><!-- ENDIF --><input name="group_name" type="<!-- IF S_SPECIAL_GROUP -->hidden<!-- ELSE -->text<!-- ENDIF -->" id="group_name" value="{GROUP_INTERNAL_NAME}" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><label for="group_desc">{L_GROUP_DESC}{L_COLON}</label></td>
- <td class="row2"><textarea id="group_desc" name="group_desc" rows="5" cols="45">{GROUP_DESC}</textarea>
- <br /><input type="checkbox" class="radio" name="desc_parse_bbcode"<!-- IF S_DESC_BBCODE_CHECKED --> checked="checked"<!-- ENDIF --> /> {L_PARSE_BBCODE} &nbsp; <input type="checkbox" class="radio" name="desc_parse_smilies"<!-- IF S_DESC_SMILIES_CHECKED --> checked="checked"<!-- ENDIF --> /> {L_PARSE_SMILIES} &nbsp; <input type="checkbox" class="radio" name="desc_parse_urls"<!-- IF S_DESC_URLS_CHECKED --> checked="checked"<!-- ENDIF --> /> {L_PARSE_URLS}
- </td>
- </tr>
- <!-- IF not S_SPECIAL_GROUP -->
- <tr>
- <td class="row1" width="35%"><label for="group_type">{L_GROUP_TYPE}{L_COLON}</label><br /><span>{L_GROUP_TYPE_EXPLAIN}</span></td>
- <td class="row2">
- <input name="group_type" type="radio" class="radio" id="group_type" value="{GROUP_TYPE_FREE}"{GROUP_FREE} /> {L_GROUP_OPEN} &nbsp;
- <input name="group_type" type="radio" class="radio" value="{GROUP_TYPE_OPEN}"{GROUP_OPEN} /> {L_GROUP_REQUEST} &nbsp;
- <input name="group_type" type="radio" class="radio" value="{GROUP_TYPE_CLOSED}"{GROUP_CLOSED} /> {L_GROUP_CLOSED} &nbsp;
- <input name="group_type" type="radio" class="radio" value="{GROUP_TYPE_HIDDEN}"{GROUP_HIDDEN} /> {L_GROUP_HIDDEN}
- </td>
- </tr>
- <!-- ELSE -->
- <tr style="display:none;"><td><input name="group_type" type="hidden" value="{GROUP_TYPE_SPECIAL}" /></td></tr>
- <!-- ENDIF -->
-
- <tr>
- <th colspan="2">{L_GROUP_SETTINGS_SAVE}</th>
- </tr>
- <tr>
- <td class="row1" width="35%"><label for="group_colour">{L_GROUP_COLOR}{L_COLON}</label><br /><span>{L_GROUP_COLOR_EXPLAIN}</span></td>
- <td class="row2">
- <input name="group_colour" type="text" id="group_colour" value="{GROUP_COLOUR}" size="6" maxlength="6" />&nbsp;&nbsp;
- <span>[ <a href="#" id="color_palette_toggle">{L_COLOUR_SWATCH}</a> ]</span>
- <div id="color_palette_placeholder" style="display: none;" data-orientation="h" data-height="12" data-width="15" data-target="#group_colour"></div>
- </td>
- </tr>
- <tr>
- <td class="row1" width="35%"><label for="group_rank">{L_GROUP_RANK}{L_COLON}</label></td>
- <td class="row2"><select name="group_rank" id="group_rank">{S_RANK_OPTIONS}</select></td>
- </tr>
- <tr>
- <th colspan="2">{L_GROUP_AVATAR}</th>
- </tr>
- <tr>
- <td class="row1" width="35%"><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></td>
- <td class="row2">{AVATAR_IMAGE}<br /><br /><input type="checkbox" class="radio" name="avatar_delete" />&nbsp;<span>{L_DELETE_AVATAR}</span></td>
- </tr>
-<!-- IF not S_AVATARS_ENABLED -->
- <tr>
- <td class="row3" colspan="2" align="center">{L_AVATAR_FEATURES_DISABLED}</td>
- </tr>
-<!-- ENDIF -->
- <tr>
- <th colspan="2">{L_AVATAR_SELECT}</th>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_AVATAR_TYPE}{L_COLON}</b></td>
- <td class="row2">
- <select name="avatar_driver" id="avatar_driver">
- <!-- BEGIN avatar_drivers -->
- <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_drivers.L_TITLE}</option>
- <!-- END avatar_drivers -->
- </select></td>
- </tr>
-<!-- BEGIN avatar_drivers -->
- <tr class="avatar_option_{avatar_drivers.DRIVER}">
- <td class="row1" width="35%" colspan="2"><noscript><b class="genmed">{avatar_drivers.L_TITLE} </b><br /></noscript>{avatar_drivers.L_EXPLAIN}</span></td>
- </tr>
- <tr class="avatar_option_{avatar_drivers.DRIVER}">
- <td colspan="2" style="padding: 0">{avatar_drivers.OUTPUT}</td>
- </tr>
-<!-- END avatar_drivers -->
-
- <tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnlite" type="submit" id="submit" name="update" value="{L_SUBMIT}" />&nbsp;
- <input class="btnmain" type="reset" id="reset" name="reset" value="{L_RESET}" /></td>
- </tr>
- </table>
-
-<!-- INCLUDEJS avatars.js -->
-
-<!-- ELSEIF S_LIST -->
-
- <h1>{L_GROUP_MEMBERS}</h1>
-
- <p>{L_GROUP_MEMBERS_EXPLAIN}</p>
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_USERNAME}</th>
- <th>{L_GROUP_DEFAULT}</th>
- <th>{L_JOINED}</th>
- <th>{L_POSTS}</th>
- <th>{L_MARK}</th>
- </tr>
-
- <tr>
- <td class="row3" colspan="5"><b>{L_GROUP_LEAD}</b></td>
- </tr>
- <!-- BEGIN leader -->
- <!-- IF leader.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td>{leader.USERNAME_FULL}</td>
- <td style="text-align: center;"><!-- IF leader.S_GROUP_DEFAULT -->{L_YES}<!-- ELSE -->{L_NO}<!-- ENDIF --></td>
- <td style="text-align: center;">{leader.JOINED}</td>
- <td style="text-align: center;">{leader.USER_POSTS}</td>
- <td style="text-align: center;"></td>
- </tr>
- <!-- END leader -->
-
- <!-- BEGIN member -->
- <!-- IF member.S_PENDING -->
- <tr>
- <td class="row3" colspan="5"><b>{L_GROUP_PENDING}</b></td>
- </tr>
- <!-- ELSEIF member.S_APPROVED -->
- <tr>
- <td class="row3" colspan="5"><b>{L_GROUP_APPROVED}</b></td>
- </tr>
- <!-- ELSE -->
- <!-- IF member.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td>{member.USERNAME_FULL}</td>
- <td style="text-align: center;"><!-- IF member.S_GROUP_DEFAULT -->{L_YES}<!-- ELSE -->{L_NO}<!-- ENDIF --></td>
- <td style="text-align: center;">{member.JOINED}</td>
- <td style="text-align: center;">{member.USER_POSTS}</td>
- <td style="text-align: center;"><input type="checkbox" class="radio" name="mark[]" value="{member.USER_ID}" /></td>
- </tr>
- <!-- ENDIF -->
- <!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="5" style="text-align: center;">{L_GROUPS_NO_MEMBERS}</td>
- </tr>
- <!-- END member -->
- <tr>
- <td class="cat" colspan="5" align="center"><div style="float: {S_CONTENT_FLOW_END};"><span class="small"><a href="#" onclick="marklist('ucp', 'mark', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('ucp', 'mark', false); return false;">{L_UNMARK_ALL}</a></span></div><div style="float: {S_CONTENT_FLOW_BEGIN};"><select name="action"><option class="sep" value="">{L_SELECT_OPTION}</option>{S_ACTION_OPTIONS}</select> <input class="btnmain" type="submit" name="update" value="{L_SUBMIT}" /></div></td>
- </tr>
- </table>
-
- <div class="pagination" style="float: {S_CONTENT_FLOW_BEGIN};">
- <!-- IF .pagination -->
- <!-- INCLUDE pagination.html -->
- <!-- ELSE -->
- {PAGE_NUMBER}
- <!-- ENDIF -->
- </div>
-
- <br />
- <br />
-
- <h1>{L_ADD_USERS}</h1>
-
- <p>{L_ADD_USERS_UCP_EXPLAIN}</p>
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="2">{L_ADD_USERS}</th>
- </tr>
- <tr>
- <td class="row1"><label for="default">{L_USER_GROUP_DEFAULT}{L_COLON}</label><br /><span>{L_USER_GROUP_DEFAULT_EXPLAIN}</span></td>
- <td class="row2"><input name="default" type="radio" class="radio" value="1" /> {L_YES} &nbsp; <input name="default" type="radio" class="radio" id="default" value="0" checked="checked" /> {L_NO}</td>
- </tr>
- <tr>
- <td class="row1"><label for="usernames">{L_USERNAME}{L_COLON}</label><br /><span>{L_USERNAMES_EXPLAIN}</span></td>
- <td class="row2"><textarea id="usernames" name="usernames" cols="40" rows="5"></textarea><br />[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</td>
- </tr>
- <tr>
- <td class="cat" colspan="2" align="center"><input class="btnmain" type="submit" name="addusers" value="{L_SUBMIT}" /></td>
- </tr>
- </table>
-
-<!-- ELSE -->
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="3">{L_USERGROUPS}</th>
- </tr>
- <tr>
- <td class="row1" colspan="3"><span class="genmed">{L_GROUPS_EXPLAIN}</span></td>
- </tr>
-
- <tr>
- <th>{L_GROUP_DETAILS}</th>
- <th colspan="2">{L_OPTIONS}</th>
- </tr>
- <tr>
- <td class="row3" colspan="3"><b class="gensmall">{L_GROUP_LEADER}</b></td>
- </tr>
- <!-- BEGIN leader -->
- <!-- IF leader.S_ROW_COUNT is odd --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td><b class="genmed"<!-- IF leader.GROUP_COLOUR --> style="color: #{leader.GROUP_COLOUR};"<!-- ENDIF -->>{leader.GROUP_NAME}</b><!-- IF leader.GROUP_DESC --><p class="forumdesc">{leader.GROUP_DESC}</p><!-- ENDIF --></td>
- <td style="text-align: center;"><a href="{leader.U_EDIT}">{L_EDIT}</a></td>
- <td style="text-align: center;"><a href="{leader.U_LIST}">{L_GROUP_LIST}</a></td>
-
- </tr>
- <!-- BEGINELSE -->
- <tr>
- <td class="row2" align="center" colspan="3"><b class="genmed">{L_NO_LEADERS}</b></td>
- </tr>
- <!-- END leader -->
-
- <tr>
- <td class="cat" align="{S_CONTENT_FLOW_END}" colspan="3">&nbsp;</td>
- </tr>
- </table>
-
-<!-- ENDIF -->
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_groups_membership.html b/phpBB/styles/subsilver2/template/ucp_groups_membership.html
deleted file mode 100644
index 846d48007e..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_groups_membership.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="3">{L_USERGROUPS}</th>
-</tr>
-<tr>
- <td class="row1" colspan="3"><span class="genmed">{L_GROUPS_EXPLAIN}</span></td>
-</tr>
-
-<tr>
- <th colspan="2">{L_GROUP_DETAILS}</th>
- <th>{L_SELECT}</th>
-</tr>
-
-<!-- BEGIN leader -->
- <!-- IF leader.S_FIRST_ROW -->
- <tr>
- <td class="row3" colspan="3"><b class="gensmall">{L_GROUP_LEADER}</b></td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF leader.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td width="6%" align="center" nowrap="nowrap"><!-- IF S_CHANGE_DEFAULT --><input type="radio" class="radio" name="default"<!-- IF leader.S_GROUP_DEFAULT --> checked="checked"<!-- ENDIF --> value="{leader.GROUP_ID}" /><!-- ENDIF --></td>
- <td>
- <b class="genmed"><a href="{leader.U_VIEW_GROUP}"<!-- IF leader.GROUP_COLOUR --> style="color: #{leader.GROUP_COLOUR};"<!-- ENDIF -->>{leader.GROUP_NAME}</a></b>
- <!-- IF leader.GROUP_DESC --><br /><span class="genmed">{leader.GROUP_DESC}</span><!-- ENDIF -->
- <!-- IF not leader.GROUP_SPECIAL --><br /><i class="gensmall">{leader.GROUP_STATUS}</i><!-- ENDIF -->
- </td>
- <td width="6%" align="center" nowrap="nowrap"><!-- IF not leader.GROUP_SPECIAL --><input type="radio" class="radio" name="selected" value="{leader.GROUP_ID}" /><!-- ENDIF --></td>
- </tr>
-<!-- END leader -->
-
-<!-- BEGIN member -->
- <!-- IF member.S_FIRST_ROW -->
- <tr>
- <td class="row3" colspan="3"><b class="gensmall">{L_GROUP_MEMBER}</b></td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF member.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td width="6%" align="center" nowrap="nowrap"><!-- IF S_CHANGE_DEFAULT --><input type="radio" class="radio" name="default"<!-- IF member.S_GROUP_DEFAULT --> checked="checked"<!-- ENDIF --> value="{member.GROUP_ID}" /><!-- ENDIF --></td>
- <td>
- <b class="genmed"><a href="{member.U_VIEW_GROUP}"<!-- IF member.GROUP_COLOUR --> style="color: #{member.GROUP_COLOUR};"<!-- ENDIF -->>{member.GROUP_NAME}</a></b>
- <!-- IF member.GROUP_DESC --><br /><span class="genmed">{member.GROUP_DESC}</span><!-- ENDIF -->
- <!-- IF not member.GROUP_SPECIAL --><br /><i class="gensmall">{member.GROUP_STATUS}</i><!-- ENDIF -->
- </td>
- <td width="6%" align="center" nowrap="nowrap"><!-- IF not member.GROUP_SPECIAL --><input type="radio" class="radio" name="selected" value="{member.GROUP_ID}" /><!-- ENDIF --></td>
- </tr>
-<!-- END member -->
-
-<!-- BEGIN pending -->
- <!-- IF pending.S_FIRST_ROW -->
- <tr>
- <td class="row3" colspan="3"><b class="gensmall">{L_GROUP_PENDING}</b></td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF pending.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td width="6%" align="center" nowrap="nowrap">&nbsp;</td>
- <td>
- <b class="genmed"><a href="{pending.U_VIEW_GROUP}"<!-- IF pending.GROUP_COLOUR --> style="color: #{pending.GROUP_COLOUR};"<!-- ENDIF -->>{pending.GROUP_NAME}</a></b>
- <!-- IF pending.GROUP_DESC --><br /><span class="genmed">{pending.GROUP_DESC}</span><!-- ENDIF -->
- <!-- IF not pending.GROUP_SPECIAL --><br /><i class="gensmall">{pending.GROUP_STATUS}</i><!-- ENDIF -->
- </td>
- <td width="6%" align="center" nowrap="nowrap"><!-- IF not pending.GROUP_SPECIAL --><input type="radio" class="radio" name="selected" value="{pending.GROUP_ID}" /><!-- ENDIF --></td>
- </tr>
-<!-- END pending -->
-
-<!-- BEGIN nonmember -->
- <!-- IF nonmember.S_FIRST_ROW -->
- <tr>
- <td class="row3" colspan="3"><b class="gensmall">{L_GROUP_NONMEMBER}</b></td>
- </tr>
- <!-- ENDIF -->
-
- <!-- IF nonmember.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td width="6%" align="center" nowrap="nowrap">&nbsp;</td>
- <td>
- <b class="genmed"><a href="{nonmember.U_VIEW_GROUP}"<!-- IF nonmember.GROUP_COLOUR --> style="color: #{nonmember.GROUP_COLOUR};"<!-- ENDIF -->>{nonmember.GROUP_NAME}</a></b>
- <!-- IF nonmember.GROUP_DESC --><br /><span class="genmed">{nonmember.GROUP_DESC}</span><!-- ENDIF -->
- <!-- IF not nonmember.GROUP_SPECIAL --><br /><i class="gensmall">{nonmember.GROUP_STATUS}</i><!-- ENDIF -->
- </td>
- <td width="6%" align="center" nowrap="nowrap"><!-- IF nonmember.S_CAN_JOIN --><input type="radio" class="radio" name="selected" value="{nonmember.GROUP_ID}" /><!-- ENDIF --></td>
- </tr>
-<!-- END nonmember -->
-
-<tr>
- <td class="cat" colspan="3"><!-- IF S_CHANGE_DEFAULT --><div style="float: {S_CONTENT_FLOW_BEGIN};"><input class="btnlite" type="submit" name="change_default" value="{L_CHANGE_DEFAULT_GROUP}" /></div><!-- ENDIF --><div style="float: {S_CONTENT_FLOW_END};"><span class="genmed">{L_SELECT}{L_COLON} </span><select name="action"><option value="join">{L_JOIN_SELECTED}</option><option value="resign">{L_RESIGN_SELECTED}</option><option value="demote">{L_DEMOTE_SELECTED}</option></select>&nbsp;<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;</div></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_header.html b/phpBB/styles/subsilver2/template/ucp_header.html
deleted file mode 100644
index dff2841b54..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_header.html
+++ /dev/null
@@ -1,165 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-
-<!-- IF S_SHOW_PM_BOX and S_POST_ACTION -->
- <form action="{S_POST_ACTION}" method="post" name="postform"{S_FORM_ENCTYPE}>
-<!-- ENDIF -->
-<table width="100%" cellspacing="0" cellpadding="0" border="0">
-<tr>
- <td width="20%" valign="top">
-
-<!-- IF S_SHOW_PM_BOX and S_POST_ACTION -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_PM_TO}</th>
- </tr>
- <!-- IF not S_ALLOW_MASS_PM -->
- <tr>
- <td class="row1"><b class="genmed">{L_USERNAME}{L_COLON}</b><br />[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</td>
- </tr>
-
- <tr>
- <td class="row2"><input class="post" type="text" name="username_list" size="20" value="" />&nbsp;<input class="post" type="submit" name="add_to" value="{L_ADD}" /></td>
- </tr>
- <!-- ELSE -->
- <tr>
- <td class="row1"><b class="genmed">{L_USERNAMES}{L_COLON}</b></td>
- </tr>
- <!-- EVENT posting_pm_header_find_username_before -->
- <tr>
- <td class="row2"><textarea name="username_list" rows="5" cols="22" tabindex="1"></textarea><br />
- [ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]
- </td>
- </tr>
- <!-- EVENT posting_pm_header_find_username_after -->
- <!-- ENDIF -->
- <!-- IF S_GROUP_OPTIONS -->
- <tr>
- <td class="row1"><b class="genmed">{L_USERGROUPS}{L_COLON}</b></td>
- </tr>
- <tr>
- <td class="row2"><select name="group_list[]" multiple="multiple" size="5" style="width:150px">{S_GROUP_OPTIONS}</select></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_ALLOW_MASS_PM -->
- <tr>
- <td class="row1"><div style="float: {S_CONTENT_FLOW_BEGIN};">&nbsp;<input class="post" type="submit" name="add_bcc" value="{L_ADD_BCC}" tabindex="1" />&nbsp;</div><div style="float: {S_CONTENT_FLOW_END};">&nbsp;<input class="post" type="submit" name="add_to" value="{L_ADD_TO}" tabindex="1" />&nbsp;</div></td>
- </tr>
- <!-- ENDIF -->
- </table>
- <div style="padding: 2px;"></div>
-<!-- ENDIF -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th>{L_OPTIONS}</th>
-</tr>
-
-<!-- BEGIN l_block1 -->
- <tr>
- <!-- IF l_block1.S_SELECTED -->
- <td class="row1"><b class="nav">{l_block1.L_TITLE}</b>
-
- <!-- IF S_PRIVMSGS -->
-
- <!-- the ! at the beginning of the loop name forces the loop to be not a nested one of l_block1 (it gets parsed separately) -->
- <!-- BEGIN !folder -->
- <!-- IF folder.S_FIRST_ROW -->
- <ul class="nav" style="margin: 0; padding: 0; list-style-type: none; line-height: 175%;">
- <!-- ENDIF -->
-
- <!-- IF folder.S_CUR_FOLDER -->
- <li class="row2" style="padding: 1px 0;">&#187; <a href="{folder.U_FOLDER}">{folder.FOLDER_NAME}<!-- IF folder.S_UNREAD_MESSAGES --> ({folder.UNREAD_MESSAGES})<!-- ENDIF --></a></li>
- <!-- ELSE -->
- <li>&#187; <a href="{folder.U_FOLDER}">{folder.FOLDER_NAME}<!-- IF folder.S_UNREAD_MESSAGES --> ({folder.UNREAD_MESSAGES})<!-- ENDIF --></a></li>
- <!-- ENDIF -->
-
- <!-- IF folder.S_LAST_ROW -->
- </ul>
- <hr />
- <!-- ENDIF -->
- <!-- END !folder -->
-
- <!-- ENDIF -->
-
- <ul class="nav" style="margin: 0; padding: 0; list-style-type: none; line-height: 175%;">
- <!-- BEGIN l_block2 -->
- <li>&#187; <!-- IF l_block1.l_block2.S_SELECTED --><b>{l_block1.l_block2.L_TITLE}</b><!-- ELSE --><a href="{l_block1.l_block2.U_TITLE}">{l_block1.l_block2.L_TITLE}</a><!-- ENDIF --></li>
- <!-- END l_block2 -->
- </ul>
- <!-- ELSE -->
- <td class="row2" nowrap="nowrap" onmouseover="this.className='row1'" onmouseout="this.className='row2'" onclick="location.href=this.firstChild.href;"><a class="nav" href="{l_block1.U_TITLE}">{l_block1.L_TITLE}</a>
- <!-- ENDIF -->
- </td>
- </tr>
-<!-- END l_block1 -->
-</table>
-
-<div style="padding: 2px;"></div>
-
-<!-- IF S_SHOW_COLOUR_LEGEND -->
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
- <tr>
- <th colspan="2">{L_MESSAGE_COLOURS}</th>
- </tr>
- <!-- BEGIN pm_colour_info -->
- <tr>
- <!-- IF not pm_colour_info.IMG -->
- <td class="row1 {pm_colour_info.CLASS}" width="5"><img src="images/spacer.gif" width="5" alt="{pm_colour_info.LANG}" /></td>
- <!-- ELSE -->
- <td class="row1" width="25" align="center">{pm_colour_info.IMG}</td>
- <!-- ENDIF -->
- <td class="row1"><span class="genmed">{pm_colour_info.LANG}</span></td>
- </tr>
- <!-- END pm_colour_info -->
- </table>
-
- <div style="padding: 2px;"></div>
-<!-- ENDIF -->
-
-<!-- IF S_ZEBRA_ENABLED and S_ZEBRA_FRIENDS_ENABLED -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{L_FRIENDS}</th>
- </tr>
- <tr>
- <td class="row1" align="center">
-
- <b class="genmed online">{L_FRIENDS_ONLINE}</b>
-
- <ul class="nav" style="margin: 0; padding: 0; list-style-type: none; line-height: 175%;">
- <!-- BEGIN friends_online -->
- <li>{friends_online.USERNAME_FULL}
- <!-- IF S_SHOW_PM_BOX -->
- &nbsp;[ <input class="post" style="font-size: 90%;" type="submit" name="add_to[{friends_online.USER_ID}]" value="{L_ADD}" /> ]
- <!-- ENDIF -->
- </li>
- <!-- BEGINELSE -->
- <li>{L_NO_FRIENDS_ONLINE}</li>
- <!-- END friends_online -->
- </ul>
-
- <hr />
-
- <b class="genmed offline">{L_FRIENDS_OFFLINE}</b>
-
- <ul class="nav" style="margin: 0; padding: 0; list-style-type: none; line-height: 175%;">
- <!-- BEGIN friends_offline -->
- <li>{friends_offline.USERNAME_FULL}
- <!-- IF S_SHOW_PM_BOX -->
- &nbsp;[ <input class="post" style="font-size: 90%;" type="submit" name="add_to[{friends_offline.USER_ID}]" value="{L_ADD}" /> ]
- <!-- ENDIF -->
- </li>
- <!-- BEGINELSE -->
- <li>{L_NO_FRIENDS_OFFLINE}</li>
- <!-- END friends_offline -->
- </ul>
-
- </td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-</td>
-<td><img src="images/spacer.gif" width="4" alt="" /></td>
-<td width="80%" valign="top"><!-- IF not S_PRIVMSGS or S_SHOW_DRAFTS --><form name="ucp" id="ucp" method="post" action="{S_UCP_ACTION}"{S_FORM_ENCTYPE}><!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/ucp_login_link.html b/phpBB/styles/subsilver2/template/ucp_login_link.html
deleted file mode 100644
index 6db9890d8c..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_login_link.html
+++ /dev/null
@@ -1,74 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th>{SITENAME} - {L_LOGIN_LINK}</th>
- </tr>
-
- <tr>
- <td class="row1" align="center"><span class="genmed">{L_LOGIN_LINK_EXPLAIN}</span></td>
- </tr>
-
- <!-- IF LOGIN_LINK_ERROR -->
- <tr>
- <td class="row1" align="center"><span class="genmed error">{LOGIN_LINK_ERROR}</span></td>
- </tr>
- <!-- ENDIF -->
-
- <tr>
- <td class="row1">
- <form action="{REGISTER_ACTION}" method="post" id="register">
- <table width="100%" cellspacing="1">
- <tr>
- <th colspan="2">{L_REGISTER}</th>
- </tr>
-
- <tr>
- <td>{S_HIDDEN_FIELDS}<input type="submit" name="register" tabindex="1" value="{L_REGISTER}" class="button1" /></td>
- </tr>
- </table>
- </form>
- </td>
- </tr>
-
- <tr>
- <td class="row1">
- <form action="{LOGIN_ACTION}" method="post" id="login">
- <table width="100%" cellspacing="1">
- <tr>
- <th colspan="2">{L_LOGIN}</th>
- </tr>
-
- <!-- IF LOGIN_ERROR -->
- <tr>
- <td class="row1" align="center" colspan="2"><span class="genmed error">{LOGIN_ERROR}</span></td>
- </tr>
- <!-- ENDIF -->
-
- <tr>
- <td><label for="{USERNAME_CREDENTIAL}">{L_USERNAME}{L_COLON}</label></td>
- <td><input type="text" tabindex="2" name="{USERNAME_CREDENTIAL}" id="{USERNAME_CREDENTIAL}" size="25" value="{LOGIN_USERNAME}" class="inputbox autowidth" /></td>
- </tr>
-
- <tr>
- <td><label for="{PASSWORD_CREDENTIAL}">{L_PASSWORD}{L_COLON}</label></td>
- <td><input type="password" tabindex="3" id="{PASSWORD_CREDENTIAL}" name="{PASSWORD_CREDENTIAL}" size="25" class="inputbox autowidth" autocomplete="off" /></td>
- </tr>
-
- <!-- IF CAPTCHA_TEMPLATE and S_CONFIRM_CODE -->
- <!-- DEFINE $CAPTCHA_TAB_INDEX = 4 -->
- <!-- INCLUDE {CAPTCHA_TEMPLATE} -->
- <!-- ENDIF -->
-
- {S_LOGIN_REDIRECT}
- <tr>
- <td>&nbsp;</td>
- <td>{S_HIDDEN_FIELDS}<input type="submit" name="login" tabindex="5" value="{L_LOGIN}" class="button1" /></td>
- </tr>
- </table>
- </form>
- </td>
- </tr>
-</table>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_main_bookmarks.html b/phpBB/styles/subsilver2/template/ucp_main_bookmarks.html
deleted file mode 100644
index e91417503f..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_main_bookmarks.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="4">{L_UCP}</th>
-</tr>
-<tr>
- <td class="row1" colspan="4" align="center"><span class="genmed">{L_BOOKMARKS_EXPLAIN}</span></td>
-</tr>
-<!-- IF .topicrow -->
-<tr>
- <th colspan="4">{L_BOOKMARKS}</th>
-</tr>
-<!-- ENDIF -->
-
-<!-- IF S_NO_DISPLAY_BOOKMARKS -->
- <tr class="row1">
- <td colspan="4" align="center"><b class="genmed">{L_BOOKMARKS_DISABLED}</b></td>
- </tr>
-<!-- ELSE -->
-
- <!-- IF TOTAL_TOPICS -->
- <tr>
- <td class="row3" colspan="4">
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ {TOTAL_TOPICS} ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- ENDIF -->
-
- <!-- BEGIN topicrow -->
-
- <!-- IF topicrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td style="padding: 4px;" width="20" align="center" valign="middle">{topicrow.TOPIC_FOLDER_IMG}</td>
- <!-- IF topicrow.S_DELETED_TOPIC -->
- <td class="postdetails" style="padding: 4px" width="100%" colspan="2">{L_DELETED_TOPIC}</td>
- <!-- ELSE -->
- <td style="padding: 4px;" width="100%" valign="top">
- <p class="topictitle"><!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF -->{topicrow.ATTACH_ICON_IMG} <a href="{topicrow.U_VIEW_TOPIC}">{topicrow.TOPIC_TITLE}</a></p>
- <!-- IF topicrow.S_GLOBAL_TOPIC --><span class="gensmall">{L_GLOBAL_ANNOUNCEMENT}</span><!-- ELSE --><span class="gensmall"><b>{L_FORUM}{L_COLON} </b><a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a></span><!-- ENDIF -->
- <!-- IF .topicrow.pagination -->
- <p class="gensmall"> [ {GOTO_PAGE_IMG}{L_GOTO_PAGE}{L_COLON}
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><strong>{topicrow.pagination.PAGE_NUMBER}</strong>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --> {L_ELLIPSIS}
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a>
- <!-- ENDIF -->
- <!-- END pagination -->
- ] </p>
- <!-- ENDIF -->
- </td>
- <td style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top" nowrap="nowrap">
- <p class="topicdetails">{topicrow.LAST_POST_TIME}</p>
- <p class="topicdetails">{topicrow.LAST_POST_AUTHOR_FULL}
- <a href="{topicrow.U_LAST_POST}">{LAST_POST_IMG}</a>
- </p>
- </td>
- <!-- ENDIF -->
- <td style="padding: 4px;"> <input type="checkbox" class="radio" name="t[{topicrow.TOPIC_ID}]" /> </td>
- </tr>
- <!-- BEGINELSE -->
- <tr class="row1">
- <td colspan="4" align="center"><b class="genmed">{L_NO_BOOKMARKS}</b></td>
- </tr>
- <!-- END topicrow -->
-
- <!-- IF .topicrow -->
- <tr>
- <td class="cat" colspan="5" align="{S_CONTENT_FLOW_END}"><input class="btnlite" type="submit" name="unbookmark" value="{L_REMOVE_BOOKMARK_MARKED}" />&nbsp;</td>
- </tr>
- <!-- ENDIF -->
- <!-- ENDIF -->
-</table>
-
-<!-- IF not S_NO_DISPLAY_BOOKMARKS and .topicrow -->
- <div class="gensmall" style="float: {S_CONTENT_FLOW_END}; padding-top: 2px;"><b><a href="#" onclick="marklist('ucp', 't', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('ucp', 't', false); return false;">{L_UNMARK_ALL}</a></b></div>
-<!-- ENDIF -->
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_main_drafts.html b/phpBB/styles/subsilver2/template/ucp_main_drafts.html
deleted file mode 100644
index d63d678250..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_main_drafts.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="4">{L_UCP}</th>
-</tr>
-<tr>
- <td class="row1" colspan="4" align="center"><span class="genmed">{L_DRAFTS_EXPLAIN}</span></td>
-</tr>
-
-<!-- IF ERROR -->
- <tr>
- <td class="row1" colspan="2" align="center"><span class="genmed error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF not S_EDIT_DRAFT -->
-
- <!-- IF S_DRAFT_ROWS -->
- <tr>
- <th>{L_SAVE_DATE}</th>
- <th>{L_DRAFT_TITLE}</th>
- <th>{L_OPTIONS}</th>
- <th>{L_DELETE}</th>
- </tr>
- <!-- ENDIF -->
-
- <!-- BEGIN draftrow -->
-
- <!-- IF draftrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td class="postdetails" style="padding: 4px;" nowrap="nowrap">{draftrow.DATE}</td>
- <td style="padding: 4px;" valign="top" width="100%">
- <p class="topictitle">{draftrow.DRAFT_SUBJECT}</p>
- <!-- IF draftrow.S_LINK_TOPIC --><span class="gensmall">{L_TOPIC}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a></span>
- <!-- ELSEIF draftrow.S_LINK_FORUM --><span class="gensmall">{L_FORUM}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a></span>
- <!-- ELSEIF draftrow.S_LINK_PM --><span class="gensmall">{L_PRIVATE_MESSAGE}</span>
- <!-- ELSE --><span class="gensmall">{L_NO_TOPIC_FORUM}</span><!-- ENDIF -->
- </td>
- <td style="padding: 4px;" align="center" nowrap="nowrap"><span class="genmed"><!-- IF draftrow.U_INSERT --><a href="{draftrow.U_INSERT}">{L_LOAD_DRAFT}</a><br /><!-- ENDIF --><a href="{draftrow.U_VIEW_EDIT}">{L_VIEW_EDIT}</a></span></td>
- <td style="padding: 4px;" align="center"><input type="checkbox" class="radio" name="d[{draftrow.DRAFT_ID}]" /></td>
- </tr>
- <!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="4" align="center"><b class="genmed">{L_NO_SAVED_DRAFTS}</b></td>
- </tr>
- <!-- END draftrow -->
-
- <!-- IF S_DRAFT_ROWS -->
- <tr>
- <td class="cat" colspan="4" align="{S_CONTENT_FLOW_END}"><input class="btnlite" type="submit" name="delete" value="{L_DELETE_MARKED}" />&nbsp;</td>
- </tr>
- <!-- ENDIF -->
-
-<!-- ELSEIF S_EDIT_DRAFT -->
- <tr>
- <td class="row1" width="22%"><b class="genmed">{L_SUBJECT}{L_COLON}</b></td>
- <td class="row2"><input class="post" style="width:450px" type="text" name="subject" size="45" maxlength="64" tabindex="2" value="{DRAFT_SUBJECT}" /></td>
- </tr>
- <tr>
- <td class="row1" width="22%"><b class="genmed">{L_MESSAGE}{L_COLON} </b><br /><span class="gensmall">{L_EDIT_DRAFT_EXPLAIN}</span></td>
- <td class="row2">
- <script type="text/javascript">
- // <![CDATA[
- var form_name = 'ucp';
- var text_name = 'message';
- // ]]>
- </script>
- <table cellspacing="0" cellpadding="2" border="0">
- <!-- INCLUDE posting_buttons.html -->
- <tr>
- <td colspan="9"><textarea class="post" name="message" rows="10" cols="70" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" onfocus="initInsertions();">{DRAFT_MESSAGE}</textarea></td>
- </tr>
- <tr>
- <td colspan="9">
- <table cellspacing="0" cellpadding="0" border="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}" id="color_palette_placeholder" data-orientation="h" data-width="11" data-height="10" data-bbcode="true">
- </td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <tr class="row1">
- <td colspan="9" align="{S_CONTENT_FLOW_BEGIN}"><p class="topictitle"><a href="{S_UCP_ACTION}">{L_BACK_TO_DRAFTS}</a></p></td>
- </tr>
- <tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
- </tr>
-<!-- ENDIF -->
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_main_front.html b/phpBB/styles/subsilver2/template/ucp_main_front.html
deleted file mode 100644
index 485a58b7ab..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_main_front.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="3">{L_UCP}</th>
-</tr>
-<tr>
- <td class="row1" colspan="3" align="center"><p class="genmed">{L_UCP_WELCOME}</p></td>
-</tr>
-<tr>
- <th colspan="3">{L_IMPORTANT_NEWS}</th>
-</tr>
-
-<!-- BEGIN topicrow -->
-
- <!-- IF topicrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td class="row1" width="25" align="center">{topicrow.TOPIC_FOLDER_IMG}</td>
- <td class="row1" width="100%">
- <p class="topictitle"><!-- IF topicrow.S_UNREAD --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF -->{topicrow.ATTACH_ICON_IMG} <a href="{topicrow.U_VIEW_TOPIC}">{topicrow.TOPIC_TITLE}</a></p><p class="gensmall">{topicrow.GOTO_PAGE}</p>
- </td>
- <td class="row1" width="120" align="center" nowrap="nowrap">
- <p class="topicdetails">{topicrow.LAST_POST_TIME}</p>
- <p class="topicdetails">{topicrow.LAST_POST_AUTHOR_FULL}
- <a href="{topicrow.U_LAST_POST}">{LAST_POST_IMG}</a>
- </p>
- </td>
- </tr>
-<!-- BEGINELSE -->
- <tr class="row1">
- <td align="center" colspan="3"><b class="gen">{L_NO_IMPORTANT_NEWS}</b></td>
- </tr>
-<!-- END topicrow -->
-
-<tr>
- <th colspan="3">{L_YOUR_DETAILS}</th>
-</tr>
-<tr>
-<!-- EVENT ucp_main_front_user_activity_before -->
- <td class="row1" colspan="3">
- <table width="100%" cellspacing="1" cellpadding="4">
- <!-- EVENT ucp_main_front_user_activity_prepend -->
- <tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="genmed">{L_JOINED}{L_COLON} </b></td>
- <td width="100%"><b class="gen">{JOINED}</b></td>
- </tr>
- <tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="genmed">{L_TOTAL_POSTS}{L_COLON} </b></td>
- <td><!-- IF POSTS_PCT --><b class="gen">{POSTS}</b><br /><span class="genmed">[{POSTS_PCT} / {POSTS_DAY}]<!-- IF S_DISPLAY_SEARCH --><br /><a href="{U_SEARCH_SELF}">{L_SEARCH_YOUR_POSTS}</a><!-- ENDIF --></span><!-- ELSE --><b class="gen">{POSTS}<b><!-- ENDIF --></td>
- </tr>
- <!-- IF S_SHOW_ACTIVITY -->
- <tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="genmed">{L_ACTIVE_IN_FORUM}{L_COLON} </b></td>
- <td><!-- IF ACTIVE_FORUM != '' --><b><a class="gen" href="{U_ACTIVE_FORUM}">{ACTIVE_FORUM}</a></b><br /><span class="genmed">[ {ACTIVE_FORUM_POSTS} / {ACTIVE_FORUM_PCT} ]</span><!-- ELSE --><span class="gen">-</span><!-- ENDIF --></td>
- </tr>
- <tr>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><b class="genmed">{L_ACTIVE_IN_TOPIC}{L_COLON} </b></td>
- <td><!-- IF ACTIVE_TOPIC != '' --><b><a class="gen" href="{U_ACTIVE_TOPIC}">{ACTIVE_TOPIC}</a></b><br /><span class="genmed">[ {ACTIVE_TOPIC_POSTS} / {ACTIVE_TOPIC_PCT} ]</span><!-- ELSE --><span class="gen">-</span><!-- ENDIF --></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF WARNINGS -->
- <tr>
- <td align="{S_CONTENT_FLOW_END}" valign="middle" nowrap="nowrap"><b class="genmed">{L_YOUR_WARNINGS}{L_COLON} </b></td>
- <td class="genmed">{WARNING_IMG} [ <b>{WARNINGS}</b> ]</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT ucp_main_front_user_activity_append -->
- </table>
- </td>
-<!-- EVENT ucp_main_front_user_activity_after -->
-</tr>
-<tr>
- <td class="cat" colspan="3">&nbsp;</td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_main_subscribed.html b/phpBB/styles/subsilver2/template/ucp_main_subscribed.html
deleted file mode 100644
index c6ae1b6cab..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_main_subscribed.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="4">{L_UCP}</th>
-</tr>
-<tr>
- <td class="row1" colspan="4" align="center"><span class="genmed">{L_WATCHED_EXPLAIN}</span></td>
-</tr>
-<!-- IF S_FORUM_NOTIFY -->
- <tr>
- <th colspan="4">{L_WATCHED_FORUMS}</th>
- </tr>
-
- <!-- BEGIN forumrow -->
-
- <!-- IF forumrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td style="padding: 4px;" width="20" align="center" valign="middle">{forumrow.FORUM_FOLDER_IMG}</td>
- <td style="padding: 4px;" width="100%"><p class="topictitle"><a href="{forumrow.U_VIEWFORUM}">{forumrow.FORUM_NAME}</a></p></td>
- <td class="gensmall" style="padding: 4px;" align="center" valign="middle" nowrap="nowrap"><!-- IF forumrow.LAST_POST_TIME -->{forumrow.LAST_POST_TIME}<br />{forumrow.LAST_POST_AUTHOR_FULL} <a href="{forumrow.U_LAST_POST}" class="imageset">{LAST_POST_IMG}</a><!-- ELSE -->{L_NO_POSTS}<!-- ENDIF --></td>
- <td style="padding: 4px;"> <input type="checkbox" class="radio" name="f[{forumrow.FORUM_ID}]" /> </td>
- </tr>
- <!-- BEGINELSE -->
- <tr class="row1">
- <td colspan="4" align="center"><b class="genmed">{L_NO_WATCHED_FORUMS}</b></td>
- </tr>
- <!-- END forumrow -->
-<!-- ENDIF -->
-<!-- IF S_TOPIC_NOTIFY -->
- <tr>
- <th colspan="4">{L_WATCHED_TOPICS}</th>
- </tr>
-
- <!-- IF TOTAL_TOPICS -->
- <tr>
- <td class="row3" colspan="4">
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ {TOTAL_TOPICS} ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- ENDIF -->
-
- <!-- BEGIN topicrow -->
-
- <!-- IF topicrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td style="padding: 4px;" width="20" align="center" valign="middle">{topicrow.TOPIC_FOLDER_IMG}</td>
- <td style="padding: 4px;" width="100%" valign="top">
- <p class="topictitle">
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="imageset">{NEWEST_POST_IMG}</a> <!-- ENDIF -->{topicrow.ATTACH_ICON_IMG}<a href="{topicrow.U_VIEW_TOPIC}">{topicrow.TOPIC_TITLE}</a>
- </p>
- <!-- IF topicrow.S_GLOBAL_TOPIC --><span class="gensmall">{L_GLOBAL_ANNOUNCEMENT}</span><!-- ELSE --><span class="gensmall"><b>{L_FORUM}{L_COLON} </b><a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a></span><!-- ENDIF -->
- <!-- IF .topicrow.pagination -->
- <p class="gensmall"> [ {GOTO_PAGE_IMG}{L_GOTO_PAGE}{L_COLON}
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><strong>{topicrow.pagination.PAGE_NUMBER}</strong>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --> {L_ELLIPSIS}
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a>
- <!-- ENDIF -->
- <!-- END pagination -->
- ] </p>
- <!-- ENDIF -->
- </td>
- <td style="padding: 4px;" align="{S_CONTENT_FLOW_BEGIN}" valign="top" nowrap="nowrap">
- <p class="topicdetails">{topicrow.LAST_POST_TIME}</p>
- <p class="topicdetails">{topicrow.LAST_POST_AUTHOR_FULL}
- <a href="{topicrow.U_LAST_POST}" class="imageset">{LAST_POST_IMG}</a>
- </p>
- </td>
- <td style="padding: 4px;"> <input type="checkbox" class="radio" name="t[{topicrow.TOPIC_ID}]" /> </td>
- </tr>
- <!-- BEGINELSE -->
- <tr class="row1">
- <td colspan="4" align="center"><b class="genmed">{L_NO_WATCHED_TOPICS}</b></td>
- </tr>
- <!-- END topicrow -->
-<!-- ENDIF -->
-
-<!-- IF .topicrow or .forumrow -->
-<tr>
- <td class="cat" colspan="4" align="{S_CONTENT_FLOW_END}"><input class="btnlite" type="submit" name="unwatch" value="{L_UNWATCH_MARKED}" />&nbsp;</td>
-</tr>
-<!-- ENDIF -->
-</table>
-<!-- IF .topicrow or .forumrow -->
-<div class="gensmall" style="float: {S_CONTENT_FLOW_END}; padding-top: 2px;"><b><a href="#" onclick="marklist('ucp', 't', true); marklist('ucp', 'f', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('ucp', 't', false);marklist('ucp', 'f', false); return false;">{L_UNMARK_ALL}</a></b></div>
-<!-- ENDIF -->
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_notifications.html b/phpBB/styles/subsilver2/template/ucp_notifications.html
deleted file mode 100644
index b0d2925b68..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_notifications.html
+++ /dev/null
@@ -1,141 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<form id="ucp" method="post" action="{S_UCP_ACTION}"{S_FORM_ENCTYPE}>
-
-<!-- IF MODE == 'notification_options' -->
- <table width="100%" cellspacing="1">
- <tr>
- <th colspan="{NOTIFICATION_TYPES_COLS}">{TITLE}</th>
- </tr>
- <tr>
- <td class="row1" colspan="{NOTIFICATION_TYPES_COLS}" align="center"><span class="genmed">{TITLE_EXPLAIN}</span></td>
- </tr>
- <tr>
- <th>{L_NOTIFICATION_TYPE}</th>
- <th width="10%">{L_NOTIFICATIONS}</th>
- <!-- BEGIN notification_methods -->
- <th width="10%">{notification_methods.NAME}</th>
- <!-- END notification_methods -->
- </tr>
-
- <!-- BEGIN notification_types -->
- <!-- IF notification_types.GROUP_NAME -->
- <tr>
- <td class="row3" colspan="{NOTIFICATION_TYPES_COLS}">{notification_types.GROUP_NAME}</td>
- </tr>
- <!-- ELSE -->
- <!-- IF notification_types.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td>
- {notification_types.NAME}
- <!-- IF notification_types.EXPLAIN --><br />&nbsp; &nbsp;{notification_types.EXPLAIN}<!-- ENDIF -->
- </td>
- <td align="center"><input type="checkbox" name="{notification_types.TYPE}_notification"<!-- IF notification_types.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
- <!-- BEGIN notification_methods -->
- <td align="center"><input type="checkbox" name="{notification_types.TYPE}_{notification_methods.METHOD}"<!-- IF notification_methods.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
- <!-- END notification_methods -->
- </tr>
- <!-- ENDIF -->
- <!-- END notification_types -->
- <tr>
- <td class="cat" colspan="{NOTIFICATION_TYPES_COLS}" align="center">
- <input type="hidden" name="form_time" value="{FORM_TIME}" />
- {S_HIDDEN_FIELDS}
- <input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;
- <input class="btnlite" type="reset" value="{L_RESET}" name="reset" />
- {S_FORM_TOKEN}
- </td>
- </tr>
- </table>
-<!-- ELSE -->
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
- <tr>
- <td class="row1">
- <table border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}">
- <!-- IF TOTAL_COUNT -->
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}</td>
- <td class="gensmall" nowrap="nowrap" width="100%">&nbsp;{L_NOTIFICATIONS} [ <b>{TOTAL_COUNT}</b> ]&nbsp;</td>
- </tr>
- </table>
- <!-- ENDIF -->
- </td>
- <td align="{S_CONTENT_FLOW_END}"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
-
- <div class="notification_list">
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat" colspan="3">
- <table width="100%" cellspacing="0">
- <tr class="nav">
- <td align="{S_CONTENT_FLOW_END}" valign="middle"><!-- IF U_MARK_ALL --><a href="{U_MARK_ALL}">{L_NOTIFICATIONS_MARK_ALL_READ}</a><!-- ENDIF --></td>
- </tr>
- </table>
- </td>
- </tr>
- <tr>
- <th colspan="2">{L_NOTIFICATIONS}</th>
- <th width="15%">{L_MARK_READ}</th>
- </tr>
- <!-- BEGIN notification_list -->
- <tr class="row<!-- IF notification_list.UNREAD -->3<!-- ELSEIF notification_list.S_ROW_COUNT is even -->1<!-- ELSE -->2<!-- ENDIF -->">
- <td width="50">
- <!-- IF notification_list.AVATAR -->{notification_list.AVATAR}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF -->
- </td>
- <td valign="top">
- <span class="gen">
- <!-- IF notification_list.URL --><a href="<!-- IF notification_list.UNREAD -->{notification_list.U_MARK_READ}<!-- ELSE -->{notification_list.URL}<!-- ENDIF -->"><!-- ENDIF -->
- {notification_list.FORMATTED_TITLE}<!-- IF notification_list.REFERENCE --> {notification_list.REFERENCE}<!-- ENDIF -->
- <!-- IF notification_list.URL --></a><!-- ENDIF --><br />
- <!-- IF notification_list.FORUM --><span class="notifications_forum">{notification_list.FORUM}</span><br /><!-- ENDIF -->
- <!-- IF notification_list.REASON --><span class="notifications_reason">{notification_list.REASON}</span><br /><!-- ENDIF -->
- <span class="notifications_time">{notification_list.TIME}</span>
- </span>
- </td>
- <td align="center">
- <input type="checkbox" name="mark[]" value="{notification_list.NOTIFICATION_ID}"<!-- IF not notification_list.UNREAD --> disabled="disabled"<!-- ENDIF --> />
- </td>
- </tr>
- <!-- END notification_list -->
- <tr>
- <td class="cat" colspan="3" align="center">
- <input type="hidden" name="form_time" value="{FORM_TIME}" />
- {S_HIDDEN_FIELDS}
- <input class="btnmain" type="submit" name="submit" value="{L_MARK_READ}" />
- {S_FORM_TOKEN}
- </td>
- </tr>
- </table>
- </div>
-
- <!-- IF .pagination -->
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
- <tr>
- <td class="row1">
- <table border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}">
- <!-- INCLUDE pagination.html -->
- </td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- <!-- ENDIF -->
-<!-- ENDIF -->
-
-<!-- IF .notifications -->
-<div class="gensmall" style="float: {S_CONTENT_FLOW_END}; padding-top: 2px;"><b><a href="#" onclick="$('#ucp input:checkbox').prop('checked', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="$('#ucp input:checkbox').prop('checked', false); return false;">{L_UNMARK_ALL}</a></b></div>
-<!-- ENDIF -->
-
-</form>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_history.html b/phpBB/styles/subsilver2/template/ucp_pm_history.html
deleted file mode 100644
index b478431fa5..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_pm_history.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!-- EVENT ucp_pm_history_review_before -->
-<script type="text/javascript">
-// <![CDATA[
- bbcodeEnabled = {S_BBCODE_ALLOWED};
-// ]]>
-</script>
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th align="center">{L_MESSAGE_HISTORY}</th>
-</tr>
-<tr>
- <td class="row1"><div style="overflow: auto; width: 100%; height: 300px;">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th width="22%">{L_AUTHOR}</th>
- <th>{L_MESSAGE}</th>
- </tr>
- <!-- BEGIN history_row -->
- <!-- IF history_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td rowspan="2" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><a name="{history_row.MSG_ID}" class="anchor"></a>
- <table width="150" cellspacing="0">
- <tr>
- <td align="center" colspan="2"><span class="postauthor">{history_row.MESSAGE_AUTHOR_FULL}</span></td>
- </tr>
- </table>
- </td>
- <td width="100%"<!-- IF history_row.S_CURRENT_MSG --> class="current"<!-- ENDIF -->>
- <div class="gensmall" style="float: {S_CONTENT_FLOW_BEGIN};"><b>{L_PM_SUBJECT}{L_COLON}</b>&nbsp;{history_row.SUBJECT}</div><div class="gensmall" style="float: {S_CONTENT_FLOW_END};"><b>{L_FOLDER}{L_COLON}</b>&nbsp;{history_row.FOLDER}</div>
- </td>
- </tr>
-
- <!-- IF history_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td valign="top">
- <table width="100%" cellspacing="0">
- <tr>
- <td valign="top">
- <table width="100%" cellspacing="0" cellpadding="2">
- <tr>
- <td><div class="postbody"><!-- IF history_row.MESSAGE -->{history_row.MESSAGE}<!-- ELSE --><span class="error">{L_MESSAGE_REMOVED_FROM_OUTBOX}</span><!-- ENDIF --></div><div id="message_{history_row.MSG_ID}" style="display: none;">{history_row.DECODED_MESSAGE}</div></td>
- </tr>
- </table>
- </td>
- </tr>
- <tr>
- <td>
- <table width="100%" cellspacing="0">
- <tr valign="middle">
- <td width="100%">&nbsp;</td>
- <td width="10" nowrap="nowrap">{history_row.MINI_POST_IMG}</td>
- <td class="gensmall" nowrap="nowrap"><b>{L_SENT_AT}{L_COLON}</b> {history_row.SENT_DATE}</td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
- </tr>
-
- <!-- IF history_row.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td class="gensmall"><a href="{history_row.U_VIEW_MESSAGE}">{L_VIEW_PM}</a></td>
- <td>
- <div class="gensmall" style="float: {S_CONTENT_FLOW_BEGIN};">
- &nbsp;<!-- IF history_row.U_PROFILE --><a href="{history_row.U_PROFILE}" class="imageset">{PROFILE_IMG}</a> <!-- ENDIF -->
- <!-- IF history_row.U_EMAIL --><a href="{history_row.U_EMAIL}" class="imageset">{EMAIL_IMG}</a> <!-- ENDIF -->&nbsp;
- </div>
- <div class="gensmall" style="float: {S_CONTENT_FLOW_END};">
- <!-- EVENT ucp_pm_history_post_buttons_before -->
- <!-- IF history_row.U_QUOTE or history_row.MESSAGE_AUTHOR_QUOTE --> <a <!-- IF history_row.U_QUOTE -->href="{history_row.U_QUOTE}"<!-- ELSE -->href="#" onclick="addquote({history_row.MSG_ID}, '{history_row.MESSAGE_AUTHOR_QUOTE}', '{LA_WROTE}'); return false;"<!-- ENDIF --> class="imageset">{QUOTE_IMG}</a> <!-- ENDIF -->
- <!-- IF history_row.U_POST_REPLY_PM --><a href="{history_row.U_POST_REPLY_PM}" class="imageset">{REPLY_IMG}</a><!-- ENDIF -->&nbsp;
- <!-- EVENT ucp_pm_history_post_buttons_after -->
- </div>
- </td>
- </tr>
- <tr>
- <td class="spacer" colspan="2"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
- </tr>
- <!-- END history_row -->
- </table>
- </div></td>
-</tr>
-</table>
-<!-- EVENT ucp_pm_history_review_after -->
-
-<br clear="all" />
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_message_footer.html b/phpBB/styles/subsilver2/template/ucp_pm_message_footer.html
deleted file mode 100644
index 20c5c7fe9f..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_pm_message_footer.html
+++ /dev/null
@@ -1,47 +0,0 @@
-
-<!-- IF not S_VIEW_MESSAGE -->
- {S_FORM_TOKEN}
- </form>
-<!-- ENDIF -->
-
-<table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
-<tr>
- <td class="row1">
- <table border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}"><!-- INCLUDE pagination.html -->
- <!-- IF S_VIEW_MESSAGE -->
- <span class="gensmall">
- <!-- IF U_PRINT_PM --><a href="{U_PRINT_PM}" title="{L_PRINT_PM}">{L_PRINT_PM}</a><!-- IF U_FORWARD_PM --> | <!-- ENDIF --><!-- ENDIF -->
- <!-- IF U_FORWARD_PM --><a href="{U_FORWARD_PM}" title="{L_FORWARD_PM}">{L_FORWARD_PM}</a><!-- ENDIF -->
- <!-- IF U_POST_REPLY_PM and S_PM_RECIPIENTS gt 1 --><!-- IF U_PRINT_PM or U_FORWARD_PM --> | <!-- ENDIF --><a title="{L_REPLY_TO_ALL}" href="{U_POST_REPLY_ALL}">{L_REPLY_TO_ALL}</a><!-- ENDIF -->
- </span>
- <!-- ENDIF -->
- </td>
- <td align="{S_CONTENT_FLOW_END}" nowrap="nowrap">
- <!-- IF S_VIEW_MESSAGE -->
- <!-- IF not S_SPECIAL_FOLDER -->
- <form name="movepm" method="post" action="{S_PM_ACTION}" style="margin:0px">
- <input type="hidden" name="marked_msg_id[]" value="{MSG_ID}" />
- <input type="hidden" name="cur_folder_id" value="{CUR_FOLDER_ID}" />
- <input type="hidden" name="p" value="{MSG_ID}" />
- <select name="dest_folder">{S_TO_FOLDER_OPTIONS}</select>&nbsp;<input class="btnlite" type="submit" name="move_pm" value="{L_MOVE_TO_FOLDER}" />
- {S_FORM_TOKEN}
- </form>
- <!-- ENDIF -->
- <!-- ELSE -->
- <form name="sortmsg" method="post" action="{S_PM_ACTION}" style="margin:0px">
- <span class="gensmall">{L_DISPLAY_MESSAGES}{L_COLON}</span> {S_SELECT_SORT_DAYS} <span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR} <input class="btnlite" type="submit" name="sort" value="{L_GO}" />
- {S_FORM_TOKEN}
- </form>
- <!-- ENDIF -->
- </td>
- </tr>
- </table>
- </td>
-</tr>
-</table>
-
-<!-- IF not S_VIEW_MESSAGE -->
- <div style="float: {S_CONTENT_FLOW_END};"><b class="gensmall"><a href="#" onclick="marklist('viewfolder', 'marked_msg_id', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('viewfolder', 'marked_msg_id', false); return false;">{L_UNMARK_ALL}</a></b></div>
-<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_message_header.html b/phpBB/styles/subsilver2/template/ucp_pm_message_header.html
deleted file mode 100644
index 370fa673dd..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_pm_message_header.html
+++ /dev/null
@@ -1,34 +0,0 @@
-
-<table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
-<tr>
- <td class="row1">
- <table border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}">
- <!-- IF TOTAL_MESSAGES -->
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <!-- IF FOLDER_MAX_MESSAGES neq 0 -->
- <td class="gensmall" nowrap="nowrap" width="100%">&nbsp;[ <b>{FOLDER_CUR_MESSAGES}</b>/{FOLDER_MAX_MESSAGES} {L_MESSAGES} ({FOLDER_PERCENT}%) ]&nbsp;</td>
- <!-- ELSE -->
- <td class="gensmall" nowrap="nowrap" width="100%">&nbsp;[ <b>{FOLDER_CUR_MESSAGES}</b> {L_MESSAGES} ]&nbsp;</td>
- <!-- ENDIF -->
- </tr>
- </table>
- <!-- ENDIF -->
-
- <!-- IF S_VIEW_MESSAGE -->
- <span class="gensmall">
- <!-- IF S_DISPLAY_HISTORY -->
- <!-- IF U_VIEW_PREVIOUS_HISTORY --><a href="{U_VIEW_PREVIOUS_HISTORY}">{L_VIEW_PREVIOUS_HISTORY}</a> | <!-- ENDIF --><!-- IF U_VIEW_NEXT_HISTORY --><a href="{U_VIEW_NEXT_HISTORY}">{L_VIEW_NEXT_HISTORY}</a> | <!-- ENDIF -->
- <!-- ENDIF --><a href="{U_PREVIOUS_PM}">{L_VIEW_PREVIOUS_PM}</a> | <a href="{U_NEXT_PM}">{L_VIEW_NEXT_PM}</a>&nbsp;
- </span>
- <!-- ENDIF -->
- </td>
- <td align="{S_CONTENT_FLOW_END}"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
- </td>
-</tr>
-</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_options.html b/phpBB/styles/subsilver2/template/ucp_pm_options.html
deleted file mode 100644
index beb867c75a..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_pm_options.html
+++ /dev/null
@@ -1,192 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<!-- IF ERROR_MESSAGE or NOTIFICATION_MESSAGE -->
- <table border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td class="row3" align="center">
- <!-- IF ERROR_MESSAGE --><span class="genmed error">{ERROR_MESSAGE}</span><!-- ENDIF -->
- <!-- IF NOTIFICATION_MESSAGE --><span class="genmed error">{NOTIFICATION_MESSAGE}</span><!-- ENDIF -->
- </td>
- </tr>
- </table>
- <div style="padding: 2px;"></div>
-<!-- ENDIF -->
-
-<form name="ucp" method="post" action="{S_UCP_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="3">{L_ADD_NEW_RULE}</th>
-</tr>
-<!-- IF S_CHECK_DEFINED -->
- <tr>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><b class="gen">{L_IF}{L_COLON}</b></td>
- <td class="row2" align="center" valign="top"><!-- IF S_CHECK_SELECT --><select name="check_option">{S_CHECK_OPTIONS}</select><!-- ELSE --><b class="gen">{CHECK_CURRENT}</b><input type="hidden" name="check_option" value="{CHECK_OPTION}" /><!-- ENDIF --></td>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_END}" valign="top"><!-- IF S_CHECK_SELECT --><input type="submit" name="next" value="{L_NEXT_STEP}" class="btnlite" /><!-- ELSE -->&nbsp;<!-- ENDIF --></td>
- </tr>
-<!-- ENDIF -->
-<!-- IF S_RULE_DEFINED -->
- <tr>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><!-- IF S_RULE_SELECT --><input type="submit" name="back[rule]" value="{L_PREVIOUS_STEP}" class="btnlite" /><!-- ELSE -->&nbsp;<!-- ENDIF --></td>
- <td class="row2" align="center" valign="top"><!-- IF S_RULE_SELECT --><select name="rule_option">{S_RULE_OPTIONS}</select><!-- ELSE --><b class="gen">{RULE_CURRENT}</b><input type="hidden" name="rule_option" value="{RULE_OPTION}" /><!-- ENDIF --></td>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_END}" valign="top"><!-- IF S_RULE_SELECT --><input type="submit" name="next" value="{L_NEXT_STEP}" class="btnlite" /><!-- ELSE -->&nbsp;<!-- ENDIF --></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_COND_DEFINED -->
- <!-- IF S_COND_SELECT or COND_CURRENT -->
- <tr>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><!-- IF S_COND_SELECT --><input type="submit" name="back[cond]" value="{L_PREVIOUS_STEP}" class="btnlite" /><!-- ELSE -->&nbsp;<!-- ENDIF --></td>
- <td class="row2" align="center" valign="top">
- <!-- IF S_COND_SELECT -->
- <!-- IF S_TEXT_CONDITION -->
- <input type="text" name="rule_string" value="{CURRENT_STRING}" size="30" maxlength="250" class="post" />
- <!-- ELSEIF S_USER_CONDITION -->
- <input type="text" class="post" name="rule_string" value="{CURRENT_STRING}" size="20" />&nbsp;<span class="gensmall">[ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</span>
- <!-- ELSEIF S_GROUP_CONDITION -->
- <input type="hidden" name="rule_string" value="{CURRENT_STRING}" /><!-- IF S_GROUP_OPTIONS --><select name="rule_group_id">{S_GROUP_OPTIONS}</select><!-- ELSE -->{L_NO_GROUPS}<!-- ENDIF -->
- <!-- ENDIF -->
- <!-- ELSE -->
- <b class="gen">{COND_CURRENT}</b>
- <input type="hidden" name="rule_string" value="{CURRENT_STRING}" /><input type="hidden" name="rule_user_id" value="{CURRENT_USER_ID}" /><input type="hidden" name="rule_group_id" value="{CURRENT_GROUP_ID}" />
- <!-- ENDIF -->
- </td>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_END}" valign="top"><!-- IF S_COND_SELECT --><input type="submit" name="next" value="{L_NEXT_STEP}" class="btnlite" /><!-- ELSE -->&nbsp;<!-- ENDIF --></td>
- </tr>
- <!-- ENDIF -->
- <input type="hidden" name="cond_option" value="{COND_OPTION}" />
-<!-- ENDIF -->
-
-<!-- IF NONE_CONDITION --><input type="hidden" name="cond_option" value="none" /><!-- ENDIF -->
-
-<!-- IF S_ACTION_DEFINED -->
- <tr>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_BEGIN}" valign="top"><!-- IF S_ACTION_SELECT --><input type="submit" name="back[action]" value="{L_PREVIOUS_STEP}" class="btnlite" /><!-- ELSE -->&nbsp;<!-- ENDIF --></td>
- <td class="row2" align="center" valign="top"><!-- IF S_ACTION_SELECT --><select name="action_option">{S_ACTION_OPTIONS}</select><!-- ELSE --><b class="gen">{ACTION_CURRENT}</b><input type="hidden" name="action_option" value="{ACTION_OPTION}" /><!-- ENDIF --></td>
- <td class="row1" width="50" align="{S_CONTENT_FLOW_END}" valign="top"><!-- IF S_ACTION_SELECT --><input type="submit" name="add_rule" value="{L_ADD_RULE}" class="btnlite" /><!-- ELSE -->&nbsp;<!-- ENDIF --></td>
- </tr>
-<!-- ENDIF -->
-</table>
-
-<div style="padding: 2px;"></div>
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="6">{L_DEFINED_RULES}</th>
-</tr>
-<!-- BEGIN rule -->
- <tr>
- <td class="row1" width="25" align="center"><span class="gen">#{rule.COUNT}</span></td>
- <td class="row2" width="120"><span class="gen"><strong>{L_IF}</strong> {rule.CHECK}</span></td>
- <td class="row1" width="120"><span class="gen">{rule.RULE}</span></td>
- <td class="row2" width="120"><span class="gen"><!-- IF rule.STRING -->{rule.STRING}<!-- ENDIF --></span></td>
- <td class="row1"><span class="gen">{rule.ACTION}<!-- IF rule.FOLDER --> -&gt; {rule.FOLDER}<!-- ENDIF --></span></td>
- <td class="row2" width="25"><input type="submit" name="delete_rule[{rule.RULE_ID}]" value="{L_DELETE_RULE}" class="btnlite" /></td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td colspan="6" class="row3" align="center"><span class="gen">{L_NO_RULES_DEFINED}</span></td>
- </tr>
-<!-- END rule -->
-</table>
-
-<div style="padding: 2px;"></div>
-
-<!-- IF S_FOLDER_OPTIONS -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="2">{L_RENAME_FOLDER}</th>
- </tr>
- <tr>
- <td class="row1" width="200"><b class="gen">{L_RENAME_FOLDER}{L_COLON} </b></td>
- <td class="row1"><select name="rename_folder_id">{S_FOLDER_OPTIONS}</select></td>
- </tr>
- <tr>
- <td class="row1" width="200"><b class="gen">{L_NEW_FOLDER_NAME}{L_COLON} </b></td>
- <td class="row1"><input type="text" class="post" name="new_folder_name" size="30" maxlength="30" /></td>
- </tr>
- <tr>
- <td class="row1" align="{S_CONTENT_FLOW_END}" colspan="2"><input class="btnlite" style="width:150px" type="submit" name="rename_folder" value="{L_RENAME}" /></td>
- </tr>
- </table>
-
- <div style="padding: 2px;"></div>
-<!-- ENDIF -->
-
-<!-- IF not S_MAX_FOLDER_ZERO -->
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2">{L_ADD_FOLDER}</th>
-</tr>
-<!-- IF S_MAX_FOLDER_REACHED -->
- <tr>
- <td colspan="2">{L_MAX_FOLDER_REACHED}</td>
- </tr>
-<!-- ELSE -->
- <tr>
- <td class="row1" width="200"><b class="gen">{L_ADD_FOLDER}{L_COLON} </b></td>
- <td class="row1"><input type="text" class="post" name="foldername" size="30" maxlength="30" /></td>
- </tr>
- <tr>
- <td class="row1" align="{S_CONTENT_FLOW_END}" colspan="2"><input class="btnlite" style="width:150px" type="submit" name="addfolder" value="{L_ADD}" /></td>
- </tr>
-<!-- ENDIF -->
-</table>
-<!-- ENDIF -->
-
-<div style="padding: 2px;"></div>
-
-<!-- IF S_FOLDER_OPTIONS -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <th colspan="3">{L_REMOVE_FOLDER}</th>
- </tr>
- <tr>
- <td class="row1" width="200"><b class="gen">{L_REMOVE_FOLDER}{L_COLON} </b></td>
- <td class="row1"><select name="remove_folder_id">{S_FOLDER_OPTIONS}</select></td>
- <td class="row1"><b class="genmed">{L_AND}</b></td>
- </tr>
- <tr>
- <td class="row2" width="200">&nbsp;</td>
- <td class="row2" colspan="2"><input type="radio" class="radio" name="remove_action" value="1" checked="checked" />&nbsp;<span class="genmed">{L_MOVE_DELETED_MESSAGES_TO} </span>&nbsp;<select name="move_to">{S_TO_FOLDER_OPTIONS}</select></td>
- </tr>
- <tr>
- <td class="row2" width="200">&nbsp;</td>
- <td class="row2" colspan="2"><input type="radio" class="radio" name="remove_action" value="2" />&nbsp;<span class="genmed">{L_DELETE_MESSAGES_IN_FOLDER}</span></td>
- </tr>
- <tr>
- <td class="row2" width="200">&nbsp;</td>
- <td class="row2" colspan="2" align="{S_CONTENT_FLOW_END}"><input class="btnlite" style="width:150px" type="submit" name="remove_folder" value="{L_REMOVE}" /></td>
- </tr>
- </table>
-
- <div style="padding: 2px;"></div>
-<!-- ENDIF -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2">{L_FOLDER_OPTIONS}</th>
-</tr>
-<tr>
- <td class="row1" width="200"><span><b class="genmed">{L_IF_FOLDER_FULL}{L_COLON} </b></span></td>
- <td class="row1"><input type="radio" class="radio" name="full_action" value="1"{S_DELETE_CHECKED} />&nbsp;<span class="genmed">{L_DELETE_OLDEST_MESSAGES}</span></td>
-</tr>
-<tr>
- <td class="row1" width="200">&nbsp;</td>
- <td class="row1"><input type="radio" class="radio" name="full_action" value="2"{S_MOVE_CHECKED} />&nbsp;<span class="genmed">{L_MOVE_TO_FOLDER}{L_COLON} </span><select name="full_move_to">{S_FULL_FOLDER_OPTIONS}</select></td>
-</tr>
-<tr>
- <td class="row1" width="200">&nbsp;</td>
- <td class="row1"><input type="radio" class="radio" name="full_action" value="3"{S_HOLD_CHECKED} />&nbsp;<span class="genmed">{L_HOLD_NEW_MESSAGES}</span></td>
-</tr>
-<tr>
- <td class="row2" width="200"><b class="genmed">{L_DEFAULT_ACTION}{L_COLON} </b><br /><span class="gensmall">{L_DEFAULT_ACTION_EXPLAIN}</span></td>
- <td class="row2"><span class="genmed">{DEFAULT_ACTION}</span></td>
-</tr>
-<tr>
- <td class="row1" colspan="2" align="{S_CONTENT_FLOW_END}"><input class="btnlite" style="width:150px" type="submit" name="fullfolder" value="{L_CHANGE}" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html b/phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html
deleted file mode 100644
index 6ab32df255..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html
+++ /dev/null
@@ -1,131 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<div id="pagecontent">
-
-<!-- IF not PROMPT -->
- <!-- INCLUDE ucp_pm_message_header.html -->
-<!-- ENDIF -->
-
-<div style="padding: 2px;"></div>
-
-<!-- IF S_PM_ICONS -->
- <!-- DEFINE $COLSPAN = 6 -->
-<!-- ELSE -->
- <!-- DEFINE $COLSPAN = 5 -->
-<!-- ENDIF -->
-
-<form name="viewfolder" method="post" action="{S_PM_ACTION}" style="margin:0px">
-
-<!-- IF PROMPT -->
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0" border="0">
- <tr>
- <th colspan="2" valign="middle">{L_OPTIONS}</th>
- </tr>
- <tr>
- <td class="row1" width="35%">{L_DELIMITER}{L_COLON} </td>
- <td class="row2"><input class="post" type="text" name="delimiter" value="," /></td>
- </tr>
- <tr>
- <td class="row1" width="35%">{L_ENCLOSURE}{L_COLON} </td>
- <td class="row2"><input class="post" type="text" name="enclosure" value="&#034;" /></td>
- </tr>
- <tr>
- <td class="cat" colspan="2" align="center"><input type="hidden" name="export_option" value="CSV" /><input class="btnmain" type="submit" name="submit_export" value="{L_EXPORT_FOLDER}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
- </tr>
- </table>
- {S_FORM_TOKEN}
-
-</form>
-<!-- ELSE -->
-
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0" border="0">
- <!-- IF NUM_NOT_MOVED or NUM_REMOVED -->
- <tr>
- <td class="row3" colspan="{$COLSPAN}" align="center"><span class="gen">
- <!-- IF NUM_REMOVED -->
- {RULE_REMOVED_MESSAGES}
- <!-- IF NUM_NOT_MOVED --><br /><!-- ENDIF -->
- <!-- ENDIF -->
- <!-- IF NUM_NOT_MOVED -->
- {NOT_MOVED_MESSAGES}<br />{RELEASE_MESSAGE_INFO}
- <!-- ENDIF -->
- </span></td>
- </tr>
- <!-- ENDIF -->
- <tr>
- <th colspan="<!-- IF S_PM_ICONS -->3<!-- ELSE -->2<!-- ENDIF -->">&nbsp;{L_SUBJECT}&nbsp;</th>
- <th>&nbsp;<!-- IF S_SHOW_RECIPIENTS -->{L_RECIPIENTS}<!-- ELSE -->{L_AUTHOR}<!-- ENDIF -->&nbsp;</th>
- <th>&nbsp;{L_SENT_AT}&nbsp;</th>
- <th>&nbsp;{L_MARK}&nbsp;</th>
- </tr>
-
- <!-- BEGIN messagerow -->
- <tr>
- <td class="row1" width="25" align="center" nowrap="nowrap">{messagerow.FOLDER_IMG}</td>
- <!-- IF S_PM_ICONS -->
- <td class="row1" width="25" align="center">{messagerow.PM_ICON_IMG}</td>
- <!-- ENDIF -->
-
- <!-- IF messagerow.S_PM_DELETED --><td class="row3"><!-- ELSE --><td class="row1"><!-- ENDIF -->
- <!-- IF not messagerow.PM_IMG and messagerow.PM_CLASS -->
- <span class="{messagerow.PM_CLASS}" style="float: {S_CONTENT_FLOW_BEGIN};"><img src="images/spacer.gif" width="10" height="10" alt="" /></span>&nbsp;
- <!-- ELSEIF messagerow.PM_IMG -->
- {messagerow.PM_IMG}&nbsp;
- <!-- ENDIF -->
-
- <span class="topictitle">
- {messagerow.ATTACH_ICON_IMG}
- <!-- IF messagerow.S_PM_DELETED -->
- {L_MESSAGE_REMOVED_FROM_OUTBOX}<br />
- <a href="{messagerow.U_REMOVE_PM}" style="float: {S_CONTENT_FLOW_END};">{L_DELETE_MESSAGE}</a>
- <!-- ELSE -->
- <a href="{messagerow.U_VIEW_PM}">{messagerow.SUBJECT}</a>
- <!-- ENDIF -->
- <!-- IF messagerow.S_PM_REPORTED -->
- <a href="{messagerow.U_MCP_REPORT}" class="imageset">{REPORTED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF messagerow.S_AUTHOR_DELETED -->
- <br /><em class="gensmall">{L_PM_FROM_REMOVED_AUTHOR}</em>
- <!-- ENDIF -->
- </span></td>
-
- <td class="row1" width="100" align="center"><p class="topicauthor"><!-- IF S_SHOW_RECIPIENTS -->{messagerow.RECIPIENTS}<!-- ELSE -->{messagerow.MESSAGE_AUTHOR_FULL}<!-- ENDIF --></p></td>
- <td class="row1" width="120" align="center"><p class="topicdetails">{messagerow.SENT_TIME}</p></td>
- <td class="row1" width="20" align="center"><p class="topicdetails"><input type="checkbox" class="radio" name="marked_msg_id[]" value="{messagerow.MESSAGE_ID}" /></p></td>
- </tr>
- <!-- BEGINELSE -->
- <tr>
- <td class="row1" colspan="{$COLSPAN}" height="30" align="center" valign="middle"><span class="gen">
- <!-- IF S_COMPOSE_PM_VIEW and S_NO_AUTH_SEND_MESSAGE -->
- <!-- IF S_USER_NEW -->{L_USER_NEW_PERMISSION_DISALLOWED}<!-- ELSE -->{L_NO_AUTH_SEND_MESSAGE}<!-- ENDIF -->
- <!-- ELSE -->
- {L_NO_MESSAGES}
- <!-- ENDIF -->
- </span></td>
- </tr>
- <!-- END messagerow -->
-</table>
-
-<input type="hidden" name="cur_folder_id" value="{CUR_FOLDER_ID}" />
-
-<table border="0" cellspacing="0" cellpadding="0" width="100%">
-<tr>
- <td class="cat">
-<!-- IF .messagerow -->
- <div style="float: {S_CONTENT_FLOW_BEGIN};"><select name="export_option"><option value="CSV">{L_EXPORT_AS_CSV}</option><option value="CSV_EXCEL">{L_EXPORT_AS_CSV_EXCEL}</option><option value="XML">{L_EXPORT_AS_XML}</option></select>&nbsp;<input class="btnlite" type="submit" name="submit_export" value="{L_EXPORT_FOLDER}" /></div>
- <div style="float: {S_CONTENT_FLOW_END};"><select name="mark_option">{S_MARK_OPTIONS}{S_MOVE_MARKED_OPTIONS}</select>&nbsp;<input class="btnlite" type="submit" name="submit_mark" value="{L_GO}" />&nbsp;</div>
-<!-- ENDIF -->
- </td>
-</tr>
-</table>
-
-<div style="padding: 2px;"></div>
-<!-- INCLUDE ucp_pm_message_footer.html -->
-
-<!-- ENDIF -->
-
-<br clear="all" />
-
-</div>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html b/phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html
deleted file mode 100644
index 9536b1f8c5..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html
+++ /dev/null
@@ -1,136 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<div id="pagecontent">
-
-<!-- INCLUDE ucp_pm_message_header.html -->
-<div style="padding: 2px;"></div>
-
-<table class="tablebg" width="100%" cellspacing="1" cellpadding="4">
-
-<tr class="row1">
- <td class="genmed" nowrap="nowrap" width="150"><b>{L_PM_SUBJECT}{L_COLON}</b></td>
- <td class="gen">{SUBJECT}</td>
-</tr>
-
-<tr class="row1">
- <td class="genmed" nowrap="nowrap" width="150"><b>{L_PM_FROM}{L_COLON}</b></td>
- <td class="gen">{MESSAGE_AUTHOR_FULL}</td>
-</tr>
-
-<tr class="row1">
- <td class="genmed" nowrap="nowrap" width="150"><b>{L_SENT_AT}{L_COLON}</b></td>
- <td class="gen">{SENT_DATE}</td>
-</tr>
-
-<!-- IF S_TO_RECIPIENT -->
- <tr class="row1">
- <td class="genmed" nowrap="nowrap" width="150"><b>{L_TO}{L_COLON}</b></td>
- <td class="gen">
- <!-- BEGIN to_recipient -->
- <!-- IF to_recipient.IS_GROUP --><span class="sep"><a href="{to_recipient.U_VIEW}">{to_recipient.NAME}</a></span><!-- ELSE -->{to_recipient.NAME_FULL}&nbsp;<!-- ENDIF -->
- <!-- END to_recipient -->
- </td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_BCC_RECIPIENT -->
- <tr class="row1">
- <td class="genmed" nowrap="nowrap" width="150"><b>{L_BCC}{L_COLON}</b></td>
- <td class="gen">
- <!-- BEGIN bcc_recipient -->
- <!-- IF bcc_recipient.IS_GROUP --><span class="sep"><a href="{bcc_recipient.U_VIEW}">{bcc_recipient.NAME}</a></span><!-- ELSE -->{bcc_recipient.NAME_FULL}&nbsp;<!-- ENDIF -->
- <!-- END bcc_recipient -->
- </td>
- </tr>
-<!-- ENDIF -->
-</table>
-
-<div style="padding: 2px;"></div>
-
-<table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
-
-<tr>
- <th nowrap="nowrap">{L_MESSAGE}</th>
-</tr>
-
-<tr>
- <td class="spacer" height="1"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
-</tr>
-
-<tr class="row1">
- <td valign="top">
- <table width="100%" cellspacing="5">
- <tr>
- <td>
- <div class="postbody">{MESSAGE}</div>
-
- <!-- IF S_HAS_ATTACHMENTS -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <td class="row2">{attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
-
- <!-- IF S_DISPLAY_NOTICE -->
- <span class="gensmall error"><br /><br />{L_DOWNLOAD_NOTICE}</span>
- <!-- ENDIF -->
- <!-- IF SIGNATURE -->
- <span class="postbody"><br />_________________<br />{SIGNATURE}</span>
- <!-- ENDIF -->
- <!-- IF EDITED_MESSAGE -->
- <span class="gensmall">{EDITED_MESSAGE}</span>
- <!-- ENDIF -->
-
- <!-- IF not S_HAS_ATTACHMENTS --><br clear="all" /><br /><!-- ENDIF -->
-
- <table width="100%" cellspacing="0">
- <tr valign="middle">
- <td class="gensmall" align="{S_CONTENT_FLOW_END}"> <!-- IF U_REPORT --><a href="{U_REPORT}" class="imageset">{REPORT_IMG}</a> <!-- ENDIF --><!-- IF U_DELETE --><a href="{U_DELETE}" class="imageset">{DELETE_IMG}</a> <!-- ENDIF --></td>
- </tr>
- </table>
-
- </td>
- </tr>
- </table>
- </td>
-</tr>
-
-<tr class="row1">
- <td>
- <div class="gensmall" style="float: {S_CONTENT_FLOW_BEGIN};">
- &nbsp;<!-- IF U_MESSAGE_AUTHOR --><a href="{U_MESSAGE_AUTHOR}" class="imageset">{PROFILE_IMG}</a> <!-- ENDIF -->
- <!-- IF U_EMAIL --><a href="{U_EMAIL}" class="imageset">{EMAIL_IMG}</a> <!-- ENDIF -->
- &nbsp;</div>
- <div class="gensmall" style="float: {S_CONTENT_FLOW_END};">
- <!-- EVENT ucp_pm_viewmessage_post_buttons_before -->
- <!-- IF U_EDIT --><a href="{U_EDIT}" class="imageset">{EDIT_IMG}</a> <!-- ENDIF -->
- <!-- IF U_QUOTE --><a href="{U_QUOTE}" class="imageset">{QUOTE_IMG}</a> <!-- ENDIF -->
- <!-- IF U_POST_REPLY_PM --><a href="{U_POST_REPLY_PM}" class="imageset">{REPLY_IMG}</a><!-- ENDIF -->
- <!-- EVENT ucp_pm_viewmessage_post_buttons_after -->
- &nbsp;</div>
- </td>
-</tr>
-
-<tr>
- <td class="spacer" height="1"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
-</tr>
-</table>
-
-<div style="padding: 2px;"></div>
-<!-- INCLUDE ucp_pm_message_footer.html -->
-
-<br clear="all" />
-
-</div>
-
-<!-- IF S_DISPLAY_HISTORY --><!-- INCLUDE ucp_pm_history.html --><!-- ENDIF -->
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html b/phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html
deleted file mode 100644
index 624a6ea8ef..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage_print.html
+++ /dev/null
@@ -1,122 +0,0 @@
-<!DOCTYPE html>
-<html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">
-<head>
-<meta charset="utf-8" />
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="robots" content="noindex" />
-<title>{SITENAME} :: {PAGE_TITLE}</title>
-
-<style type="text/css">
-<!--
-
-body {
- font-family: Verdana,serif;
- font-size: 10pt;
-}
-
-td {
- font-family: Verdana,serif;
- font-size: 10pt;
- line-height: 150%;
-}
-
-.code,
-.quote {
- font-size: smaller;
- border: black solid 1px;
-}
-
-.forum {
- font-family: Arial,Helvetica,sans-serif;
- font-weight: bold;
- font-size: 18pt;
-}
-
-.topic {
- font-family: Arial,Helvetica,sans-serif;
- font-size: 14pt;
- font-weight: bold;
-}
-
-.gensmall {
- font-size: 8pt;
-}
-
-hr {
- color: #888;
- height: 3px;
- border-style: solid;
-}
-
-hr.sep {
- color: #aaa;
- height: 1px;
- border-style: dashed;
-}
-//-->
-</style>
-<!-- EVENT ucp_pm_viewmessage_print_head_append -->
-</head>
-<body>
-
-<table width="85%" cellspacing="3" cellpadding="0" border="0" align="center">
-<tr>
- <td colspan="2" align="center"><span class="Forum">{SITENAME}</span><br /><span class="gensmall">{L_PRIVATE_MESSAGING}</span></td>
-</tr>
-<tr>
- <td colspan="2"><br /></td>
-</tr>
-<tr>
- <td><span class="topic">{SUBJECT}</span><br /></td>
- <td align="{S_CONTENT_FLOW_END}" valign="bottom"><span class="gensmall">{PAGE_NUMBER}</span></td>
-</tr>
-</table>
-
-<hr width="85%" />
-
-<table width="85%" cellspacing="3" cellpadding="0" border="0" align="center">
-<tr>
- <td width="10%" nowrap="nowrap">{L_PM_FROM}{L_COLON}&nbsp;</td>
- <td><b>{MESSAGE_AUTHOR}</b> [ {SENT_DATE} ]</td>
-</tr>
-
-<!-- IF S_TO_RECIPIENT -->
- <tr>
- <td width="10%" nowrap="nowrap">{L_TO}{L_COLON}</td>
- <td>
- <!-- BEGIN to_recipient -->
- <span<!-- IF to_recipient.IS_GROUP --> class="sep"<!-- ENDIF -->>{to_recipient.NAME}</span>&nbsp;
- <!-- END to_recipient -->
- </td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_BCC_RECIPIENT -->
- <tr>
- <td width="10%" nowrap="nowrap">{L_BCC}{L_COLON}</td>
- <td>
- <!-- BEGIN bcc_recipient -->
- <!-- IF bcc_recipient.COLOUR --><span style="color:{bcc_recipient.COLOUR}"><!-- ELSE --><span<!-- IF bcc_recipient.IS_GROUP --> class="sep"<!-- ENDIF -->><!-- ENDIF -->{bcc_recipient.NAME}</span>&nbsp;
- <!-- END bcc_recipient -->
- </td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td colspan="2"><hr class="sep" />{MESSAGE}</td>
-</tr>
-</table>
-
-<hr width="85%" />
-
-<table width="85%" cellspacing="3" cellpadding="0" border="0" align="center">
-<tr>
- <td><span class="gensmall">{PAGE_NUMBER}</span></td>
- <td align="{S_CONTENT_FLOW_END}"><span class="gensmall">{S_TIMEZONE}</span></td>
-</tr>
-<tr>
- <td colspan="2" align="center"><span class="gensmall">Powered by phpBB&reg; Forum Software &copy; phpBB Limited<br />https://www.phpbb.com/</span></td>
-</tr>
-</table>
-
-</body>
-</html>
diff --git a/phpBB/styles/subsilver2/template/ucp_prefs_personal.html b/phpBB/styles/subsilver2/template/ucp_prefs_personal.html
deleted file mode 100644
index 0dd50b8fa2..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_prefs_personal.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<script type="text/javascript">
-// <![CDATA[
- var default_dateformat = '{A_DEFAULT_DATEFORMAT}';
-// ]]>
-</script>
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT ucp_prefs_personal_prepend -->
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_SHOW_EMAIL}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="viewemail" value="1"<!-- IF S_VIEW_EMAIL --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_YES}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="viewemail" value="0"<!-- IF not S_VIEW_EMAIL --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_ADMIN_EMAIL}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="massemail" value="1"<!-- IF S_MASS_EMAIL --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_YES}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="massemail" value="0"<!-- IF not S_MASS_EMAIL --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_ALLOW_PM}{L_COLON}</b><br /><span class="gensmall">{L_ALLOW_PM_EXPLAIN}</span></td>
- <td class="row2"><input type="radio" class="radio" name="allowpm" value="1"<!-- IF S_ALLOW_PM --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_YES}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="allowpm" value="0"<!-- IF not S_ALLOW_PM --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_NO}</span></td>
-</tr>
-<!-- IF S_CAN_HIDE_ONLINE -->
- <tr>
- <td class="row1" width="50%"><b class="genmed">{L_HIDE_ONLINE}{L_COLON}</b><br /><span class="gensmall">{L_HIDE_ONLINE_EXPLAIN}</span></td>
- <td class="row2"><input type="radio" class="radio" name="hideonline" value="1"<!-- IF S_HIDE_ONLINE --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_YES}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="hideonline" value="0"<!-- IF not S_HIDE_ONLINE --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_NO}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- IF S_SELECT_NOTIFY -->
- <tr>
- <td class="row1" width="50%"><b class="genmed">{L_NOTIFY_METHOD}{L_COLON}</b><br /><span class="gensmall">{L_NOTIFY_METHOD_EXPLAIN}</span></td>
- <td class="row2"><input type="radio" class="radio" name="notifymethod" value="0"<!-- IF S_NOTIFY_EMAIL --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_NOTIFY_METHOD_EMAIL}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="notifymethod" value="1"<!-- IF S_NOTIFY_IM --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_NOTIFY_METHOD_IM}</span>&nbsp;&nbsp;<input type="radio" class="radio" name="notifymethod" value="2"<!-- IF S_NOTIFY_BOTH --> checked="checked"<!-- ENDIF --> /><span class="genmed">{L_NOTIFY_METHOD_BOTH}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- IF S_MORE_LANGUAGES -->
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_BOARD_LANGUAGE}{L_COLON}</b></td>
- <td class="row2"><select name="lang">{S_LANG_OPTIONS}</select></td>
-</tr>
-<!-- ENDIF -->
-<!-- IF S_STYLE_OPTIONS and S_MORE_STYLES -->
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_BOARD_STYLE}{L_COLON}</b></td>
- <td class="row2"><select name="user_style">{S_STYLE_OPTIONS}</select></td>
-</tr>
-<!-- ENDIF -->
-<!-- INCLUDE timezone_option.html -->
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_BOARD_DATE_FORMAT}{L_COLON}</b><br /><span class="gensmall">{L_BOARD_DATE_FORMAT_EXPLAIN}</span></td>
- <td class="row2">
- <select name="dateoptions" id="dateoptions" onchange="if(this.value=='custom'){phpbb.toggleDisplay('custom_date',1);}else{phpbb.toggleDisplay('custom_date',-1);} if (this.value == 'custom') { document.getElementById('dateformat').value = default_dateformat; } else { document.getElementById('dateformat').value = this.value; }">
- {S_DATEFORMAT_OPTIONS}
- </select>
- <div id="custom_date"<!-- IF not S_CUSTOM_DATEFORMAT --> style="display:none;"<!-- ENDIF -->><input type="text" name="dateformat" id="dateformat" value="{DATE_FORMAT}" maxlength="64" class="post" style="margin-top: 3px;" /></div>
- </td>
-</tr>
-<!-- EVENT ucp_prefs_personal_append -->
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_prefs_post.html b/phpBB/styles/subsilver2/template/ucp_prefs_post.html
deleted file mode 100644
index 0a558b863c..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_prefs_post.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT ucp_prefs_post_prepend -->
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_DEFAULT_BBCODE}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="bbcode" value="1"<!-- IF S_BBCODE --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="bbcode" value="0"<!-- IF not S_BBCODE --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_DEFAULT_SMILIES}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="smilies" value="1"<!-- IF S_SMILIES --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="smilies" value="0"<!-- IF not S_SMILIES --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_DEFAULT_ADD_SIG}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="sig" value="1"<!-- IF S_SIG --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="sig" value="0"<!-- IF not S_SIG --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_DEFAULT_NOTIFY}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="notify" value="1"<!-- IF S_NOTIFY --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="notify" value="0"<!-- IF not S_NOTIFY --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<!-- EVENT ucp_prefs_post_append -->
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_prefs_view.html b/phpBB/styles/subsilver2/template/ucp_prefs_view.html
deleted file mode 100644
index c10c458627..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_prefs_view.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT ucp_prefs_view_radio_buttons_prepend -->
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_IMAGES}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="images" value="1"<!-- IF S_IMAGES --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="images" value="0"<!-- IF not S_IMAGES --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_FLASH}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="flash" value="1"<!-- IF S_FLASH --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="flash" value="0"<!-- IF not S_FLASH --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_SMILIES}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="smilies" value="1"<!-- IF S_SMILIES --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="smilies" value="0"<!-- IF not S_SMILIES --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_SIGS}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="sigs" value="1"<!-- IF S_SIGS --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="sigs" value="0"<!-- IF not S_SIGS --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_AVATARS}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="avatars" value="1"<!-- IF S_AVATARS --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="avatars" value="0"<!-- IF not S_AVATARS --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
-</tr>
-<!-- IF S_CHANGE_CENSORS -->
- <tr>
- <td class="row1" width="50%"><b class="genmed">{L_DISABLE_CENSORS}{L_COLON}</b></td>
- <td class="row2"><input type="radio" class="radio" name="wordcensor" value="1"<!-- IF S_DISABLE_CENSORS --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_YES}</span>&nbsp; &nbsp;<input type="radio" class="radio" name="wordcensor" value="0"<!-- IF not S_DISABLE_CENSORS --> checked="checked"<!-- ENDIF --> /><span class="gen">{L_NO}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT ucp_prefs_view_radio_buttons_append -->
-<tr>
- <td colspan="2" class="spacer"></td>
-</tr>
-<!-- EVENT ucp_prefs_view_select_menu_prepend -->
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_TOPICS_DAYS}{L_COLON}</b></td>
- <td class="row2">{S_TOPIC_SORT_DAYS}</td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_TOPICS_KEY}{L_COLON}</b></td>
- <td class="row2">{S_TOPIC_SORT_KEY}</td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_TOPICS_DIR}{L_COLON}</b></td>
- <td class="row2">{S_TOPIC_SORT_DIR}</td>
-</tr>
-<tr>
- <td colspan="2" class="spacer"></td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_POSTS_DAYS}{L_COLON}</b></td>
- <td class="row2">{S_POST_SORT_DAYS}</td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_POSTS_KEY}{L_COLON}</b></td>
- <td class="row2">{S_POST_SORT_KEY}</td>
-</tr>
-<tr>
- <td class="row1" width="50%"><b class="genmed">{L_VIEW_POSTS_DIR}{L_COLON}</b></td>
- <td class="row2">{S_POST_SORT_DIR}</td>
-</tr>
-<!-- EVENT ucp_prefs_view_select_menu_append -->
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html b/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html
deleted file mode 100644
index 087ae89743..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_profile_autologin_keys.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="4">{L_TITLE}</th>
-</tr>
-
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="4" align="center"><span class="genmed error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<tr>
- <td colspan="4" class="row1">{L_PROFILE_AUTOLOGIN_KEYS}</td>
-</tr>
-<tr>
- <th>{L_LOGIN_KEY}</th>
- <th class="center">{L_IP}</th>
- <th class="center">{L_LOGIN_TIME}</th>
- <th class="center">{L_MARK}</th>
-</tr>
-<!-- BEGIN sessions -->
- <!-- IF sessions.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td class="genmed"><label for="{sessions.KEY}">{sessions.KEY}</label></td>
- <td class="genmed" style="text-align: center">{sessions.IP}</td>
- <td class="genmed" style="text-align: center">{sessions.LOGIN_TIME}</td>
- <td class="genmed" style="text-align: center"><input type="checkbox" name="keys[]" value="{sessions.KEY}" id="{sessions.KEY}"/></td>
- </tr>
-<!-- BEGINELSE -->
- <tr>
- <td colspan="4" class="row1" style="text-align: center">{L_PROFILE_NO_AUTOLOGIN_KEYS}</td>
- </tr>
-<!-- END sessions -->
-
-<!-- IF .sessions -->
- <tr>
- <td class="cat" colspan="4" align="{S_CONTENT_FLOW_END}">
- {S_HIDDEN_FIELDS}<input class="btnlite" type="submit" name="submit" value="{L_DELETE_MARKED}" />
- {S_FORM_TOKEN}
- </td>
- </tr>
-<!-- ENDIF -->
-</table>
-
-<!-- IF .sessions -->
- <div class="gensmall" style="float: {S_CONTENT_FLOW_END}; padding-top: 2px;"><b><a href="#" onclick="marklist('ucp', 'keys', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="marklist('ucp', 'keys', false); return false;">{L_UNMARK_ALL}</a></b></div>
-<!-- ENDIF -->
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_avatar.html b/phpBB/styles/subsilver2/template/ucp_profile_avatar.html
deleted file mode 100644
index 8b1e8cffac..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_profile_avatar.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td class="row1" width="35%"><b class="genmed">{L_CURRENT_IMAGE}{L_COLON} </b><br /><span class="gensmall">{L_AVATAR_EXPLAIN}</span></td>
- <td class="row2" align="center"><br />
- <!-- IF AVATAR -->{AVATAR}<br /><br /><input type="checkbox" class="radio" name="avatar_delete" />&nbsp;<span class="gensmall">{L_DELETE_AVATAR}</span>
- <!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" />
- <!-- ENDIF --></td>
-</tr>
-<!-- IF not S_AVATARS_ENABLED -->
- <tr>
- <td class="row3" colspan="2" align="center">{L_AVATAR_FEATURES_DISABLED}</td>
- </tr>
-<!-- ENDIF -->
- <tr>
- <th colspan="2">{L_AVATAR_SELECT}</th>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_AVATAR_TYPE}{L_COLON}</b></td>
- <td class="row2">
- <select name="avatar_driver" id="avatar_driver" data-togglable-settings="true">
- <!-- BEGIN avatar_drivers -->
- <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF --> data-toggle-setting=".avatar_option_{avatar_drivers.DRIVER}">{avatar_drivers.L_TITLE}</option>
- <!-- END avatar_drivers -->
- </select></td>
- </tr>
-<!-- BEGIN avatar_drivers -->
- <tr class="avatar_option_{avatar_drivers.DRIVER}">
- <td class="row1" width="35%" colspan="2"><noscript><b class="genmed">{avatar_drivers.L_TITLE} </b><br /></noscript>{avatar_drivers.L_EXPLAIN}</span></td>
- </tr>
- <tr class="avatar_option_{avatar_drivers.DRIVER}">
- <td colspan="2" style="padding: 0">{avatar_drivers.OUTPUT}</td>
- </tr>
-<!-- END avatar_drivers -->
-
- <tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<!-- IF S_IN_AVATAR_GALLERY --><input class="btnlite" type="submit" name="cancel" value="{L_CANCEL}" /><!-- ELSE --><input class="btnlite" type="reset" value="{L_RESET}" name="reset" /><!-- ENDIF --></td>
- </tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_profile_info.html b/phpBB/styles/subsilver2/template/ucp_profile_profile_info.html
deleted file mode 100644
index bfc2dd0244..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_profile_profile_info.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td class="row1" colspan="2"><span class="gensmall">{L_PROFILE_INFO_NOTICE}</span></td>
-</tr>
-<!-- EVENT ucp_profile_profile_info_before -->
-<!-- IF S_JABBER_ENABLED -->
-<tr>
- <td class="row1" width="35%"><b class="genmed">{L_UCP_JABBER}{L_COLON} </b></td>
- <td class="row2"><input class="post" type="text" name="jabber" size="30" maxlength="255" value="{JABBER}" /></td>
-</tr>
-<!-- ENDIF -->
-<!-- IF S_BIRTHDAYS_ENABLED -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_BIRTHDAY}{L_COLON} </b><br /><span class="gensmall">{L_BIRTHDAY_EXPLAIN}</span></td>
- <td class="row2"><span class="genmed">{L_DAY}{L_COLON}</span> <select name="bday_day">{S_BIRTHDAY_DAY_OPTIONS}</select> <span class="genmed">{L_MONTH}{L_COLON}</span> <select name="bday_month">{S_BIRTHDAY_MONTH_OPTIONS}</select> <span class="genmed">{L_YEAR}{L_COLON}</span> <select name="bday_year">{S_BIRTHDAY_YEAR_OPTIONS}</select></td>
- </tr>
-<!-- ENDIF -->
-<!-- BEGIN profile_fields -->
- <tr>
- <td class="row1" width="35%">
- <b class="genmed">{profile_fields.LANG_NAME}{L_COLON} </b>
- <!-- IF profile_fields.S_REQUIRED --><b>*</b><!-- ENDIF -->
- <!-- IF profile_fields.LANG_EXPLAIN --><br /><span class="gensmall">{profile_fields.LANG_EXPLAIN}</span><!-- ENDIF -->
- </td>
- <td class="row2">{profile_fields.FIELD}<!-- IF profile_fields.ERROR --><br /><span class="gensmall error">{profile_fields.ERROR}</span><!-- ENDIF --></td>
- </tr>
-<!-- END profile_fields -->
-<!-- EVENT ucp_profile_profile_info_after -->
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_reg_details.html b/phpBB/styles/subsilver2/template/ucp_profile_reg_details.html
deleted file mode 100644
index 862956a1d0..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_profile_reg_details.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<!-- IF S_FORCE_PASSWORD -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{L_FORCE_PASSWORD_EXPLAIN}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT ucp_profile_register_details_before -->
-<tr>
- <td class="row1" width="35%"><b class="genmed">{L_USERNAME}{L_COLON} </b><br /><span class="gensmall">{L_USERNAME_EXPLAIN}</span></td>
- <td class="row2"><!-- IF S_CHANGE_USERNAME --><input type="text" class="post" name="username" size="30" value="{USERNAME}" /><!-- ELSE --><b class="gen">{USERNAME}</b><!-- ENDIF --></td>
-</tr>
-<tr>
- <td class="row1" width="35%"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b></td>
- <td class="row2"><!-- IF S_CHANGE_EMAIL --><input type="email" class="post" name="email" size="30" maxlength="100" value="{EMAIL}" autocomplete="off" /><!-- ELSE --><b class="gen">{EMAIL}</b><!-- ENDIF --></td>
-</tr>
-<!-- IF S_CHANGE_PASSWORD -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_NEW_PASSWORD}{L_COLON} </b><br /><span class="gensmall">{L_CHANGE_PASSWORD_EXPLAIN}</span></td>
- <td class="row2"><input type="password" class="post" name="new_password" size="30" maxlength="255" value="{NEW_PASSWORD}" autocomplete="off" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_CONFIRM_PASSWORD}{L_COLON} </b><br /><span class="gensmall">{L_CONFIRM_PASSWORD_EXPLAIN}</span></td>
- <td class="row2"><input type="password" class="post" name="password_confirm" size="30" maxlength="255" value="{PASSWORD_CONFIRM}" autocomplete="off" /></td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT ucp_profile_register_details_after -->
-<tr>
- <th colspan="2">{L_CONFIRM_CHANGES}</th>
-</tr>
-<tr>
- <td class="row1" width="35%"><b class="genmed">{L_CURRENT_PASSWORD}{L_COLON} </b><br /><span class="gensmall"><!-- IF S_CHANGE_PASSWORD -->{L_CURRENT_CHANGE_PASSWORD_EXPLAIN}<!-- ELSE -->{L_CURRENT_PASSWORD_EXPLAIN}<!-- ENDIF --></span></td>
- <td class="row2"><input type="password" class="post" name="cur_password" size="30" maxlength="255" value="{CUR_PASSWORD}" autocomplete="off" /></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_signature.html b/phpBB/styles/subsilver2/template/ucp_profile_signature.html
deleted file mode 100644
index 5a2690edda..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_profile_signature.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<script type="text/javascript">
-// <![CDATA[
- var form_name = 'ucp';
- var text_name = 'signature';
-// ]]>
-</script>
-
-<!-- DEFINE $S_SIGNATURE = 1 -->
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2">{L_TITLE}</th>
-</tr>
-<!-- IF not S_SMILIES_ALLOWED -->
-<tr>
- <td colspan="2" class="row1">{L_SIGNATURE_EXPLAIN}</td>
-</tr>
-<!-- ENDIF -->
-
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="genmed error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<tr>
- <!-- IF S_SMILIES_ALLOWED -->
- <td class="row1" width="22%" valign="top">
- {L_SIGNATURE_EXPLAIN}
- <table width="100%" cellspacing="5" cellpadding="0" border="0" align="center">
- <tr>
- <td class="gensmall" align="center"><b>{L_SMILIES}</b></td>
- </tr>
- <tr>
- <td align="center">
- <!-- BEGIN smiley -->
- <a href="#" onclick="insert_text('{smiley.A_SMILEY_CODE}', true); return false;" style="line-height: 20px;"><img src="{smiley.SMILEY_IMG}" width="{smiley.SMILEY_WIDTH}" height="{smiley.SMILEY_HEIGHT}" alt="{smiley.SMILEY_CODE}" title="{smiley.SMILEY_DESC}" hspace="2" vspace="2" /></a>
- <!-- END smiley -->
- </td>
- </tr>
- <!-- IF S_SHOW_SMILEY_LINK -->
- <tr>
- <td align="center"><a class="nav" href="{U_MORE_SMILIES}" onclick="popup(this.href, 300, 350, '_phpbbsmilies'); return false;">{L_MORE_SMILIES}</a></td>
- </tr>
- <!-- ENDIF -->
- </table>
- </td>
- <td class="row2">
- <!-- ELSE -->
- <td class="row2" colspan="2">
- <!-- ENDIF -->
-
- <table cellspacing="0" cellpadding="2" border="0" width="99%">
- <!-- INCLUDE posting_buttons.html -->
- <tr>
- <td colspan="2"><textarea class="post" name="signature" rows="10" cols="76" style="width: 90%;" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" onfocus="initInsertions();">{SIGNATURE}</textarea></td>
- </tr>
- <!-- IF S_BBCODE_ALLOWED -->
- <tr>
- <td colspan="2">
- <table cellspacing="0" cellpadding="0" border="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}" id="color_palette_placeholder" data-orientation="h" data-width="11" data-height="10">
- </td>
- </tr>
- </table>
- </td>
- </tr>
- <!-- ENDIF -->
- </table>
- </td>
-</tr>
-<tr>
- <td class="row1" valign="top"><b class="genmed">{L_OPTIONS}</b><br />
- <table cellspacing="2" cellpadding="0" border="0">
- <tr>
- <td class="gensmall">{BBCODE_STATUS}</td>
- </tr>
- <tr>
- <td class="gensmall">{IMG_STATUS}</td>
- </tr>
- <tr>
- <td class="gensmall">{FLASH_STATUS}</td>
- </tr>
- <tr>
- <td class="gensmall">{URL_STATUS}</td>
- </tr>
- <tr>
- <td class="gensmall">{SMILIES_STATUS}</td>
- </tr>
- </table>
- </td>
- <td class="row2" valign="top">
- <table cellspacing="0" cellpadding="1" border="0">
- <!-- IF S_BBCODE_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="disable_bbcode"{S_BBCODE_CHECKED} /></td>
- <td class="gen">{L_DISABLE_BBCODE}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_SMILIES_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="disable_smilies"{S_SMILIES_CHECKED} /></td>
- <td class="gen">{L_DISABLE_SMILIES}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_LINKS_ALLOWED -->
- <tr>
- <td><input type="checkbox" class="radio" name="disable_magic_url"{S_MAGIC_URL_CHECKED} /></td>
- <td class="gen">{L_DISABLE_MAGIC_URL}</td>
- </tr>
- <!-- ENDIF -->
- </table>
- </td>
-</tr>
-
-<!-- IF SIGNATURE_PREVIEW != '' -->
- <tr>
- <th colspan="2" valign="middle">{L_SIGNATURE_PREVIEW}</th>
- </tr>
- <tr>
- <td class="row1" colspan="2"><div class="postbody" style="padding: 6px;">{SIGNATURE_PREVIEW}</div></td>
- </tr>
-<!-- ENDIF -->
-
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnlite" type="submit" name="preview" value="{L_PREVIEW}" />&nbsp;&nbsp;<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_register.html b/phpBB/styles/subsilver2/template/ucp_register.html
deleted file mode 100644
index db26f51ebd..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_register.html
+++ /dev/null
@@ -1,103 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<script type="text/javascript">
-// <![CDATA[
- /**
- * Change language
- */
- function change_language(lang_iso)
- {
- document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}';
- document.forms['register'].change_lang.value = lang_iso;
- document.forms['register'].submit.click();
- }
-
-// ]]>
-</script>
-
-<form name="register" method="post" action="{S_UCP_ACTION}">
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_REGISTRATION}</th>
-</tr>
-
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF L_REG_COND -->
- <tr>
- <td class="row2" colspan="2"><span class="gensmall">{L_REG_COND}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- EVENT ucp_register_credentials_before -->
-<tr>
- <td class="row1" width="38%"><b class="genmed">{L_USERNAME}{L_COLON} </b><br /><span class="gensmall">{L_USERNAME_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="username" size="25" value="{USERNAME}" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b></td>
- <td class="row2"><input class="post" type="email" name="email" size="25" maxlength="100" value="{EMAIL}" autocomplete="off" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_PASSWORD}{L_COLON} </b><br /><span class="gensmall">{L_PASSWORD_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="password" name="new_password" size="25" value="{PASSWORD}" autocomplete="off" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_CONFIRM_PASSWORD}{L_COLON} </b></td>
- <td class="row2"><input class="post" type="password" name="password_confirm" size="25" value="{PASSWORD_CONFIRM}" autocomplete="off" /></td>
-</tr>
-<!-- EVENT ucp_register_credentials_after -->
-<!-- EVENT ucp_register_options_before -->
-<tr>
- <td class="row1"><b class="genmed">{L_LANGUAGE}{L_COLON} </b></td>
- <td class="row2"><select name="lang" onchange="change_language(this.value); return false;">{S_LANG_OPTIONS}</select></td>
-</tr>
-
-<!-- INCLUDE timezone_option.html -->
-
-<!-- EVENT ucp_register_profile_fields_before -->
-<!-- IF .profile_fields -->
- <tr>
- <td class="row2" colspan="2"><span class="gensmall">{L_ITEMS_REQUIRED}</span></td>
- </tr>
-<!-- BEGIN profile_fields -->
- <tr>
- <td class="row1" width="35%">
- <b class="genmed">{profile_fields.LANG_NAME}{L_COLON} </b>
- <!-- IF profile_fields.S_REQUIRED --><b>*</b><!-- ENDIF -->
- <!-- IF profile_fields.LANG_EXPLAIN --><br /><span class="gensmall">{profile_fields.LANG_EXPLAIN}</span><!-- ENDIF -->
- </td>
- <td class="row2">{profile_fields.FIELD}<!-- IF profile_fields.ERROR --><br /><span class="gensmall error">{profile_fields.ERROR}</span><!-- ENDIF --></td>
- </tr>
-
-<!-- END profile_fields -->
-<!-- ENDIF -->
-<!-- EVENT ucp_register_profile_fields_after -->
- <!-- IF CAPTCHA_TEMPLATE -->
- <!-- INCLUDE {CAPTCHA_TEMPLATE} -->
- <!-- ENDIF -->
-
-<!-- IF S_COPPA -->
- <tr>
- <th colspan="2" valign="middle">{L_COPPA_COMPLIANCE}</th>
- </tr>
- <tr>
- <td class="row3" colspan="2"><span class="gensmall">{L_COPPA_EXPLAIN}</span></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- EVENT ucp_register_buttons_before -->
-
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" id="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_remind.html b/phpBB/styles/subsilver2/template/ucp_remind.html
deleted file mode 100644
index f7fde4b3be..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_remind.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div align="center">
-
-<form action="{S_PROFILE_ACTION}" method="post">
-
-<table class="tablebg" width="50%" cellspacing="1" cellpadding="4" border="0">
-<tr>
- <th colspan="2">{L_SEND_PASSWORD}</th>
-</tr>
-<tr>
- <td class="row1" width="38%"><b class="genmed">{L_USERNAME}{L_COLON} </b></td>
- <td class="row2"><input type="text" class="post" name="username" size="25" value="{USERNAME}" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b><br /><span class="gensmall">{L_EMAIL_REMIND}</span></td>
- <td class="row2"><input type="email" class="post" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input type="submit" name="submit" value="{L_SUBMIT}" class="btnmain" />&nbsp;&nbsp;<input type="reset" value="{L_RESET}" name="reset" class="btnlite" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-</form>
-
-</div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_resend.html b/phpBB/styles/subsilver2/template/ucp_resend.html
deleted file mode 100644
index 62e7e96d6b..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_resend.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<div align="center">
-
-<form action="{S_PROFILE_ACTION}" method="post">
-
-<table class="tablebg" width="50%" cellspacing="1" cellpadding="4" border="0">
-<tr>
- <th colspan="2">{L_UCP_RESEND}</th>
-</tr>
-<tr>
- <td class="row1" width="38%"><b class="genmed">{L_USERNAME}{L_COLON} </b></td>
- <td class="row2"><input type="text" class="post" name="username" size="25" value="{USERNAME}" /></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b><br /><span class="gensmall">{L_EMAIL_REMIND}</span></td>
- <td class="row2"><input type="email" class="post" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input type="submit" name="submit" value="{L_SUBMIT}" class="btnmain" />&nbsp;&nbsp;<input type="reset" value="{L_RESET}" name="reset" class="btnlite" /></td>
-</tr>
-</table>
-{S_FORM_TOKEN}
-
-</form>
-
-</div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_zebra_foes.html b/phpBB/styles/subsilver2/template/ucp_zebra_foes.html
deleted file mode 100644
index 6149a80e69..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_zebra_foes.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<tr>
- <td class="row3" colspan="2"><span class="gensmall">{L_FOES_EXPLAIN}</span></td>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td class="row1" width="40%"><b class="genmed">{L_YOUR_FOES}{L_COLON}</b><br /><span class="gensmall">{L_YOUR_FOES_EXPLAIN}</span></td>
- <td class="row2" align="center"><!-- IF S_USERNAME_OPTIONS --><select name="usernames[]" multiple="multiple" size="5">{S_USERNAME_OPTIONS}</select><!-- ELSE --><b class="genmed">{L_NO_FOES}</b><!-- ENDIF --></td>
-</tr>
-<tr>
- <td class="row1"><b class="genmed">{L_ADD_FOES}{L_COLON}</b><br /><span class="gensmall">{L_ADD_FOES_EXPLAIN} [ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</span></td>
- <td class="row2" align="center"><textarea name="add" rows="5" cols="30">{USERNAMES}</textarea><br /></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_zebra_friends.html b/phpBB/styles/subsilver2/template/ucp_zebra_friends.html
deleted file mode 100644
index 3e18af9969..0000000000
--- a/phpBB/styles/subsilver2/template/ucp_zebra_friends.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!-- INCLUDE ucp_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th colspan="2" valign="middle">{L_TITLE}</th>
-</tr>
-<!-- EVENT ucp_friend_list_before -->
-<tr>
- <td class="row3" colspan="2"><span class="gensmall">{L_FRIENDS_EXPLAIN}</span></td>
-</tr>
-<!-- IF ERROR -->
- <tr>
- <td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
- </tr>
-<!-- ENDIF -->
-<tr>
- <td class="row1" width="40%"><b class="genmed">{L_YOUR_FRIENDS}{L_COLON}</b><br /><span class="gensmall">{L_YOUR_FRIENDS_EXPLAIN}</span></td>
- <td class="row2" align="center"><!-- IF S_USERNAME_OPTIONS --><select name="usernames[]" multiple="multiple" size="5">{S_USERNAME_OPTIONS}</select><!-- ELSE --><b class="genmed">{L_NO_FRIENDS}</b><!-- ENDIF --></td>
-</tr>
-<!-- EVENT ucp_friend_list_after -->
-<tr>
- <td class="row1"><b class="genmed">{L_ADD_FRIENDS}{L_COLON}</b><br /><span class="gensmall">{L_ADD_FRIENDS_EXPLAIN} [ <a href="{U_FIND_USERNAME}" onclick="find_username(this.href); return false;">{L_FIND_USERNAME}</a> ]</span></td>
- <td class="row2" align="center"><textarea name="add" rows="5" cols="30">{USERNAMES}</textarea><br /></td>
-</tr>
-<tr>
- <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<input class="btnlite" type="reset" value="{L_RESET}" name="reset" /></td>
-</tr>
-</table>
-
-<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/viewforum_body.html b/phpBB/styles/subsilver2/template/viewforum_body.html
deleted file mode 100644
index c76c081ba7..0000000000
--- a/phpBB/styles/subsilver2/template/viewforum_body.html
+++ /dev/null
@@ -1,381 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- IF S_FORUM_RULES -->
- <div class="forumrules<!-- IF U_FORUM_RULES --> rules-link<!-- ENDIF -->">
- <!-- IF U_FORUM_RULES -->
- <h3>{L_FORUM_RULES}</h3><br />
- <a href="{U_FORUM_RULES}"><b>{L_FORUM_RULES_LINK}</b></a>
- <!-- ELSE -->
- <h3>{L_FORUM_RULES}</h3><br />
- {FORUM_RULES}
- <!-- ENDIF -->
- </div>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-<!-- IF S_DISPLAY_ACTIVE -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat" colspan="<!-- IF S_TOPIC_ICONS -->7<!-- ELSE -->6<!-- ENDIF -->"><span class="nav">{L_ACTIVE_TOPICS}</span></td>
- </tr>
-
- <tr>
- <!-- IF S_TOPIC_ICONS -->
- <th colspan="3">&nbsp;{L_TOPICS}&nbsp;</th>
- <!-- ELSE -->
- <th colspan="2">&nbsp;{L_TOPICS}&nbsp;</th>
- <!-- ENDIF -->
- <th>&nbsp;{L_AUTHOR}&nbsp;</th>
- <th>&nbsp;{L_REPLIES}&nbsp;</th>
- <th>&nbsp;{L_VIEWS}&nbsp;</th>
- <th>&nbsp;{L_LAST_POST}&nbsp;</th>
- </tr>
-
- <!-- EVENT viewforum_body_topic_row_before -->
-
- <!-- BEGIN topicrow -->
-
- <!-- EVENT viewforum_body_topicrow_row_before -->
- <tr>
- <!-- EVENT viewforum_body_topic_row_prepend -->
- <td class="row1" width="25" align="center">{topicrow.TOPIC_FOLDER_IMG}</td>
- <!-- IF S_TOPIC_ICONS -->
- <td class="row1" width="25" align="center"><!-- IF topicrow.TOPIC_ICON_IMG --><img src="{T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}" width="{topicrow.TOPIC_ICON_IMG_WIDTH}" height="{topicrow.TOPIC_ICON_IMG_HEIGHT}" alt="" title="" /><!-- ENDIF --></td>
- <!-- ENDIF -->
- <td class="row1">
- <!-- EVENT topiclist_row_prepend -->
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="imageset">{NEWEST_POST_IMG}</a><!-- ENDIF -->
- {topicrow.ATTACH_ICON_IMG} <!-- IF topicrow.S_HAS_POLL or topicrow.S_TOPIC_MOVED --><b>{topicrow.TOPIC_TYPE}</b> <!-- ENDIF --><a title="{L_POSTED}{L_COLON} {topicrow.FIRST_POST_TIME}" href="{topicrow.U_VIEW_TOPIC}"class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED -->
- <a href="{topicrow.U_MCP_QUEUE}" class="imageset">{topicrow.UNAPPROVED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_DELETED -->
- <a href="{topicrow.U_MCP_QUEUE}" class="imageset">{DELETED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED -->
- <a href="{topicrow.U_MCP_REPORT}" class="imageset">{REPORTED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- EVENT topiclist_row_topic_title_after -->
- <!-- IF .topicrow.pagination -->
- <p class="gensmall"> [ {GOTO_PAGE_IMG}{L_GOTO_PAGE}{L_COLON}
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><strong>{topicrow.pagination.PAGE_NUMBER}</strong>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --> {L_ELLIPSIS}
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a>
- <!-- ENDIF -->
- <!-- END pagination -->
- ] </p>
- <!-- ENDIF -->
- <!-- EVENT topiclist_row_append -->
- </td>
- <td class="row2" width="130" align="center"><p class="topicauthor">{topicrow.TOPIC_AUTHOR_FULL}</p></td>
- <td class="row1" width="50" align="center"><p class="topicdetails">{topicrow.REPLIES}</p></td>
- <td class="row2" width="50" align="center"><p class="topicdetails">{topicrow.VIEWS}</p></td>
- <td class="row1" width="140" align="center">
- <p class="topicdetails" style="white-space: nowrap;">{topicrow.LAST_POST_TIME}</p>
- <p class="topicdetails">{topicrow.LAST_POST_AUTHOR_FULL}
- <!-- IF not S_IS_BOT --><a href="{topicrow.U_LAST_POST}" class="imageset">{LAST_POST_IMG}</a><!-- ENDIF -->
- </p>
- </td>
- <!-- EVENT viewforum_body_topic_row_append -->
- </tr>
- <!-- EVENT viewforum_body_topic_row_after -->
-
- <!-- BEGINELSE -->
-
- <tr>
- <!-- IF S_TOPIC_ICONS -->
- <td class="row1" colspan="7" height="30" align="center" valign="middle"><span class="gen"><!-- IF not S_SORT_DAYS -->{L_NO_TOPICS}<!-- ELSE -->{L_NO_TOPICS_TIME_FRAME}<!-- ENDIF --></span></td>
- <!-- ELSE -->
- <td class="row1" colspan="6" height="30" align="center" valign="middle"><span class="gen"><!-- IF not S_SORT_DAYS -->{L_NO_TOPICS}<!-- ELSE -->{L_NO_TOPICS_TIME_FRAME}<!-- ENDIF --></span></td>
- <!-- ENDIF -->
- </tr>
- <!-- END topicrow -->
-
- <tr align="center">
- <td class="cat" colspan="<!-- IF S_TOPIC_ICONS -->7<!-- ELSE -->6<!-- ENDIF -->">&nbsp;</td>
- </tr>
- </table>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-<!-- IF S_HAS_SUBFORUM -->
- <!-- INCLUDE forumlist_body.html -->
- <br clear="all" />
-<!-- ENDIF -->
-
-<!-- IF S_IS_POSTABLE or S_NO_READ_ACCESS -->
- <div id="pageheader">
- <!-- EVENT viewforum_forum_title_before -->
- <h2><!-- EVENT viewforum_forum_name_prepend --><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a><!-- EVENT viewforum_forum_name_append --></h2>
- <!-- EVENT viewforum_forum_title_after -->
- <!-- IF MODERATORS -->
- <p class="moderators"><!-- IF S_SINGLE_MODERATOR -->{L_MODERATOR}<!-- ELSE -->{L_MODERATORS}<!-- ENDIF -->{L_COLON} {MODERATORS}</p>
- <!-- ENDIF -->
- <!-- IF U_MCP -->
- <p class="linkmcp">[&nbsp;<!-- IF U_ACP --><a href="{U_ACP}">{L_ACP}</a><!-- IF U_MCP -->&nbsp;|&nbsp;<!-- ENDIF --><!-- ENDIF --><!-- IF U_MCP --><a href="{U_MCP}">{L_MCP}</a><!-- ENDIF -->&nbsp;]</p>
- <!-- ENDIF -->
- </div>
-
- <br clear="all" /><br />
-<!-- ENDIF -->
-
-<div id="pagecontent">
-
-<!-- IF S_NO_READ_ACCESS -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row1" height="30" align="center" valign="middle"><span class="gen">{L_NO_READ_ACCESS}</span></td>
- </tr>
- </table>
-
- <!-- IF not S_USER_LOGGED_IN and not S_IS_BOT -->
-
- <br /><br />
-
- <form method="post" action="{S_LOGIN_ACTION}">
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat"><h4><a href="{U_LOGIN_LOGOUT}">{L_LOGIN_LOGOUT}</a></h4></td>
- </tr>
- <tr>
- <td class="row1" align="center"><span class="genmed">{L_USERNAME}{L_COLON}</span> <input class="post" type="text" name="username" size="10" />&nbsp; <span class="genmed">{L_PASSWORD}{L_COLON}</span> <input class="post" type="password" name="password" size="10" autocomplete="off" /><!-- IF S_AUTOLOGIN_ENABLED -->&nbsp; <span class="gensmall">{L_LOG_ME_IN}</span> <input type="checkbox" class="radio" name="autologin" /><!-- ENDIF -->&nbsp; <input type="submit" class="btnmain" name="login" value="{L_LOGIN}" /></td>
- </tr>
- </table>
- {S_LOGIN_REDIRECT}
- </form>
-
- <!-- ENDIF -->
-
- <br clear="all" />
-<!-- ENDIF -->
-
- <!-- IF S_DISPLAY_POST_INFO or TOTAL_TOPICS -->
- <table width="100%" cellspacing="1">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}" valign="middle" nowrap="nowrap">
- <!-- EVENT viewforum_buttons_top_before -->
-
- <!-- IF S_DISPLAY_POST_INFO and not S_IS_BOT -->
- <a href="{U_POST_NEW_TOPIC}" class="imageset">{POST_IMG}</a>
- <!-- ENDIF -->
-
- <!-- EVENT viewforum_buttons_top_after -->
- </td>
-
- <!-- IF TOTAL_TOPICS -->
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ {TOTAL_TOPICS} ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- <!-- ENDIF -->
- </tr>
- </table>
- <!-- ENDIF -->
-
- <!-- IF not S_DISPLAY_ACTIVE and (S_IS_POSTABLE or .topicrow) -->
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat" colspan="<!-- IF S_TOPIC_ICONS -->7<!-- ELSE -->6<!-- ENDIF -->">
- <table width="100%" cellspacing="0">
- <tr class="nav">
- <td valign="middle">&nbsp;<!-- IF U_WATCH_FORUM_LINK and not S_IS_BOT --><a href="{U_WATCH_FORUM_LINK}">{S_WATCH_FORUM_TITLE}</a><!-- ENDIF --></td>
- <td align="{S_CONTENT_FLOW_END}" valign="middle"><!-- IF not S_IS_BOT and U_MARK_TOPICS and .topicrow --><a href="{U_MARK_TOPICS}">{L_MARK_TOPICS_READ}</a><!-- ENDIF -->&nbsp;</td>
- </tr>
- </table>
- </td>
- </tr>
-
- <tr>
- <!-- IF S_TOPIC_ICONS -->
- <th colspan="3">&nbsp;{L_TOPICS}&nbsp;</th>
- <!-- ELSE -->
- <th colspan="2">&nbsp;{L_TOPICS}&nbsp;</th>
- <!-- ENDIF -->
- <th>&nbsp;{L_AUTHOR}&nbsp;</th>
- <th>&nbsp;{L_REPLIES}&nbsp;</th>
- <th>&nbsp;{L_VIEWS}&nbsp;</th>
- <th>&nbsp;{L_LAST_POST}&nbsp;</th>
- </tr>
-
- <!-- BEGIN topicrow -->
-
- <!-- IF topicrow.S_TOPIC_TYPE_SWITCH eq 1 -->
- <tr>
- <td class="row3" colspan="<!-- IF S_TOPIC_ICONS -->7<!-- ELSE -->6<!-- ENDIF -->"><b class="gensmall">{L_ANNOUNCEMENTS}</b></td>
- </tr>
- <!-- ELSEIF topicrow.S_TOPIC_TYPE_SWITCH eq 0 -->
- <tr>
- <td class="row3" colspan="<!-- IF S_TOPIC_ICONS -->7<!-- ELSE -->6<!-- ENDIF -->"><b class="gensmall">{L_TOPICS}</b></td>
- </tr>
- <!-- ENDIF -->
-
- <tr>
- <td class="row1" width="25" align="center">{topicrow.TOPIC_FOLDER_IMG}</td>
- <!-- IF S_TOPIC_ICONS -->
- <td class="row1" width="25" align="center"><!-- IF topicrow.TOPIC_ICON_IMG --><img src="{T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}" width="{topicrow.TOPIC_ICON_IMG_WIDTH}" height="{topicrow.TOPIC_ICON_IMG_HEIGHT}" alt="" title="" /><!-- ENDIF --></td>
- <!-- ENDIF -->
- <td class="row1">
- <!-- EVENT topiclist_row_prepend -->
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}" class="imageset">{NEWEST_POST_IMG}</a><!-- ENDIF -->
- {topicrow.ATTACH_ICON_IMG} <!-- IF topicrow.S_HAS_POLL or topicrow.S_TOPIC_MOVED --><b>{topicrow.TOPIC_TYPE}</b> <!-- ENDIF -->
- <a title="{L_POSTED}{L_COLON} {topicrow.FIRST_POST_TIME}" href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED -->
- <a href="{topicrow.U_MCP_QUEUE}" class="imageset">{topicrow.UNAPPROVED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_DELETED -->
- <a href="{topicrow.U_MCP_QUEUE}" class="imageset">{DELETED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED -->
- <a href="{topicrow.U_MCP_REPORT}" class="imageset">{REPORTED_IMG}</a>&nbsp;
- <!-- ENDIF -->
- <!-- IF .topicrow.pagination -->
- <p class="gensmall"> [ {GOTO_PAGE_IMG}{L_GOTO_PAGE}{L_COLON}
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><strong>{topicrow.pagination.PAGE_NUMBER}</strong>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --> {L_ELLIPSIS}
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a>
- <!-- ENDIF -->
- <!-- END pagination -->
- ] </p>
- <!-- ENDIF -->
- <!-- IF topicrow.S_POST_GLOBAL and FORUM_ID != topicrow.FORUM_ID --><p class="gensmall">{L_IN} <a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a></p><!-- ENDIF -->
- <!-- EVENT topiclist_row_append -->
- </td>
- <td class="row2" width="130" align="center"><p class="topicauthor">{topicrow.TOPIC_AUTHOR_FULL}</p></td>
- <td class="row1" width="50" align="center"><p class="topicdetails">{topicrow.REPLIES}</p></td>
- <td class="row2" width="50" align="center"><p class="topicdetails">{topicrow.VIEWS}</p></td>
- <td class="row1" width="140" align="center">
- <p class="topicdetails" style="white-space: nowrap;">{topicrow.LAST_POST_TIME}</p>
- <p class="topicdetails">{topicrow.LAST_POST_AUTHOR_FULL}
- <!-- IF not S_IS_BOT --><a href="{topicrow.U_LAST_POST}" class="imageset">{LAST_POST_IMG}</a><!-- ENDIF -->
- </p>
- </td>
- </tr>
-
- <!-- BEGINELSE -->
- <!-- IF S_IS_POSTABLE -->
- <tr>
- <!-- IF S_TOPIC_ICONS -->
- <td class="row1" colspan="7" height="30" align="center" valign="middle"><span class="gen"><!-- IF not S_SORT_DAYS -->{L_NO_TOPICS}<!-- ELSE -->{L_NO_TOPICS_TIME_FRAME}<!-- ENDIF --></span></td>
- <!-- ELSE -->
- <td class="row1" colspan="6" height="30" align="center" valign="middle"><span class="gen"><!-- IF not S_SORT_DAYS -->{L_NO_TOPICS}<!-- ELSE -->{L_NO_TOPICS_TIME_FRAME}<!-- ENDIF --></span></td>
- <!-- ENDIF -->
- </tr>
- <!-- ENDIF -->
- <!-- END topicrow -->
-
- <!-- IF not S_IS_BOT -->
- <tr align="center">
- <!-- IF S_TOPIC_ICONS -->
- <td class="cat" colspan="7">
- <!-- ELSE -->
- <td class="cat" colspan="6">
- <!-- ENDIF -->
- <form method="post" action="{S_FORUM_ACTION}"><span class="gensmall">{L_DISPLAY_TOPICS}{L_COLON}</span>&nbsp;{S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" name="sort" value="{L_GO}" /></form>
- </td>
- </tr>
- <!-- ENDIF -->
- </table>
- <!-- ENDIF -->
-
- <!-- IF S_DISPLAY_POST_INFO or TOTAL_TOPICS -->
- <table width="100%" cellspacing="1">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}" valign="middle" nowrap="nowrap">
- <!-- EVENT viewforum_buttons_bottom_before -->
-
- <!-- IF S_DISPLAY_POST_INFO and not S_IS_BOT -->
- <a href="{U_POST_NEW_TOPIC}" class="imageset">{POST_IMG}</a>
- <!-- ENDIF -->
-
- <!-- EVENT viewforum_buttons_bottom_after -->
- </td>
-
- <!-- IF TOTAL_TOPICS -->
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ {TOTAL_TOPICS} ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- <!-- ENDIF -->
- </tr>
- </table>
- <!-- ENDIF -->
-
- <br clear="all" />
-</div>
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<!-- IF S_DISPLAY_ONLINE_LIST -->
- <br clear="all" />
-
- <table class="tablebg stat-block online-list" width="100%" cellspacing="1">
- <tr>
- <td class="cat"><h4>{L_WHO_IS_ONLINE}</h4></td>
- </tr>
- <tr>
- <td class="row1"><p class="gensmall">{LOGGED_IN_USER_LIST}</p></td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-<!-- IF S_DISPLAY_POST_INFO -->
- <br clear="all" />
-
- <table width="100%" cellspacing="0">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}" valign="top">
- <table cellspacing="3" cellpadding="0" border="0">
- <tr>
- <td width="20" style="text-align: center;">{FOLDER_UNREAD_IMG}</td>
- <td class="gensmall">{L_UNREAD_POSTS}</td>
- <td>&nbsp;&nbsp;</td>
- <td width="20" style="text-align: center;">{FOLDER_IMG}</td>
- <td class="gensmall">{L_NO_UNREAD_POSTS}</td>
- <td>&nbsp;&nbsp;</td>
- <td width="20" style="text-align: center;">{FOLDER_ANNOUNCE_IMG}</td>
- <td class="gensmall">{L_ICON_ANNOUNCEMENT}</td>
- </tr>
- <tr>
- <td style="text-align: center;">{FOLDER_HOT_UNREAD_IMG}</td>
- <td class="gensmall">{L_UNREAD_POSTS_HOT}</td>
- <td>&nbsp;&nbsp;</td>
- <td style="text-align: center;">{FOLDER_HOT_IMG}</td>
- <td class="gensmall">{L_NO_UNREAD_POSTS_HOT}</td>
- <td>&nbsp;&nbsp;</td>
- <td style="text-align: center;">{FOLDER_STICKY_IMG}</td>
- <td class="gensmall">{L_ICON_STICKY}</td>
- </tr>
- <tr>
- <td style="text-align: center;">{FOLDER_LOCKED_UNREAD_IMG}</td>
- <td class="gensmall">{L_UNREAD_POSTS_LOCKED}</td>
- <td>&nbsp;&nbsp;</td>
- <td style="text-align: center;">{FOLDER_LOCKED_IMG}</td>
- <td class="gensmall">{L_NO_UNREAD_POSTS_LOCKED}</td>
- <td>&nbsp;&nbsp;</td>
- <td style="text-align: center;">{FOLDER_MOVED_IMG}</td>
- <td class="gensmall">{L_TOPIC_MOVED}</td>
- </tr>
- </table>
- </td>
- <td align="{S_CONTENT_FLOW_END}"><span class="gensmall"><!-- BEGIN rules -->{rules.RULE}<br /><!-- END rules --></span></td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-<br clear="all" />
-
-<table width="100%" cellspacing="0">
-<tr>
- <td><!-- IF S_DISPLAY_SEARCHBOX --><!-- INCLUDE searchbox.html --><!-- ENDIF --></td>
- <td align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></td>
-</tr>
-</table>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/viewonline_body.html b/phpBB/styles/subsilver2/template/viewonline_body.html
deleted file mode 100644
index 70b8b52efa..0000000000
--- a/phpBB/styles/subsilver2/template/viewonline_body.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<h4>{TOTAL_REGISTERED_USERS_ONLINE}</h4>
-<h4>{TOTAL_GUEST_USERS_ONLINE}<!-- IF S_SWITCH_GUEST_DISPLAY --> [ <a href="{U_SWITCH_GUEST_DISPLAY}">{L_SWITCH_GUEST_DISPLAY}</a> ]<!-- ENDIF --></h4>
-<br />
-
-<!-- IF .pagination -->
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th width="40%"><a href="{U_SORT_USERNAME}">{L_USERNAME}</a></th>
- <th width="20%"><a href="{U_SORT_UPDATED}">{L_LAST_UPDATED}</a></th>
- <th width="40%"><a href="{U_SORT_LOCATION}">{L_FORUM_LOCATION}</a></th>
-</tr>
-<!-- BEGIN user_row -->
- <tr>
- <td class="row1"><p class="gen">{user_row.USERNAME_FULL}</p><!-- IF user_row.USER_IP --><p class="gensmall">{L_IP}{L_COLON} <a href="{user_row.U_USER_IP}">{user_row.USER_IP}</a> &#187; <a href="{user_row.U_WHOIS}" onclick="popup(this.href, 750, 500); return false;">{L_WHOIS}</a></p><!-- ENDIF -->
- <!-- IF user_row.USER_BROWSER -->{user_row.USER_BROWSER}<!-- ENDIF --></td>
- <td class="row2" align="center" nowrap="nowrap"><p class="genmed">&nbsp;{user_row.LASTUPDATE}</p></td>
- <td class="row1"><p class="genmed"><a href="{user_row.U_FORUM_LOCATION}">{user_row.FORUM_LOCATION}</a></p></td>
- </tr>
-<!-- END user_row -->
-
-<!-- IF LEGEND -->
- <tr>
- <td class="row1" colspan="3"><b class="gensmall">{L_LEGEND} :: {LEGEND}</b></td>
- </tr>
-<!-- ENDIF -->
-</table>
-
-<!-- IF .pagination -->
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-<div class="gensmall" align="{S_CONTENT_FLOW_END}">{L_ONLINE_EXPLAIN}</div>
-
-<br clear="all" />
-
-<!-- INCLUDE breadcrumbs.html -->
-
-<br clear="all" />
-
-<div align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></div>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/viewonline_whois.html b/phpBB/styles/subsilver2/template/viewonline_whois.html
deleted file mode 100644
index ca5b326df8..0000000000
--- a/phpBB/styles/subsilver2/template/viewonline_whois.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!-- INCLUDE simple_header.html -->
-
-<table class="tablebg" width="100%" cellspacing="1">
-<tr>
- <th>{L_WHOIS}</th>
-</tr>
-<tr>
- <td class="row1"><pre>{WHOIS}</pre><br /><a class="nav" href="#" onclick="window.close(); return false;">{L_CLOSE_WINDOW}</a></td>
-</tr>
-</table>
-
-<!-- INCLUDE simple_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/viewtopic_body.html b/phpBB/styles/subsilver2/template/viewtopic_body.html
deleted file mode 100644
index e340334cf8..0000000000
--- a/phpBB/styles/subsilver2/template/viewtopic_body.html
+++ /dev/null
@@ -1,462 +0,0 @@
-<!-- INCLUDE overall_header.html -->
-
-<!-- IF S_FORUM_RULES -->
- <div class="forumrules<!-- IF U_FORUM_RULES --> rules-link<!-- ENDIF -->">
- <!-- IF U_FORUM_RULES -->
- <h3>{L_FORUM_RULES}</h3><br />
- <a href="{U_FORUM_RULES}"><b>{L_FORUM_RULES_LINK}</b></a>
- <!-- ELSE -->
- <h3>{L_FORUM_RULES}</h3><br />
- {FORUM_RULES}
- <!-- ENDIF -->
- </div>
-
- <br clear="all" />
-<!-- ENDIF -->
-
-<div id="pageheader">
- <h2><!-- EVENT viewtopic_topic_title_prepend --><a class="titles" href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a><!-- EVENT viewtopic_topic_title_append --></h2>
- <!-- EVENT viewtopic_topic_title_after -->
-
-<!-- IF MODERATORS -->
- <p class="moderators"><!-- IF S_SINGLE_MODERATOR -->{L_MODERATOR}<!-- ELSE -->{L_MODERATORS}<!-- ENDIF -->{L_COLON} {MODERATORS}</p>
-<!-- ENDIF -->
-<!-- IF U_MCP -->
- <p class="linkmcp">[&nbsp;<!-- IF U_ACP --><a href="{U_ACP}">{L_ACP}</a><!-- IF U_MCP -->&nbsp;|&nbsp;<!-- ENDIF --><!-- ENDIF --><!-- IF U_MCP --><a href="{U_MCP}">{L_MCP}</a><!-- ENDIF -->&nbsp;]</p>
-<!-- ENDIF -->
-</div>
-
-<br clear="all" /><br />
-
-<div id="pagecontent">
-
- <table width="100%" cellspacing="1">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}" valign="middle" nowrap="nowrap">
- <!-- EVENT viewtopic_buttons_top_before -->
-
- <!-- IF not S_IS_BOT -->
- <!-- IF S_DISPLAY_POST_INFO --><a href="{U_POST_NEW_TOPIC}" class="imageset">{POST_IMG}</a>&nbsp;<!-- ENDIF -->
- <!-- IF S_DISPLAY_REPLY_INFO --><a href="{U_POST_REPLY_TOPIC}" class="imageset">{REPLY_IMG}</a><!-- ENDIF -->
- <!-- ENDIF -->
-
- <!-- EVENT viewtopic_buttons_top_after -->
- </td>
- <!-- IF TOTAL_POSTS -->
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ {TOTAL_POSTS} ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --><!-- EVENT viewtopic_body_pagination_top_after --></td>
- <!-- ENDIF -->
- </tr>
- </table>
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat">
- <table width="100%" cellspacing="0">
- <tr>
- <td class="nav" nowrap="nowrap">&nbsp;
- <!-- IF not S_IS_BOT -->
- <!-- IF U_WATCH_TOPIC --><a href="{U_WATCH_TOPIC}" title="{S_WATCH_TOPIC_TITLE}">{S_WATCH_TOPIC_TITLE}</a><!-- IF U_PRINT_TOPIC or U_EMAIL_TOPIC or U_BUMP_TOPIC or U_BOOKMARK_TOPIC --> | <!-- ENDIF --><!-- ENDIF -->
- <!-- IF U_BOOKMARK_TOPIC --><a href="{U_BOOKMARK_TOPIC}" title="{S_BOOKMARK_TOPIC}">{S_BOOKMARK_TOPIC}</a><!-- IF U_PRINT_TOPIC or U_EMAIL_TOPIC or U_BUMP_TOPIC --> | <!-- ENDIF --><!-- ENDIF -->
- <!-- IF U_PRINT_TOPIC --><a href="{U_PRINT_TOPIC}" title="{L_PRINT_TOPIC}">{L_PRINT_TOPIC}</a><!-- IF U_EMAIL_TOPIC or U_BUMP_TOPIC --> | <!-- ENDIF --><!-- ENDIF -->
- <!-- IF U_EMAIL_TOPIC --><a href="{U_EMAIL_TOPIC}" title="{L_EMAIL_TOPIC}">{L_EMAIL_TOPIC}</a><!-- IF U_BUMP_TOPIC --> | <!-- ENDIF --><!-- ENDIF -->
- <!-- IF U_BUMP_TOPIC --><a href="{U_BUMP_TOPIC}" title="{L_BUMP_TOPIC}">{L_BUMP_TOPIC}</a><!-- ENDIF -->
- <!-- ENDIF -->
- </td>
- <td class="nav" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><a href="{U_VIEW_OLDER_TOPIC}">{L_VIEW_PREVIOUS_TOPIC}</a><!-- IF U_VIEW_UNREAD_POST and not S_IS_BOT --> | <a href="{U_VIEW_UNREAD_POST}">{L_VIEW_UNREAD_POST}</a><!-- ENDIF --> | <a href="{U_VIEW_NEWER_TOPIC}">{L_VIEW_NEXT_TOPIC}</a>&nbsp;</td>
- </tr>
- </table>
- </td>
- </tr>
-<!-- EVENT viewtopic_body_poll_before -->
-<!-- IF S_HAS_POLL -->
- <tr>
- <td class="row2" colspan="2" align="center"><br clear="all" />
-
- <form method="post" action="{S_POLL_ACTION}">
-
- <table cellspacing="0" cellpadding="4" border="0" align="center">
- <tr>
- <td align="center"><span class="gen"><!-- EVENT viewtopic_body_poll_question_prepend --><b>{POLL_QUESTION}</b><!-- EVENT viewtopic_body_poll_question_append --></span><br /><span class="gensmall">{L_POLL_LENGTH}</span></td>
- </tr>
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}">
- <table cellspacing="0" cellpadding="2" border="0">
- <!-- BEGIN poll_option -->
- <tr>
- <!-- EVENT viewtopic_body_poll_option_before -->
- <!-- IF S_CAN_VOTE -->
- <td<!-- IF poll_option.POLL_OPTION_MOST_VOTES --> class="most-votes"<!-- ENDIF -->>
- <!-- IF S_IS_MULTI_CHOICE -->
- <input type="checkbox" class="radio" name="vote_id[]" value="{poll_option.POLL_OPTION_ID}"<!-- IF poll_option.POLL_OPTION_VOTED --> checked="checked"<!-- ENDIF --> />
- <!-- ELSE -->
- <input type="radio" class="radio" name="vote_id[]" value="{poll_option.POLL_OPTION_ID}"<!-- IF poll_option.POLL_OPTION_VOTED --> checked="checked"<!-- ENDIF --> />
- <!-- ENDIF -->
- </td>
- <!-- ENDIF -->
- <td><span class="gen">{poll_option.POLL_OPTION_CAPTION}</span></td>
- <!-- IF S_DISPLAY_RESULTS -->
- <td dir="ltr">{POLL_LEFT_CAP_IMG}<span class="imageset poll_center" style="width: {poll_option.POLL_OPTION_WIDTH}px; background-repeat: repeat-x;">{poll_option.POLL_OPTION_PERCENT}</span>{POLL_RIGHT_CAP_IMG}</td>
- <td class="gen" align="{S_CONTENT_FLOW_END}"><b>&nbsp;{poll_option.POLL_OPTION_PERCENT}&nbsp;</b></td>
- <td class="gen" align="center">[ {poll_option.POLL_OPTION_RESULT} ]</td>
- <!-- IF poll_option.POLL_OPTION_VOTED -->
- <td class="gensmall" valign="top"><b title="{L_POLL_VOTED_OPTION}">x</b></td>
- <!-- ENDIF -->
- <!-- ENDIF -->
- <!-- EVENT viewtopic_body_poll_option_after -->
- </tr>
- <!-- END poll_option -->
- </table>
- </td>
- </tr>
- <!-- IF S_CAN_VOTE -->
- <tr>
- <td align="center"><span class="gensmall">{L_MAX_VOTES}</span><br /><br /><input type="submit" name="update" value="{L_SUBMIT_VOTE}" class="btnlite" /></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_DISPLAY_RESULTS -->
- <tr>
- <td class="gensmall" colspan="4" align="center"><b>{L_TOTAL_VOTES}{L_COLON} {TOTAL_VOTES}</b></td>
- </tr>
- <!-- ELSE -->
- <tr>
- <td align="center"><span class="gensmall"><b><a href="{U_VIEW_RESULTS}">{L_VIEW_RESULTS}</a></b></span></td>
- </tr>
- <!-- ENDIF -->
- </table>
- {S_HIDDEN_FIELDS}
- {S_FORM_TOKEN}
- </form>
-
- </td>
- </tr>
-<!-- ENDIF -->
-<!-- EVENT viewtopic_body_poll_after -->
- </table>
-
-<!-- BEGIN postrow -->
- <!-- EVENT viewtopic_body_postrow_post_before -->
- <table class="tablebg" width="100%" cellspacing="1">
- <!-- IF postrow.S_FIRST_ROW -->
- <tr>
- <th>{L_AUTHOR}</th>
- <th>{L_MESSAGE}</th>
- </tr>
- <!-- ENDIF -->
- <!-- IF postrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <!-- IF postrow.S_POST_HIDDEN -->
- <td class="gensmall" colspan="2" height="25" align="center">
- <!-- IF postrow.S_FIRST_UNREAD --><a id="unread" class="anchor" data-url="{postrow.U_MINI_POST}"></a><!-- ENDIF -->
- <a name="p{postrow.POST_ID}" class="anchor"></a>
- <!-- IF postrow.S_POST_HIDDEN -->
- <!-- IF postrow.S_POST_DELETED -->
- {postrow.L_POST_DELETED_MESSAGE}
- <!-- ELSEIF postrow.S_IGNORE_POST -->
- {postrow.L_IGNORE_POST}
- <!-- ENDIF -->
- <br />{postrow.L_POST_DISPLAY}
- <!-- ENDIF -->
- </td>
- <!-- ELSE -->
-
- <td align="center" valign="middle">
- <!-- IF postrow.S_FIRST_UNREAD -->
- <a id="unread" class="anchor"<!-- IF S_UNREAD_VIEW --> data-url="{postrow.U_MINI_POST}"<!-- ENDIF -->></a>
- <!-- ENDIF -->
- <a name="p{postrow.POST_ID}" class="anchor"></a>
- <!-- EVENT viewtopic_body_post_author_before -->
- <b class="postauthor"<!-- IF postrow.POST_AUTHOR_COLOUR --> style="color: {postrow.POST_AUTHOR_COLOUR}"<!-- ENDIF -->>{postrow.POST_AUTHOR}</b>
- <!-- EVENT viewtopic_body_post_author_after -->
- </td>
- <!-- EVENT viewtopic_body_postrow_post_details_before -->
- <!-- EVENT viewtopic_body_post_subject_before -->
- <td width="100%" height="25">
- <table width="100%" cellspacing="0">
- <tr>
- <!-- IF postrow.POST_ICON_IMG -->
- <td><img src="{T_ICONS_PATH}{postrow.POST_ICON_IMG}" width="{postrow.POST_ICON_IMG_WIDTH}" height="{postrow.POST_ICON_IMG_HEIGHT}" alt="" title="" /></td>
- <!-- ENDIF -->
- <td class="gensmall" width="100%"><div style="float: {S_CONTENT_FLOW_BEGIN};">&nbsp;<b>{L_POST_SUBJECT}{L_COLON}</b> <a href="#p{postrow.POST_ID}">{postrow.POST_SUBJECT}</a></div><div style="float: {S_CONTENT_FLOW_END};"><!-- IF S_IS_BOT -->{postrow.MINI_POST_IMG}<!-- ELSE --><a href="{postrow.U_MINI_POST}" class="imageset">{postrow.MINI_POST_IMG}</a><!-- ENDIF --><b>{L_POSTED}{L_COLON}</b> {postrow.POST_DATE}&nbsp;</div></td>
- </tr>
- </table>
- </td>
- <!-- EVENT viewtopic_body_postrow_post_details_after -->
- </tr>
-
- <!-- IF postrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <td valign="top" class="profile">
- <table cellspacing="4" align="center" width="150">
- <!-- IF postrow.ONLINE_IMG -->
- <tr>
- <td>{postrow.ONLINE_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT viewtopic_body_postrow_rank_before -->
- <!-- IF postrow.RANK_TITLE -->
- <tr>
- <td class="postdetails">{postrow.RANK_TITLE}</td>
- </tr>
- <!-- ENDIF -->
- <!-- IF postrow.RANK_IMG -->
- <tr>
- <td>{postrow.RANK_IMG}</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT viewtopic_body_postrow_rank_after -->
-
- <!-- EVENT viewtopic_body_avatar_before -->
- <!-- IF postrow.POSTER_AVATAR -->
- <tr>
- <td>{postrow.POSTER_AVATAR}</td>
- </tr>
- <!-- ENDIF -->
- <!-- EVENT viewtopic_body_avatar_after -->
-
- <!-- IF not (postrow.ONLINE_IMG or postrow.RANK_TITLE or postrow.RANK_IMG or postrow.POSTER_AVATAR) -->
- <tr>
- <td></td>
- </tr>
- <!-- ENDIF -->
- </table>
-
- <span class="postdetails">
- <!-- IF postrow.POSTER_JOINED --><br /><b>{L_JOINED}{L_COLON}</b> {postrow.POSTER_JOINED}<!-- ENDIF -->
- <!-- IF postrow.POSTER_POSTS != '' --><br /><b>{L_POSTS}{L_COLON}</b> {postrow.POSTER_POSTS}<!-- ENDIF -->
- <!-- IF postrow.POSTER_WARNINGS --><br /><b>{L_WARNINGS}{L_COLON}</b> {postrow.POSTER_WARNINGS}<!-- ENDIF -->
-
- <!-- IF postrow.S_PROFILE_FIELD1 -->
- <!-- Use a construct like this to include admin defined profile fields. Replace FIELD1 with the name of your field. -->
- <br /><b>{postrow.PROFILE_FIELD1_NAME}{L_COLON}</b> {postrow.PROFILE_FIELD1_VALUE}
- <!-- ENDIF -->
-
- <!-- EVENT viewtopic_body_postrow_custom_fields_before -->
- <!-- BEGIN custom_fields -->
- <!-- IF not postrow.custom_fields.S_PROFILE_CONTACT -->
- <br /><b>{postrow.custom_fields.PROFILE_FIELD_NAME}{L_COLON}</b> {postrow.custom_fields.PROFILE_FIELD_VALUE}
- <!-- ENDIF -->
- <!-- END custom_fields -->
- <!-- EVENT viewtopic_body_postrow_custom_fields_after -->
- </span>
-
- </td>
- <td valign="top">
- <table width="100%" cellspacing="5">
- <tr>
- <td>
- <!-- IF postrow.S_POST_UNAPPROVED or postrow.S_POST_DELETED or postrow.S_POST_REPORTED -->
- <table width="100%" cellspacing="0">
- <tr>
- <td class="gensmall">
- <!-- IF postrow.S_POST_UNAPPROVED --><span class="postapprove">{UNAPPROVED_IMG} <a href="{postrow.U_MCP_APPROVE}">{L_POST_UNAPPROVED}</a></span><br /> <!-- ENDIF -->
- <!-- IF postrow.S_POST_DELETED --><span class="postapprove">{DELETED_IMG} <a href="{postrow.U_MCP_RESTORE}">{L_POST_DELETED}</a></span><br /> <!-- ENDIF -->
- <!-- IF postrow.S_POST_REPORTED --><span class="postreported">{REPORTED_IMG} <a href="{postrow.U_MCP_REPORT}">{L_POST_REPORTED}</a></span><!-- ENDIF -->
- </td>
- </tr>
- </table>
-
- <br clear="all" />
- <!-- ENDIF -->
-
- <div class="postbody">{postrow.MESSAGE}</div>
-
- <!-- IF postrow.S_HAS_ATTACHMENTS -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <!-- IF postrow.attachment.S_ROW_COUNT is even --><td class="row2"><!-- ELSE --><td class="row1"><!-- ENDIF -->{postrow.attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
-
- <!-- IF postrow.S_DISPLAY_NOTICE -->
- <span class="gensmall error"><br /><br />{L_DOWNLOAD_NOTICE}</span>
- <!-- ENDIF -->
- <!-- IF postrow.SIGNATURE -->
- <div class="postbody"><br />_________________<br />{postrow.SIGNATURE}</div>
- <!-- ENDIF -->
-
- <!-- EVENT viewtopic_body_postrow_post_notices_before -->
- <!-- IF postrow.DELETED_MESSAGE or postrow.DELETE_REASON -->
- <!-- IF postrow.DELETE_REASON -->
- <br /><br />
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><span class="gensmall">{postrow.DELETED_MESSAGE}</span></td>
- </tr>
- <tr>
- <td class="row2"><span class="genmed">{postrow.DELETE_REASON}</span></td>
- </tr>
- </table>
- <!-- ELSE -->
- <br /><br />
- <span class="gensmall">{postrow.DELETED_MESSAGE}</span>
- <!-- ENDIF -->
- <!-- ELSEIF postrow.EDITED_MESSAGE or postrow.EDIT_REASON -->
- <!-- IF postrow.EDIT_REASON -->
- <br /><br />
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="row3"><span class="gensmall">{postrow.EDITED_MESSAGE}</span></td>
- </tr>
- <tr>
- <td class="row2"><span class="genmed">{postrow.EDIT_REASON}</span></td>
- </tr>
- </table>
- <!-- ELSE -->
- <br /><br />
- <span class="gensmall">{postrow.EDITED_MESSAGE}</span>
- <!-- ENDIF -->
- <!-- ENDIF -->
-
- <!-- IF postrow.BUMPED_MESSAGE -->
- <span class="gensmall"><br /><br />{postrow.BUMPED_MESSAGE}</span>
- <!-- ENDIF -->
- <!-- EVENT viewtopic_body_postrow_post_notices_after -->
-
- <!-- EVENT viewtopic_body_postrow_post_content_footer -->
-
- <!-- IF not postrow.S_HAS_ATTACHMENTS --><br clear="all" /><br /><!-- ENDIF -->
-
- <table width="100%" cellspacing="0">
- <tr valign="middle">
- <td class="gensmall" align="{S_CONTENT_FLOW_END}">
- <!-- IF not S_IS_BOT -->
- <!-- IF postrow.U_REPORT --><a href="{postrow.U_REPORT}" class="imageset">{REPORT_IMG}</a> <!-- ENDIF -->
- <!-- IF postrow.U_INFO --><a href="{postrow.U_INFO}" class="imageset">{INFO_IMG}</a> <!-- ENDIF -->
- <!-- IF postrow.U_WARN --><a href="{postrow.U_WARN}" class="imageset">{WARN_IMG}</a> <!-- ENDIF -->
- <!-- IF postrow.U_DELETE --><a href="{postrow.U_DELETE}" class="imageset">{DELETE_IMG}</a> <!-- ENDIF -->
- <!-- ENDIF -->
- </td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </td>
- </tr>
-
- <!-- IF postrow.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
-
- <!-- EVENT viewtopic_body_postrow_back2top_before -->
- <td class="profile"><!-- EVENT viewtopic_body_postrow_back2top_prepend --><strong><a href="#wrapheader">{L_BACK_TO_TOP}</a></strong><!-- EVENT viewtopic_body_postrow_back2top_append --></td>
- <!-- EVENT viewtopic_body_postrow_back2top_after -->
- <td>
- <div class="gensmall" style="float: {S_CONTENT_FLOW_BEGIN};">
- &nbsp;<!-- IF postrow.U_POST_AUTHOR --><a href="{postrow.U_POST_AUTHOR}" class="imageset">{PROFILE_IMG}</a><!-- ENDIF -->
- <!-- IF postrow.U_PM --><a href="{postrow.U_PM}" class="imageset">{PM_IMG}</a><!-- ENDIF -->
- <!-- IF postrow.U_EMAIL --><a href="{postrow.U_EMAIL}" class="imageset">{EMAIL_IMG}</a><!-- ENDIF -->
- &nbsp;</div>
- <div class="gensmall" style="float: {S_CONTENT_FLOW_END};">
- <!-- EVENT viewtopic_body_post_buttons_before -->
- <!-- IF not S_IS_BOT -->
- <!-- IF postrow.U_EDIT --><a href="{postrow.U_EDIT}" class="imageset">{EDIT_IMG}</a><!-- ENDIF -->
- <!-- IF postrow.U_QUOTE --><a href="{postrow.U_QUOTE}" class="imageset">{QUOTE_IMG}</a><!-- ENDIF -->
- <!-- ENDIF -->
- <!-- EVENT viewtopic_body_post_buttons_after -->
- &nbsp;</div>
- </td>
- <!-- ENDIF -->
- </tr>
-
- <tr>
- <td class="spacer" colspan="2" height="1"><img src="images/spacer.gif" alt="" width="1" height="1" /></td>
- </tr>
- </table>
- <!-- EVENT viewtopic_body_postrow_post_after -->
-<!-- END postrow -->
-
- <!-- IF not S_IS_BOT -->
- <table width="100%" cellspacing="1" class="tablebg">
- <tr align="center">
- <td class="cat"><form name="viewtopic" method="post" action="{S_TOPIC_ACTION}"><span class="gensmall">{L_DISPLAY_POSTS}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" value="{L_GO}" name="sort" /></form></td>
- </tr>
- </table>
- <!-- ENDIF -->
-
- <!-- EVENT viewtopic_body_topic_actions_before -->
-
- <table width="100%" cellspacing="1">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}" valign="middle" nowrap="nowrap">
- <!-- EVENT viewtopic_buttons_bottom_before -->
-
- <!-- IF not S_IS_BOT -->
- <!-- IF S_DISPLAY_POST_INFO --><a href="{U_POST_NEW_TOPIC}" class="imageset">{POST_IMG}</a>&nbsp;<!-- ENDIF -->
- <!-- IF S_DISPLAY_REPLY_INFO --><a href="{U_POST_REPLY_TOPIC}" class="imageset">{REPLY_IMG}</a><!-- ENDIF -->
- <!-- ENDIF -->
-
- <!-- EVENT viewtopic_buttons_bottom_after -->
- </td>
- <!-- IF TOTAL_POSTS -->
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}<br /></td>
- <td class="gensmall" nowrap="nowrap">&nbsp;[ {TOTAL_POSTS} ]&nbsp;</td>
- <td class="gensmall" width="100%" align="{S_CONTENT_FLOW_END}" nowrap="nowrap"><!-- INCLUDE pagination.html --></td>
- <!-- ENDIF -->
- </tr>
- </table>
-
-</div>
-
-<div id="pagefooter"></div>
-
-<br clear="all" />
-<!-- IF S_QUICK_REPLY -->
-<!-- INCLUDE quickreply_editor.html -->
-<!-- ENDIF -->
-
-<!-- EVENT viewtopic_body_footer_before -->
-<!-- INCLUDE breadcrumbs.html -->
-
-<!-- IF S_DISPLAY_ONLINE_LIST -->
- <br clear="all" />
-
- <table class="tablebg stat-block online-list" width="100%" cellspacing="1">
- <tr>
- <td class="cat"><h4>{L_WHO_IS_ONLINE}</h4></td>
- </tr>
- <tr>
- <td class="row1"><p class="gensmall">{LOGGED_IN_USER_LIST}</p></td>
- </tr>
- </table>
-<!-- ENDIF -->
-
-<br clear="all" />
-
-<table width="100%" cellspacing="1">
-<tr>
- <td width="40%" valign="top" nowrap="nowrap" align="{S_CONTENT_FLOW_BEGIN}">
- <!-- IF .quickmod -->
- <form method="post" action="{S_MOD_ACTION}">
- <span class="gensmall">{L_QUICK_MOD}{L_COLON}</span>
- <select name="action" id="quick-mod-select">
- <!-- BEGIN quickmod -->
- <option value="{quickmod.VALUE}">{quickmod.TITLE}</option>
- <!-- END quickmod -->
- </select>
- <input class="btnlite" type="submit" value="{L_GO}" />
- </form>
- <!-- ENDIF -->
- </td>
- <td align="{S_CONTENT_FLOW_END}" valign="top" nowrap="nowrap"><span class="gensmall"><!-- BEGIN rules -->{rules.RULE}<br /><!-- END rules --></span></td>
-</tr>
-</table>
-
-<br clear="all" />
-
-<table width="100%" cellspacing="0">
-<tr>
- <td><!-- IF S_DISPLAY_SEARCHBOX --><!-- INCLUDE searchbox.html --><!-- ENDIF --></td>
- <td align="{S_CONTENT_FLOW_END}"><!-- INCLUDE jumpbox.html --></td>
-</tr>
-</table>
-
-<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/viewtopic_print.html b/phpBB/styles/subsilver2/template/viewtopic_print.html
deleted file mode 100644
index 53b38f414e..0000000000
--- a/phpBB/styles/subsilver2/template/viewtopic_print.html
+++ /dev/null
@@ -1,136 +0,0 @@
-<!DOCTYPE html>
-<html dir="{S_CONTENT_DIRECTION}" lang="{S_USER_LANG}">
-<head>
-<meta charset="utf-8" />
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="robots" content="noindex" />
-<title>{SITENAME} :: {PAGE_TITLE}</title>
-
-<style type="text/css">
-<!--
-
-body {
- font-family: Verdana,serif;
- font-size: 10pt;
-}
-
-img {
- border: 0;
-}
-
-td {
- font-family: Verdana,serif;
- font-size: 10pt;
- line-height: 150%;
-}
-
-.code, .codecontent,
-.quote, .quotecontent {
- margin: 0 5px 0 5px;
- padding: 5px;
- font-size: smaller;
- border: black solid 1px;
-}
-
-.quotetitle {
- color: black;
- display : block;
- font-weight: bold;
-}
-
-.forum {
- font-family: Arial,Helvetica,sans-serif;
- font-weight: bold;
- font-size: 18pt;
-}
-
-.topic {
- font-family: Arial,Helvetica,sans-serif;
- font-size: 14pt;
- font-weight: bold;
-}
-
-.gensmall {
- font-size: 8pt;
-}
-
-hr {
- color: #888;
- height: 3px;
- border-style: solid;
-}
-
-hr.sep {
- color: #aaa;
- height: 1px;
- border-style: dashed;
-}
-//-->
-</style>
-<!-- EVENT viewtopic_print_head_append -->
-</head>
-<body>
-
-<table width="85%" cellspacing="3" cellpadding="0" border="0" align="center">
-<tr>
- <td colspan="2" align="center"><span class="Forum">{SITENAME}</span><br /><span class="gensmall"><a href="{U_FORUM}">{U_FORUM}</a></span></td>
-</tr>
-<tr>
- <td colspan="2"><br /></td>
-</tr>
-<tr>
- <td><span class="topic">{TOPIC_TITLE}</span><br /><span class="gensmall"><a href="{U_TOPIC}">{U_TOPIC}</a></span></td>
- <td align="{S_CONTENT_FLOW_END}" valign="bottom"><span class="gensmall">{PAGE_NUMBER}</span></td>
-</tr>
-</table>
-
-<!-- BEGIN postrow -->
-
- <hr width="85%" />
-
- <table width="85%" cellspacing="3" cellpadding="0" border="0" align="center">
- <tr>
- <td width="10%" nowrap="nowrap">{L_AUTHOR}{L_COLON}&nbsp;</td>
- <td><b>{postrow.POST_AUTHOR}</b> [ {postrow.POST_DATE} ]</td>
- </tr>
- <tr>
- <td width="10%" nowrap="nowrap">{L_POST_SUBJECT}{L_COLON}&nbsp;</td>
- <td><b>{postrow.POST_SUBJECT}</b></td>
- </tr>
- <tr>
- <td colspan="2"><hr class="sep" />{postrow.MESSAGE}
-
- <!-- IF postrow.S_HAS_ATTACHMENTS -->
- <br clear="all" /><br />
-
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td><b class="genmed">{L_ATTACHMENTS}{L_COLON} </b></td>
- </tr>
- <!-- BEGIN attachment -->
- <tr>
- <td>{postrow.attachment.DISPLAY_ATTACHMENT}</td>
- </tr>
- <!-- END attachment -->
- </table>
- <!-- ENDIF -->
-
- </td>
- </tr>
- </table>
-<!-- END postrow -->
-
-<hr width="85%" />
-
-<table width="85%" cellspacing="3" cellpadding="0" border="0" align="center">
-<tr>
- <td><span class="gensmall">{PAGE_NUMBER}</span></td>
- <td align="{S_CONTENT_FLOW_END}"><span class="gensmall">{S_TIMEZONE}</span></td>
-</tr>
-<tr>
- <td colspan="2" align="center"><span class="gensmall">Powered by phpBB&reg; Forum Software &copy; phpBB Limited<br />https://www.phpbb.com/</span></td>
-</tr>
-</table>
-
-</body>
-</html>
diff --git a/phpBB/styles/subsilver2/theme/en/button_pm_new.gif b/phpBB/styles/subsilver2/theme/en/button_pm_new.gif
deleted file mode 100644
index 07df748d3a..0000000000
--- a/phpBB/styles/subsilver2/theme/en/button_pm_new.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/button_pm_reply.gif b/phpBB/styles/subsilver2/theme/en/button_pm_reply.gif
deleted file mode 100644
index c476f06a44..0000000000
--- a/phpBB/styles/subsilver2/theme/en/button_pm_reply.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/button_topic_locked.gif b/phpBB/styles/subsilver2/theme/en/button_topic_locked.gif
deleted file mode 100644
index 124a2d4a7d..0000000000
--- a/phpBB/styles/subsilver2/theme/en/button_topic_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/button_topic_new.gif b/phpBB/styles/subsilver2/theme/en/button_topic_new.gif
deleted file mode 100644
index 66e1007129..0000000000
--- a/phpBB/styles/subsilver2/theme/en/button_topic_new.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/button_topic_reply.gif b/phpBB/styles/subsilver2/theme/en/button_topic_reply.gif
deleted file mode 100644
index e8fe5115a0..0000000000
--- a/phpBB/styles/subsilver2/theme/en/button_topic_reply.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_aim.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_aim.gif
deleted file mode 100644
index c6533e2817..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_aim.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_email.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_email.gif
deleted file mode 100644
index f126a1960d..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_email.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_icq.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_icq.gif
deleted file mode 100644
index ba3fa12436..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_icq.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_jabber.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_jabber.gif
deleted file mode 100644
index be2e53f9c2..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_jabber.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_msnm.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_msnm.gif
deleted file mode 100644
index 1bf681e9a2..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_msnm.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_pm.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_pm.gif
deleted file mode 100644
index 26ac558c2f..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_pm.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_www.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_www.gif
deleted file mode 100644
index 14a33b36a5..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_www.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_contact_yahoo.gif b/phpBB/styles/subsilver2/theme/en/icon_contact_yahoo.gif
deleted file mode 100644
index d11711789f..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_contact_yahoo.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_post_delete.gif b/phpBB/styles/subsilver2/theme/en/icon_post_delete.gif
deleted file mode 100644
index e008e5ff9f..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_post_delete.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_post_edit.gif b/phpBB/styles/subsilver2/theme/en/icon_post_edit.gif
deleted file mode 100644
index 1511ee34d3..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_post_edit.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_post_info.gif b/phpBB/styles/subsilver2/theme/en/icon_post_info.gif
deleted file mode 100644
index 166de2724f..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_post_info.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_post_quote.gif b/phpBB/styles/subsilver2/theme/en/icon_post_quote.gif
deleted file mode 100644
index 4cf103280c..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_post_quote.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_post_report.gif b/phpBB/styles/subsilver2/theme/en/icon_post_report.gif
deleted file mode 100644
index 9a3f65b1e3..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_post_report.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_user_offline.gif b/phpBB/styles/subsilver2/theme/en/icon_user_offline.gif
deleted file mode 100644
index 3065f4d7fe..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_user_offline.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_user_online.gif b/phpBB/styles/subsilver2/theme/en/icon_user_online.gif
deleted file mode 100644
index b950612c57..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_user_online.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_user_profile.gif b/phpBB/styles/subsilver2/theme/en/icon_user_profile.gif
deleted file mode 100644
index d9cf7f4c4a..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_user_profile.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_user_search.gif b/phpBB/styles/subsilver2/theme/en/icon_user_search.gif
deleted file mode 100644
index 46475fbf4c..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_user_search.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/icon_user_warn.gif b/phpBB/styles/subsilver2/theme/en/icon_user_warn.gif
deleted file mode 100644
index 44cbcc953a..0000000000
--- a/phpBB/styles/subsilver2/theme/en/icon_user_warn.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/en/stylesheet.css b/phpBB/styles/subsilver2/theme/en/stylesheet.css
deleted file mode 100644
index 57f9fce26d..0000000000
--- a/phpBB/styles/subsilver2/theme/en/stylesheet.css
+++ /dev/null
@@ -1,116 +0,0 @@
-/* EN Language Pack */
-.imageset.phpbb_aol-icon, .imageset.icon_contact_aim {
- background-image: url("./icon_contact_aim.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_contact_email {
- background-image: url("./icon_contact_email.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_icq-icon, .imageset.icon_contact_icq {
- background-image: url("./icon_contact_icq.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_contact_jabber {
- background-image: url("./icon_contact_jabber.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_wlm-icon, .imageset.icon_contact_msnm {
- background-image: url("./icon_contact_msnm.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_contact_pm {
- background-image: url("./icon_contact_pm.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_yahoo-icon, .imageset.icon_contact_yahoo {
- background-image: url("./icon_contact_yahoo.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_website-icon, .imageset.icon_contact_www {
- background-image: url("./icon_contact_www.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_post_delete {
- background-image: url("./icon_post_delete.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_edit {
- background-image: url("./icon_post_edit.gif");
- padding-left: 90px;
- padding-top: 20px;
-}
-.imageset.icon_post_info {
- background-image: url("./icon_post_info.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_quote {
- background-image: url("./icon_post_quote.gif");
- padding-left: 90px;
- padding-top: 20px;
-}
-.imageset.icon_post_report {
- background-image: url("./icon_post_report.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_user_online {
- background-image: url("./icon_user_online.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_offline {
- background-image: url("./icon_user_offline.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_profile {
- background-image: url("./icon_user_profile.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_search {
- background-image: url("./icon_user_search.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_warn {
- background-image: url("./icon_user_warn.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.button_pm_new {
- background-image: url("./button_pm_new.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
-.imageset.button_pm_reply {
- background-image: url("./button_pm_reply.gif");
- padding-left: 90px;
- padding-top: 20px;
-}
-.imageset.button_topic_locked {
- background-image: url("./button_topic_locked.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
-.imageset.button_topic_new {
- background-image: url("./button_topic_new.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
-.imageset.button_topic_reply {
- background-image: url("./button_topic_reply.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
diff --git a/phpBB/styles/subsilver2/theme/images/announce_read.gif b/phpBB/styles/subsilver2/theme/images/announce_read.gif
deleted file mode 100644
index 0589feb14f..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_read.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/announce_read_locked.gif b/phpBB/styles/subsilver2/theme/images/announce_read_locked.gif
deleted file mode 100644
index a738616e06..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_read_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/announce_read_locked_mine.gif b/phpBB/styles/subsilver2/theme/images/announce_read_locked_mine.gif
deleted file mode 100644
index f7ffe7f8dd..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_read_locked_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/announce_read_mine.gif b/phpBB/styles/subsilver2/theme/images/announce_read_mine.gif
deleted file mode 100644
index 636d353867..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_read_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/announce_unread.gif b/phpBB/styles/subsilver2/theme/images/announce_unread.gif
deleted file mode 100644
index 56b2702b17..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_unread.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/announce_unread_locked.gif b/phpBB/styles/subsilver2/theme/images/announce_unread_locked.gif
deleted file mode 100644
index 37033da653..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_unread_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/announce_unread_locked_mine.gif b/phpBB/styles/subsilver2/theme/images/announce_unread_locked_mine.gif
deleted file mode 100644
index d91f2520ca..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_unread_locked_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/announce_unread_mine.gif b/phpBB/styles/subsilver2/theme/images/announce_unread_mine.gif
deleted file mode 100644
index e1dd23a0bf..0000000000
--- a/phpBB/styles/subsilver2/theme/images/announce_unread_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/background.gif b/phpBB/styles/subsilver2/theme/images/background.gif
deleted file mode 100644
index 5c731e4fc2..0000000000
--- a/phpBB/styles/subsilver2/theme/images/background.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/cellpic.gif b/phpBB/styles/subsilver2/theme/images/cellpic.gif
deleted file mode 100644
index 47457ef5f7..0000000000
--- a/phpBB/styles/subsilver2/theme/images/cellpic.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/cellpic1.gif b/phpBB/styles/subsilver2/theme/images/cellpic1.gif
deleted file mode 100644
index 715b8d4aa8..0000000000
--- a/phpBB/styles/subsilver2/theme/images/cellpic1.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/cellpic2.jpg b/phpBB/styles/subsilver2/theme/images/cellpic2.jpg
deleted file mode 100644
index a0ca7e89d3..0000000000
--- a/phpBB/styles/subsilver2/theme/images/cellpic2.jpg
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/cellpic2_rtl.jpg b/phpBB/styles/subsilver2/theme/images/cellpic2_rtl.jpg
deleted file mode 100644
index 201e063725..0000000000
--- a/phpBB/styles/subsilver2/theme/images/cellpic2_rtl.jpg
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/cellpic3.gif b/phpBB/styles/subsilver2/theme/images/cellpic3.gif
deleted file mode 100644
index ecf70e1fd1..0000000000
--- a/phpBB/styles/subsilver2/theme/images/cellpic3.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/created_by.jpg b/phpBB/styles/subsilver2/theme/images/created_by.jpg
deleted file mode 100644
index f27472781e..0000000000
--- a/phpBB/styles/subsilver2/theme/images/created_by.jpg
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/forum_link.gif b/phpBB/styles/subsilver2/theme/images/forum_link.gif
deleted file mode 100644
index d5e86d47d7..0000000000
--- a/phpBB/styles/subsilver2/theme/images/forum_link.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/forum_read.gif b/phpBB/styles/subsilver2/theme/images/forum_read.gif
deleted file mode 100644
index 9b2bc47c67..0000000000
--- a/phpBB/styles/subsilver2/theme/images/forum_read.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/forum_read_locked.gif b/phpBB/styles/subsilver2/theme/images/forum_read_locked.gif
deleted file mode 100644
index 436f3d21c8..0000000000
--- a/phpBB/styles/subsilver2/theme/images/forum_read_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/forum_read_subforum.gif b/phpBB/styles/subsilver2/theme/images/forum_read_subforum.gif
deleted file mode 100644
index 9179303e7f..0000000000
--- a/phpBB/styles/subsilver2/theme/images/forum_read_subforum.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/forum_unread.gif b/phpBB/styles/subsilver2/theme/images/forum_unread.gif
deleted file mode 100644
index 5eec565b38..0000000000
--- a/phpBB/styles/subsilver2/theme/images/forum_unread.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/forum_unread_locked.gif b/phpBB/styles/subsilver2/theme/images/forum_unread_locked.gif
deleted file mode 100644
index 58a79c376c..0000000000
--- a/phpBB/styles/subsilver2/theme/images/forum_unread_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/forum_unread_subforum.gif b/phpBB/styles/subsilver2/theme/images/forum_unread_subforum.gif
deleted file mode 100644
index af3c93b1a1..0000000000
--- a/phpBB/styles/subsilver2/theme/images/forum_unread_subforum.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_faq.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_faq.gif
deleted file mode 100644
index fc50e7ca30..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_faq.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_groups.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_groups.gif
deleted file mode 100644
index a4d1c7bb70..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_groups.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_login.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_login.gif
deleted file mode 100644
index c7590a423f..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_login.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_members.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_members.gif
deleted file mode 100644
index d636089b38..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_members.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_message.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_message.gif
deleted file mode 100644
index b8aea1eafb..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_message.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_notification.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_notification.gif
deleted file mode 100644
index f165d3cb27..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_notification.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_profile.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_profile.gif
deleted file mode 100644
index 1ec7c649e9..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_profile.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_register.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_register.gif
deleted file mode 100644
index b49ac31ec9..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_register.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_mini_search.gif b/phpBB/styles/subsilver2/theme/images/icon_mini_search.gif
deleted file mode 100644
index 2bd1a648c0..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_mini_search.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_post_target.gif b/phpBB/styles/subsilver2/theme/images/icon_post_target.gif
deleted file mode 100644
index d172abb060..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_post_target.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_post_target_unread.gif b/phpBB/styles/subsilver2/theme/images/icon_post_target_unread.gif
deleted file mode 100644
index 8ec44a1787..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_post_target_unread.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_topic_attach.gif b/phpBB/styles/subsilver2/theme/images/icon_topic_attach.gif
deleted file mode 100644
index 1c9c89bc70..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_topic_attach.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_topic_deleted.png b/phpBB/styles/subsilver2/theme/images/icon_topic_deleted.png
deleted file mode 100644
index 494b4fb563..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_topic_deleted.png
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_topic_latest.gif b/phpBB/styles/subsilver2/theme/images/icon_topic_latest.gif
deleted file mode 100644
index b45e57aedb..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_topic_latest.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_topic_newest.gif b/phpBB/styles/subsilver2/theme/images/icon_topic_newest.gif
deleted file mode 100644
index eca2861836..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_topic_newest.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_topic_reported.gif b/phpBB/styles/subsilver2/theme/images/icon_topic_reported.gif
deleted file mode 100644
index 026092854a..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_topic_reported.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/icon_topic_unapproved.gif b/phpBB/styles/subsilver2/theme/images/icon_topic_unapproved.gif
deleted file mode 100644
index 2ccaf19c23..0000000000
--- a/phpBB/styles/subsilver2/theme/images/icon_topic_unapproved.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/index.htm b/phpBB/styles/subsilver2/theme/images/index.htm
deleted file mode 100644
index 957f68a803..0000000000
--- a/phpBB/styles/subsilver2/theme/images/index.htm
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-<head>
-<title>subSilver created by subBlue Design</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-</head>
-
-<body bgcolor="#FFFFFF" text="#000000">
-
-<table width="100%" height="100%" cellspacing="0" cellpadding="0" border="0">
- <tr>
- <td align="center" valign="middle"><a href="http://www.subblue.com/" target="_new"><img src="created_by.jpg" width="400" height="300" alt="Created by subBlue Design" /></a></td>
- </tr>
-</table>
-
-</body>
-</html> \ No newline at end of file
diff --git a/phpBB/styles/subsilver2/theme/images/no_avatar.gif b/phpBB/styles/subsilver2/theme/images/no_avatar.gif
deleted file mode 100644
index ad73330e71..0000000000
--- a/phpBB/styles/subsilver2/theme/images/no_avatar.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/poll_center.gif b/phpBB/styles/subsilver2/theme/images/poll_center.gif
deleted file mode 100644
index 99473151ec..0000000000
--- a/phpBB/styles/subsilver2/theme/images/poll_center.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/poll_left.gif b/phpBB/styles/subsilver2/theme/images/poll_left.gif
deleted file mode 100644
index 269088b81d..0000000000
--- a/phpBB/styles/subsilver2/theme/images/poll_left.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/poll_right.gif b/phpBB/styles/subsilver2/theme/images/poll_right.gif
deleted file mode 100644
index f9584e23a1..0000000000
--- a/phpBB/styles/subsilver2/theme/images/poll_right.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/site_logo.gif b/phpBB/styles/subsilver2/theme/images/site_logo.gif
deleted file mode 100644
index abce3cd51d..0000000000
--- a/phpBB/styles/subsilver2/theme/images/site_logo.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/spacer.gif b/phpBB/styles/subsilver2/theme/images/spacer.gif
deleted file mode 100644
index 5bfd67a2d6..0000000000
--- a/phpBB/styles/subsilver2/theme/images/spacer.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_read.gif b/phpBB/styles/subsilver2/theme/images/sticky_read.gif
deleted file mode 100644
index 09861a996c..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_read.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_read_locked.gif b/phpBB/styles/subsilver2/theme/images/sticky_read_locked.gif
deleted file mode 100644
index 24bca303d6..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_read_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_read_locked_mine.gif b/phpBB/styles/subsilver2/theme/images/sticky_read_locked_mine.gif
deleted file mode 100644
index 3fd04ec3a9..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_read_locked_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_read_mine.gif b/phpBB/styles/subsilver2/theme/images/sticky_read_mine.gif
deleted file mode 100644
index 381634c364..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_read_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_unread.gif b/phpBB/styles/subsilver2/theme/images/sticky_unread.gif
deleted file mode 100644
index dd2e366543..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_unread.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_unread_locked.gif b/phpBB/styles/subsilver2/theme/images/sticky_unread_locked.gif
deleted file mode 100644
index 608f4822e3..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_unread_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_unread_locked_mine.gif b/phpBB/styles/subsilver2/theme/images/sticky_unread_locked_mine.gif
deleted file mode 100644
index fe5e115312..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_unread_locked_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/sticky_unread_mine.gif b/phpBB/styles/subsilver2/theme/images/sticky_unread_mine.gif
deleted file mode 100644
index b5fc3b3627..0000000000
--- a/phpBB/styles/subsilver2/theme/images/sticky_unread_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_moved.gif b/phpBB/styles/subsilver2/theme/images/topic_moved.gif
deleted file mode 100644
index fe758f02ca..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_moved.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_read.gif b/phpBB/styles/subsilver2/theme/images/topic_read.gif
deleted file mode 100644
index c16bfa75d5..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_read.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_read_hot.gif b/phpBB/styles/subsilver2/theme/images/topic_read_hot.gif
deleted file mode 100644
index a7a7e8fc78..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_read_hot.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_read_hot_mine.gif b/phpBB/styles/subsilver2/theme/images/topic_read_hot_mine.gif
deleted file mode 100644
index 853452a74b..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_read_hot_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_read_locked.gif b/phpBB/styles/subsilver2/theme/images/topic_read_locked.gif
deleted file mode 100644
index 10eb776972..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_read_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_read_locked_mine.gif b/phpBB/styles/subsilver2/theme/images/topic_read_locked_mine.gif
deleted file mode 100644
index 3f24928b48..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_read_locked_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_read_mine.gif b/phpBB/styles/subsilver2/theme/images/topic_read_mine.gif
deleted file mode 100644
index 560927aa06..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_read_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_unread.gif b/phpBB/styles/subsilver2/theme/images/topic_unread.gif
deleted file mode 100644
index 4e56157dce..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_unread.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_unread_hot.gif b/phpBB/styles/subsilver2/theme/images/topic_unread_hot.gif
deleted file mode 100644
index ceef4919d5..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_unread_hot.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_unread_hot_mine.gif b/phpBB/styles/subsilver2/theme/images/topic_unread_hot_mine.gif
deleted file mode 100644
index 1c748f708a..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_unread_hot_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_unread_locked.gif b/phpBB/styles/subsilver2/theme/images/topic_unread_locked.gif
deleted file mode 100644
index 720e210289..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_unread_locked.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_unread_locked_mine.gif b/phpBB/styles/subsilver2/theme/images/topic_unread_locked_mine.gif
deleted file mode 100644
index 90873431ef..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_unread_locked_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/topic_unread_mine.gif b/phpBB/styles/subsilver2/theme/images/topic_unread_mine.gif
deleted file mode 100644
index 34fd2ec179..0000000000
--- a/phpBB/styles/subsilver2/theme/images/topic_unread_mine.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/upload_bar.gif b/phpBB/styles/subsilver2/theme/images/upload_bar.gif
deleted file mode 100644
index 75cf61c59e..0000000000
--- a/phpBB/styles/subsilver2/theme/images/upload_bar.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/images/whosonline.gif b/phpBB/styles/subsilver2/theme/images/whosonline.gif
deleted file mode 100644
index b450927432..0000000000
--- a/phpBB/styles/subsilver2/theme/images/whosonline.gif
+++ /dev/null
Binary files differ
diff --git a/phpBB/styles/subsilver2/theme/stylesheet.css b/phpBB/styles/subsilver2/theme/stylesheet.css
deleted file mode 100644
index 8f0bbffdda..0000000000
--- a/phpBB/styles/subsilver2/theme/stylesheet.css
+++ /dev/null
@@ -1,1256 +0,0 @@
-/* phpBB3 Style Sheet
- --------------------------------------------------------------
- Style name: subsilver2
- Based on style: subSilver (the default phpBB 2.0.x style)
- Original author: Tom Beddard ( http://www.subblue.com/ )
- Modified by: phpBB Limited ( https://www.phpbb.com/ )
- --------------------------------------------------------------
-*/
-
-/* Layout
- ------------ */
-* {
- /* Reset browsers default margin, padding and font sizes */
- margin: 0;
- padding: 0;
-}
-
-abbr {
- text-decoration: none;
-}
-
-html {
- font-size: 100%;
-}
-
-body {
- /* Text-Sizing with ems: http://www.clagnut.com/blog/348/ */
- font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;
- color: #323D4F;
- background-color: #FFFFFF;
- font-size: 62.5%; /* This sets the default font size to be equivalent to 10px */
- margin: 0;
-}
-
-#wrapheader {
- height: auto !important;
- padding: 0;
-}
-
-#wrapcentre {
- margin: 15px 25px 0 25px;
-}
-
-#wrapfooter {
- text-align: center;
- clear: both;
-}
-
-#wrapnav {
- width: 100%;
- margin: 0;
- background-color: #ECECEC;
- border-width: 1px;
- border-style: solid;
- border-color: #A9B8C2;
-}
-
-#logodesc {
- background-color: #C1CAD2;
- background-image: url('./images/background.gif');
- background-repeat: repeat-x;
- background-position: center bottom;
- padding: 0 25px 15px 25px;
-}
-
-#menubar {
- margin: 0 25px;
-}
-
-#datebar {
- margin: 10px 25px 0 25px;
-}
-
-#findbar {
- width: 100%;
- margin: 0;
- padding: 0;
- border: 0;
-}
-
-.forumrules {
- background-color: #F9CC79;
- border-width: 1px;
- border-style: solid;
- border-color: #BB9860;
- padding: 4px;
- font-weight: normal;
- font-size: 1.1em;
- font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
-}
-
-.forumrules h3 {
- color: red;
-}
-
-#pageheader { }
-#pagecontent { }
-#pagefooter { }
-
-#poll { }
-#postrow { }
-#postdata { }
-
-
-/* Text
- --------------------- */
-h1 {
- color: black;
- font-family: "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
- font-weight: bold;
- font-size: 1.8em;
- text-decoration: none;
-}
-
-h2 {
- font-family: Arial, Helvetica, sans-serif;
- font-weight: bold;
- font-size: 1.5em;
- text-decoration: none;
- line-height: 120%;
-}
-
-h3 {
- font-size: 1.3em;
- font-weight: bold;
- font-family: Arial, Helvetica, sans-serif;
- line-height: 120%;
-}
-
-h4 {
- margin: 0;
- font-size: 1.1em;
- font-weight: bold;
-}
-
-p {
- font-size: 1.1em;
-}
-
-p.moderators {
- margin: 0;
- float: left;
- color: black;
- font-weight: bold;
-}
-
-.rtl p.moderators {
- float: right;
-}
-
-p.linkmcp {
- margin: 0;
- float: right;
- white-space: nowrap;
-}
-
-.rtl p.linkmcp {
- float: left;
-}
-
-p.breadcrumbs {
- margin: 0;
- float: left;
- color: black;
- font-weight: bold;
- white-space: normal;
- font-size: 1em;
-}
-
-.rtl p.breadcrumbs {
- float: right;
-}
-
-p.datetime {
- margin: 0;
- float: right;
- white-space: nowrap;
- font-size: 1em;
-}
-
-.rtl p.datetime {
- float: left;
-}
-
-p.searchbar {
- padding: 2px 0;
- white-space: nowrap;
-}
-
-p.searchbarreg {
- margin: 0;
- float: right;
- white-space: nowrap;
-}
-
-.rtl p.searchbarreg {
- float: left;
-}
-
-p.forumdesc {
- padding-bottom: 4px;
-}
-
-p.topicauthor {
- margin: 1px 0;
-}
-
-p.topicdetails {
- margin: 1px 0;
-}
-
-.postreported, .postreported a:link, .postreported a:visited, .postreported a:hover, .postreported a:active {
- margin: 1px 0;
- color: red;
- font-weight:bold;
-}
-
-.postapprove, .postapprove a:link, .postapprove a:visited, .postapprove a:hover, .postapprove a:active {
- color: green;
- font-weight:bold;
-}
-
-.postapprove img, .postreported img {
- vertical-align: bottom;
- padding-top: 5px;
-}
-
-.postauthor {
- color: #000000;
-}
-
-.postdetails {
- color: #000000;
-}
-
-.postbody {
- font-size: 1.3em;
- line-height: 1.4em;
- font-family: "Lucida Grande", "Trebuchet MS", Helvetica, Arial, sans-serif;
-}
-
-.postbody li, ol, ul {
- margin: 0 0 0 1.5em;
-}
-
-.rtl .postbody li, .rtl ol, .rtl ul {
- margin: 0 1.5em 0 0;
-}
-
-.posthilit {
- background-color: yellow;
-}
-
-.nav {
- margin: 0;
- color: black;
- font-weight: bold;
-}
-
-.pagination {
- padding: 4px;
- color: black;
- font-size: 1em;
- font-weight: bold;
-}
-
-.cattitle {
-
-}
-
-.gen {
- margin: 1px 1px;
- font-size: 1.2em;
-}
-
-.genmed {
- margin: 1px 1px;
- font-size: 1.1em;
-}
-
-.gensmall {
- margin: 1px 1px;
- font-size: 1em;
-}
-
-.copyright {
- color: #444;
- font-weight: normal;
- font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
-}
-
-.titles {
- font-family: "Lucida Grande", Helvetica, Arial, sans-serif;
- font-weight: bold;
- font-size: 1.3em;
- text-decoration: none;
-}
-
-.online {
- color: green;
-}
-
-.offline, .error, .inactive {
- color: red;
-}
-
-
-/* Tables
- ------------ */
-#color_palette_placeholder table {
- border-collapse: separate;
- border-spacing: 1px;
-}
-
-#color_palette_placeholder td {
- padding: 0;
-}
-
-th {
- color: #FFA34F;
- font-size: 1.1em;
- font-weight: bold;
- background-color: #006699;
- background-image: url('./images/cellpic3.gif');
- white-space: nowrap;
- padding: 7px 5px;
-}
-
-th.center {
- text-align: center;
-}
-
-td {
- padding: 2px;
-}
-td.profile {
- padding: 4px;
-}
-
-.tablebg {
- background-color: #A9B8C2;
-}
-
-.catdiv {
- height: 28px;
- margin: 0;
- padding: 0;
- border: 0;
- background: white url('./images/cellpic2.jpg') repeat-y scroll top left;
-}
-.rtl .catdiv {
- background: white url('./images/cellpic2_rtl.jpg') repeat-y scroll top right;
-}
-
-.cat {
- height: 28px;
- margin: 0;
- padding: 0;
- border: 0;
- background-color: #C7D0D7;
- background-image: url('./images/cellpic1.gif');
- text-indent: 4px;
-}
-
-.row1 {
- background-color: #ECECEC;
- padding: 4px;
-}
-
-.row2 {
- background-color: #DCE1E5;
- padding: 4px;
-}
-
-.row3 {
- background-color: #C0C8D0;
- padding: 4px;
-}
-
-.spacer {
- background-color: #D1D7DC;
-}
-
-.current {
- background-color: lightblue;
-}
-
-hr {
- height: 1px;
- border-width: 0;
- background-color: #D1D7DC;
- color: #D1D7DC;
-}
-
-.legend {
- text-align:center;
- margin: 0 auto;
-}
-
-/* Links
- ------------ */
-
-/* Links adjustment to correctly display an order of rtl/ltr mixed content */
-.rtl a {
- direction: rtl;
- unicode-bidi: embed;
-}
-
-/* CSS spec requires a:link, a:visited, a:hover and a:active rules to be specified in this order. */
-/* See http://www.phpbb.com/bugs/phpbb3/59685 */
-a:link {
- color: #006597;
- text-decoration: none;
-}
-
-a:visited {
- color: #005784;
- text-decoration: none;
-}
-
-a:hover {
- color: #D46400;
- text-decoration: underline;
-}
-
-a:active {
- color: #005784;
- text-decoration: none;
-}
-
-a.forumlink {
- color: #069;
- font-weight: bold;
- font-family: "Lucida Grande", Helvetica, Arial, sans-serif;
- font-size: 1.2em;
-}
-
-a.topictitle {
- margin: 1px 0;
- font-family: "Lucida Grande", Helvetica, Arial, sans-serif;
- font-weight: bold;
- font-size: 1.2em;
-}
-
-a.topictitle:visited {
- color: #5493B4;
- text-decoration: none;
-}
-
-a.lastsubject {
- font-weight: bold;
- text-decoration: none;
-}
-
-a.lastsubject:hover {
- text-decoration: underline;
-}
-
-th a,
-th a:visited {
- color: #FFA34F !important;
- text-decoration: none;
-}
-
-th a:hover {
- text-decoration: underline;
-}
-
-a.anchor {
- display: block;
-}
-
-
-/* Form Elements
- ------------ */
-form {
- margin: 0;
- padding: 0;
- border: 0;
-}
-
-input {
- color: #333333;
- font-family: "Lucida Grande", Verdana, Helvetica, sans-serif;
- font-size: 1.1em;
- font-weight: normal;
- padding: 1px;
- border: 1px solid #A9B8C2;
- background-color: #FAFAFA;
-}
-
-textarea {
- background-color: #FAFAFA;
- color: #333333;
- font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;
- font-size: 1.3em;
- line-height: 1.4em;
- font-weight: normal;
- border: 1px solid #A9B8C2;
- padding: 2px;
-}
-
-select {
- color: #333333;
- background-color: #FAFAFA;
- font-family: "Lucida Grande", Verdana, Helvetica, sans-serif;
- font-size: 1.1em;
- font-weight: normal;
- border: 1px solid #A9B8C2;
- padding: 1px;
-}
-
-option {
- padding: 0 1em 0 0;
-}
-
-option.disabled-option {
- color: graytext;
-}
-
-.rtl option {
- padding: 0 0 0 1em;
-}
-
-input.radio {
- border: none;
- background-color: transparent;
-}
-
-.post {
- background-color: white;
- border-style: solid;
- border-width: 1px;
-}
-
-.btnbbcode {
- color: #000000;
- font-weight: normal;
- font-size: 1.1em;
- font-family: "Lucida Grande", Verdana, Helvetica, sans-serif;
- background-color: #EFEFEF;
- border: 1px solid #666666;
-}
-
-.btnmain {
- font-weight: bold;
- background-color: #ECECEC;
- border: 1px solid #A9B8C2;
- cursor: pointer;
- padding: 1px 5px;
- font-size: 1.1em;
-}
-
-.btnlite {
- font-weight: normal;
- background-color: #ECECEC;
- border: 1px solid #A9B8C2;
- cursor: pointer;
- padding: 1px 5px;
- font-size: 1.1em;
-}
-
-.btnfile {
- font-weight: normal;
- background-color: #ECECEC;
- border: 1px solid #A9B8C2;
- padding: 1px 5px;
- font-size: 1.1em;
-}
-
-.helpline {
- background-color: #DEE3E7;
- border-style: none;
-}
-
-input:focus, select:focus, textarea:focus {
- outline-style: none;
-}
-
-/* BBCode
- ------------ */
-.quotetitle, .attachtitle {
- margin: 10px 5px 0 5px;
- padding: 4px;
- border-width: 1px 1px 0 1px;
- border-style: solid;
- border-color: #A9B8C2;
- color: #333333;
- background-color: #A9B8C2;
- font-size: 0.85em;
- font-weight: bold;
-}
-
-.quotetitle .quotetitle {
- font-size: 1em;
-}
-
-.quotecontent, .attachcontent {
- margin: 0 5px 10px 5px;
- padding: 5px;
- border-color: #A9B8C2;
- border-width: 0 1px 1px 1px;
- border-style: solid;
- font-weight: normal;
- font-size: 1em;
- line-height: 1.4em;
- font-family: "Lucida Grande", "Trebuchet MS", Helvetica, Arial, sans-serif;
- background-color: #FAFAFA;
- color: #4B5C77;
-}
-
-.attachcontent {
- font-size: 0.85em;
-}
-
-.codetitle {
- margin: 10px 5px 0 5px;
- padding: 2px 4px;
- border-width: 1px 1px 0 1px;
- border-style: solid;
- border-color: #A9B8C2;
- color: #333333;
- background-color: #A9B8C2;
- font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;
- font-size: 0.8em;
-}
-
-.codecontent {
- direction: ltr;
- margin: 0 5px 10px 5px;
- padding: 5px;
- border-color: #A9B8C2;
- border-width: 0 1px 1px 1px;
- border-style: solid;
- font-weight: normal;
- color: #006600;
- font-size: 0.85em;
- font-family: Monaco, 'Courier New', monospace;
- background-color: #FAFAFA;
-}
-
-.postimage {
- max-width: 100%;
-}
-
-.syntaxbg {
- color: #FFFFFF;
-}
-
-.syntaxcomment {
- color: #FF8000;
-}
-
-.syntaxdefault {
- color: #0000BB;
-}
-
-.syntaxhtml {
- color: #000000;
-}
-
-.syntaxkeyword {
- color: #007700;
-}
-
-.syntaxstring {
- color: #DD0000;
-}
-
-
-/* Private messages
- ------------------ */
-.pm_marked_colour {
- background-color: #000000;
-}
-
-.pm_replied_colour {
- background-color: #A9B8C2;
-}
-
-.pm_friend_colour {
- background-color: #007700;
-}
-
-.pm_foe_colour {
- background-color: #DD0000;
-}
-
-
-/* Misc
- ------------ */
-img {
- border: none;
-}
-
-.sep {
- color: black;
- background-color: #FFA34F;
-}
-
-table.colortable td {
- padding: 0;
-}
-
-pre {
- font-size: 1.1em;
- font-family: Monaco, 'Courier New', monospace;
-}
-
-.nowrap {
- white-space: nowrap;
-}
-
-.username-coloured {
- font-weight: bold;
-}
-
-
-/* Former imageset */
-span.imageset {
- display: inline-block;
- background: transparent none 0 0 no-repeat;
- margin: 0;
- padding: 0;
- width: 0;
- height: 0;
- overflow: hidden;
-}
-a.imageset {
- text-decoration: none !important;
-}
-
-/* Global imageset items */
-.imageset.site_logo {
- background-image: url("./images/site_logo.gif");
- padding-left: 170px;
- padding-top: 94px;
-}
-.imageset.upload_bar {
- background-image: url("./images/upload_bar.gif");
- padding-left: 280px;
- padding-top: 16px;
-}
-.imageset.poll_left {
- background-image: url("./images/poll_left.gif");
- padding-left: 4px;
- padding-top: 12px;
-}
-.imageset.poll_center {
- background-image: url("./images/poll_center.gif");
- padding-left: 1px;
- padding-top: 12px;
-}
-.imageset.poll_right {
- background-image: url("./images/poll_right.gif");
- padding-left: 4px;
- padding-top: 12px;
-}
-.imageset.forum_link {
- background-image: url("./images/forum_link.gif");
- padding-left: 46px;
- padding-top: 25px;
-}
-.imageset.forum_read {
- background-image: url("./images/forum_read.gif");
- padding-left: 46px;
- padding-top: 25px;
-}
-.imageset.forum_read_locked {
- background-image: url("./images/forum_read_locked.gif");
- padding-left: 46px;
- padding-top: 25px;
-}
-.imageset.forum_read_subforum {
- background-image: url("./images/forum_read_subforum.gif");
- padding-left: 46px;
- padding-top: 25px;
-}
-.imageset.forum_unread {
- background-image: url("./images/forum_unread.gif");
- padding-left: 46px;
- padding-top: 25px;
-}
-.imageset.forum_unread_locked {
- background-image: url("./images/forum_unread_locked.gif");
- padding-left: 46px;
- padding-top: 25px;
-}
-.imageset.forum_unread_subforum {
- background-image: url("./images/forum_unread_subforum.gif");
- padding-left: 46px;
- padding-top: 25px;
-}
-.imageset.topic_moved {
- background-image: url("./images/topic_moved.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_read {
- background-image: url("./images/topic_read.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_read_mine {
- background-image: url("./images/topic_read_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_read_hot {
- background-image: url("./images/topic_read_hot.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_read_hot_mine {
- background-image: url("./images/topic_read_hot_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_read_locked {
- background-image: url("./images/topic_read_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_read_locked_mine {
- background-image: url("./images/topic_read_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_unread {
- background-image: url("./images/topic_unread.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_unread_mine {
- background-image: url("./images/topic_unread_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_unread_hot {
- background-image: url("./images/topic_unread_hot.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_unread_hot_mine {
- background-image: url("./images/topic_unread_hot_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_unread_locked {
- background-image: url("./images/topic_unread_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.topic_unread_locked_mine {
- background-image: url("./images/topic_unread_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_read {
- background-image: url("./images/sticky_read.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_read_mine {
- background-image: url("./images/sticky_read_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_read_locked {
- background-image: url("./images/sticky_read_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_read_locked_mine {
- background-image: url("./images/sticky_read_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_unread {
- background-image: url("./images/sticky_unread.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_unread_mine {
- background-image: url("./images/sticky_unread_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_unread_locked {
- background-image: url("./images/sticky_unread_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.sticky_unread_locked_mine {
- background-image: url("./images/sticky_unread_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_read {
- background-image: url("./images/announce_read.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_read_mine {
- background-image: url("./images/announce_read_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_read_locked {
- background-image: url("./images/announce_read_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_read_locked_mine {
- background-image: url("./images/announce_read_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_unread {
- background-image: url("./images/announce_unread.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_unread_mine {
- background-image: url("./images/announce_unread_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_unread_locked {
- background-image: url("./images/announce_unread_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.announce_unread_locked_mine {
- background-image: url("./images/announce_unread_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_read {
- background-image: url("./images/announce_read.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_read_mine {
- background-image: url("./images/announce_read_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_read_locked {
- background-image: url("./images/announce_read_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_read_locked_mine {
- background-image: url("./images/announce_read_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_unread {
- background-image: url("./images/announce_unread.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_unread_mine {
- background-image: url("./images/announce_unread_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_unread_locked {
- background-image: url("./images/announce_unread_locked.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.global_unread_locked_mine {
- background-image: url("./images/announce_unread_locked_mine.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.pm_read {
- background-image: url("./images/topic_read.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.pm_unread {
- background-image: url("./images/topic_unread.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.icon_post_target {
- background-image: url("./images/icon_post_target.gif");
- padding-left: 12px;
- padding-top: 9px;
-}
-.imageset.icon_post_target_unread {
- background-image: url("./images/icon_post_target_unread.gif");
- padding-left: 12px;
- padding-top: 9px;
-}
-.imageset.icon_topic_attach {
- background-image: url("./images/icon_topic_attach.gif");
- padding-left: 14px;
- padding-top: 18px;
-}
-.imageset.icon_topic_latest {
- background-image: url("./images/icon_topic_latest.gif");
- padding-left: 18px;
- padding-top: 9px;
-}
-.imageset.icon_topic_newest {
- background-image: url("./images/icon_topic_newest.gif");
- padding-left: 18px;
- padding-top: 9px;
-}
-.imageset.icon_topic_reported {
- background-image: url("./images/icon_topic_reported.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.icon_topic_unapproved {
- background-image: url("./images/icon_topic_unapproved.gif");
- padding-left: 19px;
- padding-top: 18px;
-}
-.imageset.icon_topic_deleted {
- background-image: url("./images/icon_topic_deleted.png");
- padding-left: 14px;
- padding-top: 14px;
-}
-
-
-/* English images for fallback */
-.imageset.phpbb_aol-icon, .imageset.icon_contact_aim {
- background-image: url("./en/icon_contact_aim.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_contact_email {
- background-image: url("./en/icon_contact_email.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_icq-icon, .imageset.icon_contact_icq {
- background-image: url("./en/icon_contact_icq.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_contact_jabber {
- background-image: url("./en/icon_contact_jabber.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_wlm-icon, .imageset.icon_contact_msnm {
- background-image: url("./en/icon_contact_msnm.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_contact_pm {
- background-image: url("./en/icon_contact_pm.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_yahoo-icon, .imageset.icon_contact_yahoo {
- background-image: url("./en/icon_contact_yahoo.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.phpbb_website-icon, .imageset.icon_contact_www {
- background-image: url("./en/icon_contact_www.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_post_delete {
- background-image: url("./en/icon_post_delete.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_edit {
- background-image: url("./en/icon_post_edit.gif");
- padding-left: 90px;
- padding-top: 20px;
-}
-.imageset.icon_post_info {
- background-image: url("./en/icon_post_info.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_post_quote {
- background-image: url("./en/icon_post_quote.gif");
- padding-left: 90px;
- padding-top: 20px;
-}
-.imageset.icon_post_report {
- background-image: url("./en/icon_post_report.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.icon_user_online {
- background-image: url("./en/icon_user_online.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_offline {
- background-image: url("./en/icon_user_offline.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_profile {
- background-image: url("./en/icon_user_profile.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_search {
- background-image: url("./en/icon_user_search.gif");
- padding-left: 72px;
- padding-top: 20px;
-}
-.imageset.icon_user_warn {
- background-image: url("./en/icon_user_warn.gif");
- padding-left: 20px;
- padding-top: 20px;
-}
-.imageset.button_pm_new {
- background-image: url("./en/button_pm_new.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
-.imageset.button_pm_reply {
- background-image: url("./en/button_pm_reply.gif");
- padding-left: 90px;
- padding-top: 20px;
-}
-.imageset.button_topic_locked {
- background-image: url("./en/button_topic_locked.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
-.imageset.button_topic_new {
- background-image: url("./en/button_topic_new.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
-.imageset.button_topic_reply {
- background-image: url("./en/button_topic_reply.gif");
- padding-left: 97px;
- padding-top: 27px;
-}
-
-/* RTL imageset entries */
-.rtl .imageset.site_logo {
- padding-right: 170px;
- padding-left: 0;
-}
-.rtl .imageset.upload_bar {
- padding-right: 280px;
- padding-left: 0;
-}
-.rtl .imageset.poll_left, .rtl .imageset.poll_right {
- padding-right: 4px;
- padding-left: 0;
-}
-.rtl .imageset.poll_center {
- padding-right: 1px;
- padding-left: 0;
-}
-.rtl .imageset.forum_link, .rtl .imageset.forum_read, .rtl .imageset.forum_read_locked, .rtl .imageset.forum_read_subforum, .rtl .imageset.forum_unread, .rtl .imageset.forum_unread_locked, .rtl .imageset.forum_unread_subforum {
- padding-right: 46px;
- padding-left: 0;
-}
-.rtl .imageset.topic_moved, .rtl .imageset.topic_read, .rtl .imageset.topic_read_mine, .rtl .imageset.topic_read_hot, .rtl .imageset.topic_read_hot_mine, .rtl .imageset.topic_read_locked, .rtl .imageset.topic_read_locked_mine, .rtl .imageset.topic_unread, .rtl .imageset.topic_unread_mine, .rtl .imageset.topic_unread_hot, .rtl .imageset.topic_unread_hot_mine, .rtl .imageset.topic_unread_locked, .rtl .imageset.topic_unread_locked_mine, .rtl .imageset.sticky_read, .rtl .imageset.sticky_read_mine, .rtl .imageset.sticky_read_locked, .rtl .imageset.sticky_read_locked_mine, .rtl .imageset.sticky_unread, .rtl .imageset.sticky_unread_mine, .rtl .imageset.sticky_unread_locked, .rtl .imageset.sticky_unread_locked_mine, .rtl .imageset.announce_read, .rtl .imageset.announce_read_mine, .rtl .imageset.announce_read_locked, .rtl .imageset.announce_read_locked_mine, .rtl .imageset.announce_unread, .rtl .imageset.announce_unread_mine, .rtl .imageset.announce_unread_locked, .rtl .imageset.announce_unread_locked_mine, .rtl .imageset.global_read, .rtl .imageset.global_read_mine, .rtl .imageset.global_read_locked, .rtl .imageset.global_read_locked_mine, .rtl .imageset.global_unread, .rtl .imageset.global_unread_mine, .rtl .imageset.global_unread_locked, .rtl .imageset.global_unread_locked_mine, .rtl .imageset.pm_read, .rtl .imageset.pm_unread, .rtl .imageset.icon_topic_reported, .rtl .imageset.icon_topic_unapproved {
- padding-right: 19px;
- padding-left: 0;
-}
-.rtl .imageset.icon_post_target, .rtl .imageset.icon_post_target_unread {
- padding-right: 12px;
- padding-left: 0;
-}
-.rtl .imageset.icon_topic_attach {
- padding-right: 14px;
- padding-left: 0;
-}
-.rtl .imageset.icon_topic_latest, .rtl .imageset.icon_topic_newest {
- padding-right: 18px;
- padding-left: 0;
-}
-
-#notification_list {
- display: none;
- position: absolute;
- width: 310px;
- z-index: 1;
- box-shadow: 3px 3px 5px darkgray;
-}
-
-#notification_list .notification_scroll {
- max-height: 350px;
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-#notification_list table {
- width: 100%;
-}
-
-#notification_list .notification_title {
- padding: 3px;
-}
-
-#notification_list .notification_title:after {
- clear: both;
- content: '';
- display: block;
-}
-
-#notification_list .header {
- padding: 5px;
- font-weight: bold;
- border: 1px solid #A9B8C2;
- border-bottom: 0;
-}
-
-#notification_list > .header > .header_settings {
- float: right;
- font-weight: normal;
- text-transform: none;
-}
-
-#notification_list .header:after {
- content: '';
- display: table;
- clear: both;
-}
-
-#notification_list .footer {
- text-align: center;
- font-size: 1.2em;
- border: 1px solid #A9B8C2;
- border-top: 0;
-}
-
-.notification_list img {
- max-width: 50px;
- max-height: 50px;
-}
-
-#notification_list .footer > a {
- display: block;
-}
-
-#notification_list .notification-time {
- font-size: 0.9em;
- float: right;
-}
-
-.notification_list .notifications_time {
- font-size: 0.8em;
-}
diff --git a/phpBB/ucp.php b/phpBB/ucp.php
index 5cd602bab5..96a3efea97 100644
--- a/phpBB/ucp.php
+++ b/phpBB/ucp.php
@@ -22,14 +22,20 @@ require($phpbb_root_path . 'includes/functions_user.' . $phpEx);
require($phpbb_root_path . 'includes/functions_module.' . $phpEx);
// Basic parameter data
-$id = request_var('i', '');
-$mode = request_var('mode', '');
+$id = $request->variable('i', '');
+$mode = $request->variable('mode', '');
if (in_array($mode, array('login', 'login_link', 'logout', 'confirm', 'sendpassword', 'activate')))
{
define('IN_LOGIN', true);
}
+if ($mode === 'delete_cookies')
+{
+ define('SKIP_CHECK_BAN', true);
+ define('SKIP_CHECK_DISABLED', true);
+}
+
// Start session management
$user->session_begin();
$auth->acl($user->data);
@@ -81,7 +87,7 @@ switch ($mode)
redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
}
- login_box(request_var('redirect', "index.$phpEx"));
+ login_box($request->variable('redirect', "index.$phpEx"));
break;
case 'login_link':
@@ -138,7 +144,7 @@ switch ($mode)
'AGREEMENT_TITLE' => $user->lang[$title],
'AGREEMENT_TEXT' => sprintf($user->lang[$message], $config['sitename'], generate_board_url()),
'U_BACK' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login'),
- 'L_BACK' => $user->lang['BACK_TO_LOGIN'],
+ 'L_BACK' => $user->lang['BACK_TO_PREV'],
));
page_footer();
@@ -212,7 +218,7 @@ switch ($mode)
case 'switch_perm':
- $user_id = request_var('u', 0);
+ $user_id = $request->variable('u', 0);
$sql = 'SELECT *
FROM ' . USERS_TABLE . '
@@ -221,7 +227,7 @@ switch ($mode)
$user_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- if (!$auth->acl_get('a_switchperm') || !$user_row || $user_id == $user->data['user_id'] || !check_link_hash(request_var('hash', ''), 'switchperm'))
+ if (!$auth->acl_get('a_switchperm') || !$user_row || $user_id == $user->data['user_id'] || !check_link_hash($request->variable('hash', ''), 'switchperm'))
{
redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
}
@@ -234,7 +240,7 @@ switch ($mode)
redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
}
- add_log('admin', 'LOG_ACL_TRANSFER_PERMISSIONS', $user_row['username']);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ACL_TRANSFER_PERMISSIONS', false, array($user_row['username']));
$message = sprintf($user->lang['PERMISSIONS_TRANSFERRED'], $user_row['username']) . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
@@ -270,7 +276,7 @@ switch ($mode)
$username = $db->sql_fetchfield('username');
$db->sql_freeresult($result);
- add_log('admin', 'LOG_ACL_RESTORE_PERMISSIONS', $username);
+ $phpbb_log->add('admin', $user->data['user_id'], $user->ip, 'LOG_ACL_RESTORE_PERMISSIONS', false, array($username));
$message = $user->lang['PERMISSIONS_RESTORED'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>');
@@ -310,7 +316,7 @@ if (!$user->data['is_registered'])
if ($id == 'pm' && $mode == 'view' && isset($_GET['p']))
{
- $redirect_url = append_sid("{$phpbb_root_path}ucp.$phpEx?i=pm&p=" . request_var('p', 0));
+ $redirect_url = append_sid("{$phpbb_root_path}ucp.$phpEx?i=pm&p=" . $request->variable('p', 0));
login_box($redirect_url, $user->lang['LOGIN_EXPLAIN_UCP']);
}
diff --git a/phpBB/viewforum.php b/phpBB/viewforum.php
index 5c51975150..4691512cbd 100644
--- a/phpBB/viewforum.php
+++ b/phpBB/viewforum.php
@@ -25,18 +25,19 @@ $user->session_begin();
$auth->acl($user->data);
// Start initial var setup
-$forum_id = request_var('f', 0);
-$mark_read = request_var('mark', '');
-$start = request_var('start', 0);
+$forum_id = $request->variable('f', 0);
+$mark_read = $request->variable('mark', '');
+$start = $request->variable('start', 0);
$default_sort_days = (!empty($user->data['user_topic_show_days'])) ? $user->data['user_topic_show_days'] : 0;
$default_sort_key = (!empty($user->data['user_topic_sortby_type'])) ? $user->data['user_topic_sortby_type'] : 't';
$default_sort_dir = (!empty($user->data['user_topic_sortby_dir'])) ? $user->data['user_topic_sortby_dir'] : 'd';
-$sort_days = request_var('st', $default_sort_days);
-$sort_key = request_var('sk', $default_sort_key);
-$sort_dir = request_var('sd', $default_sort_dir);
+$sort_days = $request->variable('st', $default_sort_days);
+$sort_key = $request->variable('sk', $default_sort_key);
+$sort_dir = $request->variable('sd', $default_sort_dir);
+/* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
// Check if the user has actually sent a forum ID with his/her request
@@ -86,10 +87,11 @@ if (isset($_GET['e']) && !$user->data['is_registered'])
}
// Permissions check
-if (!$auth->acl_gets('f_list', 'f_read', $forum_id) || ($forum_data['forum_type'] == FORUM_LINK && $forum_data['forum_link'] && !$auth->acl_get('f_read', $forum_id)))
+if (!$auth->acl_gets('f_list', 'f_list_topics', 'f_read', $forum_id) || ($forum_data['forum_type'] == FORUM_LINK && $forum_data['forum_link'] && !$auth->acl_get('f_read', $forum_id)))
{
if ($user->data['user_id'] != ANONYMOUS)
{
+ send_status_line(403, 'Forbidden');
trigger_error('SORRY_AUTH_READ');
}
@@ -159,7 +161,22 @@ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
$topics_count = $phpbb_content_visibility->get_count('forum_topics', $forum_data, $forum_id);
$start = $pagination->validate_start($start, $config['topics_per_page'], $topics_count);
-page_header($forum_data['forum_name'] . ($start ? ' - ' . $user->lang('PAGE_TITLE_NUMBER', $pagination->get_on_page($config['topics_per_page'], $start)) : ''), true, $forum_id);
+$page_title = $forum_data['forum_name'] . ($start ? ' - ' . $user->lang('PAGE_TITLE_NUMBER', $pagination->get_on_page($config['topics_per_page'], $start)) : '');
+
+/**
+* You can use this event to modify the page title of the viewforum page
+*
+* @event core.viewforum_modify_page_title
+* @var string page_title Title of the viewforum page
+* @var array forum_data Array with forum data
+* @var int forum_id The forum ID
+* @var int start Start offset used to calculate the page
+* @since 3.2.2-RC1
+*/
+$vars = array('page_title', 'forum_data', 'forum_id', 'start');
+extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_page_title', compact($vars)));
+
+page_header($page_title, true, $forum_id);
$template->set_filenames(array(
'body' => 'viewforum_body.html')
@@ -179,7 +196,7 @@ if (!($forum_data['forum_type'] == FORUM_POST || (($forum_data['forum_flags'] &
// Ok, if someone has only list-access, we only display the forum list.
// We also make this circumstance available to the template in case we want to display a notice. ;)
-if (!$auth->acl_get('f_read', $forum_id))
+if (!$auth->acl_gets('f_read', 'f_list_topics', $forum_id))
{
$template->assign_vars(array(
'S_NO_READ_ACCESS' => true,
@@ -191,10 +208,10 @@ if (!$auth->acl_get('f_read', $forum_id))
// Handle marking posts
if ($mark_read == 'topics')
{
- $token = request_var('hash', '');
+ $token = $request->variable('hash', '');
if (check_link_hash($token, 'global'))
{
- markread('topics', array($forum_id), false, request_var('mark_time', 0));
+ markread('topics', array($forum_id), false, $request->variable('mark_time', 0));
}
$redirect_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
meta_refresh(3, $redirect_url);
@@ -205,7 +222,7 @@ if ($mark_read == 'topics')
$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()) : '',
+ '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(), false) : '',
'MESSAGE_TITLE' => $user->lang['INFORMATION'],
'MESSAGE_TEXT' => $user->lang['TOPICS_MARKED']
);
@@ -219,6 +236,7 @@ if ($mark_read == 'topics')
// Do the forum Prune thang - cron type job ...
if (!$config['use_system_cron'])
{
+ /* @var $cron \phpbb\cron\manager */
$cron = $phpbb_container->get('cron.manager');
$task = $cron->find_task('cron.task.core.prune_forum');
@@ -267,6 +285,20 @@ $limit_days = array(0 => $user->lang['ALL_TOPICS'], 1 => $user->lang['1_DAY'], 7
$sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']);
$sort_by_sql = array('a' => 't.topic_first_poster_name', 't' => array('t.topic_last_post_time', 't.topic_last_post_id'), 'r' => (($auth->acl_get('m_approve', $forum_id)) ? 't.topic_posts_approved + t.topic_posts_unapproved + t.topic_posts_softdeleted' : 't.topic_posts_approved'), 's' => 'LOWER(t.topic_title)', 'v' => 't.topic_views');
+/**
+ * Modify the topic ordering if needed
+ *
+ * @event core.viewforum_modify_topic_ordering
+ * @var array sort_by_text Topic ordering options
+ * @var array sort_by_sql Topic orderings options SQL equivalent
+ * @since 3.2.5-RC1
+ */
+$vars = array(
+ 'sort_by_text',
+ 'sort_by_sql',
+);
+extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_topic_ordering', compact($vars)));
+
$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param, $default_sort_days, $default_sort_key, $default_sort_dir);
@@ -382,7 +414,7 @@ $template->assign_vars(array(
'S_SELECT_SORT_DIR' => $s_sort_dir,
'S_SELECT_SORT_KEY' => $s_sort_key,
'S_SELECT_SORT_DAYS' => $s_limit_days,
- 'S_TOPIC_ICONS' => ($s_display_active && sizeof($active_forum_ary)) ? max($active_forum_ary['enable_icons']) : (($forum_data['enable_icons']) ? true : false),
+ 'S_TOPIC_ICONS' => ($s_display_active && count($active_forum_ary)) ? max($active_forum_ary['enable_icons']) : (($forum_data['enable_icons']) ? true : false),
'U_WATCH_FORUM_LINK' => $s_watching_forum['link'],
'U_WATCH_FORUM_TOGGLE' => $s_watching_forum['link_toggle'],
'S_WATCH_FORUM_TITLE' => $s_watching_forum['title'],
@@ -392,7 +424,7 @@ $template->assign_vars(array(
'S_DISPLAY_SEARCHBOX' => ($auth->acl_get('u_search') && $auth->acl_get('f_search', $forum_id) && $config['load_search']) ? true : false,
'S_SEARCHBOX_ACTION' => append_sid("{$phpbb_root_path}search.$phpEx"),
'S_SEARCH_LOCAL_HIDDEN_FIELDS' => build_hidden_fields($s_search_hidden_fields),
- 'S_SINGLE_MODERATOR' => (!empty($moderators[$forum_id]) && sizeof($moderators[$forum_id]) > 1) ? false : true,
+ 'S_SINGLE_MODERATOR' => (!empty($moderators[$forum_id]) && count($moderators[$forum_id]) > 1) ? false : true,
'S_IS_LOCKED' => ($forum_data['forum_status'] == ITEM_LOCKED) ? true : false,
'S_VIEWFORUM' => true,
@@ -462,7 +494,7 @@ if ($user->data['is_registered'])
$sql_array['LEFT_JOIN'][] = array('FROM' => array(TOPICS_TRACK_TABLE => 'tt'), 'ON' => 'tt.topic_id = t.topic_id AND tt.user_id = ' . $user->data['user_id']);
$sql_array['SELECT'] .= ', tt.mark_time';
- if ($s_display_active && sizeof($active_forum_ary))
+ if ($s_display_active && count($active_forum_ary))
{
$sql_array['LEFT_JOIN'][] = array('FROM' => array(FORUMS_TRACK_TABLE => 'ft'), 'ON' => 'ft.forum_id = t.forum_id AND ft.user_id = ' . $user->data['user_id']);
$sql_array['SELECT'] .= ', ft.mark_time AS forum_mark_time';
@@ -488,7 +520,7 @@ if ($forum_data['forum_type'] == FORUM_POST)
'WHERE' => '(t.forum_id = ' . $forum_id . '
AND t.topic_type = ' . POST_ANNOUNCE . ') OR
- (' . $db->sql_in_set('t.forum_id', $g_forum_ary) . '
+ (' . $db->sql_in_set('t.forum_id', $g_forum_ary, false, true) . '
AND t.topic_type = ' . POST_GLOBAL . ')',
'ORDER_BY' => 't.topic_time DESC',
@@ -520,7 +552,7 @@ if ($forum_data['forum_type'] == FORUM_POST)
while ($row = $db->sql_fetchrow($result))
{
- if ($row['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $row['forum_id']))
+ if (!$phpbb_content_visibility->is_visible('topic', $row['forum_id'], $row))
{
// Do not display announcements that are waiting for approval or soft deleted.
continue;
@@ -570,8 +602,8 @@ if ($start > $topics_count / 2)
// Select the sort order
$direction = (($sort_dir == 'd') ? 'ASC' : 'DESC');
- $sql_limit = $pagination->reverse_limit($start, $sql_limit, $topics_count - sizeof($announcement_list));
- $sql_start = $pagination->reverse_start($start, $sql_limit, $topics_count - sizeof($announcement_list));
+ $sql_limit = $pagination->reverse_limit($start, $sql_limit, $topics_count - count($announcement_list));
+ $sql_start = $pagination->reverse_start($start, $sql_limit, $topics_count - count($announcement_list));
}
else
{
@@ -580,6 +612,18 @@ else
$sql_start = $start;
}
+/**
+ * Modify the topics sort ordering if needed
+ *
+ * @event core.viewforum_modify_sort_direction
+ * @var string direction Topics sort order
+ * @since 3.2.5-RC1
+ */
+$vars = array(
+ 'direction',
+);
+extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_sort_direction', compact($vars)));
+
if (is_array($sort_by_sql[$sort_key]))
{
$sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction;
@@ -589,7 +633,7 @@ else
$sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction;
}
-if ($forum_data['forum_type'] == FORUM_POST || !sizeof($active_forum_ary))
+if ($forum_data['forum_type'] == FORUM_POST || !count($active_forum_ary))
{
$sql_where = 't.forum_id = ' . $forum_id;
}
@@ -600,7 +644,7 @@ else if (empty($active_forum_ary['exclude_forum_id']))
else
{
$get_forum_ids = array_diff($active_forum_ary['forum_id'], $active_forum_ary['exclude_forum_id']);
- $sql_where = (sizeof($get_forum_ids)) ? $db->sql_in_set('t.forum_id', $get_forum_ids) : 't.forum_id = ' . $forum_id;
+ $sql_where = (count($get_forum_ids)) ? $db->sql_in_set('t.forum_id', $get_forum_ids) : 't.forum_id = ' . $forum_id;
}
// Grab just the sorted topic ids
@@ -659,7 +703,7 @@ $db->sql_freeresult($result);
// For storing shadow topics
$shadow_topic_list = array();
-if (sizeof($topic_list))
+if (count($topic_list))
{
// SQL array for obtaining topics/stickies
$sql_array = array(
@@ -689,7 +733,7 @@ if (sizeof($topic_list))
}
// If we have some shadow topics, update the rowset to reflect their topic information
-if (sizeof($shadow_topic_list))
+if (count($shadow_topic_list))
{
// SQL array for obtaining shadow topics
$sql_array = array(
@@ -729,7 +773,7 @@ if (sizeof($shadow_topic_list))
}
// Do not include those topics the user has no permission to access
- if (!$auth->acl_get('f_read', $row['forum_id']))
+ if (!$auth->acl_gets('f_read', 'f_list_topics', $row['forum_id']))
{
// We need to remove any trace regarding this topic. :)
unset($rowset[$orig_topic_id]);
@@ -764,7 +808,7 @@ if ($s_display_active)
// We need to remove the global announcements from the forums total topic count,
// otherwise the number is different from the one on the forum list
-$total_topic_count = $topics_count - sizeof($announcement_list);
+$total_topic_count = $topics_count - count($announcement_list);
$base_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id" . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : ''));
$pagination->generate_template_pagination($base_url, 'pagination', 'start', $total_topic_count, $config['topics_per_page'], $start);
@@ -791,7 +835,7 @@ $vars = array('topic_list', 'rowset', 'total_topic_count', 'forum_id');
extract($phpbb_dispatcher->trigger_event('core.viewforum_modify_topics_data', compact($vars)));
// Okay, lets dump out the page ...
-if (sizeof($topic_list))
+if (count($topic_list))
{
$mark_forum_read = true;
$mark_time_forum = 0;
@@ -872,7 +916,7 @@ if (sizeof($topic_list))
// Generate all the URIs ...
$view_topic_url_params = 'f=' . $row['forum_id'] . '&amp;t=' . $topic_id;
- $view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params);
+ $view_topic_url = $auth->acl_get('f_read', $forum_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params) : false;
$topic_unapproved = (($row['topic_visibility'] == ITEM_UNAPPROVED || $row['topic_visibility'] == ITEM_REAPPROVE) && $auth->acl_get('m_approve', $row['forum_id']));
$posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $row['forum_id']));
@@ -889,9 +933,12 @@ if (sizeof($topic_list))
'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
'TOPIC_AUTHOR_FULL' => get_username_string('full', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
'FIRST_POST_TIME' => $user->format_date($row['topic_time']),
+ 'FIRST_POST_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_time']),
'LAST_POST_SUBJECT' => censor_text($row['topic_last_post_subject']),
'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']),
+ 'LAST_POST_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_last_post_time']),
'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']),
+ 'LAST_VIEW_TIME_RFC3339' => gmdate(DATE_RFC3339, $row['topic_last_view_time']),
'LAST_POST_AUTHOR' => get_username_string('username', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
'LAST_POST_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
'LAST_POST_AUTHOR_FULL' => get_username_string('full', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
@@ -926,8 +973,8 @@ if (sizeof($topic_list))
'S_TOPIC_LOCKED' => ($row['topic_status'] == ITEM_LOCKED) ? true : false,
'S_TOPIC_MOVED' => ($row['topic_status'] == ITEM_MOVED) ? true : false,
- 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;view=unread') . '#unread',
- 'U_LAST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;p=' . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'],
+ 'U_NEWEST_POST' => $auth->acl_get('f_read', $forum_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;view=unread') . '#unread' : false,
+ 'U_LAST_POST' => $auth->acl_get('f_read', $forum_id) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params . '&amp;p=' . $row['topic_last_post_id']) . '#p' . $row['topic_last_post_id'] : false,
'U_LAST_POST_AUTHOR' => get_username_string('profile', $row['topic_last_poster_id'], $row['topic_last_poster_name'], $row['topic_last_poster_colour']),
'U_TOPIC_AUTHOR' => get_username_string('profile', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
'U_VIEW_TOPIC' => $view_topic_url,
@@ -990,11 +1037,21 @@ if (sizeof($topic_list))
}
}
+/**
+* This event is to perform additional actions on viewforum page
+*
+* @event core.viewforum_generate_page_after
+* @var array forum_data Array with the forum data
+* @since 3.2.2-RC1
+*/
+$vars = array('forum_data');
+extract($phpbb_dispatcher->trigger_event('core.viewforum_generate_page_after', compact($vars)));
+
// This is rather a fudge but it's the best I can think of without requiring information
// on all topics (as we do in 2.0.x). It looks for unread or new topics, if it doesn't find
// any it updates the forum last read cookie. This requires that the user visit the forum
// after reading a topic
-if ($forum_data['forum_type'] == FORUM_POST && sizeof($topic_list) && $mark_forum_read)
+if ($forum_data['forum_type'] == FORUM_POST && count($topic_list) && $mark_forum_read)
{
update_forum_tracking_info($forum_id, $forum_data['forum_last_post_time'], false, $mark_time_forum);
}
diff --git a/phpBB/viewonline.php b/phpBB/viewonline.php
index 0a8af2001c..d5ddb0ba13 100644
--- a/phpBB/viewonline.php
+++ b/phpBB/viewonline.php
@@ -25,25 +25,29 @@ $auth->acl($user->data);
$user->setup('memberlist');
// Get and set some variables
-$mode = request_var('mode', '');
-$session_id = request_var('s', '');
-$start = request_var('start', 0);
-$sort_key = request_var('sk', 'b');
-$sort_dir = request_var('sd', 'd');
-$show_guests = ($config['load_online_guests']) ? request_var('sg', 0) : 0;
+$mode = $request->variable('mode', '');
+$session_id = $request->variable('s', '');
+$start = $request->variable('start', 0);
+$sort_key = $request->variable('sk', 'b');
+$sort_dir = $request->variable('sd', 'd');
+$show_guests = ($config['load_online_guests']) ? $request->variable('sg', 0) : 0;
// Can this user view profiles/memberlist?
if (!$auth->acl_gets('u_viewprofile', 'a_user', 'a_useradd', 'a_userdel'))
{
if ($user->data['user_id'] != ANONYMOUS)
{
+ send_status_line(403, 'Forbidden');
trigger_error('NO_VIEW_USERS');
}
login_box('', $user->lang['LOGIN_EXPLAIN_VIEWONLINE']);
}
+/* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
+
+/* @var $viewonline_helper \phpbb\viewonline_helper */
$viewonline_helper = $phpbb_container->get('viewonline_helper');
$sort_key_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_JOINED'], 'c' => $user->lang['SORT_LOCATION']);
@@ -126,7 +130,6 @@ if (!$show_guests)
{
switch ($db->get_sql_layer())
{
- case 'sqlite':
case 'sqlite3':
$sql = 'SELECT COUNT(session_ip) as num_guests
FROM (
@@ -181,6 +184,12 @@ $result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
$prev_id = $prev_ip = $user_list = array();
$logged_visible_online = $logged_hidden_online = $counter = 0;
+/** @var \phpbb\controller\helper $controller_helper */
+$controller_helper = $phpbb_container->get('controller.helper');
+
+/** @var \phpbb\group\helper $group_helper */
+$group_helper = $phpbb_container->get('group_helper');
+
while ($row = $db->sql_fetchrow($result))
{
if ($row['user_id'] != ANONYMOUS && !isset($prev_id[$row['user_id']]))
@@ -305,11 +314,6 @@ while ($row = $db->sql_fetchrow($result))
$location_url = append_sid("{$phpbb_root_path}search.$phpEx");
break;
- case 'faq':
- $location = $user->lang['VIEWING_FAQ'];
- $location_url = append_sid("{$phpbb_root_path}faq.$phpEx");
- break;
-
case 'viewonline':
$location = $user->lang['VIEWING_ONLINE'];
$location_url = append_sid("{$phpbb_root_path}viewonline.$phpEx");
@@ -375,6 +379,13 @@ while ($row = $db->sql_fetchrow($result))
default:
$location = $user->lang['INDEX'];
$location_url = append_sid("{$phpbb_root_path}index.$phpEx");
+
+ if ($row['session_page'] === 'app.' . $phpEx . '/help/faq' ||
+ $row['session_page'] === 'app.' . $phpEx . '/help/bbcode')
+ {
+ $location = $user->lang['VIEWING_FAQ'];
+ $location_url = $controller_helper->route('phpbb_help_faq_controller');
+ }
break;
}
@@ -464,7 +475,7 @@ while ($row = $db->sql_fetchrow($result))
}
else
{
- $legend .= (($legend != '') ? ', ' : '') . '<a style="color:#' . $row['group_colour'] . '" href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $row['group_id']) . '">' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</a>';
+ $legend .= (($legend != '') ? ', ' : '') . '<a style="color:#' . $row['group_colour'] . '" href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $row['group_id']) . '">' . $group_helper->get_name($row['group_name']) . '</a>';
}
}
$db->sql_freeresult($result);
diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php
index 103fc7f108..4e502538c8 100644
--- a/phpBB/viewtopic.php
+++ b/phpBB/viewtopic.php
@@ -27,34 +27,35 @@ $user->session_begin();
$auth->acl($user->data);
// Initial var setup
-$forum_id = request_var('f', 0);
-$topic_id = request_var('t', 0);
-$post_id = request_var('p', 0);
-$voted_id = request_var('vote_id', array('' => 0));
+$forum_id = $request->variable('f', 0);
+$topic_id = $request->variable('t', 0);
+$post_id = $request->variable('p', 0);
+$voted_id = $request->variable('vote_id', array('' => 0));
-$voted_id = (sizeof($voted_id) > 1) ? array_unique($voted_id) : $voted_id;
+$voted_id = (count($voted_id) > 1) ? array_unique($voted_id) : $voted_id;
-$start = request_var('start', 0);
-$view = request_var('view', '');
+$start = $request->variable('start', 0);
+$view = $request->variable('view', '');
$default_sort_days = (!empty($user->data['user_post_show_days'])) ? $user->data['user_post_show_days'] : 0;
$default_sort_key = (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't';
$default_sort_dir = (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a';
-$sort_days = request_var('st', $default_sort_days);
-$sort_key = request_var('sk', $default_sort_key);
-$sort_dir = request_var('sd', $default_sort_dir);
+$sort_days = $request->variable('st', $default_sort_days);
+$sort_key = $request->variable('sk', $default_sort_key);
+$sort_dir = $request->variable('sd', $default_sort_dir);
-$update = request_var('update', false);
+$update = $request->variable('update', false);
+/* @var $pagination \phpbb\pagination */
$pagination = $phpbb_container->get('pagination');
$s_can_vote = false;
/**
* @todo normalize?
*/
-$hilit_words = request_var('hilit', '', true);
+$hilit_words = $request->variable('hilit', '', true);
// Do we have a topic or post id?
if (!$topic_id && !$post_id)
@@ -62,6 +63,7 @@ if (!$topic_id && !$post_id)
trigger_error('NO_TOPIC');
}
+/* @var $phpbb_content_visibility \phpbb\content_visibility */
$phpbb_content_visibility = $phpbb_container->get('content.visibility');
// Find topic id if user requested a newer or older topic
@@ -261,8 +263,26 @@ if (!$topic_data)
$forum_id = (int) $topic_data['forum_id'];
+/**
+ * Modify the forum ID to handle the correct display of viewtopic if needed
+ *
+ * @event core.viewtopic_modify_forum_id
+ * @var string forum_id forum ID
+ * @var array topic_data array of topic's data
+ * @since 3.2.5-RC1
+ */
+$vars = array(
+ 'forum_id',
+ 'topic_data',
+);
+extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_forum_id', compact($vars)));
+
+// If the request is missing the f parameter, the forum id in the user session data is 0 at the moment.
+// Let's fix that now so that the user can't hide from the forum's Who Is Online list.
+$user->page['forum'] = $forum_id;
+
// Now we know the forum_id and can check the permissions
-if ($topic_data['topic_visibility'] != ITEM_APPROVED && !$auth->acl_get('m_approve', $forum_id))
+if (!$phpbb_content_visibility->is_visible('topic', $forum_id, $topic_data))
{
trigger_error('NO_TOPIC');
}
@@ -321,8 +341,8 @@ if ($post_id)
$topic_id = (int) $topic_data['topic_id'];
$topic_replies = $phpbb_content_visibility->get_count('topic_posts', $topic_data, $forum_id) - 1;
-// Check sticky/announcement time limit
-if (($topic_data['topic_type'] == POST_STICKY || $topic_data['topic_type'] == POST_ANNOUNCE) && $topic_data['topic_time_limit'] && ($topic_data['topic_time'] + $topic_data['topic_time_limit']) < time())
+// Check sticky/announcement/global time limit
+if (($topic_data['topic_type'] != POST_NORMAL) && $topic_data['topic_time_limit'] && ($topic_data['topic_time'] + $topic_data['topic_time_limit']) < time())
{
$sql = 'UPDATE ' . TOPICS_TABLE . '
SET topic_type = ' . POST_NORMAL . ', topic_time_limit = 0
@@ -336,6 +356,12 @@ if (($topic_data['topic_type'] == POST_STICKY || $topic_data['topic_type'] == PO
// Setup look and feel
$user->setup('viewtopic', $topic_data['forum_style']);
+if ($view == 'print' && !$auth->acl_get('f_print', $forum_id))
+{
+ send_status_line(403, 'Forbidden');
+ trigger_error('NO_AUTH_PRINT_TOPIC');
+}
+
$overrides_f_read_check = false;
$overrides_forum_password_check = false;
$topic_tracking_info = isset($topic_tracking_info) ? $topic_tracking_info : null;
@@ -374,6 +400,7 @@ if (!$overrides_f_read_check && !$auth->acl_get('f_read', $forum_id))
{
if ($user->data['user_id'] != ANONYMOUS)
{
+ send_status_line(403, 'Forbidden');
trigger_error('SORRY_AUTH_READ');
}
@@ -426,6 +453,38 @@ $join_user_sql = array('a' => true, 't' => false, 's' => false);
$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
+/**
+* Event to add new sorting options
+*
+* @event core.viewtopic_gen_sort_selects_before
+* @var array limit_days Limit results by time
+* @var array sort_by_text Language strings for sorting options
+* @var array sort_by_sql SQL conditions for sorting options
+* @var array join_user_sql SQL joins required for sorting options
+* @var int sort_days User selected sort days
+* @var string sort_key User selected sort key
+* @var string sort_dir User selected sort direction
+* @var string s_limit_days Initial value of limit days selectbox
+* @var string s_sort_key Initial value of sort key selectbox
+* @var string s_sort_dir Initial value of sort direction selectbox
+* @var string u_sort_param Initial value of sorting form action
+* @since 3.2.8-RC1
+*/
+$vars = array(
+ 'limit_days',
+ 'sort_by_text',
+ 'sort_by_sql',
+ 'join_user_sql',
+ 'sort_days',
+ 'sort_key',
+ 'sort_dir',
+ 's_limit_days',
+ 's_sort_key',
+ 's_sort_dir',
+ 'u_sort_param',
+);
+extract($phpbb_dispatcher->trigger_event('core.viewtopic_gen_sort_selects_before', compact($vars)));
+
gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param, $default_sort_days, $default_sort_key, $default_sort_dir);
// Obtain correct post count and ordering SQL if user has
@@ -518,9 +577,9 @@ $vars = array(
extract($phpbb_dispatcher->trigger_event('core.viewtopic_highlight_modify', compact($vars)));
// Bookmarks
-if ($config['allow_bookmarks'] && $user->data['is_registered'] && request_var('bookmark', 0))
+if ($config['allow_bookmarks'] && $user->data['is_registered'] && $request->variable('bookmark', 0))
{
- if (check_link_hash(request_var('hash', ''), "topic_$topic_id"))
+ if (check_link_hash($request->variable('hash', ''), "topic_$topic_id"))
{
if (!$topic_data['bookmarked'])
{
@@ -603,10 +662,10 @@ $quickmod_array = array(
'merge' => array('MERGE_POSTS', $auth->acl_get('m_merge', $forum_id)),
'merge_topic' => array('MERGE_TOPIC', $auth->acl_get('m_merge', $forum_id)),
'fork' => array('FORK_TOPIC', $auth->acl_get('m_move', $forum_id)),
- 'make_normal' => array('MAKE_NORMAL', ($allow_change_type && $auth->acl_gets('f_sticky', 'f_announce', $forum_id) && $topic_data['topic_type'] != POST_NORMAL)),
+ 'make_normal' => array('MAKE_NORMAL', ($allow_change_type && $auth->acl_gets('f_sticky', 'f_announce', 'f_announce_global', $forum_id) && $topic_data['topic_type'] != POST_NORMAL)),
'make_sticky' => array('MAKE_STICKY', ($allow_change_type && $auth->acl_get('f_sticky', $forum_id) && $topic_data['topic_type'] != POST_STICKY)),
'make_announce' => array('MAKE_ANNOUNCE', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_ANNOUNCE)),
- 'make_global' => array('MAKE_GLOBAL', ($allow_change_type && $auth->acl_get('f_announce', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)),
+ 'make_global' => array('MAKE_GLOBAL', ($allow_change_type && $auth->acl_get('f_announce_global', $forum_id) && $topic_data['topic_type'] != POST_GLOBAL)),
'topic_logs' => array('VIEW_TOPIC_LOGS', $auth->acl_get('m_', $forum_id)),
);
@@ -733,7 +792,7 @@ $template->assign_vars(array(
'TOTAL_POSTS' => $user->lang('VIEW_TOPIC_POSTS', (int) $total_posts),
'U_MCP' => ($auth->acl_get('m_', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&amp;mode=topic_view&amp;f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . ((strlen($u_sort_param)) ? "&amp;$u_sort_param" : ''), true, $user->session_id) : '',
- 'MODERATORS' => (isset($forum_moderators[$forum_id]) && sizeof($forum_moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]) : '',
+ 'MODERATORS' => (isset($forum_moderators[$forum_id]) && count($forum_moderators[$forum_id])) ? implode($user->lang['COMMA_SEPARATOR'], $forum_moderators[$forum_id]) : '',
'POST_IMG' => ($topic_data['forum_status'] == ITEM_LOCKED) ? $user->img('button_topic_locked', 'FORUM_LOCKED') : $user->img('button_topic_new', 'POST_NEW_TOPIC'),
'QUOTE_IMG' => $user->img('icon_post_quote', 'REPLY_WITH_QUOTE'),
@@ -756,7 +815,7 @@ $template->assign_vars(array(
'S_SELECT_SORT_DIR' => $s_sort_dir,
'S_SELECT_SORT_KEY' => $s_sort_key,
'S_SELECT_SORT_DAYS' => $s_limit_days,
- 'S_SINGLE_MODERATOR' => (!empty($forum_moderators[$forum_id]) && sizeof($forum_moderators[$forum_id]) > 1) ? false : true,
+ 'S_SINGLE_MODERATOR' => (!empty($forum_moderators[$forum_id]) && count($forum_moderators[$forum_id]) > 1) ? false : true,
'S_TOPIC_ACTION' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start")),
'S_MOD_ACTION' => $s_quickmod_action,
@@ -773,7 +832,7 @@ $template->assign_vars(array(
'U_TOPIC' => "{$server_path}viewtopic.$phpEx?f=$forum_id&amp;t=$topic_id",
'U_FORUM' => $server_path,
- 'U_VIEW_TOPIC' => $viewtopic_url,
+ 'U_VIEW_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start") . (strlen($u_sort_param) ? "&amp;$u_sort_param" : '')),
'U_CANONICAL' => generate_board_url() . '/' . append_sid("viewtopic.$phpEx", "t=$topic_id" . (($start) ? "&amp;start=$start" : ''), true, ''),
'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id),
'U_VIEW_OLDER_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id&amp;view=previous"),
@@ -849,9 +908,9 @@ if (!empty($topic_data['poll_start']))
(($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0) &&
$topic_data['topic_status'] != ITEM_LOCKED &&
$topic_data['forum_status'] != ITEM_LOCKED &&
- (!sizeof($cur_voted_id) ||
+ (!count($cur_voted_id) ||
($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']))) ? true : false;
- $s_display_results = (!$s_can_vote || ($s_can_vote && sizeof($cur_voted_id)) || $view == 'viewpoll') ? true : false;
+ $s_display_results = (!$s_can_vote || ($s_can_vote && count($cur_voted_id)) || $view == 'viewpoll') ? true : false;
/**
* Event to manipulate the poll data
@@ -886,16 +945,16 @@ if (!empty($topic_data['poll_start']))
if ($update && $s_can_vote)
{
- if (!sizeof($voted_id) || sizeof($voted_id) > $topic_data['poll_max_options'] || in_array(VOTE_CONVERTED, $cur_voted_id) || !check_form_key('posting'))
+ if (!count($voted_id) || count($voted_id) > $topic_data['poll_max_options'] || in_array(VOTE_CONVERTED, $cur_voted_id) || !check_form_key('posting'))
{
$redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id" . (($start == 0) ? '' : "&amp;start=$start"));
meta_refresh(5, $redirect_url);
- if (!sizeof($voted_id))
+ if (!count($voted_id))
{
$message = 'NO_VOTE_OPTION';
}
- else if (sizeof($voted_id) > $topic_data['poll_max_options'])
+ else if (count($voted_id) > $topic_data['poll_max_options'])
{
$message = 'TOO_MANY_VOTE_OPTIONS';
}
@@ -989,8 +1048,31 @@ if (!empty($topic_data['poll_start']))
'user_votes' => array_flip($valid_user_votes),
'vote_counts' => $vote_counts,
'total_votes' => array_sum($vote_counts),
- 'can_vote' => !sizeof($valid_user_votes) || ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']),
+ 'can_vote' => !count($valid_user_votes) || ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']),
);
+
+ /**
+ * Event to manipulate the poll data sent by AJAX response
+ *
+ * @event core.viewtopic_modify_poll_ajax_data
+ * @var array data JSON response data
+ * @var array valid_user_votes Valid user votes
+ * @var array vote_counts Vote counts
+ * @var int forum_id Forum ID
+ * @var array topic_data Topic data
+ * @var array poll_info Array with the poll information
+ * @since 3.2.4-RC1
+ */
+ $vars = array(
+ 'data',
+ 'valid_user_votes',
+ 'vote_counts',
+ 'forum_id',
+ 'topic_data',
+ 'poll_info',
+ );
+ extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_poll_ajax_data', compact($vars)));
+
$json_response = new \phpbb\json_response();
$json_response->send($data);
}
@@ -1009,7 +1091,7 @@ if (!empty($topic_data['poll_start']))
$parse_flags = ($poll_info[0]['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
- for ($i = 0, $size = sizeof($poll_info); $i < $size; $i++)
+ for ($i = 0, $size = count($poll_info); $i < $size; $i++)
{
$poll_info[$i]['poll_option_text'] = generate_text_for_display($poll_info[$i]['poll_option_text'], $poll_info[$i]['bbcode_uid'], $poll_option['bbcode_bitfield'], $parse_flags, true);
}
@@ -1141,6 +1223,29 @@ $sql = 'SELECT p.post_id
" . (($join_user_sql[$sort_key]) ? 'AND u.user_id = p.poster_id': '') . "
$limit_posts_time
ORDER BY $sql_sort_order";
+
+/**
+* Event to modify the SQL query that gets post_list
+*
+* @event core.viewtopic_modify_post_list_sql
+* @var string sql The SQL query to generate the post_list
+* @var int sql_limit The number of posts the query fetches
+* @var int sql_start The index the query starts to fetch from
+* @var string sort_key Key the posts are sorted by
+* @var string sort_days Display posts of previous x days
+* @var int forum_id Forum ID
+* @since 3.2.4-RC1
+*/
+$vars = array(
+ 'sql',
+ 'sql_limit',
+ 'sql_start',
+ 'sort_key',
+ 'sort_days',
+ 'forum_id',
+);
+extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_list_sql', compact($vars)));
+
$result = $db->sql_query_limit($sql, $sql_limit, $sql_start);
$i = ($store_reverse) ? $sql_limit - 1 : 0;
@@ -1151,7 +1256,7 @@ while ($row = $db->sql_fetchrow($result))
}
$db->sql_freeresult($result);
-if (!sizeof($post_list))
+if (!count($post_list))
{
if ($sort_days)
{
@@ -1452,6 +1557,7 @@ $db->sql_freeresult($result);
// Load custom profile fields
if ($config['load_cpf_viewtopic'])
{
+ /* @var $cp \phpbb\profilefields\manager */
$cp = $phpbb_container->get('profilefields.manager');
// Grab all profile fields from users in id cache for later use - similar to the poster cache
@@ -1474,7 +1580,7 @@ if ($config['load_cpf_viewtopic'])
}
// Generate online information for user
-if ($config['load_onlinetrack'] && sizeof($id_cache))
+if ($config['load_onlinetrack'] && count($id_cache))
{
$sql = 'SELECT session_user_id, MAX(session_time) as online_time, MIN(session_viewonline) AS viewonline
FROM ' . SESSIONS_TABLE . '
@@ -1492,7 +1598,7 @@ if ($config['load_onlinetrack'] && sizeof($id_cache))
unset($id_cache);
// Pull attachment data
-if (sizeof($attach_list))
+if (count($attach_list))
{
if ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id))
{
@@ -1510,7 +1616,7 @@ if (sizeof($attach_list))
$db->sql_freeresult($result);
// No attachments exist, but post table thinks they do so go ahead and reset post_attach flags
- if (!sizeof($attachments))
+ if (!count($attachments))
{
$sql = 'UPDATE ' . POSTS_TABLE . '
SET post_attachment = 0
@@ -1518,7 +1624,7 @@ if (sizeof($attach_list))
$db->sql_query($sql);
// We need to update the topic indicator too if the complete topic is now without an attachment
- if (sizeof($rowset) != $total_posts)
+ if (count($rowset) != $total_posts)
{
// Not all posts are displayed so we query the db to find if there's any attachment for this topic
$sql = 'SELECT a.post_msg_id as post_id
@@ -1568,19 +1674,27 @@ if (sizeof($attach_list))
}
}
-// Get the list of users who can receive private messages
-$can_receive_pm_list = $auth->acl_get_list(array_keys($user_cache), 'u_readpm');
-$can_receive_pm_list = (empty($can_receive_pm_list) || !isset($can_receive_pm_list[0]['u_readpm'])) ? array() : $can_receive_pm_list[0]['u_readpm'];
+if ($config['enable_accurate_pm_button'])
+{
+ // Get the list of users who can receive private messages
+ $can_receive_pm_list = $auth->acl_get_list(array_keys($user_cache), 'u_readpm');
+ $can_receive_pm_list = (empty($can_receive_pm_list) || !isset($can_receive_pm_list[0]['u_readpm'])) ? array() : $can_receive_pm_list[0]['u_readpm'];
-// Get the list of permanently banned users
-$permanently_banned_users = phpbb_get_banned_user_ids(array_keys($user_cache), false);
+ // Get the list of permanently banned users
+ $permanently_banned_users = phpbb_get_banned_user_ids(array_keys($user_cache), false);
+}
+else
+{
+ $can_receive_pm_list = array_keys($user_cache);
+ $permanently_banned_users = [];
+}
-$i_total = sizeof($rowset) - 1;
+$i_total = count($rowset) - 1;
$prev_post_id = '';
$template->assign_vars(array(
'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'],
- 'S_NUM_POSTS' => sizeof($post_list))
+ 'S_NUM_POSTS' => count($post_list))
);
/**
@@ -1625,7 +1739,7 @@ extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_data', comp
// Output the posts
$first_unread = $post_unread = false;
-for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
+for ($i = 0, $end = count($post_list); $i < $end; ++$i)
{
// A non-existing rowset only happens if there was no user present for the entered poster_id
// This could be a broken posts table.
@@ -1642,6 +1756,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
{
$parse_flags = ($user_cache[$poster_id]['sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
$user_cache[$poster_id]['sig'] = generate_text_for_display($user_cache[$poster_id]['sig'], $user_cache[$poster_id]['sig_bbcode_uid'], $user_cache[$poster_id]['sig_bbcode_bitfield'], $parse_flags, true);
+ $user_cache[$poster_id]['sig_parsed'] = true;
}
// Parse the message and subject
@@ -1667,7 +1782,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
if (($row['post_edit_count'] && $config['display_last_edited']) || $row['post_edit_reason'])
{
// Get usernames for all following posts if not already stored
- if (!sizeof($post_edit_list) && ($row['post_edit_reason'] || ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']]))))
+ if (!count($post_edit_list) && ($row['post_edit_reason'] || ($row['post_edit_user'] && !isset($user_cache[$row['post_edit_user']]))))
{
// Remove all post_ids already parsed (we do not have to check them)
$post_storage_list = (!$store_reverse) ? array_slice($post_list, $i) : array_slice(array_reverse($post_list), $i);
@@ -1731,7 +1846,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
if ($row['post_visibility'] == ITEM_DELETED && $row['post_delete_user'])
{
// Get usernames for all following posts if not already stored
- if (!sizeof($post_delete_list) && ($row['post_delete_reason'] || ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']]))))
+ if (!count($post_delete_list) && ($row['post_delete_reason'] || ($row['post_delete_user'] && !isset($user_cache[$row['post_delete_user']]))))
{
// Remove all post_ids already parsed (we do not have to check them)
$post_storage_list = (!$store_reverse) ? array_slice($post_list, $i) : array_slice(array_reverse($post_list), $i);
@@ -1929,6 +2044,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
'CONTACT_USER' => $user_cache[$poster_id]['contact_user'],
'POST_DATE' => $user->format_date($row['post_time'], false, ($view == 'print') ? true : false),
+ 'POST_DATE_RFC3339' => gmdate(DATE_RFC3339, $row['post_time']),
'POST_SUBJECT' => $row['post_subject'],
'MESSAGE' => $message,
'SIGNATURE' => ($row['enable_sig']) ? $user_cache[$poster_id]['sig'] : '',
@@ -1942,6 +2058,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
'POST_ICON_IMG' => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['img'] : '',
'POST_ICON_IMG_WIDTH' => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['width'] : '',
'POST_ICON_IMG_HEIGHT' => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['height'] : '',
+ 'POST_ICON_IMG_ALT' => ($topic_data['enable_icons'] && !empty($row['icon_id'])) ? $icons[$row['icon_id']]['alt'] : '',
'ONLINE_IMG' => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? '' : (($user_cache[$poster_id]['online']) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')),
'S_ONLINE' => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? false : (($user_cache[$poster_id]['online']) ? true : false),
@@ -1956,7 +2073,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
'U_JABBER' => $user_cache[$poster_id]['jabber'],
'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&amp;p={$row['post_id']}&amp;f=$forum_id&amp;redirect=" . urlencode(str_replace('&amp;', '&', $viewtopic_url . '&amp;p=' . $row['post_id'] . '#p' . $row['post_id']))),
- 'U_REPORT' => ($auth->acl_get('f_report', $forum_id)) ? append_sid("{$phpbb_root_path}report.$phpEx", 'f=' . $forum_id . '&amp;p=' . $row['post_id']) : '',
+ 'U_REPORT' => ($auth->acl_get('f_report', $forum_id)) ? $phpbb_container->get('controller.helper')->route('phpbb_report_post_controller', array('id' => $row['post_id'])) : '',
'U_MCP_REPORT' => ($auth->acl_get('m_report', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=report_details&amp;f=' . $forum_id . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
'U_MCP_APPROVE' => ($auth->acl_get('m_approve', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=approve_details&amp;f=' . $forum_id . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
'U_MCP_RESTORE' => ($auth->acl_get('m_approve', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=' . (($topic_data['topic_visibility'] != ITEM_DELETED) ? 'deleted_posts' : 'deleted_topics') . '&amp;f=' . $forum_id . '&amp;p=' . $row['post_id'], true, $user->session_id) : '',
@@ -1969,9 +2086,11 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
'POST_ID' => $row['post_id'],
'POST_NUMBER' => $i + $start + 1,
'POSTER_ID' => $poster_id,
+ 'MINI_POST' => ($post_unread) ? $user->lang['UNREAD_POST'] : $user->lang['POST'],
+
'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false,
- 'S_MULTIPLE_ATTACHMENTS' => !empty($attachments[$row['post_id']]) && sizeof($attachments[$row['post_id']]) > 1,
+ 'S_MULTIPLE_ATTACHMENTS' => !empty($attachments[$row['post_id']]) && count($attachments[$row['post_id']]) > 1,
'S_POST_UNAPPROVED' => ($row['post_visibility'] == ITEM_UNAPPROVED || $row['post_visibility'] == ITEM_REAPPROVE) ? true : false,
'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED) ? true : false,
'L_POST_DELETED_MESSAGE' => $l_deleted_message,
@@ -1980,8 +2099,9 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
'S_FRIEND' => ($row['friend']) ? true : false,
'S_UNREAD_POST' => $post_unread,
'S_FIRST_UNREAD' => $s_first_unread,
- 'S_CUSTOM_FIELDS' => (isset($cp_row['row']) && sizeof($cp_row['row'])) ? true : false,
+ 'S_CUSTOM_FIELDS' => (isset($cp_row['row']) && count($cp_row['row'])) ? true : false,
'S_TOPIC_POSTER' => ($topic_data['topic_poster'] == $poster_id) ? true : false,
+ 'S_FIRST_POST' => ($topic_data['topic_first_post_id'] == $row['post_id']) ? true : false,
'S_IGNORE_POST' => ($row['foe']) ? true : false,
'L_IGNORE_POST' => ($row['foe']) ? sprintf($user->lang['POST_BY_FOE'], get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username'])) : '',
@@ -2009,10 +2129,13 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
* @var array user_poster_data Poster's data from user cache
* @var array post_row Template block array of the post
* @var array topic_data Array with topic data
+ * @var array user_cache Array with cached user data
+ * @var array post_edit_list Array with post edited list
* @since 3.1.0-a1
* @changed 3.1.0-a3 Added vars start, current_row_number, end, attachments
* @changed 3.1.0-b3 Added topic_data array, total_posts
* @changed 3.1.0-RC3 Added poster_id
+ * @changed 3.2.2-RC1 Added user_cache and post_edit_list
*/
$vars = array(
'start',
@@ -2026,12 +2149,14 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
'user_poster_data',
'post_row',
'topic_data',
+ 'user_cache',
+ 'post_edit_list',
);
extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_post_row', compact($vars)));
$i = $current_row_number;
- if (isset($cp_row['row']) && sizeof($cp_row['row']))
+ if (isset($cp_row['row']) && count($cp_row['row']))
{
$post_row = array_merge($post_row, $cp_row['row']);
}
@@ -2043,7 +2168,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
array(
'ID' => 'pm',
'NAME' => $user->lang['SEND_PRIVATE_MESSAGE'],
- 'U_CONTACT' => $u_pm,
+ 'U_CONTACT' => $post_row['U_PM'],
),
array(
'ID' => 'email',
@@ -2144,7 +2269,7 @@ if (isset($user->data['session_page']) && !$user->data['is_bot'] && (strpos($use
$db->sql_query($sql);
// Update the attachment download counts
- if (sizeof($update_count))
+ if (count($update_count))
{
$sql = 'UPDATE ' . ATTACHMENTS_TABLE . '
SET download_count = download_count + 1
@@ -2223,7 +2348,6 @@ if ($s_can_vote || $s_quick_reply)
$qr_hidden_fields = array(
'topic_cur_post_id' => (int) $topic_data['topic_last_post_id'],
- 'lastclick' => (int) time(),
'topic_id' => (int) $topic_data['topic_id'],
'forum_id' => (int) $forum_id,
);
@@ -2236,12 +2360,25 @@ if ($s_can_vote || $s_quick_reply)
($s_notify) ? $qr_hidden_fields['notify'] = 1 : true;
($topic_data['topic_status'] == ITEM_LOCKED) ? $qr_hidden_fields['lock_topic'] = 1 : true;
- $template->assign_vars(array(
+ $tpl_ary = [
'S_QUICK_REPLY' => true,
'U_QR_ACTION' => append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&amp;f=$forum_id&amp;t=$topic_id"),
'QR_HIDDEN_FIELDS' => build_hidden_fields($qr_hidden_fields),
'SUBJECT' => 'Re: ' . censor_text($topic_data['topic_title']),
- ));
+ ];
+
+ /**
+ * Event after the quick-reply has been setup
+ *
+ * @event core.viewtopic_modify_quick_reply_template_vars
+ * @var array tpl_ary Array with template data
+ * @var array topic_data Array with topic data
+ * @since 3.2.9-RC1
+ */
+ $vars = ['tpl_ary', 'topic_data'];
+ extract($phpbb_dispatcher->trigger_event('core.viewtopic_modify_quick_reply_template_vars', compact($vars)));
+
+ $template->assign_vars($tpl_ary);
}
}
// now I have the urge to wash my hands :(
@@ -2250,13 +2387,13 @@ if ($s_can_vote || $s_quick_reply)
// We overwrite $_REQUEST['f'] if there is no forum specified
// to be able to display the correct online list.
// One downside is that the user currently viewing this topic/post is not taken into account.
-if (!request_var('f', 0))
+if (!$request->variable('f', 0))
{
$request->overwrite('f', $forum_id);
}
// We need to do the same with the topic_id. See #53025.
-if (!request_var('t', 0) && !empty($topic_id))
+if (!$request->variable('t', 0) && !empty($topic_id))
{
$request->overwrite('t', $topic_id);
}
diff --git a/tests/RUNNING_TESTS.md b/tests/RUNNING_TESTS.md
index afd7caa709..12ae7fa687 100644
--- a/tests/RUNNING_TESTS.md
+++ b/tests/RUNNING_TESTS.md
@@ -30,7 +30,9 @@ Some of the functionality in phpBB and/or the test suite uses additional
PHP extensions. If these extensions are not loaded, respective tests
will be skipped:
-- apc (APC cache driver)
+- apc (APC cache driver, php5 only)
+- apcu (APCu cache driver - native API, php7+)
+- apcu_bc, apcu (APCu cache driver - APC API, php7+)
- bz2 (compress tests)
- mysql, pdo_mysql (MySQL database driver)
- mysqli, pdo_mysql (MySQLi database driver)
@@ -117,11 +119,20 @@ directory (above phpBB):
$ phpBB/vendor/bin/phpunit
+To generate an xml log file, run:
+
+ $ phpBB/vendor/bin/phpunit --log-junit tests/tmp/log/log.xml
+
+If you are getting a memory exhausted error after running a few tests, you can try running:
+
+ $ phpBB/vendor/bin/phpunit -d memory_limit=2048M
+
Slow tests
--------------
-Certain tests, such as the UTF-8 normalizer or the DNS tests tend to be slow.
-Thus these tests are in the `slow` group, which is excluded by default. If you
+Certain tests, such as the DNS tests tend to be slow.
+Thus these tests are in the `slow` group, which is excluded by default. You can
+enable slow tests by copying the phpunit.xml.all file to phpunit.xml. If you
only want the slow tests, run:
$ phpBB/vendor/bin/phpunit --group slow
@@ -132,14 +143,14 @@ If you want all tests, run:
Functional tests
------------------
+================
Functional tests test software the way a user would. They simulate a user
browsing the website, but they do these steps in an automated way.
phpBB allows you to write such tests.
Running
-=======
+-------
Running the tests requires your phpBB3 repository to be accessible through a
local web server. You will need to supply the URL to the webserver in
@@ -159,6 +170,27 @@ If you only want the functional tests, run:
This will change your board's config.php file, but it makes a backup at
config_dev.php, so you can restore it after the test run is complete.
+UI tests
+========
+
+UI tests are functional tests that also support running JavaScript in a
+headless browser. These should be used when functionality that is only
+executed using JS needs to be tested. They require a running
+[PhantomJS WebDriver instance](http://phantomjs.org/). The executable can
+either be downloaded from [PhantomJS](http://phantomjs.org/download.html)
+or alternatively be installed with npm:
+
+ $ npm install -g phantomjs-prebuilt
+
+You might have to run the command as superuser / administrator on some
+systems. Afterwards, a new WebDriver instance can be started via command
+line:
+
+ $ phantomjs --webdriver=127.0.0.1:8910
+
+Port 8910 is the default port that will be used by UI tests to connect
+to the WebDriver instance.
+
More Information
================
diff --git a/tests/attachment/delete_test.php b/tests/attachment/delete_test.php
new file mode 100644
index 0000000000..f1835dd37a
--- /dev/null
+++ b/tests/attachment/delete_test.php
@@ -0,0 +1,127 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once(dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php');
+
+class phpbb_attachment_delete_test extends \phpbb_database_test_case
+{
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ /** @var \phpbb\filesystem\filesystem */
+ protected $filesystem;
+
+ /** @var \phpbb\attachment\resync */
+ protected $resync;
+
+ /** @var \phpbb\attachment\delete */
+ protected $attachment_delete;
+
+ protected $phpbb_root_path;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml');
+ }
+
+ public function setUp()
+ {
+ global $db, $phpbb_root_path;
+
+ parent::setUp();
+
+ $this->config = new \phpbb\config\config(array());
+ $this->db = $this->new_dbal();
+ $db = $this->db;
+ $this->resync = new \phpbb\attachment\resync($this->db);
+ $this->filesystem = $this->getMock('\phpbb\filesystem\filesystem', array('remove', 'exists'));
+ $this->filesystem->expects($this->any())
+ ->method('remove')
+ ->willReturn(false);
+ $this->filesystem->expects($this->any())
+ ->method('exists')
+ ->willReturn(true);
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->dispatcher = new \phpbb_mock_event_dispatcher();
+ $this->attachment_delete = new \phpbb\attachment\delete($this->config, $this->db, $this->dispatcher, $this->filesystem, $this->resync, $phpbb_root_path);
+ }
+
+ public function data_attachment_delete()
+ {
+ return array(
+ array('attach', '', false, false),
+ array('meh', 5, false, 0),
+ array('attach', array(5), false, 0),
+ array('attach', array(1,2), false, 2),
+ array('attach', array(1,2), true, 2),
+ array('post', 5, false, 0),
+ array('topic', 5, false, 0),
+ array('topic', 1, true, 3),
+ array('user', 1, false, 0),
+ );
+ }
+
+ /**
+ * @dataProvider data_attachment_delete
+ */
+ public function test_attachment_delete($mode, $ids, $resync, $expected)
+ {
+ // We need to reset the attachment ID sequence to properly test this
+ if ($this->db->get_sql_layer() === 'postgres')
+ {
+ $sql = 'ALTER SEQUENCE phpbb_attachments_seq RESTART WITH 1';
+ $this->db->sql_query($sql);
+ }
+
+ $this->assertSame($expected, $this->attachment_delete->delete($mode, $ids, $resync));
+ }
+
+ public function data_attachment_unlink()
+ {
+ return array(
+ array(true, true, true),
+ array(true, false, false),
+ array(true, true, false, true),
+ );
+ }
+
+ /**
+ * @dataProvider data_attachment_unlink
+ */
+ public function test_attachment_delete_success($remove_success, $exists_success, $expected, $throw_exception = false)
+ {
+ $this->filesystem = $this->getMock('\phpbb\filesystem\filesystem', array('remove', 'exists'));
+ if ($throw_exception)
+ {
+ $this->filesystem->expects($this->any())
+ ->method('remove')
+ ->willThrowException(new \phpbb\filesystem\exception\filesystem_exception);;
+ }
+ else
+ {
+ $this->filesystem->expects($this->any())
+ ->method('remove')
+ ->willReturn($remove_success);
+ }
+
+ $this->filesystem->expects($this->any())
+ ->method('exists')
+ ->willReturn($exists_success);
+
+ $this->attachment_delete = new \phpbb\attachment\delete($this->config, $this->db, $this->dispatcher, $this->filesystem, $this->resync, $this->phpbb_root_path);
+ $this->assertSame($expected, $this->attachment_delete->unlink_attachment('foobar'));
+ }
+}
diff --git a/tests/attachment/fixtures/resync.xml b/tests/attachment/fixtures/resync.xml
new file mode 100644
index 0000000000..af04701b4a
--- /dev/null
+++ b/tests/attachment/fixtures/resync.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_attachments">
+ <column>attach_id</column>
+ <column>post_msg_id</column>
+ <column>topic_id</column>
+ <column>in_message</column>
+ <column>is_orphan</column>
+ <column>attach_comment</column>
+ <column>physical_filename</column>
+ <column>thumbnail</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ <value>foo</value>
+ <value>foo</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value>foo2</value>
+ <value>foo2</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value>foo2</value>
+ <value>foo2</value>
+ <value>1</value>
+ </row>
+ </table>
+ <table name="phpbb_extensions">
+ <column>extension_id</column>
+ <column>extension</column>
+ <column>group_id</column>
+ <row>
+ <value>1</value>
+ <value>jpg</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>png</value>
+ <value>1</value>
+ </row>
+ </table>
+ <table name="phpbb_extension_groups">
+ <column>cat_id</column>
+ <column>group_id</column>
+ <column>download_mode</column>
+ <column>upload_icon</column>
+ <column>max_filesize</column>
+ <column>allow_group</column>
+ <column>allow_in_pm</column>
+ <column>allowed_forums</column>
+ <column>group_name</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value> </value>
+ <value>1000</value>
+ <value>1</value>
+ <value>1</value>
+ <value>a:1:{i:0;i:1;}</value>
+ <value>Images</value>
+ </row>
+ </table>
+ <table name="phpbb_posts">
+ <column>post_id</column>
+ <column>post_text</column>
+ <column>poster_id</column>
+ <column>post_attachment</column>
+ <row>
+ <value>1</value>
+ <value>foo</value>
+ <value>1</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>foo</value>
+ <value>1</value>
+ <value>1</value>
+ </row>
+ </table>
+ <table name="phpbb_privmsgs">
+ <column>msg_id</column>
+ <column>message_text</column>
+ <column>message_attachment</column>
+ <column>to_address</column>
+ <column>bcc_address</column>
+ <row>
+ <value>1</value>
+ <value>foo</value>
+ <value>1</value>
+ <value>2</value>
+ <value>2</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>foo</value>
+ <value>1</value>
+ <value>2</value>
+ <value>2</value>
+ </row>
+ </table>
+ <table name="phpbb_topics">
+ <column>topic_id</column>
+ <column>forum_id</column>
+ <column>topic_title</column>
+ <column>topic_attachment</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>foo</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>bar</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/attachment/manager_test.php b/tests/attachment/manager_test.php
new file mode 100644
index 0000000000..47d7f38b1d
--- /dev/null
+++ b/tests/attachment/manager_test.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_attachment_manager_test extends \phpbb_test_case
+{
+ protected $delete;
+ protected $resync;
+ protected $upload;
+
+ public function setUp()
+ {
+ $this->delete = $this->getMockBuilder('\phpbb\attachment\delete')
+ ->disableOriginalConstructor()
+ ->setMethods(['delete', 'unlink_attachment'])
+ ->getMock();
+ $this->resync = $this->getMockBuilder('\phpbb\attachment\resync')
+ ->disableOriginalConstructor()
+ ->setMethods(['resync'])
+ ->getMock();
+ $this->upload = $this->getMockBuilder('\phpbb\attachment\upload')
+ ->disableOriginalConstructor()
+ ->setMethods(['upload'])
+ ->getMock();
+ }
+
+ protected function get_manager()
+ {
+ return new \phpbb\attachment\manager($this->delete, $this->resync, $this->upload);
+ }
+
+ public function data_manager()
+ {
+ return array(
+ array(
+ 'delete',
+ 'unlink_attachment',
+ 'unlink',
+ ['foo'],
+ ['foo', 'file', false],
+ true,
+ true,
+ ),
+ array(
+ 'delete',
+ 'unlink_attachment',
+ 'unlink',
+ ['foo', 'bar'],
+ ['foo', 'bar', false],
+ true,
+ true,
+ ),
+ array(
+ 'delete',
+ 'unlink_attachment',
+ 'unlink',
+ ['foo', 'bar', true],
+ ['foo', 'bar', true],
+ true,
+ true,
+ ),
+ array(
+ 'delete',
+ 'delete',
+ 'delete',
+ ['foo', [1, 2, 3]],
+ ['foo', [1, 2, 3], true],
+ 5,
+ 5,
+ ),
+ array(
+ 'delete',
+ 'delete',
+ 'delete',
+ ['foo', [1, 2, 3], false],
+ ['foo', [1, 2, 3], false],
+ 2,
+ 2,
+ ),
+ array(
+ 'resync',
+ 'resync',
+ 'resync',
+ ['foo', [1, 2, 3]],
+ ['foo', [1, 2, 3]],
+ true,
+ null,
+ ),
+ array(
+ 'upload',
+ 'upload',
+ 'upload',
+ ['foo', 1],
+ ['foo', 1, false, '', false, []],
+ true,
+ true,
+ ),
+ array(
+ 'upload',
+ 'upload',
+ 'upload',
+ ['foo', 1, true, 'bar', true, ['filename' => 'foobar']],
+ ['foo', 1, true, 'bar', true, ['filename' => 'foobar']],
+ true,
+ true,
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_manager
+ */
+ public function test_manager($class, $method_class, $method_manager, $input_manager, $input_method, $return, $output)
+ {
+ $mock = call_user_func_array([$this->{$class}, 'expects'], [$this->atLeastOnce()]);
+ $mock = $mock->method($method_class);
+ $mock = call_user_func_array([$mock, 'with'], $input_method);
+ $mock->willReturn($return);
+ $manager = $this->get_manager();
+ $this->assertSame($output, call_user_func_array([$manager, $method_manager], $input_manager));
+ }
+}
diff --git a/tests/attachment/resync_test.php b/tests/attachment/resync_test.php
new file mode 100644
index 0000000000..f882af9ae5
--- /dev/null
+++ b/tests/attachment/resync_test.php
@@ -0,0 +1,74 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_attachment_resync_test extends \phpbb_database_test_case
+{
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ /** @var \phpbb\attachment\resync */
+ protected $resync;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml');
+ }
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->db = $this->new_dbal();
+ $this->resync = new \phpbb\attachment\resync($this->db);
+ }
+
+ public function data_resync()
+ {
+ return array(
+ array('', array(1), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '1')),
+ array('post', array(1), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '1')),
+ array('post', array(2), 'post_id', POSTS_TABLE, array('post_attachment' => '1'), array('post_attachment' => '0')),
+ array('topic', array(1), 'topic_id', TOPICS_TABLE, array('topic_attachment' => '1'), array('topic_attachment' => '1')),
+ array('topic', array(2), 'topic_id', TOPICS_TABLE, array('topic_attachment' => '1'), array('topic_attachment' => '0')),
+ array('message', array(1), 'msg_id', PRIVMSGS_TABLE, array('message_attachment' => '1'), array('message_attachment' => '1')),
+ array('message', array(2), 'msg_id', PRIVMSGS_TABLE, array('message_attachment' => '1'), array('message_attachment' => '0')),
+ );
+ }
+
+ /**
+ * @dataProvider data_resync
+ */
+ public function test_resync($type, $ids, $sql_id, $exist_table, $exist_data, $resync_data)
+ {
+ $sql_prefix = ($type) ?: 'post';
+ $sql = 'SELECT ' . $sql_prefix . '_attachment
+ FROM ' . $exist_table . '
+ WHERE ' . $sql_id . ' = ' . $ids[0];
+ $result = $this->db->sql_query($sql);
+ $data = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->assertEquals($exist_data, $data);
+
+ $this->resync->resync($type, $ids);
+
+ $sql = 'SELECT ' . $sql_prefix . '_attachment
+ FROM ' . $exist_table . '
+ WHERE ' . $sql_id . ' = ' . $ids[0];
+ $result = $this->db->sql_query($sql);
+ $data = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $this->assertEquals($resync_data, $data);
+ }
+}
diff --git a/tests/attachment/upload_test.php b/tests/attachment/upload_test.php
new file mode 100644
index 0000000000..235ecd082a
--- /dev/null
+++ b/tests/attachment/upload_test.php
@@ -0,0 +1,429 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once(dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php');
+
+class phpbb_attachment_upload_test extends \phpbb_database_test_case
+{
+ /** @var \phpbb\auth\auth */
+ protected $auth;
+
+ /** @var \phpbb\cache\service */
+ protected $cache;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /** @var \phpbb\files\upload */
+ protected $files_upload;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\mimetype\guesser */
+ protected $mimetype_guesser;
+
+ /** @var \phpbb\event\dispatcher */
+ protected $phpbb_dispatcher;
+
+ /** @var \phpbb\plupload\plupload */
+ protected $plupload;
+
+ /** @var \phpbb\user */
+ protected $user;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ /** @var \phpbb\attachment\upload */
+ protected $upload;
+
+ private $filesystem;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/resync.xml');
+ }
+
+ public function setUp()
+ {
+ global $config, $phpbb_root_path, $phpEx;
+
+ parent::setUp();
+
+ $this->auth = new \phpbb\auth\auth();
+ $this->config = new \phpbb\config\config(array(
+ 'upload_path' => '',
+ 'img_create_thumbnail' => true,
+ ));
+ $config = $this->config;
+ $this->db = $this->new_dbal();
+ $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\dummy(), $this->config, $this->db, $phpbb_root_path, $phpEx);
+ $this->request = $this->getMock('\phpbb\request\request');
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+ $guessers = array(
+ new \Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser(),
+ new \Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser(),
+ new \phpbb\mimetype\content_guesser(),
+ new \phpbb\mimetype\extension_guesser(),
+ );
+ $guessers[2]->set_priority(-2);
+ $guessers[3]->set_priority(-2);
+ $this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers);
+ $this->plupload = new \phpbb\plupload\plupload($phpbb_root_path, $this->config, $this->request, new \phpbb\user($this->language, '\phpbb\datetime'), $this->php_ini, $this->mimetype_guesser);
+ $factory_mock = $this->getMockBuilder('\phpbb\files\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory_mock->expects($this->any())
+ ->method('get')
+ ->willReturn(new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $this->phpbb_root_path,
+ $this->mimetype_guesser
+ ));
+
+ $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
+ $this->container->set('files.filespec', new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ ))));
+ $this->container->set('files.types.form', new \phpbb\files\types\form(
+ $factory_mock,
+ $this->language,
+ $this->php_ini,
+ $this->plupload,
+ $this->request
+ ));
+ $this->container->set('files.types.local', new \phpbb\files\types\local(
+ $factory_mock,
+ $this->language,
+ $this->php_ini,
+ $this->request
+ ));
+ $this->factory = new \phpbb\files\factory($this->container);
+ $this->files_upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $this->phpbb_dispatcher = new phpbb_mock_event_dispatcher();
+ $this->user = new \phpbb\user($this->language, '\phpbb\datetime');
+
+
+ $this->upload = new \phpbb\attachment\upload(
+ $this->auth,
+ $this->cache,
+ $this->config,
+ $this->files_upload,
+ $this->language,
+ $this->mimetype_guesser,
+ $this->phpbb_dispatcher,
+ $this->plupload,
+ $this->user,
+ $this->phpbb_root_path
+ );
+ }
+
+ public function data_upload()
+ {
+ return array(
+ array('foobar', 1, false,
+ array(),
+ array(
+ 'error' => array(
+ 'Upload initiated but no valid file upload form found.',
+ ),
+ 'post_attach' => false,
+ )
+ ),
+ array('foobar', 1, true,
+ array(
+ 'realname' => 'foobar.jpg',
+ 'type' => 'jpg',
+ 'size' => 100,
+ ),
+ array(
+ 'error' => array(
+ 'NOT_UPLOADED',
+ 'The image file you tried to attach is invalid.',
+ ),
+ 'post_attach' => false,
+ 'thumbnail' => 1,
+ )
+ ),
+ array('foobar', 1, true,
+ array(),
+ array(
+ 'error' => array(
+ 'NOT_UPLOADED',
+ ),
+ 'post_attach' => false,
+ 'thumbnail' => 0,
+ )
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_upload
+ */
+ public function test_upload($form_name, $forum_id, $local, $filedata, $expected)
+ {
+ $filedata = $this->upload->upload($form_name, $forum_id, $local, '', false, $filedata);
+
+ $this->assertSame($expected, $filedata);
+ }
+
+ public function test_init_error()
+ {
+ $filespec = $this->getMockBuilder('\phpbb\files\filespec')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $filespec->expects($this->any())
+ ->method('init_error')
+ ->willReturn(true);
+ $filespec->expects($this->any())
+ ->method('set_upload_namespace')
+ ->willReturnSelf();
+ $filespec->expects($this->any())
+ ->method('set_upload_ary')
+ ->willReturnSelf();
+ $this->container->set('files.filespec', $filespec);
+ $factory_mock = $this->getMockBuilder('\phpbb\files\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory_mock->expects($this->any())
+ ->method('get')
+ ->willReturn($filespec);
+ $this->container->set('files.types.local', new \phpbb\files\types\local(
+ $factory_mock,
+ $this->language,
+ $this->php_ini,
+ $this->request
+ ));
+
+ $this->upload = new \phpbb\attachment\upload(
+ $this->auth,
+ $this->cache,
+ $this->config,
+ $this->files_upload,
+ $this->language,
+ $this->mimetype_guesser,
+ $this->phpbb_dispatcher,
+ $this->plupload,
+ $this->user,
+ $this->phpbb_root_path
+ );
+
+ $filedata = $this->upload->upload('foobar', 1, true);
+
+ $this->assertSame(array(
+ 'error' => array(),
+ 'post_attach' => false,
+ ), $filedata);
+ }
+
+ public function data_image_upload()
+ {
+ return array(
+ array(false, false, array(),
+ array(
+ 'error' => array('The image file you tried to attach is invalid.'),
+ 'post_attach' => false,
+ 'thumbnail' => 1,
+ )
+ ),
+ array(false, true, array(),
+ array(
+ 'error' => array('The image file you tried to attach is invalid.'),
+ 'post_attach' => false,
+ 'thumbnail' => 1,
+ )
+ ),
+ array(true, false, array(),
+ array(
+ 'error' => array(),
+ 'post_attach' => true,
+ // thumbnail gets reset to 0 as creation was not possible
+ 'thumbnail' => 0,
+ 'filesize' => 100,
+ 'mimetype' => 'jpg',
+ 'extension' => 'jpg',
+ 'real_filename' => 'foobar.jpg',
+ )
+ ),
+ array(true, false,
+ array(
+ 'check_attachment_content' => true,
+ 'mime_triggers' => '',
+ ),
+ array(
+ 'error' => array(),
+ 'post_attach' => true,
+ // thumbnail gets reset to 0 as creation was not possible
+ 'thumbnail' => 0,
+ 'filesize' => 100,
+ 'mimetype' => 'jpg',
+ 'extension' => 'jpg',
+ 'real_filename' => 'foobar.jpg',
+ )
+ ),
+ array(true, false,
+ array(
+ 'attachment_quota' => 150,
+ ),
+ array(
+ 'error' => array(),
+ 'post_attach' => true,
+ // thumbnail gets reset to 0 as creation was not possible
+ 'thumbnail' => 0,
+ 'filesize' => 100,
+ 'mimetype' => 'jpg',
+ 'extension' => 'jpg',
+ 'real_filename' => 'foobar.jpg',
+ )
+ ),
+ array(true, false,
+ array(
+ 'attachment_quota' => 50,
+ ),
+ array(
+ 'error' => array(
+ 'ATTACH_QUOTA_REACHED',
+ ),
+ 'post_attach' => false,
+ 'thumbnail' => 1,
+ 'filesize' => 100,
+ 'mimetype' => 'jpg',
+ 'extension' => 'jpg',
+ 'real_filename' => 'foobar.jpg',
+ )
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_image_upload
+ */
+ public function test_image_upload($is_image, $plupload_active, $config_data, $expected)
+ {
+ $filespec = $this->getMock('\phpbb\files\filespec',
+ array(
+ 'init_error',
+ 'is_image',
+ 'move_file',
+ 'is_uploaded',
+ ),
+ array(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $this->phpbb_root_path,
+ $this->mimetype_guesser,
+ $this->plupload
+ ));
+ foreach ($config_data as $key => $value)
+ {
+ $this->config[$key] = $value;
+ }
+ $filespec->set_upload_namespace($this->files_upload);
+ $filespec->expects($this->any())
+ ->method('init_error')
+ ->willReturn(false);
+ $filespec->expects($this->any())
+ ->method('is_image')
+ ->willReturn($is_image);
+ $filespec->expects($this->any())
+ ->method('is_uploaded')
+ ->willReturn(true);
+ $filespec->expects($this->any())
+ ->method('move_file')
+ ->willReturn(false);
+ $this->container->set('files.filespec', $filespec);
+ $factory_mock = $this->getMockBuilder('\phpbb\files\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory_mock->expects($this->any())
+ ->method('get')
+ ->willReturn($filespec);
+ $this->container->set('files.types.local', new \phpbb\files\types\local(
+ $factory_mock,
+ $this->language,
+ $this->php_ini,
+ $this->request
+ ));
+
+ $plupload = $this->getMockBuilder('\phpbb\plupload\plupload')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $plupload->expects($this->any())
+ ->method('is_active')
+ ->willReturn($plupload_active);
+ if ($plupload_active)
+ {
+ $plupload->expects($this->once())
+ ->method('emit_error')
+ ->with(104, 'ATTACHED_IMAGE_NOT_IMAGE')
+ ->willReturn(false);
+ }
+ $this->upload = new \phpbb\attachment\upload(
+ $this->auth,
+ $this->cache,
+ $this->config,
+ $this->files_upload,
+ $this->language,
+ $this->mimetype_guesser,
+ $this->phpbb_dispatcher,
+ $plupload,
+ $this->user,
+ $this->phpbb_root_path
+ );
+
+ $filedata = $this->upload->upload('foobar', 1, true, '', false, array(
+ 'realname' => 'foobar.jpg',
+ 'type' => 'jpg',
+ 'size' => 100,
+ ));
+
+ foreach ($expected as $key => $entry)
+ {
+ $this->assertEquals($entry, $filedata[$key]);
+ }
+
+ // Reset config data
+ foreach ($config_data as $key => $value)
+ {
+ $this->config->delete($key);
+ }
+ }
+}
diff --git a/tests/auth/provider_apache_test.php b/tests/auth/provider_apache_test.php
index 68ad7b2c19..7d77d763fb 100644
--- a/tests/auth/provider_apache_test.php
+++ b/tests/auth/provider_apache_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_auth_provider_apache_test extends phpbb_database_test_case
{
protected $provider;
@@ -28,8 +25,10 @@ class phpbb_auth_provider_apache_test extends phpbb_database_test_case
$db = $this->new_dbal();
$config = new \phpbb\config\config(array());
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
$this->request = $this->getMock('\phpbb\request\request');
- $this->user = new \phpbb\user('\phpbb\datetime');
+ $this->user = new \phpbb\user($lang, '\phpbb\datetime');
$driver_helper = new \phpbb\passwords\driver\helper($config);
$passwords_drivers = array(
'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $driver_helper),
diff --git a/tests/auth/provider_db_test.php b/tests/auth/provider_db_test.php
index 09ca0816bf..6ff77da564 100644
--- a/tests/auth/provider_db_test.php
+++ b/tests/auth/provider_db_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_auth_provider_db_test extends phpbb_database_test_case
{
public function getDataSet()
@@ -38,8 +35,10 @@ class phpbb_auth_provider_db_test extends phpbb_database_test_case
'ip_login_limit_use_forwarded' => 0,
'max_login_attempts' => 0,
));
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
$request = $this->getMock('\phpbb\request\request');
- $user = new \phpbb\user('\phpbb\datetime');
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$driver_helper = new \phpbb\passwords\driver\helper($config);
$passwords_drivers = array(
'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $driver_helper),
diff --git a/tests/auth/provider_oauth_token_storage_test.php b/tests/auth/provider_oauth_token_storage_test.php
index 71b49ff439..ae5de6aa7e 100644
--- a/tests/auth/provider_oauth_token_storage_test.php
+++ b/tests/auth/provider_oauth_token_storage_test.php
@@ -22,6 +22,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c
protected $session_id;
protected $token_storage;
protected $token_storage_table;
+ protected $state_table;
protected $user;
protected function setup()
@@ -31,9 +32,12 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c
global $phpbb_root_path, $phpEx;
$this->db = $this->new_dbal();
- $this->user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $this->user = new \phpbb\user($lang, '\phpbb\datetime');
$this->service_name = 'auth.provider.oauth.service.testing';
$this->token_storage_table = 'phpbb_oauth_tokens';
+ $this->state_table = 'phpbb_oauth_states';
// Give the user a session_id that we will remember
$this->session_id = '12345';
@@ -42,7 +46,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c
// Set the user id to anonymous
$this->user->data['user_id'] = ANONYMOUS;
- $this->token_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table);
+ $this->token_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table, $this->state_table);
}
public function getDataSet()
@@ -96,7 +100,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c
$expected_token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES);
// Store a token in the database
- $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table);
+ $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table, $this->state_table);
$temp_storage->storeAccessToken($this->service_name, $expected_token);
unset($temp_storage);
@@ -127,7 +131,7 @@ class phpbb_auth_provider_oauth_token_storage_test extends phpbb_database_test_c
$expected_token = new StdOAuth2Token('access', 'refresh', StdOAuth2Token::EOL_NEVER_EXPIRES);
// Store a token in the database
- $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table);
+ $temp_storage = new \phpbb\auth\provider\oauth\token_storage($this->db, $this->user, $this->token_storage_table, $this->state_table);
$temp_storage->storeAccessToken($this->service_name, $expected_token);
unset($temp_storage);
diff --git a/tests/avatar/driver/barfoo.php b/tests/avatar/driver/barfoo.php
index 0bf30b8a91..067bb3ef97 100644
--- a/tests/avatar/driver/barfoo.php
+++ b/tests/avatar/driver/barfoo.php
@@ -1,26 +1,26 @@
-<?php
-
-namespace phpbb\avatar\driver;
-
-class barfoo extends \phpbb\avatar\driver\driver
-{
- public function get_data($row)
- {
- return array();
- }
-
- public function prepare_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function process_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function get_template_name()
- {
- return 'barfoo.html';
- }
-}
+<?php
+
+namespace phpbb\avatar\driver;
+
+class barfoo extends \phpbb\avatar\driver\driver
+{
+ public function get_data($row)
+ {
+ return array();
+ }
+
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ return false;
+ }
+
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ return false;
+ }
+
+ public function get_template_name()
+ {
+ return 'barfoo.html';
+ }
+}
diff --git a/tests/avatar/driver/foobar.php b/tests/avatar/driver/foobar.php
index aabdaf5ac4..16d50ccad4 100644
--- a/tests/avatar/driver/foobar.php
+++ b/tests/avatar/driver/foobar.php
@@ -1,26 +1,26 @@
-<?php
-
-namespace phpbb\avatar\driver;
-
-class foobar extends \phpbb\avatar\driver\driver
-{
- public function get_data($row)
- {
- return array();
- }
-
- public function prepare_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function process_form($request, $template, $user, $row, &$error)
- {
- return false;
- }
-
- public function get_template_name()
- {
- return 'foobar.html';
- }
-}
+<?php
+
+namespace phpbb\avatar\driver;
+
+class foobar extends \phpbb\avatar\driver\driver
+{
+ public function get_data($row)
+ {
+ return array();
+ }
+
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ return false;
+ }
+
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ return false;
+ }
+
+ public function get_template_name()
+ {
+ return 'foobar.html';
+ }
+}
diff --git a/tests/avatar/manager_test.php b/tests/avatar/manager_test.php
index 802e71939d..d1e907b53d 100644
--- a/tests/avatar/manager_test.php
+++ b/tests/avatar/manager_test.php
@@ -35,6 +35,8 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
->method('get')
->will($this->returnArgument(0));
+ $filesystem = new \phpbb\filesystem\filesystem();
+
// Prepare dependencies for avatar manager and driver
$this->config = new \phpbb\config\config(array());
$cache = $this->getMock('\phpbb\cache\driver\driver_interface');
@@ -42,7 +44,7 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ $filesystem,
$this->getMock('\phpbb\request\request'),
$phpbb_root_path,
$phpEx
@@ -55,11 +57,12 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
new \phpbb\mimetype\content_guesser,
);
$guesser = new \phpbb\mimetype\guesser($guessers);
+ $imagesize = new \FastImageSize\FastImageSize();
$dispatcher = new phpbb_mock_event_dispatcher();
// $this->avatar_foobar will be needed later on
- $this->avatar_foobar = $this->getMock('\phpbb\avatar\driver\foobar', array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $cache));
+ $this->avatar_foobar = $this->getMock('\phpbb\avatar\driver\foobar', array('get_name'), array($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache));
$this->avatar_foobar->expects($this->any())
->method('get_name')
->will($this->returnValue('avatar.driver.foobar'));
@@ -73,15 +76,17 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
->will($this->returnValue('barfoo'));
$avatar_drivers = array($this->avatar_foobar, $this->avatar_barfoo);
+ $files_factory = new \phpbb\files\factory($phpbb_container);
+
foreach ($this->avatar_drivers() as $driver)
{
if ($driver !== 'upload')
{
- $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $cache));
+ $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $imagesize, $phpbb_root_path, $phpEx, $path_helper, $cache));
}
else
{
- $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $path_helper, $guesser, $dispatcher, $cache));
+ $cur_avatar = $this->getMock('\phpbb\avatar\driver\\' . $driver, array('get_name'), array($this->config, $phpbb_root_path, $phpEx, $filesystem, $path_helper, $dispatcher, $files_factory, $cache));
}
$cur_avatar->expects($this->any())
->method('get_name')
@@ -94,9 +99,11 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
$this->config['allow_avatar_' . get_class($this->avatar_barfoo)] = false;
// Set up avatar manager
- $this->manager = new \phpbb\avatar\manager($this->config, $avatar_drivers, $phpbb_container);
+ $this->manager = new \phpbb\avatar\manager($this->config, $dispatcher, $avatar_drivers);
$this->db = $this->new_dbal();
- $this->user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $this->user = new \phpbb\user($lang, '\phpbb\datetime');
}
protected function avatar_drivers()
@@ -178,7 +185,7 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
$avatar_settings = $this->manager->get_avatar_settings($this->avatar_foobar);
$expected_settings = array(
- 'allow_avatar_' . get_class($this->avatar_foobar) => array('lang' => 'ALLOW_' . strtoupper(get_class($this->avatar_foobar)), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
+ 'allow_avatar_' . get_class($this->avatar_foobar) => array('lang' => 'ALLOW_' . strtoupper(get_class($this->avatar_foobar)), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
);
$this->assertEquals($expected_settings, $avatar_settings);
@@ -279,7 +286,12 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
public function test_localize_errors()
{
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ global $phpbb_root_path, $phpEx;
+
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime')
+ );
$lang_array = array(
array('FOOBAR_OFF', 'foobar_off'),
array('FOOBAR_EXPLAIN', 'FOOBAR_EXPLAIN %s'),
@@ -412,11 +424,10 @@ class phpbb_avatar_manager_test extends \phpbb_database_test_case
'avatar_remote_height' => $height,
));
- $user = new \phpbb\user('\phpbb\datetime');
$row = array();
$error = array();
- $return = $remote_avatar->process_form($request, null, $user, $row, $error);
+ $return = $remote_avatar->process_form($request, null, $this->user, $row, $error);
if (count($expected_error) > 0)
{
$this->assertFalse($return);
diff --git a/tests/bbcode/parser_test.php b/tests/bbcode/parser_test.php
index 14736627f3..b569d371f1 100644
--- a/tests/bbcode/parser_test.php
+++ b/tests/bbcode/parser_test.php
@@ -11,8 +11,6 @@
*
*/
-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';
@@ -68,11 +66,6 @@ class phpbb_bbcode_parser_test extends \phpbb_test_case
'[code:]unparsed code[/code:]',
),
array(
- 'Test default bbcodes: simple php code',
- '[code=php]unparsed code[/code]',
- '[code=php:]<span class="syntaxdefault">unparsed&nbsp;code</span>[/code:]',
- ),
- array(
'Test default bbcodes: simple list',
'[list]no item[/list]',
'[list:]no item[/list:u:]',
@@ -256,9 +249,10 @@ class phpbb_bbcode_parser_test extends \phpbb_test_case
$this->markTestIncomplete($incomplete);
}
- global $user, $request;
+ global $user, $request, $symfony_request;
$user = new phpbb_mock_user;
$request = new phpbb_mock_request;
+ $symfony_request = new \phpbb\symfony_request($request);
$bbcode = new bbcode_firstpass();
$bbcode->message = $message;
diff --git a/tests/bbcode/url_bbcode_test.php b/tests/bbcode/url_bbcode_test.php
index 83176abe4c..f95970a6bb 100644
--- a/tests/bbcode/url_bbcode_test.php
+++ b/tests/bbcode/url_bbcode_test.php
@@ -11,8 +11,6 @@
*
*/
-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';
@@ -54,9 +52,10 @@ class phpbb_url_bbcode_test extends phpbb_test_case
*/
public function test_url($description, $message, $expected)
{
- global $user, $request;
+ global $user, $request, $symfony_request;
$user = new phpbb_mock_user;
$request = new phpbb_mock_request;
+ $symfony_request = new \phpbb\symfony_request($request);
$bbcode = new bbcode_firstpass();
$bbcode->message = $message;
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 0e81f4372a..18977bac88 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -12,14 +12,21 @@
*/
define('IN_PHPBB', true);
+define('PHPBB_ENVIRONMENT', 'test');
+
$phpbb_root_path = 'phpBB/';
$phpEx = 'php';
+
+global $table_prefix;
require_once $phpbb_root_path . 'includes/startup.php';
$table_prefix = 'phpbb_';
require_once $phpbb_root_path . 'includes/constants.php';
require_once $phpbb_root_path . 'phpbb/class_loader.' . $phpEx;
-require_once($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
+require_once $phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx;
+require_once $phpbb_root_path . 'includes/functions.' . $phpEx;
+require_once $phpbb_root_path . 'includes/functions_content.' . $phpEx;
+require_once $phpbb_root_path . 'includes/functions_compatibility.' . $phpEx;
$phpbb_class_loader_mock = new \phpbb\class_loader('phpbb_mock_', $phpbb_root_path . '../tests/mock/', "php");
$phpbb_class_loader_mock->register();
diff --git a/tests/cache/apc_driver_test.php b/tests/cache/apc_driver_test.php
index 10130b465b..706f274448 100644
--- a/tests/cache/apc_driver_test.php
+++ b/tests/cache/apc_driver_test.php
@@ -34,14 +34,14 @@ class phpbb_cache_apc_driver_test extends phpbb_cache_common_test_case
self::markTestSkipped('APC extension is not loaded');
}
- $php_ini = new \phpbb\php\ini;
+ $php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
- if (!$php_ini->get_bool('apc.enabled'))
+ if (!$php_ini->getBool('apc.enabled'))
{
self::markTestSkipped('APC is not enabled. Make sure apc.enabled=1 in php.ini');
}
- if (PHP_SAPI == 'cli' && !$php_ini->get_bool('apc.enable_cli'))
+ if (PHP_SAPI == 'cli' && !$php_ini->getBool('apc.enable_cli'))
{
self::markTestSkipped('APC is not enabled for CLI. Set apc.enable_cli=1 in php.ini');
}
diff --git a/tests/cache/apcu_driver_test.php b/tests/cache/apcu_driver_test.php
new file mode 100644
index 0000000000..57f640c313
--- /dev/null
+++ b/tests/cache/apcu_driver_test.php
@@ -0,0 +1,75 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+// Important: apc.enable_cli=1 must be in php.ini.
+// http://forums.devshed.com/php-development-5/apc-problem-561290.html
+// http://php.net/manual/en/apc.configuration.php
+
+require_once dirname(__FILE__) . '/common_test_case.php';
+
+class phpbb_cache_apcu_driver_test extends phpbb_cache_common_test_case
+{
+ protected static $config;
+ protected $driver;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/config.xml');
+ }
+
+ static public function setUpBeforeClass()
+ {
+ if (!extension_loaded('apcu'))
+ {
+ self::markTestSkipped('APCu extension is not loaded');
+ }
+
+ $php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+
+ if (!$php_ini->getBool('apc.enabled'))
+ {
+ self::markTestSkipped('APCu is not enabled. Make sure apc.enabled=1 in php.ini');
+ }
+
+ if (PHP_SAPI == 'cli' && !$php_ini->getBool('apc.enable_cli'))
+ {
+ self::markTestSkipped('APCu is not enabled for CLI. Set apc.enable_cli=1 in php.ini');
+ }
+ }
+
+ protected function setUp()
+ {
+ global $phpbb_container, $phpbb_root_path;
+
+ parent::setUp();
+
+ $phpbb_container = new phpbb_mock_container_builder();
+ $phpbb_container->setParameter('core.cache_dir', $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/');
+
+ $this->driver = new \phpbb\cache\driver\apcu;
+
+ $this->driver->purge();
+ }
+
+ public function test_purge()
+ {
+ /* add a cache entry which does not match our key */
+ $foreign_key = 'test_' . $this->driver->key_prefix . 'test';
+ $this->assertSame(true, apcu_store($foreign_key, 0, 600));
+ $this->assertSame(true, apcu_exists($foreign_key));
+
+ parent::test_purge();
+
+ $this->assertSame(true, apcu_exists($foreign_key));
+ }
+}
diff --git a/tests/cache/cache_memory.php b/tests/cache/cache_memory.php
index 806edb963a..565e9a48eb 100644
--- a/tests/cache/cache_memory.php
+++ b/tests/cache/cache_memory.php
@@ -18,7 +18,7 @@ class phpbb_cache_memory extends \phpbb\cache\driver\memory
/**
* Set cache path
*/
- function phpbb_cache_memory()
+ function __construct()
{
}
diff --git a/tests/cache/cache_memory_test.php b/tests/cache/cache_memory_test.php
index 9f92e8d8dc..ba1010bcf3 100644
--- a/tests/cache/cache_memory_test.php
+++ b/tests/cache/cache_memory_test.php
@@ -116,7 +116,7 @@ class phpbb_cache_memory_test extends phpbb_database_test_case
$results[] = $row;
}
$this->cache->sql_freeresult($query_id);
- $this->assertEquals($query[1], sizeof($results));
+ $this->assertEquals($query[1], count($results));
}
$this->cache->destroy('sql', $table);
diff --git a/tests/cache/dummy_driver_test.php b/tests/cache/dummy_driver_test.php
new file mode 100644
index 0000000000..6cb6b73729
--- /dev/null
+++ b/tests/cache/dummy_driver_test.php
@@ -0,0 +1,77 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_cache_dummy_driver_test extends phpbb_database_test_case
+{
+ protected $driver;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/config.xml');
+ }
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $this->driver = new \phpbb\cache\driver\dummy;
+ }
+
+ public function test_get_put()
+ {
+ $this->assertSame(false, $this->driver->get('key'));
+
+ $this->driver->put('key', 'value');
+
+ // null driver does not cache
+ $this->assertSame(false, $this->driver->get('key'));
+ }
+
+ public function test_purge()
+ {
+ $this->assertNull($this->driver->purge());
+ }
+
+ public function test_destroy()
+ {
+ $this->assertNull($this->driver->destroy('foo'));
+ }
+
+ public function test_cache_sql()
+ {
+ global $db, $cache, $phpbb_root_path, $phpEx;
+ $config = new phpbb\config\config(array());
+ $db = $this->new_dbal();
+ $cache = new \phpbb\cache\service($this->driver, $config, $db, $phpbb_root_path, $phpEx);
+
+ $sql = "SELECT * FROM phpbb_config
+ WHERE config_name = 'foo'";
+ $result = $db->sql_query($sql, 300);
+ $first_result = $db->sql_fetchrow($result);
+ $expected = array('config_name' => 'foo', 'config_value' => '23', 'is_dynamic' => 0);
+ $this->assertEquals($expected, $first_result);
+
+ $sql = 'DELETE FROM phpbb_config';
+ $result = $db->sql_query($sql);
+
+ // As null cache driver does not actually cache,
+ // this should return no results
+ $sql = "SELECT * FROM phpbb_config
+ WHERE config_name = 'foo'";
+ $result = $db->sql_query($sql, 300);
+
+ $this->assertSame(false, $db->sql_fetchrow($result));
+
+ $db->sql_close();
+ }
+}
diff --git a/tests/cache/null_driver_test.php b/tests/cache/null_driver_test.php
deleted file mode 100644
index b9f96732f5..0000000000
--- a/tests/cache/null_driver_test.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-class phpbb_cache_null_driver_test extends phpbb_database_test_case
-{
- protected $driver;
-
- public function getDataSet()
- {
- return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/config.xml');
- }
-
- protected function setUp()
- {
- parent::setUp();
-
- $this->driver = new \phpbb\cache\driver\null;
- }
-
- public function test_get_put()
- {
- $this->assertSame(false, $this->driver->get('key'));
-
- $this->driver->put('key', 'value');
-
- // null driver does not cache
- $this->assertSame(false, $this->driver->get('key'));
- }
-
- public function test_purge()
- {
- $this->assertNull($this->driver->purge());
- }
-
- public function test_destroy()
- {
- $this->assertNull($this->driver->destroy('foo'));
- }
-
- public function test_cache_sql()
- {
- global $db, $cache, $phpbb_root_path, $phpEx;
- $config = new phpbb\config\config(array());
- $db = $this->new_dbal();
- $cache = new \phpbb\cache\service($this->driver, $config, $db, $phpbb_root_path, $phpEx);
-
- $sql = "SELECT * FROM phpbb_config
- WHERE config_name = 'foo'";
- $result = $db->sql_query($sql, 300);
- $first_result = $db->sql_fetchrow($result);
- $expected = array('config_name' => 'foo', 'config_value' => '23', 'is_dynamic' => 0);
- $this->assertEquals($expected, $first_result);
-
- $sql = 'DELETE FROM phpbb_config';
- $result = $db->sql_query($sql);
-
- // As null cache driver does not actually cache,
- // this should return no results
- $sql = "SELECT * FROM phpbb_config
- WHERE config_name = 'foo'";
- $result = $db->sql_query($sql, 300);
-
- $this->assertSame(false, $db->sql_fetchrow($result));
-
- $db->sql_close();
- }
-}
diff --git a/tests/captcha/qa_test.php b/tests/captcha/qa_test.php
index 1f2f9f3070..7ec4be69f5 100644
--- a/tests/captcha/qa_test.php
+++ b/tests/captcha/qa_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_captcha_qa_test extends \phpbb_database_test_case
{
protected $request;
@@ -27,14 +25,16 @@ class phpbb_captcha_qa_test extends \phpbb_database_test_case
public function setUp()
{
- global $db;
+ global $db, $request, $phpbb_container;
$db = $this->new_dbal();
parent::setUp();
- $this->request = new \phpbb_mock_request();
- request_var(false, false, false, false, $this->request);
+ $request = new \phpbb_mock_request();
+ $phpbb_container = new \phpbb_mock_container_builder();
+ $factory = new \phpbb\db\tools\factory();
+ $phpbb_container->set('dbal.tools', $factory->get($db));
$this->qa = new \phpbb\captcha\plugins\qa('phpbb_captcha_questions', 'phpbb_captcha_answers', 'phpbb_qa_confirm');
}
@@ -87,7 +87,8 @@ class phpbb_captcha_qa_test extends \phpbb_database_test_case
*/
public function test_acp_get_question_input($value, $expected)
{
- $this->request->overwrite('answers', $value);
+ global $request;
+ $request->overwrite('answers', $value);
$this->assertEquals($expected, $this->qa->acp_get_question_input());
}
diff --git a/tests/composer.json b/tests/composer.json
deleted file mode 100644
index 057e0115a5..0000000000
--- a/tests/composer.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "require-dev": {
- "facebook/webdriver": "~1.1"
- }
-}
diff --git a/tests/composer.lock b/tests/composer.lock
deleted file mode 100644
index f172de4669..0000000000
--- a/tests/composer.lock
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "_readme": [
- "This file locks the dependencies of your project to a known state",
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
- "This file is @generated automatically"
- ],
- "hash": "25ad22c35c19f2b0a2331640fb6b5577",
- "content-hash": "617c33144bd2877c3c9a78f167a871b6",
- "packages": [],
- "packages-dev": [
- {
- "name": "facebook/webdriver",
- "version": "1.1.2",
- "source": {
- "type": "git",
- "url": "https://github.com/facebook/php-webdriver.git",
- "reference": "0b889d7de7461439f8a3bbcca46e0f696cb27986"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/facebook/php-webdriver/zipball/0b889d7de7461439f8a3bbcca46e0f696cb27986",
- "reference": "0b889d7de7461439f8a3bbcca46e0f696cb27986",
- "shasum": ""
- },
- "require": {
- "ext-curl": "*",
- "php": ">=5.3.19"
- },
- "require-dev": {
- "phpunit/phpunit": "4.6.*"
- },
- "suggest": {
- "phpdocumentor/phpdocumentor": "2.*"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Facebook\\WebDriver\\": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "Apache-2.0"
- ],
- "description": "A PHP client for WebDriver",
- "homepage": "https://github.com/facebook/php-webdriver",
- "keywords": [
- "facebook",
- "php",
- "selenium",
- "webdriver"
- ],
- "time": "2016-06-04 00:02:34"
- }
- ],
- "aliases": [],
- "minimum-stability": "stable",
- "stability-flags": [],
- "prefer-stable": false,
- "prefer-lowest": false,
- "platform": [],
- "platform-dev": []
-}
diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php
index 56c406b206..c071a049a8 100644
--- a/tests/compress/compress_test.php
+++ b/tests/compress/compress_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_compress.php';
diff --git a/tests/console/cache/purge_test.php b/tests/console/cache/purge_test.php
index 96988c1028..6c92660580 100644
--- a/tests/console/cache/purge_test.php
+++ b/tests/console/cache/purge_test.php
@@ -32,6 +32,8 @@ class phpbb_console_command_cache_purge_test extends phpbb_test_case
protected function setUp()
{
+ global $phpbb_root_path, $phpEx;
+
if (file_exists($this->cache_dir))
{
// cache directory possibly left after aborted
@@ -45,7 +47,10 @@ class phpbb_console_command_cache_purge_test extends phpbb_test_case
$this->db = $this->getMock('\phpbb\db\driver\driver_interface');
$this->config = new \phpbb\config\config(array('assets_version' => 1));
- $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $this->user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime')
+ );
}
public function test_purge()
@@ -86,7 +91,7 @@ class phpbb_console_command_cache_purge_test extends phpbb_test_case
public function get_command_tester()
{
$application = new Application();
- $application->add(new purge($this->user, $this->cache, $this->db, $this->getMock('\phpbb\auth\auth'), new \phpbb\log\null(), $this->config));
+ $application->add(new purge($this->user, $this->cache, $this->db, $this->getMock('\phpbb\auth\auth'), new \phpbb\log\dummy(), $this->config));
$command = $application->find('cache:purge');
$this->command_name = $command->getName();
diff --git a/tests/console/config/config_test.php b/tests/console/config/config_test.php
index 7c098af004..076316217d 100644
--- a/tests/console/config/config_test.php
+++ b/tests/console/config/config_test.php
@@ -22,9 +22,14 @@ class phpbb_console_command_config_test extends phpbb_test_case
public function setUp()
{
+ global $phpbb_root_path, $phpEx;
+
$this->config = new \phpbb\config\config(array());
- $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $this->user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime')
+ );
$this->user->method('lang')->will($this->returnArgument(0));
}
diff --git a/tests/console/cron/cron_list_test.php b/tests/console/cron/cron_list_test.php
index 22423304be..fdc9a05cb2 100644
--- a/tests/console/cron/cron_list_test.php
+++ b/tests/console/cron/cron_list_test.php
@@ -32,7 +32,12 @@ class phpbb_console_command_cron_list_test extends phpbb_test_case
protected function setUp()
{
- $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ global $phpbb_root_path, $phpEx;
+
+ $this->user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$this->user->method('lang')->will($this->returnArgument(0));
}
@@ -45,19 +50,19 @@ class phpbb_console_command_cron_list_test extends phpbb_test_case
public function test_only_ready()
{
$this->initiate_test(2, 0);
- $this->assertContains('TASKS_READY command1 command2', preg_replace('/\s+/', ' ', trim($this->command_tester->getDisplay())));
+ $this->assertContains('TASKS_READY command1 command2', preg_replace('/[\s*=]+/', ' ', trim($this->command_tester->getDisplay())));
}
public function test_only_not_ready()
{
$this->initiate_test(0, 2);
- $this->assertContains('TASKS_NOT_READY command1 command2', preg_replace('/\s+/', ' ', trim($this->command_tester->getDisplay())));
+ $this->assertContains('TASKS_NOT_READY command1 command2', preg_replace('/[\s*=]+/', ' ', trim($this->command_tester->getDisplay())));
}
public function test_both_ready()
{
$this->initiate_test(2, 2);
- $this->assertSame('TASKS_READY command1 command2 TASKS_NOT_READY command3 command4', preg_replace('/\s+/', ' ', trim($this->command_tester->getDisplay())));
+ $this->assertSame('TASKS_READY command1 command2 TASKS_NOT_READY command3 command4', preg_replace('/[\s*=]+/', ' ', trim($this->command_tester->getDisplay())));
}
public function get_cron_manager(array $tasks)
diff --git a/tests/console/cron/run_test.php b/tests/console/cron/run_test.php
index f76e967484..b4a0203325 100644
--- a/tests/console/cron/run_test.php
+++ b/tests/console/cron/run_test.php
@@ -16,7 +16,6 @@ use Symfony\Component\Console\Tester\CommandTester;
use phpbb\console\command\cron\run;
require_once dirname(__FILE__) . '/tasks/simple.php';
-require_once dirname(__FILE__) . '/../../../phpBB/includes/functions.php';
class phpbb_console_command_cron_run_test extends phpbb_database_test_case
{
@@ -39,10 +38,12 @@ class phpbb_console_command_cron_run_test extends phpbb_database_test_case
$db = $this->db = $this->new_dbal();
$config = $this->config = new \phpbb\config\config(array('cron_lock' => '0'));
- set_config(null, null, null, $this->config);
$this->lock = new \phpbb\lock\db('cron_lock', $this->config, $this->db);
- $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $this->user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$this->user->method('lang')->will($this->returnArgument(0));
$this->task = new phpbb_cron_task_simple();
@@ -76,6 +77,10 @@ class phpbb_console_command_cron_run_test extends phpbb_database_test_case
$this->assertSame(false, $this->lock->owns_lock());
}
+ /**
+ * @expectedException \phpbb\exception\runtime_exception
+ * @expectedExceptionMessage CRON_LOCK_ERROR
+ */
public function test_error_lock()
{
$this->lock->acquire();
@@ -124,6 +129,10 @@ class phpbb_console_command_cron_run_test extends phpbb_database_test_case
$this->assertSame(false, $this->lock->owns_lock());
}
+ /**
+ * @expectedException \phpbb\exception\runtime_exception
+ * @expectedExceptionMessage CRON_NO_SUCH_TASK
+ */
public function test_arg_invalid()
{
$command_tester = $this->get_command_tester();
diff --git a/tests/console/fixtures/png.png b/tests/console/fixtures/png.png
new file mode 100644
index 0000000000..c143a26a06
--- /dev/null
+++ b/tests/console/fixtures/png.png
Binary files differ
diff --git a/tests/console/fixtures/thumbnail.xml b/tests/console/fixtures/thumbnail.xml
new file mode 100644
index 0000000000..8037523633
--- /dev/null
+++ b/tests/console/fixtures/thumbnail.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_attachments">
+ <column>attach_id</column>
+ <column>physical_filename</column>
+ <column>real_filename</column>
+ <column>thumbnail</column>
+ <column>extension</column>
+ <column>mimetype</column>
+ <column>attach_comment</column>
+
+ <row>
+ <value>1</value>
+ <value>test_png_1</value>
+ <value>real_test.png</value>
+ <value>0</value>
+ <value>png</value>
+ <value>image/png</value>
+ <value></value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>test_png_2</value>
+ <value>real_test.png</value>
+ <value>1</value>
+ <value>png</value>
+ <value>image/png</value>
+ <value></value>
+ </row>
+ <row>
+ <value>10</value>
+ <value>test_txt</value>
+ <value>real_test.txt</value>
+ <value>0</value>
+ <value>txt</value>
+ <value>text/plain</value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/console/fixtures/txt.txt b/tests/console/fixtures/txt.txt
new file mode 100644
index 0000000000..a78c858f5c
--- /dev/null
+++ b/tests/console/fixtures/txt.txt
@@ -0,0 +1,2 @@
+<HTML>mime trigger</HTML>
+The HTML tags should remain uppercase so that case-insensitivity can be checked.
diff --git a/tests/console/thumbnail_test.php b/tests/console/thumbnail_test.php
new file mode 100644
index 0000000000..e425d998a2
--- /dev/null
+++ b/tests/console/thumbnail_test.php
@@ -0,0 +1,122 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use phpbb\console\command\thumbnail\generate;
+use phpbb\console\command\thumbnail\delete;
+use phpbb\console\command\thumbnail\recreate;
+
+class phpbb_console_command_thumbnail_test extends phpbb_database_test_case
+{
+ protected $db;
+ protected $config;
+ protected $cache;
+ protected $user;
+ protected $phpEx;
+ protected $phpbb_root_path;
+ protected $application;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/thumbnail.xml');
+ }
+
+ public function setUp()
+ {
+ global $config, $phpbb_root_path, $phpEx, $phpbb_filesystem;
+
+ if (!@extension_loaded('gd'))
+ {
+ $this->markTestSkipped('Thumbnail tests require gd extension.');
+ }
+
+ parent::setUp();
+
+ $config = $this->config = new \phpbb\config\config(array(
+ 'img_min_thumb_filesize' => 2,
+ 'img_max_thumb_width' => 2,
+ 'upload_path' => 'files',
+ ));
+
+ $this->db = $this->db = $this->new_dbal();
+ $this->user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime')
+ );
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->phpEx = $phpEx;
+
+ $this->cache = $this->getMock('\phpbb\cache\service', array(), array(new phpbb_mock_cache(), $this->config, $this->db, $this->phpbb_root_path, $this->phpEx));
+ $this->cache->expects(self::any())->method('obtain_attach_extensions')->will(self::returnValue(array(
+ 'png' => array('display_cat' => ATTACHMENT_CATEGORY_IMAGE),
+ 'txt' => array('display_cat' => ATTACHMENT_CATEGORY_NONE),
+ )));
+
+ $this->application = new Application();
+ $this->application->add(new generate($config, $this->user, $this->db, $this->cache, $this->phpbb_root_path, $this->phpEx));
+ $this->application->add(new delete($config, $this->user, $this->db, $this->phpbb_root_path));
+ $this->application->add(new recreate($this->user));
+
+ $phpbb_filesystem = new \phpbb\filesystem\filesystem();
+
+ copy(dirname(__FILE__) . '/fixtures/png.png', $this->phpbb_root_path . 'files/test_png_1');
+ copy(dirname(__FILE__) . '/fixtures/png.png', $this->phpbb_root_path . 'files/test_png_2');
+ copy(dirname(__FILE__) . '/fixtures/png.png', $this->phpbb_root_path . 'files/thumb_test_png_2');
+ copy(dirname(__FILE__) . '/fixtures/txt.txt', $this->phpbb_root_path . 'files/test_txt');
+ }
+
+ protected function tearDown()
+ {
+ parent::tearDown();
+
+ unlink($this->phpbb_root_path . 'files/test_png_1');
+ unlink($this->phpbb_root_path . 'files/test_png_2');
+ unlink($this->phpbb_root_path . 'files/test_txt');
+ unlink($this->phpbb_root_path . 'files/thumb_test_png_1');
+ unlink($this->phpbb_root_path . 'files/thumb_test_png_2');
+ }
+
+ public function test_thumbnails()
+ {
+ $command_tester = $this->get_command_tester('thumbnail:generate');
+ $exit_status = $command_tester->execute(array('command' => 'thumbnail:generate'));
+
+ self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_1'));
+ self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_2'));
+ self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_txt'));
+ self::assertSame(0, $exit_status);
+
+ $command_tester = $this->get_command_tester('thumbnail:delete');
+ $exit_status = $command_tester->execute(array('command' => 'thumbnail:delete'));
+
+ self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_png_1'));
+ self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_png_2'));
+ self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_txt'));
+ self::assertSame(0, $exit_status);
+
+ $command_tester = $this->get_command_tester('thumbnail:recreate');
+ $exit_status = $command_tester->execute(array('command' => 'thumbnail:recreate'));
+
+ self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_1'));
+ self::assertSame(true, file_exists($this->phpbb_root_path . 'files/thumb_test_png_2'));
+ self::assertSame(false, file_exists($this->phpbb_root_path . 'files/thumb_test_txt'));
+ self::assertSame(0, $exit_status);
+ }
+
+ public function get_command_tester($command_name)
+ {
+ $command = $this->application->find($command_name);
+ return new CommandTester($command);
+ }
+}
diff --git a/tests/console/update/check_test.php b/tests/console/update/check_test.php
new file mode 100644
index 0000000000..5cadc5cc97
--- /dev/null
+++ b/tests/console/update/check_test.php
@@ -0,0 +1,110 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use phpbb\console\command\update\check;
+
+require_once dirname(__FILE__) . '/../../../phpBB/includes/functions_admin.php';
+require_once dirname(__FILE__) . '/../../../phpBB/includes/functions.php';
+require_once dirname(__FILE__) . '/../../../phpBB/includes/utf/utf_tools.php';
+
+/**
+* @slow
+*/
+class phpbb_console_command_check_test extends phpbb_test_case
+{
+ protected $command_name;
+
+ protected $version_helper;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ public function test_up_to_date()
+ {
+ $command_tester = $this->get_command_tester('100000');
+ $status = $command_tester->execute(array('command' => $this->command_name, '--no-ansi' => true));
+ $this->assertSame('', $command_tester->getDisplay());
+ $this->assertSame($status, 0);
+ }
+
+ public function test_up_to_date_verbose()
+ {
+ $command_tester = $this->get_command_tester('100000');
+ $status = $command_tester->execute(array('command' => $this->command_name, '--no-ansi' => true, '--verbose' => true));
+ $this->assertContains($this->language->lang('UPDATE_NOT_NEEDED'), $command_tester->getDisplay());
+ $this->assertSame($status, 0);
+ }
+
+
+ public function test_not_up_to_date()
+ {
+ $command_tester = $this->get_command_tester('0');
+ $status = $command_tester->execute(array('command' => $this->command_name, '--no-ansi' => true));
+ $this->assertContains($this->language->lang('UPDATE_NEEDED'), $command_tester->getDisplay());
+ $this->assertSame($status, 1);
+ }
+
+ public function test_not_up_to_date_verbose()
+ {
+ $command_tester = $this->get_command_tester('0');
+ $status = $command_tester->execute(array('command' => $this->command_name, '--no-ansi' => true, '--verbose' => true));
+ $this->assertContains($this->language->lang('UPDATE_NEEDED'), $command_tester->getDisplay());
+ $this->assertContains($this->language->lang('UPDATES_AVAILABLE'), $command_tester->getDisplay());
+ $this->assertSame($status, 1);
+ }
+
+ /**
+ * @expectedException phpbb\exception\runtime_exception
+ */
+ public function test_error()
+ {
+ $command_tester = $this->get_command_tester('1');
+ $this->version_helper->set_file_location('acme.corp','foo', 'bar.json');
+
+ $status = $command_tester->execute(array('command' => $this->command_name, '--no-ansi' => true));
+ $this->assertContains('VERSIONCHECK_FAIL', $command_tester->getDisplay());
+ $this->assertSame($status, 2);
+ }
+
+ public function get_command_tester($current_version)
+ {
+ global $user, $phpbb_root_path, $phpEx;
+
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+
+ $user = $this->getMock('\phpbb\user', array(), array(
+ $this->language,
+ '\phpbb\datetime'
+ ));
+ $user->method('lang')->will($this->returnArgument(0));
+
+ $cache = $this->getMockBuilder('\phpbb\cache\service')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $config = new \phpbb\config\config(array('version' => $current_version));
+ $this->version_helper = new \phpbb\version_helper($cache, $config, new \phpbb\file_downloader());
+
+ $container = new phpbb_mock_container_builder;
+ $container->set('version_helper', $this->version_helper);
+
+ $application = new Application();
+ $application->add(new check($user, $config, $container, $this->language));
+
+ $command = $application->find('update:check');
+ $this->command_name = $command->getName();
+ return new CommandTester($command);
+ }
+}
diff --git a/tests/console/user/activate_test.php b/tests/console/user/activate_test.php
new file mode 100644
index 0000000000..1588a76e47
--- /dev/null
+++ b/tests/console/user/activate_test.php
@@ -0,0 +1,86 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use phpbb\console\command\user\activate;
+
+require_once dirname(__FILE__) . '/base.php';
+
+class phpbb_console_user_activate_test extends phpbb_console_user_base
+{
+ protected $notifications;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->notifications = $this->getMockBuilder('\phpbb\notification\manager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
+
+ public function get_command_tester()
+ {
+ $application = new Application();
+ $application->add(new activate(
+ $this->user,
+ $this->db,
+ $this->config,
+ $this->language,
+ $this->log,
+ $this->notifications,
+ $this->user_loader,
+ $this->phpbb_root_path,
+ $this->php_ext
+ ));
+
+ $command = $application->find('user:activate');
+ $this->command_name = $command->getName();
+
+ return new CommandTester($command);
+ }
+
+ public function activate_test_data()
+ {
+ return array(
+ // Test an inactive user
+ array('Test', false, 'USER_ADMIN_ACTIVATED'),
+ array('Test', true, 'CLI_DESCRIPTION_USER_ACTIVATE_INACTIVE'),
+
+ // Test an active user
+ array('Test 2', false, 'CLI_DESCRIPTION_USER_ACTIVATE_ACTIVE'),
+ array('Test 2', true, 'USER_ADMIN_DEACTIVED'),
+
+ // Test a non existent user
+ array('Foo', false, 'NO_USER'),
+ array('Foo', true, 'NO_USER'),
+ );
+ }
+
+ /**
+ * @dataProvider activate_test_data
+ */
+ public function test_activate($username, $deactivate, $expected)
+ {
+ $command_tester = $this->get_command_tester();
+
+ $command_tester->execute(array(
+ 'command' => $this->command_name,
+ 'username' => $username,
+ '--deactivate' => $deactivate,
+ ));
+
+ $this->assertContains($expected, $command_tester->getDisplay());
+ }
+}
diff --git a/tests/console/user/add_test.php b/tests/console/user/add_test.php
new file mode 100644
index 0000000000..bdfb8a8d2a
--- /dev/null
+++ b/tests/console/user/add_test.php
@@ -0,0 +1,134 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use phpbb\console\command\user\add;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\Question;
+
+require_once dirname(__FILE__) . '/base.php';
+
+class phpbb_console_user_add_test extends phpbb_console_user_base
+{
+ public function get_command_tester($question_answers = [])
+ {
+ $application = new Application();
+ $application->add(new add(
+ $this->user,
+ $this->db,
+ $this->config,
+ $this->language,
+ $this->passwords_manager,
+ $this->phpbb_root_path,
+ $this->php_ext
+ ));
+
+ $command = $application->find('user:add');
+ $this->command_name = $command->getName();
+
+ if (!empty($question_answers))
+ {
+ $ask = function(InputInterface $input, OutputInterface $output, Question $question) use ($question_answers)
+ {
+ $text = $question->getQuestion();
+
+ // handle a question
+ foreach ($question_answers as $expected_question => $answer)
+ {
+ if (strpos($text, $expected_question) !== false)
+ {
+ $response = $answer;
+ }
+ }
+
+ if (!isset($response))
+ {
+ throw new \RuntimeException('Was asked for input on an unhandled question: ' . $text);
+ }
+
+ $output->writeln(print_r($response, true));
+ return $response;
+ };
+ $helper = $this->getMock('\Symfony\Component\Console\Helper\QuestionHelper', array('ask'));
+ $helper->expects($this->any())
+ ->method('ask')
+ ->will($this->returnCallback($ask));
+ $this->question = $helper;
+ $command->getHelperSet()->set($helper, 'question');
+ }
+ else
+ {
+ $this->question = $command->getHelper('question');
+ }
+
+ return new CommandTester($command);
+ }
+
+ public function test_add_no_dialog()
+ {
+ $command_tester = $this->get_command_tester();
+
+ $this->assertEquals(2, $this->get_user_id('Admin'));
+
+ $command_tester->execute(array(
+ 'command' => $this->command_name,
+ '--username' => 'foo',
+ '--password' => 'bar',
+ '--email' => 'foo@test.com'
+ ));
+
+ $this->assertNotEquals(null, $this->get_user_id('foo'));
+ $this->assertContains('CLI_USER_ADD_SUCCESS', $command_tester->getDisplay());
+ }
+
+ public function test_add_dialog()
+ {
+ $command_tester = $this->get_command_tester([
+ 'USERNAME' => 'bar',
+ 'PASSWORD' => 'password',
+ 'EMAIL_ADDRESS' => 'bar@test.com',
+ ]);
+
+ $this->assertEquals(2, $this->get_user_id('Admin'));
+
+ $this->question->setInputStream($this->getInputStream("bar\npassword\npassword\nbar@test.com\n"));
+
+ $command_tester->execute(array(
+ 'command' => $this->command_name,
+ ));
+
+ $this->assertNotEquals(null, $this->get_user_id('bar'));
+ $this->assertContains('CLI_USER_ADD_SUCCESS', $command_tester->getDisplay());
+
+ }
+
+ public function test_add_no_dialog_invalid()
+ {
+ $command_tester = $this->get_command_tester();
+
+ $this->assertEquals(3, $this->get_user_id('Test'));
+
+ $command_tester->execute(array(
+ 'command' => $this->command_name,
+ '--username' => 'Test',
+ '--password' => '1',
+ '--email' => 'foo'
+ ));
+
+ $this->assertContains('USERNAME_TAKEN', $command_tester->getDisplay());
+ $this->assertContains('TOO_SHORT', $command_tester->getDisplay());
+ $this->assertContains('EMAIL_INVALID', $command_tester->getDisplay());
+ }
+}
diff --git a/tests/console/user/base.php b/tests/console/user/base.php
new file mode 100644
index 0000000000..ad328ac893
--- /dev/null
+++ b/tests/console/user/base.php
@@ -0,0 +1,126 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+abstract class phpbb_console_user_base extends phpbb_database_test_case
+{
+ protected $db;
+ protected $config;
+ protected $user;
+ protected $language;
+ protected $log;
+ protected $passwords_manager;
+ protected $command_name;
+ protected $question;
+ protected $user_loader;
+ protected $phpbb_root_path;
+ protected $php_ext;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/config.xml');
+ }
+
+ public function setUp()
+ {
+ global $auth, $db, $cache, $config, $user, $phpbb_dispatcher, $phpbb_container, $phpbb_root_path, $phpEx;
+
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
+ $phpbb_container = new phpbb_mock_container_builder();
+ $phpbb_container->set('cache.driver', new phpbb_mock_cache());
+ $phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
+
+ $auth = $this->getMock('\phpbb\auth\auth');
+
+ $cache = $phpbb_container->get('cache.driver');
+
+ $config = $this->config = new \phpbb\config\config(array(
+ 'board_timezone' => 'UTC',
+ 'default_lang' => 'en',
+ 'email_enable' => false,
+ 'min_name_chars' => 3,
+ 'max_name_chars' => 10,
+ 'min_pass_chars' => 3,
+ 'max_pass_chars' => 10,
+ 'pass_complex' => 'PASS_TYPE_ANY',
+ ));
+
+ $db = $this->db = $this->new_dbal();
+
+ $this->language = $this->getMockBuilder('\phpbb\language\language')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->language->expects($this->any())
+ ->method('lang')
+ ->will($this->returnArgument(0));
+ $user = $this->user = $this->getMock('\phpbb\user', array(), array(
+ $this->language,
+ '\phpbb\datetime'
+ ));
+
+ $this->user_loader = new \phpbb\user_loader($db, $phpbb_root_path, $phpEx, USERS_TABLE);
+
+ $driver_helper = new \phpbb\passwords\driver\helper($this->config);
+ $passwords_drivers = array(
+ 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($this->config, $driver_helper),
+ 'passwords.driver.bcrypt' => new \phpbb\passwords\driver\bcrypt($this->config, $driver_helper),
+ 'passwords.driver.salted_md5' => new \phpbb\passwords\driver\salted_md5($this->config, $driver_helper),
+ 'passwords.driver.phpass' => new \phpbb\passwords\driver\phpass($this->config, $driver_helper),
+ );
+
+ $passwords_helper = new \phpbb\passwords\helper;
+ $this->passwords_manager = new \phpbb\passwords\manager($this->config, $passwords_drivers, $passwords_helper, array_keys($passwords_drivers));
+
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $phpEx;
+
+ $this->log = $this->getMockBuilder('\phpbb\log\log')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $phpbb_container->set('auth.provider.db', new phpbb_mock_auth_provider());
+ $provider_collection = new \phpbb\auth\provider_collection($phpbb_container, $config);
+ $provider_collection->add('auth.provider.db');
+ $phpbb_container->set(
+ 'auth.provider_collection',
+ $provider_collection
+ );
+ $phpbb_container->setParameter('tables.auth_provider_oauth_token_storage', 'phpbb_oauth_tokens');
+ $phpbb_container->setParameter('tables.auth_provider_oauth_states', 'phpbb_oauth_states');
+ $phpbb_container->setParameter('tables.auth_provider_oauth_account_assoc', 'phpbb_oauth_accounts');
+
+ $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications');
+
+ parent::setUp();
+ }
+
+ public function get_user_id($username)
+ {
+ $sql = 'SELECT user_id
+ FROM ' . USERS_TABLE . '
+ WHERE ' . 'username = ' . "'" . $username . "'";
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ return $row['user_id'];
+ }
+
+ public function getInputStream($input)
+ {
+ $stream = fopen('php://memory', 'r+', false);
+ fputs($stream, $input);
+ rewind($stream);
+
+ return $stream;
+ }
+}
diff --git a/tests/console/user/delete_test.php b/tests/console/user/delete_test.php
new file mode 100644
index 0000000000..88f91afab1
--- /dev/null
+++ b/tests/console/user/delete_test.php
@@ -0,0 +1,93 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use phpbb\console\command\user\delete;
+
+require_once dirname(__FILE__) . '/base.php';
+
+class phpbb_console_user_delete_test extends phpbb_console_user_base
+{
+ public function get_command_tester()
+ {
+ $application = new Application();
+ $application->add(new delete(
+ $this->user,
+ $this->db,
+ $this->language,
+ $this->log,
+ $this->user_loader,
+ $this->phpbb_root_path,
+ $this->php_ext
+ ));
+
+ $command = $application->find('user:delete');
+ $this->command_name = $command->getName();
+ $this->question = $command->getHelper('question');
+
+ return new CommandTester($command);
+ }
+
+ public function test_delete()
+ {
+ $command_tester = $this->get_command_tester();
+
+ $this->assertEquals(3, $this->get_user_id('Test'));
+
+ $this->question->setInputStream($this->getInputStream("yes\n"));
+
+ $command_tester->execute(array(
+ 'command' => $this->command_name,
+ 'username' => 'Test',
+ '--delete-posts' => false,
+ ));
+
+ $this->assertNull($this->get_user_id('Test'));
+ $this->assertContains('USER_DELETED', $command_tester->getDisplay());
+ }
+
+ public function test_delete_non_user()
+ {
+ $command_tester = $this->get_command_tester();
+
+ $this->assertNull($this->get_user_id('Foo'));
+
+ $this->question->setInputStream($this->getInputStream("yes\n"));
+
+ $command_tester->execute(array(
+ 'command' => $this->command_name,
+ 'username' => 'Foo',
+ '--delete-posts' => false,
+ ));
+
+ $this->assertContains('NO_USER', $command_tester->getDisplay());
+ }
+
+ public function test_delete_cancel()
+ {
+ $command_tester = $this->get_command_tester();
+
+ $this->assertEquals(3, $this->get_user_id('Test'));
+
+ $this->question->setInputStream($this->getInputStream("no\n"));
+
+ $command_tester->execute(array(
+ 'command' => $this->command_name,
+ 'username' => 'Test',
+ '--delete-posts' => false,
+ ));
+
+ $this->assertNotNull($this->get_user_id('Test'));
+ }
+}
diff --git a/tests/console/user/fixtures/config.xml b/tests/console/user/fixtures/config.xml
new file mode 100644
index 0000000000..a988ba463f
--- /dev/null
+++ b/tests/console/user/fixtures/config.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_users">
+ <column>user_id</column>
+ <column>user_permissions</column>
+ <column>username</column>
+ <column>username_clean</column>
+ <column>user_sig</column>
+ <column>user_type</column>
+ <row>
+ <value>1</value>
+ <value></value>
+ <value>Guest</value>
+ <value>guest</value>
+ <value></value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value></value>
+ <value>Admin</value>
+ <value>admin</value>
+ <value></value>
+ <value>3</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value></value>
+ <value>Test</value>
+ <value>test</value>
+ <value></value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value></value>
+ <value>Test 2</value>
+ <value>test 2</value>
+ <value></value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value></value>
+ <value>Test Unclean</value>
+ <value>Test Unclean</value>
+ <value></value>
+ <value>0</value>
+ </row>
+ </table>
+ <table name="phpbb_groups">
+ <column>group_id</column>
+ <column>group_name</column>
+ <column>group_type</column>
+ <column>group_desc</column>
+ <row>
+ <value>1</value>
+ <value>REGISTERED</value>
+ <value>3</value>
+ <value>foobar</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/console/user/reclean_test.php b/tests/console/user/reclean_test.php
new file mode 100644
index 0000000000..1bf0b8ef5a
--- /dev/null
+++ b/tests/console/user/reclean_test.php
@@ -0,0 +1,49 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use phpbb\console\command\user\reclean;
+
+require_once dirname(__FILE__) . '/base.php';
+
+class phpbb_console_user_reclean_test extends phpbb_console_user_base
+{
+ public function get_command_tester()
+ {
+ $application = new Application();
+ $application->add(new reclean(
+ $this->user,
+ $this->db,
+ $this->language
+ ));
+
+ $command = $application->find('user:reclean');
+ $this->command_name = $command->getName();
+
+ return new CommandTester($command);
+ }
+
+ public function test_reclean()
+ {
+ $command_tester = $this->get_command_tester();
+
+ $exit_status = $command_tester->execute(array('command' => $this->command_name));
+ $this->assertSame(0, $exit_status);
+
+ $result = $this->db->sql_query('SELECT user_id FROM ' . USERS_TABLE . " WHERE username_clean = 'test unclean'");
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+ $this->assertNotNull($row['user_id']);
+ }
+}
diff --git a/tests/content_visibility/delete_post_test.php b/tests/content_visibility/delete_post_test.php
index 6ad6351a0c..4ea95b0a96 100644
--- a/tests/content_visibility/delete_post_test.php
+++ b/tests/content_visibility/delete_post_test.php
@@ -11,11 +11,8 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
require_once dirname(__FILE__) . '/../mock/search.php';
class phpbb_content_visibility_delete_post_test extends phpbb_database_test_case
@@ -292,12 +289,14 @@ class phpbb_content_visibility_delete_post_test extends phpbb_database_test_case
{
global $auth, $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
- $config['search_type'] = 'phpbb_mock_search';
+ $config = new \phpbb\config\config(array(
+ 'num_posts' => 3,
+ 'num_topics' => 1,
+ 'search_type' => 'phpbb_mock_search',
+ ));
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $phpbb_config = new \phpbb\config\config(array('num_posts' => 3, 'num_topics' => 1));
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- set_config_count(null, null, null, $phpbb_config);
// Create auth mock
$auth = $this->getMock('\phpbb\auth\auth');
@@ -307,13 +306,18 @@ class phpbb_content_visibility_delete_post_test extends phpbb_database_test_case
->will($this->returnValueMap(array(
array('m_approve', 1, true),
)));
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $attachment_delete = new \phpbb\attachment\delete($config, $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path);
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
- $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $phpbb_config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE));
+ $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE));
+ // Works as a workaround for tests
+ $phpbb_container->set('attachment.manager', $attachment_delete);
delete_post($forum_id, $topic_id, $post_id, $data, $is_soft, $reason);
diff --git a/tests/content_visibility/get_forums_visibility_sql_test.php b/tests/content_visibility/get_forums_visibility_sql_test.php
index 28e463ecb5..6c5066119e 100644
--- a/tests/content_visibility/get_forums_visibility_sql_test.php
+++ b/tests/content_visibility/get_forums_visibility_sql_test.php
@@ -134,7 +134,9 @@ class phpbb_content_visibility_get_forums_visibility_sql_test extends phpbb_data
->method('acl_getf')
->with($this->stringContains('_'), $this->anything())
->will($this->returnValueMap($permissions));
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$config = new phpbb\config\config(array());
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE);
diff --git a/tests/content_visibility/get_global_visibility_sql_test.php b/tests/content_visibility/get_global_visibility_sql_test.php
index 586bae8668..9ae4182673 100644
--- a/tests/content_visibility/get_global_visibility_sql_test.php
+++ b/tests/content_visibility/get_global_visibility_sql_test.php
@@ -134,7 +134,9 @@ class phpbb_content_visibility_get_global_visibility_sql_test extends phpbb_data
->method('acl_getf')
->with($this->stringContains('_'), $this->anything())
->will($this->returnValueMap($permissions));
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$config = new phpbb\config\config(array());
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE);
diff --git a/tests/content_visibility/get_visibility_sql_test.php b/tests/content_visibility/get_visibility_sql_test.php
index 9ae2d2fdc4..aaaf64330e 100644
--- a/tests/content_visibility/get_visibility_sql_test.php
+++ b/tests/content_visibility/get_visibility_sql_test.php
@@ -81,7 +81,9 @@ class phpbb_content_visibility_get_visibility_sql_test extends phpbb_database_te
->method('acl_get')
->with($this->stringContains('_'), $this->anything())
->will($this->returnValueMap($permissions));
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$config = new phpbb\config\config(array());
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE);
diff --git a/tests/content_visibility/set_post_visibility_test.php b/tests/content_visibility/set_post_visibility_test.php
index 36ebf58374..e33a1f30d5 100644
--- a/tests/content_visibility/set_post_visibility_test.php
+++ b/tests/content_visibility/set_post_visibility_test.php
@@ -11,11 +11,8 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
class phpbb_content_visibility_set_post_visibility_test extends phpbb_database_test_case
{
@@ -124,7 +121,9 @@ class phpbb_content_visibility_set_post_visibility_test extends phpbb_database_t
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
$auth = $this->getMock('\phpbb\auth\auth');
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$config = new phpbb\config\config(array());
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE);
@@ -175,7 +174,9 @@ class phpbb_content_visibility_set_post_visibility_test extends phpbb_database_t
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
$auth = $this->getMock('\phpbb\auth\auth');
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$config = new phpbb\config\config(array());
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE);
diff --git a/tests/content_visibility/set_topic_visibility_test.php b/tests/content_visibility/set_topic_visibility_test.php
index 6c34f42167..78431396c3 100644
--- a/tests/content_visibility/set_topic_visibility_test.php
+++ b/tests/content_visibility/set_topic_visibility_test.php
@@ -11,11 +11,8 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
class phpbb_content_visibility_set_topic_visibility_test extends phpbb_database_test_case
{
@@ -88,7 +85,9 @@ class phpbb_content_visibility_set_topic_visibility_test extends phpbb_database_
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
$auth = $this->getMock('\phpbb\auth\auth');
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$config = new phpbb\config\config(array());
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$content_visibility = new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE);
diff --git a/tests/controller/common_helper_route.php b/tests/controller/common_helper_route.php
index ea77a289c9..ea2bc042b1 100644
--- a/tests/controller/common_helper_route.php
+++ b/tests/controller/common_helper_route.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
abstract class phpbb_controller_common_helper_route extends phpbb_test_case
@@ -27,6 +25,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
private $provider;
private $filesystem;
private $phpbb_path_helper;
+ private $helper;
+ private $router;
+ private $routing_helper;
public function setUp()
{
@@ -44,10 +45,6 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
);
$this->generate_route_objects();
$phpbb_dispatcher = new phpbb_mock_event_dispatcher;
- $this->user = new \phpbb\user('\phpbb\datetime');
-
- $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0'));
- $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $this->config, $this->user, new \phpbb\template\context());
}
protected function get_phpbb_root_path()
@@ -91,7 +88,7 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
$this->symfony_request = new \phpbb\symfony_request(
$this->request
);
- $this->filesystem = new \phpbb\filesystem();
+ $this->filesystem = new \phpbb\filesystem\filesystem();
$this->phpbb_path_helper = new \phpbb\path_helper(
$this->symfony_request,
$this->filesystem,
@@ -100,15 +97,51 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
$phpEx
);
- $finder = new \phpbb\finder(
- new \phpbb\filesystem(),
+ $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0'));
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $this->user = new \phpbb\user($lang, '\phpbb\datetime');;
+
+ $container = new phpbb_mock_container_builder();
+ $container->setParameter('core.environment', PHPBB_ENVIRONMENT);
+ $cache_path = $phpbb_root_path . 'cache/twig';
+ $context = new \phpbb\template\context();
+ $loader = new \phpbb\template\twig\loader($this->filesystem, '');
+ $twig = new \phpbb\template\twig\environment(
+ $this->config,
+ $this->filesystem,
+ $this->phpbb_path_helper,
+ $cache_path,
+ null,
+ $loader,
+ new \phpbb\event\dispatcher($container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
+ );
+ $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $this->config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)));
+ $twig->setLexer(new \phpbb\template\twig\lexer($twig));
+
+ $this->extension_manager = new phpbb_mock_extension_manager(
dirname(__FILE__) . '/',
- new phpbb_mock_cache()
+ array(
+ 'vendor2/foo' => array(
+ 'ext_name' => 'vendor2/foo',
+ 'ext_active' => '1',
+ 'ext_path' => 'ext/vendor2/foo/',
+ ),
+ )
+ );
+
+ $loader = new \Symfony\Component\Routing\Loader\YamlFileLoader(
+ new \phpbb\routing\file_locator($this->filesystem, dirname(__FILE__) . '/')
);
- $finder->set_extensions(array_keys($this->extension_manager->all_enabled()));
- $this->provider = new \phpbb\controller\provider();
- $this->provider->find_routing_files($finder);
- $this->provider->find(dirname(__FILE__) . '/');
+ $resources_locator = new \phpbb\routing\resources_locator\default_resources_locator(dirname(__FILE__) . '/', PHPBB_ENVIRONMENT, $this->extension_manager);
+ $this->router = new phpbb_mock_router($container, $resources_locator, $loader, dirname(__FILE__) . '/', 'php');
+
// Set correct current phpBB root path
$this->root_path = $this->get_phpbb_root_path();
}
@@ -140,6 +173,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array('controller2', array(), true, false, '/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'),
array('controller2', array(), false, false, '/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'),
array('controller3', array('p' => 3), true, false, '/' . $this->path_to_app() . 'app.php/foo/bar/p-3', 'no params using empty array'),
+
+ // Resolves DI parameters
+ array('controller4', array(), true, false, '/' . $this->path_to_app() . 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'),
);
}
@@ -148,8 +184,10 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
*/
public function test_helper_url_no_rewrite($route, $params, $is_amp, $session_id, $expected, $description)
{
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id), $description);
+ $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0'));
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id), $description);
}
public function helper_url_data_with_rewrite()
@@ -179,6 +217,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array('controller2', array(), true, false, '/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'),
array('controller2', array(), false, false, '/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'),
array('controller3', array('p' => 3), true, false, '/' . $this->path_to_app() . 'foo/bar/p-3', 'no params using empty array'),
+
+ // Resolves DI parameters
+ array('controller4', array(), true, false, '/' . $this->path_to_app() . 'foo/' . PHPBB_ENVIRONMENT, 'di parameter'),
);
}
@@ -188,8 +229,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
public function test_helper_url_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description)
{
$this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1'));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id), $description);
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id), $description);
}
public function helper_url_data_absolute()
@@ -219,6 +261,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array('controller2', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'),
array('controller2', array(), false, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'),
array('controller3', array('p' => 3), true, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/bar/p-3', 'no params using empty array'),
+
+ // Resolves DI parameters
+ array('controller4', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'),
);
}
@@ -228,8 +273,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
public function test_helper_url_absolute($route, $params, $is_amp, $session_id, $expected, $description)
{
$this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0'));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL), $description);
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL), $description);
}
public function helper_url_data_relative_path()
@@ -259,6 +305,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array('controller2', array(), true, false, 'app.php/foo/bar', 'no params using empty array'),
array('controller2', array(), false, false, 'app.php/foo/bar', 'no params using empty array'),
array('controller3', array('p' => 3), true, false, 'app.php/foo/bar/p-3', 'no params using empty array'),
+
+ // Resolves DI parameters
+ array('controller4', array(), true, false, 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'),
);
}
@@ -268,8 +317,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
public function test_helper_url_relative_path($route, $params, $is_amp, $session_id, $expected, $description)
{
$this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0'));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH), $description);
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH), $description);
}
public function helper_url_data_network()
@@ -299,6 +349,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array('controller2', array(), true, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'),
array('controller2', array(), false, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/bar', 'no params using empty array'),
array('controller3', array('p' => 3), true, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/bar/p-3', 'no params using empty array'),
+
+ // Resolves DI parameters
+ array('controller4', array(), true, false, '//localhost/' . $this->path_to_app() . 'app.php/foo/' . PHPBB_ENVIRONMENT, 'di parameter'),
);
}
@@ -308,10 +361,11 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
public function test_helper_url_network($route, $params, $is_amp, $session_id, $expected, $description)
{
$this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '0'));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH), $description);
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH), $description);
}
-//TODO
+
public function helper_url_data_absolute_with_rewrite()
{
return array(
@@ -339,6 +393,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array('controller2', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'),
array('controller2', array(), false, false, 'http://localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'),
array('controller3', array('p' => 3), true, false, 'http://localhost/' . $this->path_to_app() . 'foo/bar/p-3', 'no params using empty array'),
+
+ // Resolves DI parameters
+ array('controller4', array(), true, false, 'http://localhost/' . $this->path_to_app() . 'foo/' . PHPBB_ENVIRONMENT, 'di parameter'),
);
}
@@ -348,8 +405,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
public function test_helper_url_absolute_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description)
{
$this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1'));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL), $description);
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::ABSOLUTE_URL), $description);
}
public function helper_url_data_relative_path_with_rewrite()
@@ -388,8 +446,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
public function test_helper_url_relative_path_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description)
{
$this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1'));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH), $description);
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::RELATIVE_PATH), $description);
}
public function helper_url_data_network_with_rewrite()
@@ -419,6 +478,9 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array('controller2', array(), true, false, '//localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'),
array('controller2', array(), false, false, '//localhost/' . $this->path_to_app() . 'foo/bar', 'no params using empty array'),
array('controller3', array('p' => 3), true, false, '//localhost/' . $this->path_to_app() . 'foo/bar/p-3', 'no params using empty array'),
+
+ // Resolves DI parameters
+ array('controller4', array(), true, false, '//localhost/' . $this->path_to_app() . 'foo/' . PHPBB_ENVIRONMENT, 'di parameter'),
);
}
@@ -427,9 +489,10 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
*/
public function test_helper_url_network_with_rewrite($route, $params, $is_amp, $session_id, $expected, $description)
{
- $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1'));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH), $description);
+ $this->config = new \phpbb\config\config(['enable_mod_rewrite' => '1']);
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route($route, $params, $is_amp, $session_id, UrlGeneratorInterface::NETWORK_PATH), $description);
}
public function helper_url_data_force_server_vars()
@@ -442,8 +505,7 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
array(false, true, 'my_server', 443, '/my/board', 'http://', UrlGeneratorInterface::ABSOLUTE_PATH, '/my/board/app.php/foo'),
array(true, true, 'my_server', 443, '/my/board', 'http://', UrlGeneratorInterface::ABSOLUTE_PATH, '/my/board/foo'),
array(false, true, 'my_server', 443, '/my/board', 'http://', UrlGeneratorInterface::RELATIVE_PATH, 'app.php/foo'),
- array(true, true, 'my_server', 443, '/my/board', 'http://', UrlGeneratorInterface::RELATIVE_PATH, 'foo'),
- );
+ array(true, true, 'my_server', 443, '/my/board', 'http://', UrlGeneratorInterface::RELATIVE_PATH, 'foo'), );
}
/**
@@ -460,8 +522,8 @@ abstract class phpbb_controller_common_helper_route extends phpbb_test_case
'server_protocol' => $server_protocol,
));
- $helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->provider, $this->extension_manager, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php', dirname(__FILE__) . '/');
- static::assertEquals($expected, $helper->route('controller1', array(), false, false, $type));
-
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $this->router, $this->symfony_request, $this->request, $this->filesystem, $this->root_path, 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $this->symfony_request, $this->request, $this->routing_helper);
+ static::assertEquals($expected, $this->helper->route('controller1', array(), false, false, $type));
}
}
diff --git a/tests/controller/config/routing.yml b/tests/controller/config/test/routing/environment.yml
index 1e7df02684..1e7df02684 100644
--- a/tests/controller/config/routing.yml
+++ b/tests/controller/config/test/routing/environment.yml
diff --git a/tests/controller/controller_test.php b/tests/controller/controller_test.php
index 62feee3fed..d921d0eade 100644
--- a/tests/controller/controller_test.php
+++ b/tests/controller/controller_test.php
@@ -11,7 +11,8 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
+include_once(__DIR__ . '/ext/vendor2/foo/controller.php');
+include_once(__DIR__.'/phpbb/controller/foo.php');
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Config\FileLocator;
@@ -30,14 +31,25 @@ class phpbb_controller_controller_test extends phpbb_test_case
'ext_active' => '1',
'ext_path' => 'ext/vendor2/foo/',
),
+ 'vendor2/bar' => array(
+ 'ext_name' => 'vendor2/bar',
+ 'ext_active' => '1',
+ 'ext_path' => 'ext/vendor2/bar/',
+ ),
));
}
- public function test_provider()
+ public function test_router_default_loader()
{
- $provider = new \phpbb\controller\provider();
- $provider->find_routing_files($this->extension_manager->get_finder());
- $routes = $provider->find(__DIR__)->get_routes();
+ $container = new phpbb_mock_container_builder();
+ $container->setParameter('core.environment', PHPBB_ENVIRONMENT);
+
+ $loader = new \Symfony\Component\Routing\Loader\YamlFileLoader(
+ new \phpbb\routing\file_locator(new \phpbb\filesystem\filesystem(), dirname(__FILE__) . '/')
+ );
+ $resources_locator = new \phpbb\routing\resources_locator\default_resources_locator(dirname(__FILE__) . '/', PHPBB_ENVIRONMENT, $this->extension_manager);
+ $router = new phpbb_mock_router($container, $resources_locator, $loader, dirname(__FILE__) . '/', 'php');
+ $routes = $router->get_routes();
// This will need to be updated if any new routes are defined
$this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('core_controller'));
@@ -49,10 +61,13 @@ class phpbb_controller_controller_test extends phpbb_test_case
$this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('controller2'));
$this->assertEquals('/foo/bar', $routes->get('controller2')->getPath());
+ $this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('controller3'));
+ $this->assertEquals('/bar', $routes->get('controller3')->getPath());
+
$this->assertNull($routes->get('controller_noroute'));
}
- public function test_controller_resolver()
+ protected function get_foo_container()
{
$container = new ContainerBuilder();
// YamlFileLoader only uses one path at a time, so we need to loop
@@ -63,26 +78,59 @@ class phpbb_controller_controller_test extends phpbb_test_case
$loader->load('services.yml');
}
- // Autoloading classes within the tests folder does not work
- // so I'll include them manually.
- if (!class_exists('vendor2\\foo\\controller'))
- {
- include(__DIR__ . '/ext/vendor2/foo/controller.php');
- }
- if (!class_exists('phpbb\\controller\\foo'))
- {
- include(__DIR__.'/phpbb/controller/foo.php');
- }
+ return $container;
+ }
- $resolver = new \phpbb\controller\resolver(new \phpbb\user('\phpbb\datetime'), $container, dirname(__FILE__) . '/');
+ public function test_controller_resolver()
+ {
+ $container = $this->get_foo_container();
+
+ $resolver = new \phpbb\controller\resolver($container, dirname(__FILE__) . '/');
$symfony_request = new Request();
$symfony_request->attributes->set('_controller', 'foo.controller:handle');
$this->assertEquals($resolver->getController($symfony_request), array(new foo\controller, 'handle'));
+ $this->assertEquals(array('foo'), $resolver->getArguments($symfony_request, $resolver->getController($symfony_request)));
$symfony_request = new Request();
$symfony_request->attributes->set('_controller', 'core_foo.controller:bar');
$this->assertEquals($resolver->getController($symfony_request), array(new phpbb\controller\foo, 'bar'));
+ $this->assertEquals(array(), $resolver->getArguments($symfony_request, $resolver->getController($symfony_request)));
+ }
+
+ public function data_get_arguments()
+ {
+ return array(
+ array(array(new foo\controller(), 'handle2'), array('foo', 0)),
+ array(array(new foo\controller(), 'handle_fail'), array('default'), array('no_default' => 'default')),
+ array(new foo\controller(), array(), array()),
+ array(array(new foo\controller(), 'handle_fail'), array(), array(), '\phpbb\controller\exception', 'CONTROLLER_ARGUMENT_VALUE_MISSING'),
+ array('', array(), array(), '\ReflectionException', 'Function () does not exist'),
+ array(new phpbb\controller\foo, array(), array(), '\ReflectionException', 'Method __invoke does not exist'),
+ );
+ }
+
+ /**
+ * @dataProvider data_get_arguments
+ */
+ public function test_get_arguments($input, $expected, $set_attributes = array(), $exception = '', $exception_message = '')
+ {
+ $container = $this->get_foo_container();
+
+ $resolver = new \phpbb\controller\resolver($container, dirname(__FILE__) . '/');
+ $symfony_request = new Request();
+
+ foreach ($set_attributes as $name => $value)
+ {
+ $symfony_request->attributes->set($name, $value);
+ }
+
+ if (!empty($exception))
+ {
+ $this->setExpectedException($exception, $exception_message);
+ }
+
+ $this->assertEquals($expected, $resolver->getArguments($symfony_request, $input));
}
}
diff --git a/tests/controller/ext/vendor2/bar/config/services.yml b/tests/controller/ext/vendor2/bar/config/services.yml
new file mode 100644
index 0000000000..05a8a1994d
--- /dev/null
+++ b/tests/controller/ext/vendor2/bar/config/services.yml
@@ -0,0 +1,3 @@
+services:
+ bar.controller:
+ class: bar\controller
diff --git a/tests/controller/ext/vendor2/bar/config/test/routing/environment.yml b/tests/controller/ext/vendor2/bar/config/test/routing/environment.yml
new file mode 100644
index 0000000000..5696ecb180
--- /dev/null
+++ b/tests/controller/ext/vendor2/bar/config/test/routing/environment.yml
@@ -0,0 +1,3 @@
+controller3:
+ path: /bar
+ defaults: { _controller: bar.controller:handle }
diff --git a/tests/controller/ext/vendor2/bar/controller.php b/tests/controller/ext/vendor2/bar/controller.php
new file mode 100644
index 0000000000..ad35f5a051
--- /dev/null
+++ b/tests/controller/ext/vendor2/bar/controller.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace bar;
+
+use Symfony\Component\HttpFoundation\Response;
+
+class controller
+{
+ /**
+ * Handle method
+ *
+ * @return null
+ */
+ public function handle()
+ {
+ return new Response('Test', 200);
+ }
+}
diff --git a/tests/controller/ext/vendor2/foo/config/routing.yml b/tests/controller/ext/vendor2/foo/config/routing.yml
index e3e8ee5f98..7d4ac7be93 100644
--- a/tests/controller/ext/vendor2/foo/config/routing.yml
+++ b/tests/controller/ext/vendor2/foo/config/routing.yml
@@ -5,3 +5,7 @@ controller1:
include_controller2:
resource: "routing_2.yml"
prefix: /foo
+
+controller4:
+ path: /foo/%core.environment%
+ defaults: { _controller: foo.controller:handle }
diff --git a/tests/controller/ext/vendor2/foo/controller.php b/tests/controller/ext/vendor2/foo/controller.php
index ce2233b3c9..cabcae042b 100644
--- a/tests/controller/ext/vendor2/foo/controller.php
+++ b/tests/controller/ext/vendor2/foo/controller.php
@@ -11,8 +11,23 @@ class controller
*
* @return null
*/
- public function handle()
+ public function handle($optional = 'foo')
{
return new Response('Test', 200);
}
+
+ public function handle2($foo = 'foo', $very_optional = 0)
+ {
+ return new Response('Test2', 200);
+ }
+
+ public function handle_fail($no_default)
+ {
+ return new Response('Test_fail', 200);
+ }
+
+ public function __invoke()
+ {
+ $this->handle();
+ }
}
diff --git a/tests/controller/helper_route_adm_subdir_test.php b/tests/controller/helper_route_adm_subdir_test.php
index f27ac81b04..a1bf1b8805 100644
--- a/tests/controller/helper_route_adm_subdir_test.php
+++ b/tests/controller/helper_route_adm_subdir_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/common_helper_route.php';
class phpbb_controller_helper_route_adm_subdir_test extends phpbb_controller_common_helper_route
diff --git a/tests/controller/helper_route_adm_test.php b/tests/controller/helper_route_adm_test.php
index 86dc36ef1f..6ee394eaaa 100644
--- a/tests/controller/helper_route_adm_test.php
+++ b/tests/controller/helper_route_adm_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/common_helper_route.php';
class phpbb_controller_helper_route_adm_test extends phpbb_controller_common_helper_route
diff --git a/tests/controller/helper_route_root_test.php b/tests/controller/helper_route_root_test.php
index 63a2f2f8f7..12462e076d 100644
--- a/tests/controller/helper_route_root_test.php
+++ b/tests/controller/helper_route_root_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/common_helper_route.php';
class phpbb_controller_helper_route_test extends phpbb_controller_common_helper_route
diff --git a/tests/controller/helper_route_slash_test.php b/tests/controller/helper_route_slash_test.php
index 3db5ec19e5..c781a6943e 100644
--- a/tests/controller/helper_route_slash_test.php
+++ b/tests/controller/helper_route_slash_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/common_helper_route.php';
class phpbb_controller_helper_route_slash_test extends phpbb_controller_common_helper_route
diff --git a/tests/controller/helper_route_unclean_path_test.php b/tests/controller/helper_route_unclean_path_test.php
index 9d8b62bc1c..80f1a99fff 100644
--- a/tests/controller/helper_route_unclean_path_test.php
+++ b/tests/controller/helper_route_unclean_path_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/common_helper_route.php';
class phpbb_controller_helper_route_unclean_path_test extends phpbb_controller_common_helper_route
diff --git a/tests/cron/manager_test.php b/tests/cron/manager_test.php
index f4dd69b19b..76f8c753bf 100644
--- a/tests/cron/manager_test.php
+++ b/tests/cron/manager_test.php
@@ -40,7 +40,7 @@ class phpbb_cron_manager_test extends \phpbb_test_case
public function test_manager_finds_all_ready_tasks()
{
$tasks = $this->manager->find_all_ready_tasks();
- $this->assertEquals(3, sizeof($tasks));
+ $this->assertEquals(3, count($tasks));
}
public function test_manager_finds_one_ready_task()
diff --git a/tests/datetime/from_format_test.php b/tests/datetime/from_format_test.php
index 8968619bb5..7ecb546768 100644
--- a/tests/datetime/from_format_test.php
+++ b/tests/datetime/from_format_test.php
@@ -37,7 +37,11 @@ class phpbb_datetime_from_format_test extends phpbb_test_case
*/
public function test_from_format($timezone, $format, $expected)
{
- $user = new \phpbb\user('\phpbb\datetime');
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->timezone = new DateTimeZone($timezone);
$user->lang['datetime'] = array(
'TODAY' => 'Today',
@@ -107,7 +111,11 @@ class phpbb_datetime_from_format_test extends phpbb_test_case
*/
public function test_relative_format_date($timestamp, $forcedate, $expected)
{
- $user = new \phpbb\user('\phpbb\datetime');
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->timezone = new DateTimeZone('UTC');
$user->lang['datetime'] = array(
'TODAY' => 'Today',
diff --git a/tests/dbal/auto_increment_test.php b/tests/dbal/auto_increment_test.php
index 1ed8ea29e3..950a4fc8f7 100644
--- a/tests/dbal/auto_increment_test.php
+++ b/tests/dbal/auto_increment_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_dbal_auto_increment_test extends phpbb_database_test_case
{
protected $db;
@@ -30,7 +28,8 @@ class phpbb_dbal_auto_increment_test extends phpbb_database_test_case
parent::setUp();
$this->db = $this->new_dbal();
- $this->tools = new \phpbb\db\tools($this->db);
+ $factory = new \phpbb\db\tools\factory();
+ $this->tools = $factory->get($this->db);
$this->table_data = array(
'COLUMNS' => array(
diff --git a/tests/dbal/boolean_processor_test.php b/tests/dbal/boolean_processor_test.php
new file mode 100644
index 0000000000..c69f60a1a8
--- /dev/null
+++ b/tests/dbal/boolean_processor_test.php
@@ -0,0 +1,321 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_boolean_processor_test extends phpbb_database_test_case
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/boolean_processor.xml');
+ }
+
+ public function test_single_not_like()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.user_id',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ ),
+ 'WHERE' => array('u.username_clean', 'NOT_LIKE', 'gr' . $db->get_any_char()),
+ 'ORDER_BY' => 'u.user_id',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(
+ array('user_id' => '1'),
+ array('user_id' => '2'),
+ array('user_id' => '3'),
+ array('user_id' => '6'),
+ ), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+ }
+
+ public function test_single_like()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.user_id',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ ),
+ 'WHERE' => array('u.username_clean', 'LIKE', 'gr' . $db->get_any_char()),
+ 'ORDER_BY' => 'u.user_id',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(
+ array('user_id' => '4'),
+ array('user_id' => '5'),
+ ), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+ }
+
+ public function test_single_not_in()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.user_id',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ ),
+ 'WHERE' => array('u.user_id', 'NOT_IN', array(3,4,5)),
+ 'ORDER_BY' => 'u.user_id',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(
+ array('user_id' => '1'),
+ array('user_id' => '2'),
+ array('user_id' => '6'),
+ ), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+ }
+
+ public function test_single_in()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.user_id',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ ),
+ 'WHERE' => array('u.user_id', 'IN', array(3,4,5)),
+ 'ORDER_BY' => 'u.user_id',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(
+ array('user_id' => '3'),
+ array('user_id' => '4'),
+ array('user_id' => '5'),
+ ), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+ }
+
+ public function test_and_of_or_of_and()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.user_id',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ 'phpbb_user_group' => 'ug',
+ ),
+ 'LEFT_JOIN' => array(
+ array(
+ 'FROM' => array(
+ 'phpbb_banlist' => 'b',
+ ),
+ 'ON' => 'u.user_id = b.ban_userid',
+ ),
+ ),
+ 'WHERE' => array('AND',
+ array(
+ array('OR',
+ array(
+ array('AND',
+ array(
+ array('ug.user_id', 'IN', array(1, 2, 3, 4)),
+ array('ug.group_id', '=', 2),
+ ),
+ ),
+ array('AND',
+ array(
+ array('ug.group_id', '=', 1),
+ array('b.ban_id', 'IS_NOT', NULL),
+ ),
+ ),
+ ),
+ ),
+ array('u.user_id', '=', 'ug.user_id'),
+ ),
+ ),
+ 'ORDER_BY' => 'u.user_id',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(
+ array('user_id' => '2'),
+ array('user_id' => '4'),
+ ), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+ }
+
+ public function test_triple_and_with_in()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.user_id',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ 'phpbb_user_group' => 'ug',
+ ),
+ 'WHERE' => array('AND',
+ array(
+ array('ug.user_id', 'IN', array(1, 2, 3, 4)),
+ array('ug.group_id', '=', 1),
+ array('u.user_id', '=', 'ug.user_id'),
+ ),
+ ),
+ 'ORDER_BY' => 'u.user_id',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(
+ array('user_id' => '1'),
+ array('user_id' => '2'),
+ array('user_id' => '3'),
+ ), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+
+ }
+
+ public function test_double_and_with_not_of_or()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.user_id',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ 'phpbb_user_group' => 'ug',
+ ),
+ 'WHERE' => array('AND',
+ array(
+ array('NOT',
+ array(
+ array('OR',
+ array(
+ array('ug.group_id', '=', 1),
+ array('ug.group_id', '=', 2),
+ ),
+ ),
+ ),
+ ),
+ array('u.user_id', '=', 'ug.user_id'),
+ ),
+ ),
+ 'ORDER_BY' => 'u.user_id',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+ }
+
+ public function test_triple_and_with_is_null()
+ {
+ $db = $this->new_dbal();
+
+ $db->sql_return_on_error(true);
+
+ $sql_ary = array(
+ 'SELECT' => 'u.username',
+ 'FROM' => array(
+ 'phpbb_users' => 'u',
+ 'phpbb_user_group' => 'ug',
+ ),
+ 'LEFT_JOIN' => array(
+ array(
+ 'FROM' => array(
+ 'phpbb_banlist' => 'b',
+ ),
+ 'ON' => 'u.user_id = b.ban_userid',
+ ),
+ ),
+ 'WHERE' => array('AND',
+ array(
+ array('ug.group_id', '=', 1),
+ array('u.user_id', '=', 'ug.user_id'),
+ array('b.ban_id', 'IS', NULL),
+ ),
+ ),
+ 'ORDER_BY' => 'u.username',
+ );
+ $sql = $db->sql_build_query('SELECT', $sql_ary);
+ $result = $db->sql_query($sql);
+
+ $db->sql_return_on_error(false);
+
+ $this->assertEquals(array(
+ array('username' => 'helper'),
+ array('username' => 'mass email'),
+ ), $db->sql_fetchrowset($result),
+ ($result === false) ?
+ "SQL ERROR:<br>" . var_export($sql, true) . "<br>" . $db->sql_error() :
+ var_export($sql, true) . ' ' . var_export($result, true)
+ );
+ }
+}
diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php
index 1ae34bd2b6..3933dab798 100644
--- a/tests/dbal/connect_test.php
+++ b/tests/dbal/connect_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_dbal_connect_test extends phpbb_database_test_case
{
public function getDataSet()
@@ -22,7 +20,9 @@ class phpbb_dbal_connect_test extends phpbb_database_test_case
public function test_failing_connect()
{
- global $phpbb_root_path, $phpEx;
+ global $phpbb_root_path, $phpEx, $phpbb_filesystem;
+
+ $phpbb_filesystem = new phpbb\filesystem\filesystem();
$config = $this->get_database_config();
diff --git a/tests/dbal/cross_join_test.php b/tests/dbal/cross_join_test.php
index 7ba937ccc6..be9258c58b 100644
--- a/tests/dbal/cross_join_test.php
+++ b/tests/dbal/cross_join_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_dbal_cross_join_test extends phpbb_database_test_case
{
public function getDataSet()
diff --git a/tests/dbal/db_tools_test.php b/tests/dbal/db_tools_test.php
index 5832b966d8..0365463a48 100644
--- a/tests/dbal/db_tools_test.php
+++ b/tests/dbal/db_tools_test.php
@@ -11,13 +11,11 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_dbal_db_tools_test extends phpbb_database_test_case
{
/** @var \phpbb\db\driver\driver_interface */
protected $db;
- /** @var \phpbb\db\tools */
+ /** @var \phpbb\db\tools\tools_interface */
protected $tools;
protected $table_exists;
protected $table_data;
@@ -32,7 +30,8 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case
parent::setUp();
$this->db = $this->new_dbal();
- $this->tools = new \phpbb\db\tools($this->db);
+ $factory = new \phpbb\db\tools\factory();
+ $this->tools = $factory->get($this->db);
$this->table_data = array(
'COLUMNS' => array(
@@ -204,8 +203,15 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case
public function test_list_columns()
{
+ $config = $this->get_database_config();
+ $table_columns = $this->table_data['COLUMNS'];
+
+ if (strpos($config['dbms'], 'mssql') !== false)
+ {
+ ksort($table_columns);
+ }
$this->assertEquals(
- array_keys($this->table_data['COLUMNS']),
+ array_keys($table_columns),
array_values($this->tools->sql_list_columns('prefix_table_name'))
);
}
@@ -340,7 +346,7 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case
public function test_perform_schema_changes_drop_tables()
{
- $db_tools = $this->getMock('\phpbb\db\tools', array(
+ $db_tools = $this->getMock('\phpbb\db\tools\tools', array(
'sql_table_exists',
'sql_table_drop',
), array(&$this->db));
@@ -366,7 +372,7 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case
public function test_perform_schema_changes_drop_columns()
{
- $db_tools = $this->getMock('\phpbb\db\tools', array(
+ $db_tools = $this->getMock('\phpbb\db\tools\tools', array(
'sql_column_exists',
'sql_column_remove',
), array(&$this->db));
@@ -422,4 +428,50 @@ class phpbb_dbal_db_tools_test extends phpbb_database_test_case
$this->assertTrue($this->tools->sql_column_add('prefix_table_name', 'c_bug_13282', array('TINT:2')));
$this->assertTrue($this->tools->sql_column_exists('prefix_table_name', 'c_bug_13282'));
}
+
+ public function test_create_index_with_long_name()
+ {
+ // This constant is being used for checking table prefix.
+ $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
+
+ if (strlen($table_prefix) > 20)
+ {
+ $this->markTestIncomplete('The table prefix length is too long for proper testing of index shortening function.');
+ }
+
+ $max_index_length = 30;
+
+ if ($this->tools instanceof \phpbb\db\tools\mssql)
+ {
+ $max_length_method = new ReflectionMethod('\phpbb\db\tools\mssql', 'get_max_index_name_length');
+ $max_length_method->setAccessible(true);
+ $max_index_length = $max_length_method->invoke($this->tools);
+ }
+
+ $table_suffix = str_repeat('a', 25 - strlen($table_prefix));
+ $table_name = $table_prefix . $table_suffix;
+
+ $this->tools->sql_create_table($table_name, $this->table_data);
+
+ // Index name and table suffix and table prefix have > maximum index length chars in total.
+ // Index name and table suffix have <= maximum index length chars in total.
+ $long_index_name = str_repeat('i', $max_index_length - strlen($table_suffix));
+ $this->assertFalse($this->tools->sql_index_exists($table_name, $long_index_name));
+ $this->assertTrue($this->tools->sql_create_index($table_name, $long_index_name, array('c_timestamp')));
+ $this->assertTrue($this->tools->sql_index_exists($table_name, $long_index_name));
+
+ // Index name and table suffix have > maximum index length chars in total.
+ $very_long_index_name = str_repeat('i', $max_index_length);
+ $this->assertFalse($this->tools->sql_index_exists($table_name, $very_long_index_name));
+ $this->assertTrue($this->tools->sql_create_index($table_name, $very_long_index_name, array('c_timestamp')));
+ $this->assertTrue($this->tools->sql_index_exists($table_name, $very_long_index_name));
+
+ $this->tools->sql_table_drop($table_name);
+
+ // Index name has > maximum index length chars - that should not be possible.
+ $too_long_index_name = str_repeat('i', $max_index_length + 1);
+ $this->assertFalse($this->tools->sql_index_exists('prefix_table_name', $too_long_index_name));
+ $this->setExpectedTriggerError(E_USER_ERROR);
+ $this->tools->sql_create_index('prefix_table_name', $too_long_index_name, array('c_timestamp'));
+ }
}
diff --git a/tests/dbal/ext/foo/bar/acp/acp_test_info.php b/tests/dbal/ext/foo/bar/acp/acp_test_info.php
new file mode 100644
index 0000000000..ac92623c3a
--- /dev/null
+++ b/tests/dbal/ext/foo/bar/acp/acp_test_info.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace foo\bar\acp;
+
+class acp_test_info
+{
+ public function module()
+ {
+ return array(
+ 'filename' => '\foo\bar\acp\acp_test_module',
+ 'title' => 'ACP_NEW_MODULE',
+ 'modes' => array(
+ 'mode_1' => array(
+ 'title' => 'ACP_NEW_MODULE_MODE_1',
+ 'auth' => '',
+ 'cat' => array('ACP_NEW_MODULE'),
+ ),
+ 'mode_2' => array(
+ 'title' => 'ACP_NEW_MODULE_MODE_2',
+ 'auth' => '',
+ 'cat' => array('ACP_NEW_MODULE'),
+ ),
+ ),
+ );
+ }
+}
diff --git a/tests/dbal/ext/foo/bar/acp/acp_test_module.php b/tests/dbal/ext/foo/bar/acp/acp_test_module.php
new file mode 100644
index 0000000000..01ce5c17dc
--- /dev/null
+++ b/tests/dbal/ext/foo/bar/acp/acp_test_module.php
@@ -0,0 +1,25 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace foo\bar\acp;
+
+class acp_test_module
+{
+ var $u_action;
+
+ function main($id, $mode)
+ {
+ $this->tpl_name = 'foobar';
+ $this->page_title = 'Bertie';
+ }
+}
diff --git a/tests/dbal/ext/foo/bar/composer.json b/tests/dbal/ext/foo/bar/composer.json
new file mode 100644
index 0000000000..2edfd43d84
--- /dev/null
+++ b/tests/dbal/ext/foo/bar/composer.json
@@ -0,0 +1,24 @@
+{
+ "name": "foo/bar",
+ "type": "phpbb-extension",
+ "description": "An example/sample extension to be used for testing purposes in phpBB Development.",
+ "version": "1.0.0",
+ "time": "2012-02-15 01:01:01",
+ "license": "GNU GPL v2",
+ "authors": [{
+ "name": "John Smith",
+ "username": "JohnSmith27",
+ "email": "email@phpbb.com",
+ "homepage": "http://phpbb.com",
+ "role": "N/A"
+ }],
+ "require": {
+ "php": ">=5.4.7"
+ },
+ "extra": {
+ "display-name": "phpBB BarFoo Extension",
+ "soft-require": {
+ "phpbb/phpbb": "3.2.*@dev"
+ }
+ }
+}
diff --git a/tests/dbal/ext/foo/bar/ucp/ucp_test_info.php b/tests/dbal/ext/foo/bar/ucp/ucp_test_info.php
new file mode 100644
index 0000000000..d3489af832
--- /dev/null
+++ b/tests/dbal/ext/foo/bar/ucp/ucp_test_info.php
@@ -0,0 +1,37 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace foo\bar\ucp;
+
+class ucp_test_info
+{
+ public function module()
+ {
+ return array(
+ 'filename' => '\foo\bar\ucp\ucp_test_module',
+ 'title' => 'UCP_NEW_MODULE',
+ 'modes' => array(
+ 'mode_1' => array(
+ 'title' => 'UCP_NEW_MODULE_MODE_1',
+ 'auth' => '',
+ 'cat' => array('UCP_NEW_MODULE'),
+ ),
+ 'mode_2' => array(
+ 'title' => 'UCP_NEW_MODULE_MODE_2',
+ 'auth' => '',
+ 'cat' => array('UCP_NEW_MODULE'),
+ ),
+ ),
+ );
+ }
+}
diff --git a/tests/dbal/ext/foo/bar/ucp/ucp_test_module.php b/tests/dbal/ext/foo/bar/ucp/ucp_test_module.php
new file mode 100644
index 0000000000..b06b3238b6
--- /dev/null
+++ b/tests/dbal/ext/foo/bar/ucp/ucp_test_module.php
@@ -0,0 +1,25 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace foo\bar\ucp;
+
+class ucp_test_module
+{
+ var $u_action;
+
+ function main($id, $mode)
+ {
+ $this->tpl_name = 'foobar';
+ $this->page_title = 'Bertie';
+ }
+}
diff --git a/tests/dbal/fixtures/boolean_processor.xml b/tests/dbal/fixtures/boolean_processor.xml
new file mode 100644
index 0000000000..d31d679f45
--- /dev/null
+++ b/tests/dbal/fixtures/boolean_processor.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_banlist">
+ <column>ban_id</column>
+ <column>ban_userid</column>
+ <row>
+ <value>1</value>
+ <value>2</value>
+ </row>
+ </table>
+ <table name="phpbb_users">
+ <column>user_id</column>
+ <column>username</column>
+ <column>username_clean</column>
+ <column>user_permissions</column>
+ <column>user_sig</column>
+ <row>
+ <value>1</value>
+ <value>mass email</value>
+ <value>mass email</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>banned</value>
+ <value>banned</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>helper</value>
+ <value>helper</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>GroupBPal</value>
+ <value>groupbpal</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>GroupBPal2</value>
+ <value>groupBPal2</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>not in group</value>
+ <value>not in group</value>
+ <value></value>
+ <value></value>
+ </row>
+ </table>
+ <table name="phpbb_user_group">
+ <column>user_id</column>
+ <column>group_id</column>
+ <column>group_leader</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>2</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>2</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>1</value>
+ <value>2</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>2</value>
+ <value>2</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>2</value>
+ <value>2</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/dbal/migration/revert_table.php b/tests/dbal/migration/revert_table.php
new file mode 100644
index 0000000000..162421be85
--- /dev/null
+++ b/tests/dbal/migration/revert_table.php
@@ -0,0 +1,39 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_dbal_migration_revert_table extends \phpbb\db\migration\migration
+{
+ function update_schema()
+ {
+ return array(
+ 'add_tables' => array(
+ 'phpbb_foobar' => array(
+ 'COLUMNS' => array(
+ 'module_id' => array('UINT:3', NULL, 'auto_increment'),
+ 'bar_column' => array('UINT', 1),
+ ),
+ 'PRIMARY_KEY' => 'module_id',
+ ),
+ ),
+ );
+ }
+
+ function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ 'phpbb_foobar',
+ ),
+ );
+ }
+}
diff --git a/tests/dbal/migration/revert_table_with_dependency.php b/tests/dbal/migration/revert_table_with_dependency.php
new file mode 100644
index 0000000000..f26ad076e6
--- /dev/null
+++ b/tests/dbal/migration/revert_table_with_dependency.php
@@ -0,0 +1,52 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_dbal_migration_revert_table_with_dependency extends \phpbb\db\migration\migration
+{
+ static public function depends_on()
+ {
+ return array('phpbb_dbal_migration_revert_table');
+ }
+
+ function update_schema()
+ {
+ return array(
+ 'add_columns' => array(
+ 'phpbb_foobar' => array(
+ 'baz_column' => array('UINT', 1),
+ ),
+ ),
+ 'drop_columns' => array(
+ 'phpbb_foobar' => array(
+ 'bar_column',
+ ),
+ ),
+ );
+ }
+
+ function revert_schema()
+ {
+ return array(
+ 'add_columns' => array(
+ 'phpbb_foobar' => array(
+ 'bar_column' => array('UINT', 1),
+ ),
+ ),
+ 'drop_columns' => array(
+ 'phpbb_foobar' => array(
+ 'baz_column',
+ ),
+ ),
+ );
+ }
+}
diff --git a/tests/dbal/migrator_test.php b/tests/dbal/migrator_test.php
index 798200eef1..372b2dbe1e 100644
--- a/tests/dbal/migrator_test.php
+++ b/tests/dbal/migrator_test.php
@@ -11,23 +11,32 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/migration/dummy.php';
require_once dirname(__FILE__) . '/migration/unfulfillable.php';
require_once dirname(__FILE__) . '/migration/if.php';
require_once dirname(__FILE__) . '/migration/recall.php';
require_once dirname(__FILE__) . '/migration/revert.php';
require_once dirname(__FILE__) . '/migration/revert_with_dependency.php';
+require_once dirname(__FILE__) . '/migration/revert_table.php';
+require_once dirname(__FILE__) . '/migration/revert_table_with_dependency.php';
require_once dirname(__FILE__) . '/migration/fail.php';
require_once dirname(__FILE__) . '/migration/installed.php';
require_once dirname(__FILE__) . '/migration/schema.php';
class phpbb_dbal_migrator_test extends phpbb_database_test_case
{
+ /** @var \phpbb\db\driver\driver_interface */
protected $db;
+
+ /** @var \phpbb\db\tools\tools_interface */
protected $db_tools;
+
+ /** @var \phpbb\db\migrator */
protected $migrator;
+ /** @var \phpbb\config\config */
+ protected $config;
+
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/migrator.xml');
@@ -38,7 +47,8 @@ class phpbb_dbal_migrator_test extends phpbb_database_test_case
parent::setUp();
$this->db = $this->new_dbal();
- $this->db_tools = new \phpbb\db\tools($this->db);
+ $factory = new \phpbb\db\tools\factory();
+ $this->db_tools = $factory->get($this->db);
$this->config = new \phpbb\config\db($this->db, new phpbb_mock_cache, 'phpbb_config');
@@ -62,14 +72,12 @@ class phpbb_dbal_migrator_test extends phpbb_database_test_case
);
$container->set('migrator', $this->migrator);
$container->set('dispatcher', new phpbb_mock_event_dispatcher());
- $user = new \phpbb\user('\phpbb\datetime');
$this->extension_manager = new \phpbb\extension\manager(
$container,
$this->db,
$this->config,
- new phpbb\filesystem(),
- $user,
+ new phpbb\filesystem\filesystem(),
'phpbb_ext',
dirname(__FILE__) . '/../../phpBB/',
'php',
@@ -243,6 +251,41 @@ class phpbb_dbal_migrator_test extends phpbb_database_test_case
$this->assertEquals(1, $migrator_test_revert_counter, 'Revert did call custom function again');
}
+ public function test_revert_table()
+ {
+ // Make sure there are no other migrations in the db, this could cause issues
+ $this->db->sql_query("DELETE FROM phpbb_migrations");
+ $this->migrator->load_migration_state();
+
+ $this->migrator->set_migrations(array('phpbb_dbal_migration_revert_table', 'phpbb_dbal_migration_revert_table_with_dependency'));
+
+ $this->assertFalse($this->migrator->migration_state('phpbb_dbal_migration_revert_table'));
+ $this->assertFalse($this->migrator->migration_state('phpbb_dbal_migration_revert_table_with_dependency'));
+
+ // Install the migration first
+ while (!$this->migrator->finished())
+ {
+ $this->migrator->update();
+ }
+
+ $this->assertTrue($this->migrator->migration_state('phpbb_dbal_migration_revert_table') !== false);
+ $this->assertTrue($this->migrator->migration_state('phpbb_dbal_migration_revert_table_with_dependency') !== false);
+
+ $this->assertTrue($this->db_tools->sql_column_exists('phpbb_foobar', 'baz_column'));
+ $this->assertFalse($this->db_tools->sql_column_exists('phpbb_foobar', 'bar_column'));
+
+ // Revert migrations
+ while ($this->migrator->migration_state('phpbb_dbal_migration_revert_table') !== false)
+ {
+ $this->migrator->revert('phpbb_dbal_migration_revert_table');
+ }
+
+ $this->assertFalse($this->migrator->migration_state('phpbb_dbal_migration_revert_table'));
+ $this->assertFalse($this->migrator->migration_state('phpbb_dbal_migration_revert_table_with_dependency'));
+
+ $this->assertFalse($this->db_tools->sql_table_exists('phpbb_foobar'));
+ }
+
public function test_fail()
{
$this->migrator->set_migrations(array('phpbb_dbal_migration_fail'));
diff --git a/tests/dbal/migrator_tool_module_test.php b/tests/dbal/migrator_tool_module_test.php
index bbe543f347..e34ee7b59c 100644
--- a/tests/dbal/migrator_tool_module_test.php
+++ b/tests/dbal/migrator_tool_module_test.php
@@ -11,7 +11,8 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
+require_once dirname(__FILE__) . '/ext/foo/bar/acp/acp_test_info.php';
+require_once dirname(__FILE__) . '/ext/foo/bar/ucp/ucp_test_info.php';
class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
{
@@ -27,19 +28,27 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
parent::setup();
- // Force add_log function to not be used
+ // Disable the logs
$skip_add_log = true;
$db = $this->db = $this->new_dbal();
- $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\null(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx);
- $user = $this->user = new \phpbb\user('\phpbb\user');
+ $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\dummy(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx);
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = $this->user = new \phpbb\user($lang, '\phpbb\datetime');
$cache = new phpbb_mock_cache;
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$auth = $this->getMock('\phpbb\auth\auth');
$phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE);
- $this->tool = new \phpbb\db\migration\tool\module($this->db, $this->cache, $this->user, $phpbb_root_path, $phpEx, 'phpbb_modules');
+ // Correctly set the root path for this test to this directory, so the classes can be found
+ $phpbb_root_path = dirname(__FILE__) . '/';
+
+ $phpbb_extension_manager = new phpbb_mock_extension_manager($phpbb_root_path);
+ $module_manager = new \phpbb\module\module_manager($cache, $this->db, $phpbb_extension_manager, MODULES_TABLE, $phpbb_root_path, $phpEx);
+
+ $this->tool = new \phpbb\db\migration\tool\module($this->db, $this->cache, $this->user, $module_manager, $phpbb_root_path, $phpEx, 'phpbb_modules');
}
public function exists_data_acp()
@@ -49,11 +58,39 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
array(
'',
'ACP_CAT',
+ false,
true,
),
array(
0,
'ACP_CAT',
+ false,
+ true,
+ ),
+ array(
+ false,
+ 'ACP_CAT',
+ false,
+ true,
+ ),
+
+ // Test the existing category lazily
+ array(
+ '',
+ 'ACP_CAT',
+ true,
+ true,
+ ),
+ array(
+ 0,
+ 'ACP_CAT',
+ true,
+ true,
+ ),
+ array(
+ false,
+ 'ACP_CAT',
+ true,
true,
),
@@ -62,16 +99,39 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
'',
'ACP_MODULE',
false,
+ false,
+ ),
+ array(
+ false,
+ 'ACP_MODULE',
+ false,
+ true,
+ ),
+ array(
+ 'ACP_CAT',
+ 'ACP_MODULE',
+ false,
+ true,
+ ),
+
+ // Test the existing module lazily
+ array(
+ '',
+ 'ACP_MODULE',
+ true,
+ false,
),
array(
false,
'ACP_MODULE',
true,
+ true,
),
array(
'ACP_CAT',
'ACP_MODULE',
true,
+ true,
),
// Test for non-existant modules
@@ -79,10 +139,38 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
'',
'ACP_NON_EXISTANT_CAT',
false,
+ false,
+ ),
+ array(
+ false,
+ 'ACP_NON_EXISTANT_CAT',
+ false,
+ false,
+ ),
+ array(
+ 'ACP_CAT',
+ 'ACP_NON_EXISTANT_MODULE',
+ false,
+ false,
+ ),
+
+ // Test for non-existant modules lazily
+ array(
+ '',
+ 'ACP_NON_EXISTANT_CAT',
+ true,
+ false,
+ ),
+ array(
+ false,
+ 'ACP_NON_EXISTANT_CAT',
+ true,
+ false,
),
array(
'ACP_CAT',
'ACP_NON_EXISTANT_MODULE',
+ true,
false,
),
);
@@ -91,9 +179,9 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
/**
* @dataProvider exists_data_acp
*/
- public function test_exists_acp($parent, $module, $expected)
+ public function test_exists_acp($parent, $module, $lazy, $expected)
{
- $this->assertEquals($expected, $this->tool->exists('acp', $parent, $module));
+ $this->assertEquals($expected, $this->tool->exists('acp', $parent, $module, $lazy));
}
public function exists_data_ucp()
@@ -103,12 +191,40 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
array(
'',
'UCP_MAIN_CAT',
+ false,
+ true,
+ ),
+ array(
+ 0,
+ 'UCP_MAIN_CAT',
+ false,
+ true,
+ ),
+ array(
+ false,
+ 'UCP_MAIN_CAT',
+ false,
+ true,
+ ),
+
+ // Test the existing category lazily
+ array(
+ '',
+ 'UCP_MAIN_CAT',
+ true,
true,
),
array(
0,
'UCP_MAIN_CAT',
true,
+ true,
+ ),
+ array(
+ false,
+ 'UCP_MAIN_CAT',
+ true,
+ true,
),
// Test the existing module
@@ -116,21 +232,51 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
'',
'UCP_SUBCATEGORY',
false,
+ false,
+ ),
+ array(
+ false,
+ 'UCP_SUBCATEGORY',
+ false,
+ true,
+ ),
+ array(
+ 'UCP_MAIN_CAT',
+ 'UCP_SUBCATEGORY',
+ false,
+ true,
+ ),
+ array(
+ 'UCP_SUBCATEGORY',
+ 'UCP_MODULE',
+ false,
+ true,
+ ),
+
+ // Test the existing module lazily
+ array(
+ '',
+ 'UCP_SUBCATEGORY',
+ true,
+ false,
),
array(
false,
'UCP_SUBCATEGORY',
true,
+ true,
),
array(
'UCP_MAIN_CAT',
'UCP_SUBCATEGORY',
true,
+ true,
),
array(
'UCP_SUBCATEGORY',
'UCP_MODULE',
true,
+ true,
),
// Test for non-existant modules
@@ -138,10 +284,26 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
'',
'UCP_NON_EXISTANT_CAT',
false,
+ false,
+ ),
+ array(
+ 'UCP_MAIN_CAT',
+ 'UCP_NON_EXISTANT_MODULE',
+ false,
+ false,
+ ),
+
+ // Test for non-existant modules lazily
+ array(
+ '',
+ 'UCP_NON_EXISTANT_CAT',
+ true,
+ false,
),
array(
'UCP_MAIN_CAT',
'UCP_NON_EXISTANT_MODULE',
+ true,
false,
),
);
@@ -150,9 +312,9 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
/**
* @dataProvider exists_data_ucp
*/
- public function test_exists_ucp($parent, $module, $expected)
+ public function test_exists_ucp($parent, $module, $lazy, $expected)
{
- $this->assertEquals($expected, $this->tool->exists('ucp', $parent, $module));
+ $this->assertEquals($expected, $this->tool->exists('ucp', $parent, $module, $lazy));
}
public function test_add()
@@ -192,25 +354,6 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
// Test adding module when plural parent module_langname exists
// PHPBB3-14703
- // Adding fail
- try
- {
- $this->tool->add('acp', 'ACP_FORUM_BASED_PERMISSIONS', array(
- 'module_basename' => 'acp_new_permissions_module',
- 'module_langname' => 'ACP_NEW_PERMISSIONS_MODULE',
- 'module_mode' => 'test',
- 'module_auth' => '',
- ));
- $this->fail('Exception not thrown');
- }
- catch (Exception $e)
- {
- $this->assertEquals('phpbb\db\migration\exception', get_class($e));
- $this->assertEquals('MODULE_EXIST_MULTIPLE', $e->getMessage());
- }
-
- // Test adding module when plural parent module_langname exists
- // PHPBB3-14703
// Adding success
try
{
@@ -266,6 +409,35 @@ class phpbb_dbal_migrator_tool_module_test extends phpbb_database_test_case
$this->fail($e);
}
$this->assertEquals(true, $this->tool->exists('ucp', 'UCP_NEW_SUBCAT', 'UCP_NEW_MODULE'));
+
+ // Test adding new UCP module the automatic way, single mode
+ try
+ {
+ $this->tool->add('ucp', 'UCP_NEW_CAT', array(
+ 'module_basename' => '\foo\bar\ucp\ucp_test_module',
+ 'modes' => array('mode_1'),
+ ));
+ }
+ catch (Exception $e)
+ {
+ $this->fail($e);
+ }
+ $this->assertEquals(true, $this->tool->exists('ucp', 'UCP_NEW_CAT', 'UCP_NEW_MODULE_MODE_1'));
+ $this->assertEquals(false, $this->tool->exists('ucp', 'UCP_NEW_CAT', 'UCP_NEW_MODULE_MODE_2'));
+
+ // Test adding new ACP module the automatic way, all modes
+ try
+ {
+ $this->tool->add('acp', 'ACP_NEW_CAT', array(
+ 'module_basename' => '\foo\bar\acp\acp_test_module',
+ ));
+ }
+ catch (Exception $e)
+ {
+ $this->fail($e);
+ }
+ $this->assertEquals(true, $this->tool->exists('acp', 'ACP_NEW_CAT', 'ACP_NEW_MODULE_MODE_1'));
+ $this->assertEquals(true, $this->tool->exists('acp', 'ACP_NEW_CAT', 'ACP_NEW_MODULE_MODE_2'));
}
public function test_remove()
diff --git a/tests/dbal/migrator_tool_permission_test.php b/tests/dbal/migrator_tool_permission_test.php
index 2d673864f7..ccad6a1387 100644
--- a/tests/dbal/migrator_tool_permission_test.php
+++ b/tests/dbal/migrator_tool_permission_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_dbal_migrator_tool_permission_test extends phpbb_database_test_case
{
public $group_ids = array(
@@ -34,7 +32,7 @@ class phpbb_dbal_migrator_tool_permission_test extends phpbb_database_test_case
parent::setup();
$db = $this->db = $this->new_dbal();
- $cache = $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\null(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx);
+ $cache = $this->cache = new \phpbb\cache\service(new \phpbb\cache\driver\dummy(), new \phpbb\config\config(array()), $this->db, $phpbb_root_path, $phpEx);
$this->auth = new \phpbb\auth\auth();
$this->tool = new \phpbb\db\migration\tool\permission($this->db, $this->cache, $this->auth, $phpbb_root_path, $phpEx);
@@ -165,7 +163,7 @@ class phpbb_dbal_migrator_tool_permission_test extends phpbb_database_test_case
$this->assertFalse($this->tool->exists('global_test', true));
}
- public function test_permission_set_data()
+ public function data_test_permission_set()
{
return array(
array(
@@ -190,7 +188,7 @@ class phpbb_dbal_migrator_tool_permission_test extends phpbb_database_test_case
}
/**
- * @dataProvider test_permission_set_data
+ * @dataProvider data_test_permission_set
*/
public function test_permission_set($group_name, $auth_option, $type, $has_permission)
{
diff --git a/tests/dbal/schema_test.php b/tests/dbal/schema_test.php
index f13c7ce032..59965655ad 100644
--- a/tests/dbal/schema_test.php
+++ b/tests/dbal/schema_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_dbal_schema_test extends phpbb_database_test_case
{
public function getDataSet()
diff --git a/tests/dbal/select_test.php b/tests/dbal/select_test.php
index b7074552ba..0dac66fc46 100644
--- a/tests/dbal/select_test.php
+++ b/tests/dbal/select_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_dbal_select_test extends phpbb_database_test_case
{
public function getDataSet()
diff --git a/tests/dbal/write_sequence_test.php b/tests/dbal/write_sequence_test.php
index a1b589c578..a2d5921797 100644
--- a/tests/dbal/write_sequence_test.php
+++ b/tests/dbal/write_sequence_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_dbal_write_sequence_test extends phpbb_database_test_case
{
public function getDataSet()
diff --git a/tests/dbal/write_test.php b/tests/dbal/write_test.php
index 2426f2b0be..4fa5cc37a2 100644
--- a/tests/dbal/write_test.php
+++ b/tests/dbal/write_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_dbal_write_test extends phpbb_database_test_case
{
public function getDataSet()
@@ -69,7 +67,7 @@ class phpbb_dbal_write_test extends phpbb_database_test_case
$result = $db->sql_query($sql);
$rows = $db->sql_fetchrowset($result);
- $this->assertEquals(1, sizeof($rows));
+ $this->assertEquals(1, count($rows));
$this->assertEquals('config2', $rows[0]['config_name']);
$db->sql_freeresult($result);
diff --git a/tests/di/create_container_test.php b/tests/di/create_container_test.php
index 1a7eb4698c..1fd2cbd7ee 100644
--- a/tests/di/create_container_test.php
+++ b/tests/di/create_container_test.php
@@ -13,7 +13,7 @@
namespace
{
- require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
+ require_once dirname(__FILE__) . '/fixtures/ext/vendor/enabled_4/di/extension.php';
class phpbb_di_container_test extends \phpbb_test_case
{
@@ -30,7 +30,8 @@ namespace
{
$this->phpbb_root_path = dirname(__FILE__) . '/';
$this->config_php = new \phpbb\config_php_file($this->phpbb_root_path . 'fixtures/', 'php');
- $this->builder = new phpbb_mock_phpbb_di_container_builder($this->config_php, $this->phpbb_root_path . 'fixtures/', 'php');
+ $this->builder = new phpbb_mock_phpbb_di_container_builder($this->phpbb_root_path . 'fixtures/', 'php');
+ $this->builder->with_config($this->config_php);
$this->filename = $this->phpbb_root_path . '../tmp/container.php';
if (is_file($this->filename))
@@ -45,6 +46,7 @@ namespace
{
$container = $this->builder->get_container();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container);
+ $this->assertFalse($container->hasParameter('container_exception'));
// Checks the core services
$this->assertTrue($container->hasParameter('core'));
@@ -57,6 +59,9 @@ namespace
// Checks use_extensions
$this->assertTrue($container->hasParameter('enabled'));
+ $this->assertTrue($container->hasParameter('enabled_2'));
+ $this->assertTrue($container->hasParameter('enabled_3'));
+ $this->assertTrue($container->hasParameter('enabled_4'));
$this->assertFalse($container->hasParameter('disabled'));
$this->assertFalse($container->hasParameter('available'));
@@ -69,14 +74,12 @@ namespace
// Checks the construction of a dumped container
$container = $this->builder->get_container();
$this->assertInstanceOf('phpbb_cache_container', $container);
- $this->assertFalse($container->isFrozen());
- $container->getParameterBag(); // needed, otherwise the container is not marked as frozen
$this->assertTrue($container->isFrozen());
}
- public function test_dump_container()
+ public function test_without_cache()
{
- $this->builder->set_dump_container(false);
+ $this->builder->without_cache();
$container = $this->builder->get_container();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container);
@@ -90,9 +93,9 @@ namespace
$this->assertTrue($container->isFrozen());
}
- public function test_use_extensions()
+ public function test_without_extensions()
{
- $this->builder->set_use_extensions(false);
+ $this->builder->without_extensions();
$container = $this->builder->get_container();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container);
@@ -105,9 +108,9 @@ namespace
$this->assertFalse($container->hasParameter('available'));
}
- public function test_compile_container()
+ public function test_without_compiled_container()
{
- $this->builder->set_compile_container(false);
+ $this->builder->without_compiled_container();
$container = $this->builder->get_container();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container);
@@ -115,19 +118,9 @@ namespace
$this->assertFalse($container->isFrozen());
}
- public function test_inject_config()
- {
- $this->builder->set_inject_config(false);
- $container = $this->builder->get_container();
- $this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container);
-
- // Checks inject_config
- $this->assertFalse($container->hasParameter('dbal.dbhost'));
- }
-
- public function test_set_config_path()
+ public function test_with_config_path()
{
- $this->builder->set_config_path($this->phpbb_root_path . 'fixtures/other_config/');
+ $this->builder->with_config_path($this->phpbb_root_path . 'fixtures/other_config/');
$container = $this->builder->get_container();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container);
@@ -135,70 +128,32 @@ namespace
$this->assertFalse($container->hasParameter('core'));
}
- public function test_set_custom_parameters()
+ public function test_with_custom_parameters()
{
- $this->builder->set_custom_parameters(array('my_parameter' => true));
+ $this->builder->with_custom_parameters(array('my_parameter' => true));
$container = $this->builder->get_container();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerBuilder', $container);
$this->assertTrue($container->hasParameter('my_parameter'));
- $this->assertFalse($container->hasParameter('core.root_path'));
}
}
}
-namespace phpbb\db\driver
+namespace phpbb\extension
{
- class container_mock extends \phpbb\db\driver\driver
+ class manager_mock extends \phpbb\extension\manager
{
- public function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- }
-
- public function sql_query($query = '', $cache_ttl = 0)
- {
- }
-
- public function sql_fetchrow($query_id = false)
- {
- }
-
- public function sql_freeresult($query_id = false)
- {
- }
-
- function sql_server_info($raw = false, $use_cache = true)
- {
- }
-
- function sql_affectedrows()
- {
- }
-
- function sql_rowseek($rownum, &$query_id)
- {
- }
-
- function sql_nextid()
- {
- }
-
- function sql_escape($msg)
- {
- }
-
- function sql_like_expression($expression)
- {
- }
-
- function sql_not_like_expression($expression)
+ public function __construct()
{
}
- function sql_fetchrowset($query_id = false)
+ public function all_enabled($phpbb_relative = true)
{
return array(
- array('ext_name' => 'vendor/enabled'),
+ 'vendor/enabled' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled/',
+ 'vendor/enabled-2' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled-2/',
+ 'vendor/enabled-3' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled-3/',
+ 'vendor/enabled_4' => dirname(__FILE__) . '/fixtures/ext/vendor/enabled_4/',
);
}
}
diff --git a/tests/di/fixtures/config.php b/tests/di/fixtures/config.php
index 04e20f63d8..1e9207d924 100644
--- a/tests/di/fixtures/config.php
+++ b/tests/di/fixtures/config.php
@@ -1,11 +1,11 @@
<?php
// phpBB 3.1.x auto-generated configuration file
// Do not change anything in this file!
-$dbms = 'container_mock';
+$dbms = 'mysql';
$dbhost = '127.0.0.1';
$dbport = '';
$dbname = 'phpbb';
$dbuser = 'root';
$dbpasswd = '';
$table_prefix = 'phpbb_';
-$acm_type = '\phpbb\cache\driver\null';
+$acm_type = '\phpbb\cache\driver\dummy';
diff --git a/tests/di/fixtures/config/production/config.yml b/tests/di/fixtures/config/production/config.yml
new file mode 100644
index 0000000000..fcfa84f68b
--- /dev/null
+++ b/tests/di/fixtures/config/production/config.yml
@@ -0,0 +1,2 @@
+core:
+ require_dev_dependencies: true
diff --git a/tests/di/fixtures/config/production/container/environment.yml b/tests/di/fixtures/config/production/container/environment.yml
new file mode 100644
index 0000000000..8281d9e941
--- /dev/null
+++ b/tests/di/fixtures/config/production/container/environment.yml
@@ -0,0 +1,32 @@
+parameters:
+ core: true
+
+services:
+ config.php:
+ synthetic: true
+
+ dbal.conn:
+ class: phpbb\db\driver\factory
+ arguments:
+ - '@service_container'
+
+ dbal.conn.driver:
+ synthetic: true
+
+ dispatcher:
+ class: phpbb\db\driver\container_mock
+
+ ext.manager:
+ class: phpbb\extension\manager_mock
+
+ template.twig.environment:
+ class: Exception
+ arguments:
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - []
diff --git a/tests/di/fixtures/config/services.yml b/tests/di/fixtures/config/services.yml
deleted file mode 100644
index 913a2603c9..0000000000
--- a/tests/di/fixtures/config/services.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-parameters:
- core: true
-
-services:
- config.php:
- synthetic: true
-
- dbal.conn:
- class: phpbb\db\driver\factory
- arguments:
- - @service_container
-
- dbal.conn.driver:
- synthetic: true
-
- dispatcher:
- class: phpbb\db\driver\container_mock
diff --git a/tests/di/fixtures/config/test/config.yml b/tests/di/fixtures/config/test/config.yml
new file mode 100644
index 0000000000..fcfa84f68b
--- /dev/null
+++ b/tests/di/fixtures/config/test/config.yml
@@ -0,0 +1,2 @@
+core:
+ require_dev_dependencies: true
diff --git a/tests/di/fixtures/config/test/container/environment.yml b/tests/di/fixtures/config/test/container/environment.yml
new file mode 100644
index 0000000000..252117dd32
--- /dev/null
+++ b/tests/di/fixtures/config/test/container/environment.yml
@@ -0,0 +1,29 @@
+parameters:
+ core: true
+
+services:
+ config.php:
+ synthetic: true
+
+ dbal.conn:
+ class: phpbb\db\driver\factory
+ arguments:
+ - '@service_container'
+
+ dbal.conn.driver:
+ synthetic: true
+
+ dispatcher:
+ class: phpbb\db\driver\container_mock
+
+ template.twig.environment:
+ class: Exception
+ arguments:
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - []
diff --git a/tests/di/fixtures/ext/vendor/disabled/config/services.yml b/tests/di/fixtures/ext/vendor/disabled/config/test/container/environment.yml
index 31ada384bf..31ada384bf 100644
--- a/tests/di/fixtures/ext/vendor/disabled/config/services.yml
+++ b/tests/di/fixtures/ext/vendor/disabled/config/test/container/environment.yml
diff --git a/tests/di/fixtures/ext/vendor/enabled-2/config/test/container/environment.yml b/tests/di/fixtures/ext/vendor/enabled-2/config/test/container/environment.yml
new file mode 100644
index 0000000000..feeb5a7a2d
--- /dev/null
+++ b/tests/di/fixtures/ext/vendor/enabled-2/config/test/container/environment.yml
@@ -0,0 +1,2 @@
+parameters:
+ enabled_2: true
diff --git a/tests/di/fixtures/ext/vendor/enabled-3/config/services.yml b/tests/di/fixtures/ext/vendor/enabled-3/config/services.yml
new file mode 100644
index 0000000000..0dae35d2bd
--- /dev/null
+++ b/tests/di/fixtures/ext/vendor/enabled-3/config/services.yml
@@ -0,0 +1,2 @@
+parameters:
+ enabled_3: true
diff --git a/tests/di/fixtures/ext/vendor/enabled/config/services.yml b/tests/di/fixtures/ext/vendor/enabled/config/default/container/environment.yml
index 88a7919ed1..88a7919ed1 100644
--- a/tests/di/fixtures/ext/vendor/enabled/config/services.yml
+++ b/tests/di/fixtures/ext/vendor/enabled/config/default/container/environment.yml
diff --git a/tests/di/fixtures/ext/vendor/enabled_4/di/extension.php b/tests/di/fixtures/ext/vendor/enabled_4/di/extension.php
new file mode 100644
index 0000000000..8e5ed6c52c
--- /dev/null
+++ b/tests/di/fixtures/ext/vendor/enabled_4/di/extension.php
@@ -0,0 +1,32 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+namespace vendor\enabled_4\di;
+
+use phpbb\extension\di\extension_base;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
+
+/**
+* Container core extension
+*/
+class extension extends extension_base
+{
+ protected function load_services(ContainerBuilder $container)
+ {
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $loader = new YamlFileLoader($container, new FileLocator($filesystem->realpath($this->ext_path)));
+ $loader->load('environment.yml');
+ }
+}
diff --git a/tests/di/fixtures/ext/vendor/enabled_4/environment.yml b/tests/di/fixtures/ext/vendor/enabled_4/environment.yml
new file mode 100644
index 0000000000..d0affe4fd6
--- /dev/null
+++ b/tests/di/fixtures/ext/vendor/enabled_4/environment.yml
@@ -0,0 +1,2 @@
+parameters:
+ enabled_4: true
diff --git a/tests/di/fixtures/other_config/production/config.yml b/tests/di/fixtures/other_config/production/config.yml
new file mode 100644
index 0000000000..fcfa84f68b
--- /dev/null
+++ b/tests/di/fixtures/other_config/production/config.yml
@@ -0,0 +1,2 @@
+core:
+ require_dev_dependencies: true
diff --git a/tests/di/fixtures/other_config/production/container/environment.yml b/tests/di/fixtures/other_config/production/container/environment.yml
new file mode 100644
index 0000000000..c0d2f87bab
--- /dev/null
+++ b/tests/di/fixtures/other_config/production/container/environment.yml
@@ -0,0 +1,32 @@
+parameters:
+ other_config: true
+
+services:
+ config.php:
+ synthetic: true
+
+ dbal.conn:
+ class: phpbb\db\driver\factory
+ arguments:
+ - '@service_container'
+
+ dbal.conn.driver:
+ synthetic: true
+
+ dispatcher:
+ class: phpbb\db\driver\container_mock
+
+ ext.manager:
+ class: phpbb\extension\manager_mock
+
+ template.twig.environment:
+ class: Exception
+ arguments:
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - []
diff --git a/tests/di/fixtures/other_config/services.yml b/tests/di/fixtures/other_config/services.yml
deleted file mode 100644
index d6246d3bc0..0000000000
--- a/tests/di/fixtures/other_config/services.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-parameters:
- other_config: true
-
-services:
- config.php:
- synthetic: true
-
- dbal.conn:
- class: phpbb\db\driver\factory
- arguments:
- - @service_container
-
- dbal.conn.driver:
- synthetic: true
-
- dispatcher:
- class: phpbb\db\driver\container_mock
diff --git a/tests/di/fixtures/other_config/test/config.yml b/tests/di/fixtures/other_config/test/config.yml
new file mode 100644
index 0000000000..fcfa84f68b
--- /dev/null
+++ b/tests/di/fixtures/other_config/test/config.yml
@@ -0,0 +1,2 @@
+core:
+ require_dev_dependencies: true
diff --git a/tests/di/fixtures/other_config/test/container/environment.yml b/tests/di/fixtures/other_config/test/container/environment.yml
new file mode 100644
index 0000000000..b9f6d05018
--- /dev/null
+++ b/tests/di/fixtures/other_config/test/container/environment.yml
@@ -0,0 +1,29 @@
+parameters:
+ other_config: true
+
+services:
+ config.php:
+ synthetic: true
+
+ dbal.conn:
+ class: phpbb\db\driver\factory
+ arguments:
+ - '@service_container'
+
+ dbal.conn.driver:
+ synthetic: true
+
+ dispatcher:
+ class: phpbb\db\driver\container_mock
+
+ template.twig.environment:
+ class: Exception
+ arguments:
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - ~
+ - []
diff --git a/tests/di/ordered_service_collection_test.php b/tests/di/ordered_service_collection_test.php
new file mode 100644
index 0000000000..47e6d23744
--- /dev/null
+++ b/tests/di/ordered_service_collection_test.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_ordered_service_collection_test extends \phpbb_test_case
+{
+ /**
+ * @var \phpbb\di\ordered_service_collection
+ */
+ protected $service_collection;
+
+ public function setUp()
+ {
+ $container = new phpbb_mock_container_builder();
+ $container->set('foo', new StdClass);
+ $container->set('bar', new StdClass);
+ $container->set('foobar', new StdClass);
+ $container->set('barfoo', new StdClass);
+
+ $this->service_collection = new \phpbb\di\ordered_service_collection($container);
+ $this->service_collection->add('foo', 7);
+ $this->service_collection->add('bar', 3);
+ $this->service_collection->add('barfoo', 5);
+ $this->service_collection->add('foobar', 2);
+
+ parent::setUp();
+ }
+
+ public function test_service_collection()
+ {
+ $service_names = array();
+
+ // Test the iterator
+ foreach ($this->service_collection as $name => $service)
+ {
+ $service_names[] = $name;
+ $this->assertInstanceOf('StdClass', $service);
+ }
+
+ $this->assertSame(array('foobar', 'bar', 'barfoo', 'foo'), $service_names);
+ }
+}
diff --git a/tests/di/service_collection_test.php b/tests/di/service_collection_test.php
new file mode 100644
index 0000000000..5b51254a4a
--- /dev/null
+++ b/tests/di/service_collection_test.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_service_collection_test extends \phpbb_test_case
+{
+ /**
+ * @var \phpbb\di\service_collection
+ */
+ protected $service_collection;
+
+ public function setUp()
+ {
+ $container = new phpbb_mock_container_builder();
+ $container->set('foo', new StdClass);
+ $container->set('bar', new StdClass);
+
+ $this->service_collection = new \phpbb\di\service_collection($container);
+ $this->service_collection->add('foo');
+ $this->service_collection->add('bar');
+
+ parent::setUp();
+ }
+
+ public function test_service_collection()
+ {
+ $service_names = array();
+
+ // Test the iterator
+ foreach ($this->service_collection as $name => $service)
+ {
+ $service_names[] = $name;
+ $this->assertInstanceOf('StdClass', $service);
+ }
+
+ $this->assertSame(array('foo', 'bar'), $service_names);
+ }
+}
diff --git a/tests/download/http_byte_range_test.php b/tests/download/http_byte_range_test.php
index f920299048..8975ec1799 100644
--- a/tests/download/http_byte_range_test.php
+++ b/tests/download/http_byte_range_test.php
@@ -45,24 +45,72 @@ class phpbb_download_http_byte_range_test extends phpbb_test_case
public function parse_range_request_data()
{
return array(
- // Does not read until the end of file.
+ // Valid request
array(
array('3-4'),
10,
- false,
+ array(
+ 'byte_pos_start' => 3,
+ 'byte_pos_end' => 4,
+ 'bytes_requested' => 2,
+ 'bytes_total' => 10,
+ ),
),
- // Valid request, handle second range.
+ // Get the beginning
array(
- array('0-0', '120-125'),
- 125,
+ array('-5'),
+ 10,
array(
- 'byte_pos_start' => 120,
- 'byte_pos_end' => 124,
+ 'byte_pos_start' => 0,
+ 'byte_pos_end' => 5,
+ 'bytes_requested' => 6,
+ 'bytes_total' => 10,
+ ),
+ ),
+
+ // Get the end
+ array(
+ array('5-'),
+ 10,
+ array(
+ 'byte_pos_start' => 5,
+ 'byte_pos_end' => 9,
'bytes_requested' => 5,
+ 'bytes_total' => 10,
+ ),
+ ),
+
+ // Overlong request
+ array(
+ array('3-20'),
+ 10,
+ array(
+ 'byte_pos_start' => 3,
+ 'byte_pos_end' => 9,
+ 'bytes_requested' => 7,
+ 'bytes_total' => 10,
+ ),
+ ),
+
+ // Multiple, contiguous range
+ array(
+ array('10-20', '21-30'),
+ 125,
+ array(
+ 'byte_pos_start' => 10,
+ 'byte_pos_end' => 30,
+ 'bytes_requested' => 21,
'bytes_total' => 125,
)
),
+
+ // We don't do multiple, non-contiguous range
+ array(
+ array('0-0', '120-125'),
+ 125,
+ false,
+ ),
);
}
}
diff --git a/tests/email/email_parsing_test.php b/tests/email/email_parsing_test.php
new file mode 100644
index 0000000000..8fdfe3035e
--- /dev/null
+++ b/tests/email/email_parsing_test.php
@@ -0,0 +1,150 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_email_parsing_test extends phpbb_test_case
+{
+ /** @var \messenger */
+ protected $messenger;
+
+ /** @var \ReflectionProperty */
+ protected $reflection_template_property;
+
+ public function setUp()
+ {
+ global $phpbb_container, $config, $phpbb_root_path, $phpEx, $request, $user;
+
+ $phpbb_container = new phpbb_mock_container_builder;
+
+ $config = new \phpbb\config\config(array(
+ 'board_email_sig' => '-- Thanks, The Management',
+ 'sitename' => 'yourdomain.com',
+ 'default_lang' => 'en',
+ ));
+ $phpbb_container->set('config', $config);
+
+ $request = new phpbb_mock_request;
+ $symfony_request = new \phpbb\symfony_request(
+ $request
+ );
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $phpbb_path_helper = new \phpbb\path_helper(
+ $symfony_request,
+ $filesystem,
+ $request,
+ $phpbb_root_path,
+ $phpEx
+ );
+ $phpbb_container->set('path_helper', $phpbb_path_helper);
+ $phpbb_container->set('filesystem', $filesystem);
+
+ $cache_path = $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/twig';
+ $phpbb_container->setParameter('core.template.cache_path', $cache_path);
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $phpbb_container->set('user', $user);
+ $extension_manager = new phpbb_mock_extension_manager(
+ dirname(__FILE__) . '/',
+ array(
+ 'vendor2/foo' => array(
+ 'ext_name' => 'vendor2/foo',
+ 'ext_active' => '1',
+ 'ext_path' => 'ext/vendor2/foo/',
+ ),
+ )
+ );
+ $phpbb_container->set('ext.manager', $extension_manager);
+
+ $context = new \phpbb\template\context();
+ $twig_extension = new \phpbb\template\twig\extension($context, $lang);
+ $phpbb_container->set('template.twig.extensions.phpbb', $twig_extension);
+
+ $twig_extensions_collection = new \phpbb\di\service_collection($phpbb_container);
+ $twig_extensions_collection->add('template.twig.extensions.phpbb');
+ $phpbb_container->set('template.twig.extensions.collection', $twig_extensions_collection);
+
+ $twig = new \phpbb\template\twig\environment(
+ $config,
+ $filesystem,
+ $phpbb_path_helper,
+ $cache_path,
+ null,
+ new \phpbb\template\twig\loader($filesystem, ''),
+ new \phpbb\event\dispatcher($phpbb_container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
+ );
+ $twig->addExtension($twig_extension);
+ $phpbb_container->set('template.twig.lexer', new \phpbb\template\twig\lexer($twig));
+
+ if (!class_exists('messenger'))
+ {
+ include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
+ }
+
+ $this->messenger = new \messenger();
+
+ $reflection = new ReflectionObject($this->messenger);
+ $this->reflection_template_property = $reflection->getProperty('template');
+ $this->reflection_template_property->setAccessible(true);
+ }
+
+ public function email_parsing_data()
+ {
+ return array(
+ array('Author username', 'Any forum', 'The topic title', 'Dear user'),
+ array('0', 'Any forum', 'The topic title', 'Dear user'),
+ );
+ }
+
+ /**
+ * @dataProvider email_parsing_data
+ */
+ public function test_email_parsing($author_name, $forum_name, $topic_title, $username)
+ {
+ global $config, $phpEx, $user;
+
+ $this->messenger->set_addresses($user->data);
+
+ $this->messenger->assign_vars(array(
+ 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])),
+ 'SITENAME' => htmlspecialchars_decode($config['sitename']),
+
+ 'AUTHOR_NAME' => $author_name,
+ 'FORUM_NAME' => $forum_name,
+ 'TOPIC_TITLE' => $topic_title,
+ 'USERNAME' => $username,
+
+ 'U_FORUM' => generate_board_url() . "/viewforum.{$phpEx}?f=1",
+ 'U_STOP_WATCHING_FORUM' => generate_board_url() . "/viewforum.{$phpEx}?uid=2&f=1&unwatch=forum",
+ ));
+ $this->messenger->template('newtopic_notify', $user->data['user_lang'], '', '');
+
+ $reflection_template = $this->reflection_template_property->getValue($this->messenger);
+ $msg = trim($reflection_template->assign_display('body'));
+
+ $this->assertContains($author_name, $msg);
+ $this->assertContains($forum_name, $msg);
+ $this->assertContains($topic_title, $msg);
+ $this->assertContains($username, $msg);
+ $this->assertContains(htmlspecialchars_decode($config['sitename']), $msg);
+ $this->assertContains(str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])), $msg);
+ $this->assertNotContains('EMAIL_SIG', $msg);
+ $this->assertNotContains('U_STOP_WATCHING_FORUM', $msg);
+ }
+}
diff --git a/tests/error_collector_test.php b/tests/error_collector_test.php
index b92c4fa6bb..8ed89bbe52 100644
--- a/tests/error_collector_test.php
+++ b/tests/error_collector_test.php
@@ -11,10 +11,17 @@
*
*/
-require_once dirname(__FILE__) . '/../phpBB/includes/functions.php';
-
class phpbb_error_collector_test extends phpbb_test_case
{
+ public function setUp()
+ {
+ parent::setUp();
+
+ global $phpbb_filesystem;
+
+ $phpbb_filesystem = new \phpbb\filesystem\filesystem();
+ }
+
public function test_collection()
{
$collector = new \phpbb\error_collector(E_ALL | E_STRICT); // php set_error_handler() default
@@ -45,8 +52,8 @@ class phpbb_error_collector_test extends phpbb_test_case
1/0; $line = __LINE__;
// Cause a notice
- $array = array('ITEM' => 'value');
- $value = $array[ITEM]; $line2 = __LINE__;
+ $array = array(0 => 'value');
+ $value = $array[1]; $line2 = __LINE__;
$collector->uninstall();
diff --git a/tests/event/dispatcher_test.php b/tests/event/dispatcher_test.php
index 7bba5bf337..da28d24daa 100644
--- a/tests/event/dispatcher_test.php
+++ b/tests/event/dispatcher_test.php
@@ -29,5 +29,21 @@ class phpbb_event_dispatcher_test extends phpbb_test_case
$result = $dispatcher->trigger_event('core.test_event', compact($vars));
$this->assertSame(array('foo' => 'foo2', 'bar' => 'bar2'), $result);
+
+ // Test migrating events
+ $dispatcher->addListener('core.foo_br', function(\phpbb\event\data $event) {
+ $event['pi'] = '3.14159';
+ });
+ $dispatcher->addListener('core.foo_bar', function(\phpbb\event\data $event) {
+ $event['pi'] = '3.1';
+ });
+
+
+ $pi = '3';
+
+ $vars = array('pi');
+ $result = $dispatcher->trigger_event(['core.foo_bar', 'core.foo_br'], compact($vars));
+
+ $this->assertSame(array('pi' => '3.14159'), $result);
}
}
diff --git a/tests/event/exception_listener_test.php b/tests/event/exception_listener_test.php
index 4d3453cd83..08679a3ed8 100644
--- a/tests/event/exception_listener_test.php
+++ b/tests/event/exception_listener_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class exception_listener extends phpbb_test_case
{
public function phpbb_exception_data()
@@ -79,10 +77,12 @@ class exception_listener extends phpbb_test_case
->disableOriginalConstructor()
->getMock();
- $user = new \phpbb\user('\phpbb\datetime');
- $user->add_lang('common');
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
- $exception_listener = new \phpbb\event\kernel_exception_subscriber($template, $user);
+ $exception_listener = new \phpbb\event\kernel_exception_subscriber($template, $lang);
$event = new \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent($this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'), $request, \Symfony\Component\HttpKernel\HttpKernelInterface::MASTER_REQUEST, $exception);
$exception_listener->on_kernel_exception($event);
diff --git a/tests/event/fixtures/event_migration.test b/tests/event/fixtures/event_migration.test
new file mode 100644
index 0000000000..b2df9f95df
--- /dev/null
+++ b/tests/event/fixtures/event_migration.test
@@ -0,0 +1,30 @@
+<?php
+
+ /**
+ * Modify pm and sender data before it is assigned to the template
+ *
+ * @event core.ucp_pm_view_message
+ * @var mixed id Active module category (can be int or string)
+ * @var string mode Active module
+ * @var int folder_id ID of the folder the message is in
+ * @var int msg_id ID of the private message
+ * @var array folder Array with data of user's message folders
+ * @var array message_row Array with message data
+ * @var array cp_row Array with senders custom profile field data
+ * @var array msg_data Template array with message data
+ * @var array user_info User data of the sender
+ * @since 3.1.0-a1
+ * @changed 3.1.6-RC1 Added user_info into event
+ */
+ $vars = array(
+ 'id',
+ 'mode',
+ 'folder_id',
+ 'msg_id',
+ 'folder',
+ 'message_row',
+ 'cp_row',
+ 'msg_data',
+ 'user_info',
+ );
+ extract($phpbb_dispatcher->trigger_event(['core.ucp_pm_view_message', 'core.ucp_pm_view_messsage'], compact($vars)));
diff --git a/tests/event/fixtures/extra_description.test b/tests/event/fixtures/extra_description.test
index ce8f97ce89..e93a1044ac 100644
--- a/tests/event/fixtures/extra_description.test
+++ b/tests/event/fixtures/extra_description.test
@@ -3,7 +3,7 @@
/**
* Description
*
-* NOTE: This will not be exported
+* NOTE: This will also be exported
*
* @event extra_description.dispatch
* @since 3.1.0-b2
diff --git a/tests/event/md_exporter_test.php b/tests/event/md_exporter_test.php
index 1a51204cbe..2eeb48ea05 100644
--- a/tests/event/md_exporter_test.php
+++ b/tests/event/md_exporter_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_event_md_exporter_test extends phpbb_test_case
{
static public function crawl_eventsmd_data()
@@ -23,7 +21,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
'event' => 'acp_bbcodes_actions_append',
'files' => array(
'prosilver' => array(),
- 'subsilver2' => array(),
'adm' => array('acp_bbcodes.html'),
),
'since' => '3.1.0-a3',
@@ -36,7 +33,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
'event' => 'acp_bbcodes_actions_prepend',
'files' => array(
'prosilver' => array(),
- 'subsilver2' => array(),
'adm' => array('acp_bbcodes.html'),
),
'since' => '3.1.0-a5',
@@ -47,7 +43,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
'event' => 'acp_bbcodes_actions_prepend2',
'files' => array(
'prosilver' => array(),
- 'subsilver2' => array(),
'adm' => array('acp_bbcodes.html'),
),
'since' => '3.1.0-a4',
@@ -63,7 +58,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
'event' => 'acp_bbcodes_actions_prepend',
'files' => array(
'prosilver' => array(),
- 'subsilver2' => array(),
'adm' => array('acp_bbcodes.html'),
),
'since' => '3.1.0-a5',
@@ -74,7 +68,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
'event' => 'acp_bbcodes_actions_prepend2',
'files' => array(
'prosilver' => array(),
- 'subsilver2' => array(),
'adm' => array('acp_bbcodes.html'),
),
'since' => '3.1.0-a4',
@@ -99,7 +92,7 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
public function test_crawl_eventsmd($file, $min_version, $max_version, $events)
{
$exporter = new \phpbb\event\md_exporter(dirname(__FILE__) . '/fixtures/', null, $min_version, $max_version);
- $this->assertSame(sizeof($events), $exporter->crawl_eventsmd($file, 'adm'));
+ $this->assertSame(count($events), $exporter->crawl_eventsmd($file, 'adm'));
$this->assertEquals($events, $exporter->get_events());
}
@@ -130,7 +123,6 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
$styles = array(
'adm/style/' => 'adm',
'styles/prosilver/template/' => 'styles',
- 'styles/subsilver2/template/' => 'styles',
);
foreach ($styles as $path => $filter)
{
@@ -154,7 +146,7 @@ class phpbb_event_md_exporter_test extends phpbb_test_case
$exporter->crawl_eventsmd('docs/events.md', $filter);
$events = $exporter->crawl_file_for_events($file);
- $this->assertGreaterThanOrEqual(0, sizeof($events));
+ $this->assertGreaterThanOrEqual(0, count($events));
$this->assertTrue($exporter->validate_events_from_file($file, $events));
}
}
diff --git a/tests/event/php_exporter_test.php b/tests/event/php_exporter_test.php
index 692a57f93c..c6670e1340 100644
--- a/tests/event/php_exporter_test.php
+++ b/tests/event/php_exporter_test.php
@@ -38,6 +38,18 @@ class phpbb_event_php_exporter_test extends phpbb_test_case
),
),
array(
+ 'event_migration.test',
+ array(
+ 'core.ucp_pm_view_message' => array(
+ 'event' => 'core.ucp_pm_view_message',
+ 'file' => 'event_migration.test',
+ 'arguments' => array('cp_row', 'folder', 'folder_id', 'id', 'message_row', 'mode', 'msg_data', 'msg_id', 'user_info'),
+ 'since' => '3.1.0-a1',
+ 'description' => 'Modify pm and sender data before it is assigned to the template',
+ ),
+ ),
+ ),
+ array(
'extra_description.test',
array(
'extra_description.dispatch' => array(
@@ -45,7 +57,7 @@ class phpbb_event_php_exporter_test extends phpbb_test_case
'file' => 'extra_description.test',
'arguments' => array(),
'since' => '3.1.0-b2',
- 'description' => 'Description',
+ 'description' => 'Description<br/><br/>NOTE: This will also be exported',
),
),
),
@@ -240,6 +252,8 @@ class phpbb_event_php_exporter_test extends phpbb_test_case
array("\t\$phpbb_dispatcher->dispatch('dispatch.one2.thr_ee4');", 'dispatch.one2.thr_ee4'),
array("\$this->dispatcher->dispatch('dispatch.one2');", 'dispatch.one2'),
array("\$phpbb_dispatcher->dispatch('dis_patch.one');", 'dis_patch.one'),
+ array("\$phpbb_dispatcher->dispatch(['dis_patch.one', 'dis_patch.one2']);", 'dis_patch.one'),
+ array("\$phpbb_dispatcher->dispatch(['dis_patch.one', 'dis_patch.one2', 'dis_patch.two3']);", 'dis_patch.one'),
);
}
@@ -259,6 +273,8 @@ class phpbb_event_php_exporter_test extends phpbb_test_case
array("\$phpbb_dispatcher->dispatch('');"),
array("\$phpbb_dispatcher->dispatch('dispatch.2one');"),
array("\$phpbb_dispatcher->dispatch('dispatch');"),
+ array("\$phpbb_dispatcher->dispatch(['dispatch.one']);"),
+ array("\$phpbb_dispatcher->dispatch(array('dispatch.one', 'dispatch.one2'));"),
);
}
@@ -279,6 +295,8 @@ class phpbb_event_php_exporter_test extends phpbb_test_case
array("\textract(\$phpbb_dispatcher->trigger_event('dispatch.one2.thr_ee4', compact(\$vars)));", 'dispatch.one2.thr_ee4'),
array("extract(\$this->dispatcher->trigger_event('dispatch.one2', compact(\$vars)));", 'dispatch.one2'),
array("extract(\$phpbb_dispatcher->trigger_event('dis_patch.one', compact(\$vars)));", 'dis_patch.one'),
+ array("extract(\$phpbb_dispatcher->trigger_event(['dis_patch.one', 'dis_patch.one2'], compact(\$vars)));", 'dis_patch.one'),
+ array("extract(\$phpbb_dispatcher->trigger_event(['dis_patch.one', 'dis_patch.one2', 'dis_patch.two3'], compact(\$vars)));", 'dis_patch.one'),
);
}
@@ -301,6 +319,7 @@ class phpbb_event_php_exporter_test extends phpbb_test_case
array("extract(\$phpbb_dispatcher->trigger_event('dispatch.one', \$vars));"),
array("extract(\$phpbb_dispatcher->trigger_event('dispatch.one', compact(\$var)));"),
array("extract(\$phpbb_dispatcher->trigger_event('dispatch.one', compact(\$array)));"),
+ array("extract(\$phpbb_dispatcher->trigger_event(['dispatch.one'], compact(\$vars)));"),
array("\$phpbb_dispatcher->trigger_event('dis_patch.one', compact(\$vars));", 'dis_patch.one'),
);
}
diff --git a/tests/extension/ext/vendor2/bar/acp/a_info.php b/tests/extension/ext/vendor2/bar/acp/a_info.php
index 8132df587f..8268006f9f 100644
--- a/tests/extension/ext/vendor2/bar/acp/a_info.php
+++ b/tests/extension/ext/vendor2/bar/acp/a_info.php
@@ -9,7 +9,6 @@ class a_info
return array(
'filename' => 'vendor2\\bar\\acp\\a_module',
'title' => 'Bar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')),
),
diff --git a/tests/extension/ext/vendor2/bar/migrations/bar.php b/tests/extension/ext/vendor2/bar/migrations/bar.php
new file mode 100644
index 0000000000..ea5ddb6b8b
--- /dev/null
+++ b/tests/extension/ext/vendor2/bar/migrations/bar.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace vendor2\foo\migrations;
+
+class bar
+{
+}
diff --git a/tests/extension/ext/vendor2/bar/migrations/foo.php b/tests/extension/ext/vendor2/bar/migrations/foo.php
new file mode 100644
index 0000000000..d727c2f954
--- /dev/null
+++ b/tests/extension/ext/vendor2/bar/migrations/foo.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace vendor2\foo\migrations;
+
+class foo implements \phpbb\db\migration\migration_interface
+{
+ /**
+ * {@inheritdoc}
+ */
+ static public function depends_on()
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function effectively_installed()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function update_schema()
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function revert_schema()
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function update_data()
+ {
+ return array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function revert_data()
+ {
+ return array();
+ }
+}
diff --git a/tests/extension/ext/vendor2/foo/acp/a_info.php b/tests/extension/ext/vendor2/foo/acp/a_info.php
index e1eaa340b7..48ab4cf8e7 100644
--- a/tests/extension/ext/vendor2/foo/acp/a_info.php
+++ b/tests/extension/ext/vendor2/foo/acp/a_info.php
@@ -9,7 +9,6 @@ class a_info
return array(
'filename' => 'vendor2\\foo\\acp\\a_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array('ACP_MODS')),
),
diff --git a/tests/extension/ext/vendor2/foo/acp/fail_info.php b/tests/extension/ext/vendor2/foo/acp/fail_info.php
index d9b4353957..78479fee70 100644
--- a/tests/extension/ext/vendor2/foo/acp/fail_info.php
+++ b/tests/extension/ext/vendor2/foo/acp/fail_info.php
@@ -13,7 +13,6 @@ class foo_info
return array(
'filename' => 'vendor2\foo\acp\fail_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')),
),
diff --git a/tests/extension/ext/vendor2/foo/mcp/a_info.php b/tests/extension/ext/vendor2/foo/mcp/a_info.php
index b5599fde65..2532e44b12 100644
--- a/tests/extension/ext/vendor2/foo/mcp/a_info.php
+++ b/tests/extension/ext/vendor2/foo/mcp/a_info.php
@@ -9,7 +9,6 @@ class a_info
return array(
'filename' => 'vendor2\\foo\\mcp\\a_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')),
),
diff --git a/tests/extension/extension_base_test.php b/tests/extension/extension_base_test.php
index eee38186db..e0c2e6d549 100644
--- a/tests/extension/extension_base_test.php
+++ b/tests/extension/extension_base_test.php
@@ -10,7 +10,9 @@
* the docs/CREDITS.txt file.
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
+require_once dirname(__FILE__) . '/ext/vendor2/bar/migrations/bar.php';
+require_once dirname(__FILE__) . '/ext/vendor2/bar/migrations/foo.php';
+require_once dirname(__FILE__) . '/ext/vendor2/bar/migrations/migration.php';
class phpbb_extension_extension_base_test extends phpbb_test_case
{
@@ -61,9 +63,7 @@ class phpbb_extension_extension_base_test extends phpbb_test_case
return array(
array(
'vendor2/bar',
- array(
- '\vendor2\bar\migrations\migration',
- ),
+ array('\vendor2\bar\migrations\migration'),
),
);
}
@@ -74,6 +74,8 @@ class phpbb_extension_extension_base_test extends phpbb_test_case
public function test_suffix_get_classes($extension_name, $expected)
{
$extension = $this->extension_manager->get_extension($extension_name);
- $this->assertEquals($expected, self::$reflection_method_get_migration_file_list->invoke($extension));
+ $migration_classes = self::$reflection_method_get_migration_file_list->invoke($extension);
+ sort($migration_classes);
+ $this->assertEquals($expected, $migration_classes);
}
}
diff --git a/tests/extension/finder_test.php b/tests/extension/finder_test.php
index 2116cc057b..71de2c2fc5 100644
--- a/tests/extension/finder_test.php
+++ b/tests/extension/finder_test.php
@@ -10,7 +10,6 @@
* the docs/CREDITS.txt file.
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_extension_finder_test extends phpbb_test_case
{
@@ -244,7 +243,7 @@ class phpbb_extension_finder_test extends phpbb_test_case
public function test_get_classes_create_cache()
{
$cache = new phpbb_mock_cache;
- $finder = new \phpbb\finder(new \phpbb\filesystem(), dirname(__FILE__) . '/', $cache, 'php', '_custom_cache_name');
+ $finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), dirname(__FILE__) . '/', $cache, 'php', '_custom_cache_name');
$finder->set_extensions(array_keys($this->extension_manager->all_enabled()));
$files = $finder->suffix('_class.php')->get_files();
@@ -284,7 +283,7 @@ class phpbb_extension_finder_test extends phpbb_test_case
);
$finder = new \phpbb\finder(
- new \phpbb\filesystem(),
+ new \phpbb\filesystem\filesystem(),
dirname(__FILE__) . '/',
new phpbb_mock_cache(array(
'_ext_finder' => array(
diff --git a/tests/extension/includes/acp/info/acp_foobar.php b/tests/extension/includes/acp/info/acp_foobar.php
index 870225ba4f..8ca1afa1c6 100644
--- a/tests/extension/includes/acp/info/acp_foobar.php
+++ b/tests/extension/includes/acp/info/acp_foobar.php
@@ -18,7 +18,6 @@ class acp_foobar_info
return array(
'filename' => 'acp_foobar',
'title' => 'ACP Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'test' => array('title' => 'Test', 'auth' => '', 'cat' => array('ACP_GENERAL')),
),
diff --git a/tests/extension/manager_test.php b/tests/extension/manager_test.php
index 0eeb060936..f619d4c19d 100644
--- a/tests/extension/manager_test.php
+++ b/tests/extension/manager_test.php
@@ -150,11 +150,11 @@ class phpbb_extension_manager_test extends phpbb_database_test_case
$config = new \phpbb\config\config(array('version' => PHPBB_VERSION));
$db = $this->new_dbal();
- $db_tools = new \phpbb\db\tools($db);
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($db);
$phpbb_root_path = __DIR__ . './../../phpBB/';
$php_ext = 'php';
$table_prefix = 'phpbb_';
- $user = new \phpbb\user('\phpbb\user');
$container = new phpbb_mock_container_builder();
@@ -176,12 +176,11 @@ class phpbb_extension_manager_test extends phpbb_database_test_case
$container,
$db,
$config,
- new \phpbb\filesystem(),
- $user,
+ new \phpbb\filesystem\filesystem(),
'phpbb_ext',
dirname(__FILE__) . '/',
$php_ext,
- ($with_cache) ? new phpbb_mock_cache() : null
+ ($with_cache) ? new \phpbb\cache\service(new phpbb_mock_cache(), $config, $db, $phpbb_root_path, $php_ext) : null
);
}
}
diff --git a/tests/extension/metadata_manager_test.php b/tests/extension/metadata_manager_test.php
index 2a746d3792..533da68c57 100644
--- a/tests/extension/metadata_manager_test.php
+++ b/tests/extension/metadata_manager_test.php
@@ -36,34 +36,49 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
{
parent::setUp();
- $this->cache = new phpbb_mock_cache();
$this->config = new \phpbb\config\config(array(
'version' => '3.1.0',
));
$this->db = $this->new_dbal();
- $this->db_tools = new \phpbb\db\tools($this->db);
+ $factory = new \phpbb\db\tools\factory();
+ $this->db_tools = $factory->get($this->db);
$this->phpbb_root_path = dirname(__FILE__) . '/';
$this->phpEx = 'php';
- $this->user = new \phpbb\user('\phpbb\datetime');
+
+ $this->cache = new \phpbb\cache\service(new phpbb_mock_cache(), $this->config, $this->db, $this->phpbb_root_path, $this->phpEx);
+
$this->table_prefix = 'phpbb_';
- $this->template = new \phpbb\template\twig\twig(
- new \phpbb\path_helper(
- new \phpbb\symfony_request(
- new phpbb_mock_request()
- ),
- new \phpbb\filesystem(),
- $this->getMock('\phpbb\request\request'),
- $this->phpbb_root_path,
- $this->phpEx
+ $container = new phpbb_mock_container_builder();
+ $cache_path = $this->phpbb_root_path . 'cache/twig';
+ $context = new \phpbb\template\context();
+ $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), '');
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $phpbb_path_helper = new \phpbb\path_helper(
+ new \phpbb\symfony_request(
+ new phpbb_mock_request()
),
+ $filesystem,
+ $this->getMock('\phpbb\request\request'),
+ $this->phpbb_root_path,
+ $this->phpEx
+ );
+ $twig = new \phpbb\template\twig\environment(
$this->config,
- $this->user,
- new \phpbb\template\context()
+ $filesystem,
+ $phpbb_path_helper,
+ $cache_path,
+ null,
+ $loader,
+ new \phpbb\event\dispatcher($container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
);
- $container = new phpbb_mock_container_builder();
-
$this->migrator = new \phpbb\db\migrator(
$container,
$this->config,
@@ -82,13 +97,22 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
$container,
$this->db,
$this->config,
- new \phpbb\filesystem(),
- $this->user,
+ new \phpbb\filesystem\filesystem(),
'phpbb_ext',
$this->phpbb_root_path,
$this->phpEx,
$this->cache
);
+
+ global $phpbb_root_path;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $this->phpEx);
+ $lang_loader->set_extension_manager($this->extension_manager);
+ $lang = new \phpbb\language\language($lang_loader);
+ $this->user = new \phpbb\user($lang, '\phpbb\datetime');
+
+ $this->template = new phpbb\template\twig\twig($phpbb_path_helper, $this->config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)));
+ $twig->setLexer(new \phpbb\template\twig\lexer($twig));
}
// Should fail from missing composer.json
@@ -104,7 +128,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
}
catch (\phpbb\extension\exception $e)
{
- $this->assertEquals((string) $e, $this->user->lang('FILE_NOT_FOUND', $this->phpbb_root_path . $this->extension_manager->get_extension_path($ext_name) . 'composer.json'));
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ $this->assertEquals($message, $this->user->lang('FILE_NOT_FOUND', $this->phpbb_root_path . $this->extension_manager->get_extension_path($ext_name) . 'composer.json'));
}
}
@@ -121,7 +146,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
}
catch (\phpbb\extension\exception $e)
{
- $this->fail($e);
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ $this->fail($message);
}
$json = json_decode(file_get_contents($this->phpbb_root_path . 'ext/vendor2/foo/composer.json'), true);
@@ -151,9 +177,10 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
$manager->validate($field_name);
$this->fail('Exception not triggered');
}
- catch(\phpbb\extension\exception $e)
+ catch (\phpbb\extension\exception $e)
{
- $this->assertEquals((string) $e, $this->user->lang('META_FIELD_NOT_SET', $field_name));
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ $this->assertEquals($message, $this->user->lang('META_FIELD_NOT_SET', $field_name));
}
}
@@ -167,7 +194,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
}
catch (\phpbb\extension\exception $e)
{
- $this->assertEquals((string) $e, $this->user->lang('META_FIELD_NOT_SET', 'authors'));
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ $this->assertEquals($message, $this->user->lang('META_FIELD_NOT_SET', 'authors'));
}
$manager->merge_metadata(array(
@@ -183,7 +211,8 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
}
catch (\phpbb\extension\exception $e)
{
- $this->assertEquals((string) $e, $this->user->lang('META_FIELD_NOT_SET', 'author name'));
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ $this->assertEquals($message, $this->user->lang('META_FIELD_NOT_SET', 'author name'));
}
}
@@ -214,9 +243,10 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
$manager->validate($field_name);
$this->fail('Exception not triggered');
}
- catch(\phpbb\extension\exception $e)
+ catch (\phpbb\extension\exception $e)
{
- $this->assertEquals((string) $e, $this->user->lang('META_FIELD_INVALID', $field_name));
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
+ $this->assertEquals($message, $this->user->lang('META_FIELD_INVALID', $field_name));
}
}
@@ -238,9 +268,9 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
{
$this->assertEquals(true, $manager->validate('enable'));
}
- catch(\phpbb\extension\exception $e)
+ catch (\phpbb\extension\exception $e)
{
- $this->fail($e);
+ $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters()));
}
}
@@ -333,11 +363,7 @@ class phpbb_extension_metadata_manager_test extends phpbb_database_test_case
{
return new phpbb_mock_metadata_manager(
$ext_name,
- $this->config,
- $this->extension_manager,
- $this->template,
- $this->user,
- $this->phpbb_root_path
+ $this->extension_manager->get_extension_path($ext_name, true)
);
}
}
diff --git a/tests/extension/modules_test.php b/tests/extension/modules_test.php
index 21f1c6aca5..88634bc6ba 100644
--- a/tests/extension/modules_test.php
+++ b/tests/extension/modules_test.php
@@ -22,6 +22,7 @@ class phpbb_extension_modules_test extends phpbb_test_case
{
protected $extension_manager;
protected $finder;
+ protected $module_manager;
public function setUp()
{
@@ -43,7 +44,14 @@ class phpbb_extension_modules_test extends phpbb_test_case
));
$phpbb_extension_manager = $this->extension_manager;
- $this->acp_modules = new acp_modules();
+ $this->module_manager = new \phpbb\module\module_manager(
+ new \phpbb\cache\driver\dummy(),
+ $this->getMock('\phpbb\db\driver\driver_interface'),
+ $this->extension_manager,
+ MODULES_TABLE,
+ dirname(__FILE__) . '/',
+ 'php'
+ );
}
public function test_get_module_infos()
@@ -56,13 +64,11 @@ class phpbb_extension_modules_test extends phpbb_test_case
$phpbb_root_path = dirname(__FILE__) . '/';
// Find acp module info files
- $this->acp_modules->module_class = 'acp';
- $acp_modules = $this->acp_modules->get_module_infos();
+ $acp_modules = $this->module_manager->get_module_infos('acp');
$this->assertEquals(array(
'vendor2\\foo\\acp\\a_module' => array(
'filename' => 'vendor2\\foo\\acp\\a_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array('ACP_MODS')),
),
@@ -70,7 +76,6 @@ class phpbb_extension_modules_test extends phpbb_test_case
'acp_foobar' => array(
'filename' => 'acp_foobar',
'title' => 'ACP Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'test' => array('title' => 'Test', 'auth' => '', 'cat' => array('ACP_GENERAL')),
),
@@ -78,13 +83,11 @@ class phpbb_extension_modules_test extends phpbb_test_case
), $acp_modules);
// Find mcp module info files
- $this->acp_modules->module_class = 'mcp';
- $acp_modules = $this->acp_modules->get_module_infos();
+ $acp_modules = $this->module_manager->get_module_infos('mcp');
$this->assertEquals(array(
'vendor2\\foo\\mcp\\a_module' => array(
'filename' => 'vendor2\\foo\\mcp\\a_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')),
),
@@ -92,27 +95,11 @@ class phpbb_extension_modules_test extends phpbb_test_case
), $acp_modules);
// Find a specific module info file (mcp_a_module)
- $this->acp_modules->module_class = 'mcp';
- $acp_modules = $this->acp_modules->get_module_infos('mcp_a_module');
- $this->assertEquals(array(
- 'vendor2\\foo\\mcp\\a_module' => array(
- 'filename' => 'vendor2\\foo\\mcp\\a_module',
- 'title' => 'Foobar',
- 'version' => '3.1.0-dev',
- 'modes' => array(
- 'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')),
- ),
- ),
- ), $acp_modules);
-
- // Find a specific module info file (mcp_a_module) with passing the module_class
- $this->acp_modules->module_class = '';
- $acp_modules = $this->acp_modules->get_module_infos('mcp_a_module', 'mcp');
+ $acp_modules = $this->module_manager->get_module_infos('mcp', 'mcp_a_module');
$this->assertEquals(array(
'vendor2\\foo\\mcp\\a_module' => array(
'filename' => 'vendor2\\foo\\mcp\\a_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('MCP_MAIN')),
),
@@ -120,23 +107,19 @@ class phpbb_extension_modules_test extends phpbb_test_case
), $acp_modules);
// The mcp module info file we're looking for shouldn't exist
- $this->acp_modules->module_class = 'mcp';
- $acp_modules = $this->acp_modules->get_module_infos('mcp_a_fail');
+ $acp_modules = $this->module_manager->get_module_infos('mcp', 'mcp_a_fail');
$this->assertEquals(array(), $acp_modules);
// As there are no ucp modules we shouldn't find any
- $this->acp_modules->module_class = 'ucp';
- $acp_modules = $this->acp_modules->get_module_infos();
+ $acp_modules = $this->module_manager->get_module_infos('ucp');
$this->assertEquals(array(), $acp_modules);
// Get module info of specified extension module
- $this->acp_modules->module_class = 'acp';
- $acp_modules = $this->acp_modules->get_module_infos('foo_acp_a_module');
+ $acp_modules = $this->module_manager->get_module_infos('acp', 'foo_acp_a_module');
$this->assertEquals(array(
'vendor2\\foo\\acp\\a_module' => array (
'filename' => 'vendor2\\foo\\acp\\a_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array (
'config' => array ('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array ('ACP_MODS')),
),
@@ -144,23 +127,20 @@ class phpbb_extension_modules_test extends phpbb_test_case
), $acp_modules);
// No specific module and module class set to an incorrect name
- $acp_modules = $this->acp_modules->get_module_infos('', 'wcp', true);
+ $acp_modules = $this->module_manager->get_module_infos('wcp', '', true);
$this->assertEquals(array(), $acp_modules);
// No specific module, no module_class set in the function parameter, and an incorrect module class
- $this->acp_modules->module_class = 'wcp';
- $acp_modules = $this->acp_modules->get_module_infos();
+ $acp_modules = $this->module_manager->get_module_infos('wcp');
$this->assertEquals(array(), $acp_modules);
// No specific module, module class set to false (will default to the above acp)
// Setting $use_all_available will cause get_module_infos() to also load not enabled extensions (vendor2/bar)
- $this->acp_modules->module_class = 'acp';
- $acp_modules = $this->acp_modules->get_module_infos('', false, true);
+ $acp_modules = $this->module_manager->get_module_infos('acp', '', true);
$this->assertEquals(array(
'vendor2\\foo\\acp\\a_module' => array(
'filename' => 'vendor2\\foo\\acp\\a_module',
'title' => 'Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => 'ext_vendor2/foo', 'cat' => array('ACP_MODS')),
),
@@ -168,7 +148,6 @@ class phpbb_extension_modules_test extends phpbb_test_case
'acp_foobar' => array(
'filename' => 'acp_foobar',
'title' => 'ACP Foobar',
- 'version' => '3.1.0-dev',
'modes' => array(
'test' => array('title' => 'Test', 'auth' => '', 'cat' => array('ACP_GENERAL')),
),
@@ -176,7 +155,6 @@ class phpbb_extension_modules_test extends phpbb_test_case
'vendor2\\bar\\acp\\a_module' => array(
'filename' => 'vendor2\\bar\\acp\\a_module',
'title' => 'Bar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')),
),
@@ -184,12 +162,11 @@ class phpbb_extension_modules_test extends phpbb_test_case
), $acp_modules);
// Specific module set to disabled extension
- $acp_modules = $this->acp_modules->get_module_infos('vendor2_bar_acp_a_module', 'acp', true);
+ $acp_modules = $this->module_manager->get_module_infos('acp', 'vendor2_bar_acp_a_module', true);
$this->assertEquals(array(
'vendor2\\bar\\acp\\a_module' => array(
'filename' => 'vendor2\\bar\\acp\\a_module',
'title' => 'Bar',
- 'version' => '3.1.0-dev',
'modes' => array(
'config' => array('title' => 'Config', 'auth' => '', 'cat' => array('ACP_MODS')),
),
diff --git a/tests/feed/attachments_base_test.php b/tests/feed/attachments_base_test.php
index c980dfd3d7..573218be42 100644
--- a/tests/feed/attachments_base_test.php
+++ b/tests/feed/attachments_base_test.php
@@ -31,8 +31,25 @@ class phpbb_feed_attachments_base_test extends phpbb_database_test_case
$this->filesystem = new \phpbb\filesystem();
$config = new \phpbb\config\config(array());
- $user = new \phpbb\user('\phpbb\datetime');
- $feed_helper = new \phpbb\feed\helper($config, $user, $phpbb_root_path, $phpEx);
+ $path_helper = new \phpbb\path_helper(
+ new \phpbb\symfony_request(
+ new phpbb_mock_request()
+ ),
+ $this->filesystem,
+ $this->getMock('\phpbb\request\request'),
+ $phpbb_root_path,
+ 'php'
+ );
+ $user = new \phpbb\user(
+ new \phpbb\language\language(
+ new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)
+ ),
+ '\phpbb\datetime'
+ );
+ $container = new phpbb_mock_container_builder();
+ $this->get_test_case_helpers()->set_s9e_services($container);
+ $container->set('feed.quote_helper', new \phpbb\feed\quote_helper($user, $phpbb_root_path, 'php'));
+ $feed_helper = new \phpbb\feed\helper($config, $container, $path_helper, $container->get('text_formatter.renderer'), $user);
$db = $this->new_dbal();
$cache = new \phpbb_mock_cache();
$auth = new \phpbb\auth\auth();
diff --git a/tests/feed/attachments_mock_feed.php b/tests/feed/attachments_mock_feed.php
index 0e623fed24..fb67a48f7c 100644
--- a/tests/feed/attachments_mock_feed.php
+++ b/tests/feed/attachments_mock_feed.php
@@ -28,4 +28,9 @@ class phpbb_feed_attachments_mock_feed extends \phpbb\feed\attachments_base
return true;
}
+
+ public function adjust_item(&$item_row, &$row)
+ {
+ return array();
+ }
}
diff --git a/tests/files/type_foo.php b/tests/files/type_foo.php
new file mode 100644
index 0000000000..95940b9d2f
--- /dev/null
+++ b/tests/files/type_foo.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+namespace phpbb\files\types;
+
+class foo extends \phpbb\files\types\remote
+{
+ static public $tempnam_path;
+}
+
+function tempnam($one, $two)
+{
+ if (empty(foo::$tempnam_path))
+ {
+ return \tempnam($one, $two);
+ }
+ else
+ {
+ return foo::$tempnam_path;
+ }
+}
diff --git a/tests/files/types_base_test.php b/tests/files/types_base_test.php
new file mode 100644
index 0000000000..e630bf8c48
--- /dev/null
+++ b/tests/files/types_base_test.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_files_types_base_test extends phpbb_test_case
+{
+ private $path;
+
+ private $filesystem;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\request\request_interface */
+ protected $request;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ protected function setUp()
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $this->request = $this->getMock('\phpbb\request\request');
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+
+ $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
+ $this->container->set('files.filespec', new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ ))));
+ $this->factory = new \phpbb\files\factory($this->container);
+
+ $this->path = __DIR__ . '/fixture/';
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ public function data_check_upload_size()
+ {
+ return array(
+ array('foo', '500KB', array()),
+ array('none', '500KB', array('PHP_SIZE_OVERRUN')),
+ array('none', '', array('PHP_SIZE_NA')),
+ );
+ }
+
+ /**
+ * @dataProvider data_check_upload_size
+ */
+ public function test_check_upload_size($filename, $max_filesize, $expected)
+ {
+ $php_ini = $this->getMock('\bantu\IniGetWrapper\IniGetWrapper');
+ $php_ini->expects($this->any())
+ ->method('getString')
+ ->willReturn($max_filesize);
+ $type_form = new \phpbb\files\types\local($this->factory, $this->language, $php_ini, $this->request);
+ $file = $this->getMockBuilder('\phpbb\files\filespec')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $file->expects($this->any())
+ ->method('get')
+ ->willReturn($filename);
+ $type_form->check_upload_size($file);
+
+ $this->assertSame($expected, $file->error);
+ }
+}
diff --git a/tests/files/types_form_test.php b/tests/files/types_form_test.php
new file mode 100644
index 0000000000..925babb47f
--- /dev/null
+++ b/tests/files/types_form_test.php
@@ -0,0 +1,172 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_files_types_form_test extends phpbb_test_case
+{
+ private $path;
+
+ private $filesystem;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\request\request_interface */
+ protected $request;
+
+ /** @var \phpbb\plupload\plupload */
+ protected $plupload;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ protected function setUp()
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $this->request = $this->getMock('\phpbb\request\request');
+ $this->request->expects($this->any())
+ ->method('file')
+ ->willReturn(array());
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+
+ $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
+ $this->container->set('files.filespec', new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ ))));
+ $this->factory = new \phpbb\files\factory($this->container);
+ $this->plupload = $this->getMockBuilder('\phpbb\plupload\plupload')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->plupload->expects($this->any())
+ ->method('handle_upload')
+ ->willReturn(array());
+
+ $this->path = __DIR__ . '/fixture/';
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ public function data_upload_form()
+ {
+ return array(
+ array(
+ array(),
+ array(''),
+ ),
+ array(
+ array(
+ 'tmp_name' => 'foo',
+ 'name' => 'foo',
+ 'size' => 500,
+ 'type' => 'image/png',
+ 'error' => UPLOAD_ERR_PARTIAL,
+ ),
+ array('PARTIAL_UPLOAD'),
+ ),
+ array(
+ array(
+ 'tmp_name' => 'foo',
+ 'name' => 'foo',
+ 'size' => 500,
+ 'type' => 'image/png',
+ 'error' => -9,
+ ),
+ array('NOT_UPLOADED'),
+ ),
+ array(
+ array(
+ 'tmp_name' => 'foo',
+ 'name' => 'foo',
+ 'size' => 0,
+ 'type' => 'image/png',
+ ),
+ array('EMPTY_FILEUPLOAD'),
+ ),
+ array(
+ array(
+ 'tmp_name' => 'none',
+ 'name' => 'none',
+ 'size' => 50,
+ 'type' => 'image/png',
+ ),
+ array('PHP_SIZE_OVERRUN'),
+ ),
+ array(
+ array(
+ 'tmp_name' => 'tests/upload/fixture/png',
+ 'name' => 'foo.png',
+ 'size' => 500,
+ 'type' => 'image/png',
+ 'local_mode' => true,
+ ),
+ array(),
+ array('local_mode' => true),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_upload_form
+ */
+ public function test_upload_form($upload, $expected, $plupload = array())
+ {
+ $this->request = $this->getMock('\phpbb\request\request');
+ $this->request->expects($this->any())
+ ->method('file')
+ ->willReturn($upload);
+ $filespec = new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $this->phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ )));
+ $this->container->set('files.filespec', $filespec);
+ $this->factory = new \phpbb\files\factory($this->container);
+ $this->plupload = $this->getMockBuilder('\phpbb\plupload\plupload')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->plupload->expects($this->any())
+ ->method('handle_upload')
+ ->willReturn($plupload);
+
+ $type_form = new \phpbb\files\types\form($this->factory, $this->language, $this->php_ini, $this->plupload, $this->request);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('png'));
+ $type_form->set_upload($upload);
+
+
+ $file = $type_form->upload('foobar');
+ $this->assertSame($expected, $file->error);
+ $this->assertInstanceOf('\phpbb\files\filespec', $file);
+ }
+}
diff --git a/tests/files/types_local_test.php b/tests/files/types_local_test.php
new file mode 100644
index 0000000000..31070de107
--- /dev/null
+++ b/tests/files/types_local_test.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_files_types_local_test extends phpbb_test_case
+{
+ private $path;
+
+ private $filesystem;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\request\request_interface */
+ protected $request;
+
+ /** @var \phpbb\plupload\plupload */
+ protected $plupload;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ protected function setUp()
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $this->request = $this->getMock('\phpbb\request\request');
+ $this->request->expects($this->any())
+ ->method('file')
+ ->willReturn(array());
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+
+ $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
+ $this->container->set('files.filespec', new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ ))));
+ $this->factory = new \phpbb\files\factory($this->container);
+ $this->plupload = $this->getMockBuilder('\phpbb\plupload\plupload')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->plupload->expects($this->any())
+ ->method('handle_upload')
+ ->willReturn(array());
+
+ $this->path = __DIR__ . '/fixture/';
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ public function test_upload_init_error()
+ {
+ $filespec = $this->getMockBuilder('\phpbb\files\filespec')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $filespec->expects($this->any())
+ ->method('init_error')
+ ->willReturn(true);
+ $filespec->expects($this->any())
+ ->method('set_upload_ary')
+ ->willReturnSelf();
+ $filespec->expects($this->any())
+ ->method('set_upload_namespace')
+ ->willReturnSelf();
+ $this->container->set('files.filespec', $filespec);
+ $this->factory = new \phpbb\files\factory($this->container);
+
+ $type_local = new \phpbb\files\types\local($this->factory, $this->language, $this->php_ini, $this->request);
+
+
+ $file = $type_local->upload('foo', false);
+ $this->assertSame(array(''), $file->error);
+ $this->assertInstanceOf('\phpbb\files\filespec', $file);
+ }
+
+ public function data_upload_form()
+ {
+ return array(
+ array(
+ 'foo',
+ array(
+ 'tmp_name' => 'foo',
+ 'size' => 500,
+ 'type' => 'image/png',
+ ),
+ array('NOT_UPLOADED'),
+ ),
+ array(
+ 'none',
+ false,
+ array('PHP_SIZE_OVERRUN'),
+ ),
+ array(
+ 'tests/upload/fixture/png',
+ array(
+ 'realname' => 'foo.png',
+ 'size' => 500,
+ 'type' => 'image/png',
+ 'local_mode' => true,
+ ),
+ array(),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_upload_form
+ */
+ public function test_upload_form($filename, $upload_ary, $expected)
+ {
+ $filespec = new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $this->phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ )));
+ $filespec_local = new ReflectionProperty($filespec, 'local');
+ $filespec_local->setAccessible(true);
+ $filespec_local->setValue($filespec, true);
+ $this->container->set('files.filespec', $filespec);
+ $this->factory = new \phpbb\files\factory($this->container);
+
+ $type_local = new \phpbb\files\types\local($this->factory, $this->language, $this->php_ini, $this->request);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('png'));
+ $type_local->set_upload($upload);
+
+
+ $file = $type_local->upload($filename, $upload_ary);
+ $this->assertSame($expected, $file->error);
+ $this->assertInstanceOf('\phpbb\files\filespec', $file);
+ }
+}
diff --git a/tests/files/types_remote_test.php b/tests/files/types_remote_test.php
new file mode 100644
index 0000000000..1a7d63d790
--- /dev/null
+++ b/tests/files/types_remote_test.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+require_once dirname(__FILE__) . '/type_foo.php';
+
+class phpbb_files_types_remote_test extends phpbb_test_case
+{
+ private $path;
+
+ private $filesystem;
+
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\request\request_interface */
+ protected $request;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ protected function setUp()
+ {
+ global $config, $phpbb_root_path, $phpEx;
+
+ $config = new \phpbb\config\config(array());
+ $this->config = $config;
+ $this->config->set('remote_upload_verify', 0);
+ $this->request = $this->getMock('\phpbb\request\request');
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+
+ $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
+ $this->container->set('files.filespec', new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ ))));
+ $this->factory = new \phpbb\files\factory($this->container);
+
+ $this->path = __DIR__ . '/fixture/';
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ public function test_upload_fsock_fail()
+ {
+ $type_remote = new \phpbb\files\types\remote($this->config, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('png'));
+ $type_remote->set_upload($upload);
+
+ $file = $type_remote->upload('https://bärföö.com/foo.png');
+
+ $this->assertSame(array('NOT_UPLOADED'), $file->error);
+ }
+
+ public function data_get_max_file_size()
+ {
+ return array(
+ array('', 'http://phpbb.com/foo/bar.png'),
+ array('2k', 'http://phpbb.com/foo/bar.png'),
+ array('500k', 'http://phpbb.com/foo/bar.png'),
+ array('500M', 'http://phpbb.com/foo/bar.png'),
+ array('500m', 'http://phpbb.com/foo/bar.png'),
+ array('500k', 'http://google.com/?.png', array('DISALLOWED_EXTENSION', 'DISALLOWED_CONTENT')),
+ array('1', 'http://google.com/?.png', array('WRONG_FILESIZE')),
+ array('500g', 'http://phpbb.com/foo/bar.png'),
+ array('foobar', 'http://phpbb.com/foo/bar.png'),
+ array('-5k', 'http://phpbb.com/foo/bar.png'),
+ );
+ }
+
+ /**
+ * @dataProvider data_get_max_file_size
+ */
+ public function test_get_max_file_size($max_file_size, $link, $expected = array('URL_NOT_FOUND'))
+ {
+ $php_ini = $this->getMock('\bantu\IniGetWrapper\IniGetWrapper', array('getString'));
+ $php_ini->expects($this->any())
+ ->method('getString')
+ ->willReturn($max_file_size);
+ $type_remote = new \phpbb\files\types\remote($this->config, $this->factory, $this->language, $php_ini, $this->request, $this->phpbb_root_path);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('png'));
+ $type_remote->set_upload($upload);
+
+ $file = $type_remote->upload($link);
+
+ $this->assertSame($expected, $file->error);
+ }
+
+ public function test_upload_wrong_path()
+ {
+ $type_remote = new \phpbb\files\types\foo($this->config, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('png'));
+ $type_remote->set_upload($upload);
+ $type_remote::$tempnam_path = $this->phpbb_root_path . 'cache/wrong/path';
+
+ $file = $type_remote->upload('http://google.com/?.png');
+
+ $this->assertSame(array('NOT_UPLOADED'), $file->error);
+ $type_remote::$tempnam_path = '';
+ }
+}
diff --git a/tests/files/upload_test.php b/tests/files/upload_test.php
new file mode 100644
index 0000000000..c41204a0d5
--- /dev/null
+++ b/tests/files/upload_test.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_files_upload_test extends phpbb_test_case
+{
+ private $path;
+
+ private $filesystem;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\request\request_interface */
+ protected $request;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
+ protected function setUp()
+ {
+ // Global $config required by unique_id
+ global $config, $phpbb_root_path, $phpEx;
+
+ if (!is_array($config))
+ {
+ $config = array();
+ }
+
+ $config['rand_seed'] = '';
+ $config['rand_seed_last_update'] = time() + 600;
+
+ $this->request = $this->getMock('\phpbb\request\request');
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+
+ $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
+ $this->container->set('files.filespec', new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ ))));
+ $this->factory = new \phpbb\files\factory($this->container);
+
+ $this->path = __DIR__ . '/fixture/';
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ public function test_reset_vars()
+ {
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_max_filesize(500);
+ $this->assertEquals(500, $upload->max_filesize);
+ $upload->reset_vars();
+ $this->assertEquals(0, $upload->max_filesize);
+ }
+
+ public function test_set_disallowed_content()
+ {
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $disallowed_content = new ReflectionProperty($upload, 'disallowed_content');
+ $disallowed_content->setAccessible(true);
+
+ $upload->set_disallowed_content(array('foo'));
+ $this->assertEquals(array('foo'), $disallowed_content->getValue($upload));
+ $upload->set_disallowed_content(array('foo', 'bar', 'meh'));
+ $this->assertEquals(array('foo', 'bar', 'meh'), $disallowed_content->getValue($upload));
+ $upload->set_disallowed_content('');
+ $this->assertEquals(array('foo', 'bar', 'meh'), $disallowed_content->getValue($upload));
+ $this->assertINstanceOf('\phpbb\files\upload', $upload->set_disallowed_content(array()));
+ $this->assertEquals(array(), $disallowed_content->getValue($upload));
+ $upload->reset_vars();
+ $this->assertEquals(array(), $disallowed_content->getValue($upload));
+ }
+
+ public function test_is_valid()
+ {
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $this->assertFalse($upload->is_valid('foobar'));
+ }
+
+ public function data_internal_error()
+ {
+ return array(
+ array(UPLOAD_ERR_INI_SIZE, 'PHP_SIZE_OVERRUN'),
+ array(UPLOAD_ERR_FORM_SIZE, 'WRONG_FILESIZE'),
+ array(UPLOAD_ERR_PARTIAL, 'PARTIAL_UPLOAD'),
+ array(UPLOAD_ERR_NO_FILE, 'NOT_UPLOADED'),
+ array(UPLOAD_ERR_NO_TMP_DIR, 'NO_TEMP_DIR'),
+ array(UPLOAD_ERR_CANT_WRITE, 'NO_TEMP_DIR'),
+ array(UPLOAD_ERR_EXTENSION, 'PHP_UPLOAD_STOPPED'),
+ array(9, false),
+ );
+ }
+
+ /**
+ * @dataProvider data_internal_error
+ */
+ public function test_assign_internal_error($error_code, $expected)
+ {
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $this->assertSame($expected, $upload->assign_internal_error($error_code));
+ }
+}
diff --git a/tests/filesystem/clean_path_test.php b/tests/filesystem/clean_path_test.php
index c585b17155..d2dec424b4 100644
--- a/tests/filesystem/clean_path_test.php
+++ b/tests/filesystem/clean_path_test.php
@@ -18,7 +18,7 @@ class phpbb_filesystem_clean_path_test extends phpbb_test_case
public function setUp()
{
parent::setUp();
- $this->filesystem = new \phpbb\filesystem();
+ $this->filesystem = new \phpbb\filesystem\filesystem();
}
public function clean_path_data()
diff --git a/tests/filesystem/is_absolute_test.php b/tests/filesystem/is_absolute_test.php
new file mode 100644
index 0000000000..7a50989b74
--- /dev/null
+++ b/tests/filesystem/is_absolute_test.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_filesystem_is_absolute_test extends phpbb_test_case
+{
+ /** @var \phpbb\filesystem\filesystem_interface */
+ protected $filesystem;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ }
+
+ static public function is_absolute_data()
+ {
+ return array(
+ // Empty
+ array('', false),
+
+ // Absolute unix style
+ array('/etc/phpbb', true),
+ // Unix does not support \ so that is not an absolute path
+ array('\etc\phpbb', false),
+
+ // Absolute windows style
+ array('c:\windows', true),
+ array('C:\Windows', true),
+ array('c:/windows', true),
+ array('C:/Windows', true),
+
+ // Executable
+ array('etc/phpbb', false),
+ array('explorer.exe', false),
+
+ // Relative subdir
+ array('Windows\System32', false),
+ array('Windows\System32\explorer.exe', false),
+ array('Windows/System32', false),
+ array('Windows/System32/explorer.exe', false),
+
+ // Relative updir
+ array('..\Windows\System32', false),
+ array('..\Windows\System32\explorer.exe', false),
+ array('../Windows/System32', false),
+ array('../Windows/System32/explorer.exe', false),
+ );
+ }
+
+ /**
+ * @dataProvider is_absolute_data
+ */
+ public function test_is_absolute($path, $expected)
+ {
+ $this->assertEquals($expected, $this->filesystem->is_absolute_path($path));
+ }
+}
diff --git a/tests/filesystem/realpath_test.php b/tests/filesystem/realpath_test.php
new file mode 100644
index 0000000000..d994935f94
--- /dev/null
+++ b/tests/filesystem/realpath_test.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_filesystem_realpath_test extends phpbb_test_case
+{
+ static protected $filesystem_own_realpath;
+
+ /** @var \phpbb\filesystem\filesystem_interface */
+ protected $filesystem;
+
+ static public function setUpBeforeClass()
+ {
+ parent::setUpBeforeClass();
+
+ $reflection_class = new ReflectionClass('\phpbb\filesystem\filesystem');
+ self::$filesystem_own_realpath = $reflection_class->getMethod('phpbb_own_realpath');
+ self::$filesystem_own_realpath->setAccessible(true);
+ }
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ }
+
+ public function realpath_resolve_absolute_without_symlinks_data()
+ {
+ return array(
+ // Constant data
+ array(__DIR__, __DIR__),
+ array(__DIR__ . '/../filesystem/../filesystem', __DIR__),
+ array(__DIR__ . '/././', __DIR__),
+ array(__DIR__ . '/non_existent', false),
+
+ array(__FILE__, __FILE__),
+ array(__FILE__ . '../', false),
+ );
+ }
+
+ public function realpath_resolve_relative_without_symlinks_data()
+ {
+ if (!function_exists('getcwd'))
+ {
+ return array();
+ }
+
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $relative_path = $filesystem->make_path_relative(__DIR__, getcwd());
+
+ return array(
+ array($relative_path, __DIR__),
+ array($relative_path . '../filesystem/../filesystem', __DIR__),
+ array($relative_path . '././', __DIR__),
+
+ array($relative_path . 'realpath_test.php', __FILE__),
+ );
+ }
+
+ /**
+ * @dataProvider realpath_resolve_absolute_without_symlinks_data
+ */
+ public function test_realpath_absolute_without_links($path, $expected)
+ {
+ $this->assertEquals($expected, self::$filesystem_own_realpath->invoke($this->filesystem, $path));
+ }
+
+ /**
+ * @dataProvider realpath_resolve_relative_without_symlinks_data
+ */
+ public function test_realpath_relative_without_links($path, $expected)
+ {
+ if (!function_exists('getcwd'))
+ {
+ $this->markTestSkipped('phpbb_own_realpath() cannot be tested with relative paths: getcwd is not available.');
+ }
+
+ $this->assertEquals($expected, self::$filesystem_own_realpath->invoke($this->filesystem, $path));
+ }
+}
diff --git a/tests/functional/acp_attachments_test.php b/tests/functional/acp_attachments_test.php
deleted file mode 100644
index 8e810a508a..0000000000
--- a/tests/functional/acp_attachments_test.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-/**
- *
- * This file is part of the phpBB Forum Software package.
- *
- * @copyright (c) phpBB Limited <https://www.phpbb.com>
- * @license GNU General Public License, version 2 (GPL-2.0)
- *
- * For full copyright and license information, please see
- * the docs/CREDITS.txt file.
- *
- */
-
-/**
- * @group functional
- */
-class phpbb_functional_acp_attachments_test extends phpbb_functional_test_case
-{
- public function data_imagick_path_linux()
- {
- return array(
- array('/usr/bin', 'Configuration updated successfully'),
- array('/usr/foobar', 'The entered path “/usr/foobar†does not exist.'),
- array('/usr/bin/which', 'The entered path “/usr/bin/which†is not a directory.'),
- );
- }
-
- /**
- * @dataProvider data_imagick_path_linux
- */
- public function test_imagick_path_linux($imagick_path, $expected)
- {
- if (strtolower(substr(PHP_OS, 0, 5)) !== 'linux')
- {
- $this->markTestSkipped('Unable to test linux specific paths on other OS.');
- }
-
- $this->login();
- $this->admin_login();
-
- $crawler = self::request('GET', 'adm/index.php?i=attachments&mode=attach&sid=' . $this->sid);
-
- $form = $crawler->selectButton('Submit')->form(array('config[img_imagick]' => $imagick_path));
-
- $crawler = self::submit($form);
- $this->assertContains($expected, $crawler->filter('#main')->text());
- }
-
- public function data_imagick_path_windows()
- {
- return array(
- array('C:\Windows', 'Configuration updated successfully'),
- array('C:\Windows\foobar1', 'The entered path “C:\Windows\foobar1†does not exist.'),
- array('C:\Windows\explorer.exe', 'The entered path “C:\Windows\explorer.exe†is not a directory.'),
- );
- }
-
- /**
- * @dataProvider data_imagick_path_windows
- */
- public function test_imagick_path_windows($imagick_path, $expected)
- {
- if (strtolower(substr(PHP_OS, 0, 3)) !== 'win')
- {
- $this->markTestSkipped('Unable to test windows specific paths on other OS.');
- }
-
- $this->login();
- $this->admin_login();
-
- $crawler = self::request('GET', 'adm/index.php?i=attachments&mode=attach&sid=' . $this->sid);
-
- $form = $crawler->selectButton('Submit')->form(array('config[img_imagick]' => $imagick_path));
-
- $crawler = self::submit($form);
- $this->assertContains($expected, $crawler->filter('#main')->text());
- }
-}
diff --git a/tests/functional/acp_bbcodes_test.php b/tests/functional/acp_bbcodes_test.php
new file mode 100644
index 0000000000..58681dfa07
--- /dev/null
+++ b/tests/functional/acp_bbcodes_test.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * @group functional
+ */
+class phpbb_functional_acp_bbcodes_test extends phpbb_functional_test_case
+{
+ public function test_htmlspecialchars()
+ {
+ $this->login();
+ $this->admin_login();
+
+ // Create the BBCode
+ $crawler = self::request('GET', 'adm/index.php?i=acp_bbcodes&sid=' . $this->sid . '&mode=bbcodes&action=add');
+ $form = $crawler->selectButton('Submit')->form(array(
+ 'bbcode_match' => '[mod="{TEXT1}"]{TEXT2}[/mod]',
+ 'bbcode_tpl' => '<div>{TEXT1}</div><div>{TEXT2}</div>'
+ ));
+ self::submit($form);
+
+ // Test it in the "new topic" preview
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2&sid=' . $this->sid);
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'subject',
+ 'message' => '[mod=a]b[/mod][mod="c"]d[/mod]'
+ ));
+ $crawler = self::submit($form);
+
+ $html = $crawler->filter('#preview')->html();
+ $this->assertContains('<div>a</div>', $html);
+ $this->assertContains('<div>b</div>', $html);
+ $this->assertContains('<div>c</div>', $html);
+ $this->assertContains('<div>d</div>', $html);
+ }
+}
diff --git a/tests/functional/acp_profile_field_test.php b/tests/functional/acp_profile_field_test.php
index 88df782faa..7a0a6ca941 100644
--- a/tests/functional/acp_profile_field_test.php
+++ b/tests/functional/acp_profile_field_test.php
@@ -28,18 +28,20 @@ class phpbb_functional_acp_profile_field_test extends phpbb_functional_test_case
public function data_add_profile_field()
{
return array(
- array('bool', 'profilefields.type.bool',
+ array('profilefields.type.bool',
array(
+ 'field_ident' => 'bool',
+ 'lang_name' => 'bool',
'lang_options[0]' => 'foo',
'lang_options[1]' => 'bar',
),
- array(),
),
- array('dropdown', 'profilefields.type.dropdown',
+ array('profilefields.type.dropdown',
array(
+ 'field_ident' => 'dropdown',
+ 'lang_name' => 'dropdown',
'lang_options' => "foo\nbar\nbar\nfoo",
),
- array(),
),
);
}
@@ -47,13 +49,12 @@ class phpbb_functional_acp_profile_field_test extends phpbb_functional_test_case
/**
* @dataProvider data_add_profile_field
*/
- public function test_add_profile_field($name, $type, $page1_settings, $page2_settings)
+ public function test_add_profile_field($type, $page1_settings)
{
// Custom profile fields page
$crawler = self::request('GET', 'adm/index.php?i=acp_profile&mode=profile&sid=' . $this->sid);
// these language strings are html
$form = $crawler->selectButton('Create new field')->form(array(
- 'field_ident' => $name,
'field_type' => $type,
));
$crawler = self::submit($form);
@@ -63,7 +64,7 @@ class phpbb_functional_acp_profile_field_test extends phpbb_functional_test_case
$crawler = self::submit($form);
// Fill form for profile field specific options
- $form = $crawler->selectButton('Save')->form($page2_settings);
+ $form = $crawler->selectButton('Save')->form();
$crawler= self::submit($form);
$this->assertContainsLang('ADDED_PROFILE_FIELD', $crawler->text());
diff --git a/tests/functional/acp_smilies_test.php b/tests/functional/acp_smilies_test.php
new file mode 100644
index 0000000000..ebe8717fa7
--- /dev/null
+++ b/tests/functional/acp_smilies_test.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * @group functional
+ */
+class phpbb_functional_acp_smilies_test extends phpbb_functional_test_case
+{
+ public function test_htmlspecialchars()
+ {
+ $this->login();
+ $this->admin_login();
+
+ // Create the BBCode
+ $crawler = self::request('GET', 'adm/index.php?i=acp_icons&sid=' . $this->sid . '&mode=smilies&action=edit&id=1');
+ $form = $crawler->selectButton('Submit')->form(array(
+ 'code[icon_e_biggrin.gif]' => '>:D',
+ 'emotion[icon_e_biggrin.gif]' => '>:D'
+ ));
+ self::submit($form);
+
+ // Test it in the "new topic" preview
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2&sid=' . $this->sid);
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'subject',
+ 'message' => '>:D'
+ ));
+ $crawler = self::submit($form);
+
+ $html = $crawler->filter('#preview')->html();
+ $this->assertRegexp('(<img [^>]+ alt="&gt;:D" title="&gt;:D"[^>]*>)', $html);
+ }
+}
diff --git a/tests/functional/browse_test.php b/tests/functional/browse_test.php
index b9e74a280f..280e814c06 100644
--- a/tests/functional/browse_test.php
+++ b/tests/functional/browse_test.php
@@ -34,9 +34,21 @@ class phpbb_functional_browse_test extends phpbb_functional_test_case
$this->assertGreaterThan(0, $crawler->filter('.postbody')->count());
}
+ public function test_help_faq()
+ {
+ $crawler = self::request('GET', 'app.php/help/faq');
+ $this->assertGreaterThan(0, $crawler->filter('h2.faq-title')->count());
+ }
+
+ public function test_help_bbcode()
+ {
+ $crawler = self::request('GET', 'app.php/help/bbcode');
+ $this->assertGreaterThan(0, $crawler->filter('h2.faq-title')->count());
+ }
+
public function test_feed()
{
- $crawler = self::request('GET', 'feed.php', array(), false);
+ $crawler = self::request('GET', 'app.php/feed', array(), false);
self::assert_response_xml();
$this->assertGreaterThan(0, $crawler->filter('entry')->count());
}
diff --git a/tests/functional/controllers_compatibility_test.php b/tests/functional/controllers_compatibility_test.php
new file mode 100644
index 0000000000..9499888a1a
--- /dev/null
+++ b/tests/functional/controllers_compatibility_test.php
@@ -0,0 +1,56 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @group functional
+*/
+
+class phpbb_functional_controllers_compatibility_test extends phpbb_functional_test_case
+{
+ public function test_report_compatibility()
+ {
+ $this->assert301('report.php?f=1&p=1', 'app.php/post/1/report');
+ $this->assert301('report.php?p=1', 'app.php/post/1/report');
+ $this->assert301('report.php?pm=1', 'app.php/pm/1/report');
+ }
+
+ public function test_feed_compatibility()
+ {
+ $this->assert301('feed.php', 'app.php/feed');
+ $this->assert301('feed.php?mode=foobar', 'app.php/feed/foobar');
+ $this->assert301('feed.php?mode=news', 'app.php/feed/news');
+ $this->assert301('feed.php?mode=topics', 'app.php/feed/topics');
+ $this->assert301('feed.php?mode=topics_news', 'app.php/feed/topics_news');
+ $this->assert301('feed.php?mode=topics_active', 'app.php/feed/topics_active');
+ $this->assert301('feed.php?mode=forums', 'app.php/feed/forums');
+ $this->assert301('feed.php?f=1', 'app.php/feed/forum/1');
+ $this->assert301('feed.php?t=1', 'app.php/feed/topic/1');
+ }
+
+ protected function assert301($from, $to)
+ {
+ self::$client->followRedirects(false);
+ self::request('GET', $from, array(), false);
+
+ // Fix sid issues
+ $location = self::$client->getResponse()->getHeader('Location');
+ $location = preg_replace('#sid=[^&]+(&(amp;)?)?#', '', $location);
+ if (substr($location, -1) === '?')
+ {
+ $location = substr($location, 0, -1);
+ }
+
+ $this->assertEquals(301, self::$client->getResponse()->getStatus());
+ $this->assertStringEndsWith($to, $location);
+ }
+}
diff --git a/tests/functional/download_test.php b/tests/functional/download_test.php
index 1e863210e6..3d4f316d72 100644
--- a/tests/functional/download_test.php
+++ b/tests/functional/download_test.php
@@ -11,10 +11,7 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
/**
* @group functional
@@ -58,7 +55,7 @@ class phpbb_functional_download_test extends phpbb_functional_test_case
// Test creating a reply
$post2 = $this->create_post($this->data['forums']['Download #1'], $post['topic_id'], 'Re: Download Topic #1-#2', 'This is a test post posted by the testing framework.', array('upload_files' => 1));
- $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
$this->assertContains('Re: Download Topic #1-#2', $crawler->filter('html')->text());
$this->data['posts']['Re: Download Topic #1-#2'] = (int) $post2['post_id'];
diff --git a/tests/functional/extension_acp_test.php b/tests/functional/extension_acp_test.php
index 8a71a5ce04..ce0f4911e3 100644
--- a/tests/functional/extension_acp_test.php
+++ b/tests/functional/extension_acp_test.php
@@ -26,7 +26,7 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case
{
parent::setUpBeforeClass();
- self::$helper = new phpbb_test_case_helpers(self);
+ self::$helper = new phpbb_test_case_helpers(__CLASS__);
self::$helper->copy_ext_fixtures(dirname(__FILE__) . '/../extension/ext/', self::$fixtures);
}
@@ -133,7 +133,7 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case
for ($i = 0; $i < $crawler->filter('dl')->count(); $i++)
{
- $text = $crawler->filter('dl')->eq($i)->text();
+ $text = trim($crawler->filter('dl')->eq($i)->text());
$match = false;
diff --git a/tests/functional/extension_controller_test.php b/tests/functional/extension_controller_test.php
index 18eb9ad4c6..58c3878b8b 100644
--- a/tests/functional/extension_controller_test.php
+++ b/tests/functional/extension_controller_test.php
@@ -34,7 +34,7 @@ class phpbb_functional_extension_controller_test extends phpbb_functional_test_c
{
parent::setUpBeforeClass();
- self::$helper = new phpbb_test_case_helpers(self);
+ self::$helper = new phpbb_test_case_helpers(__CLASS__);
self::$helper->copy_ext_fixtures(dirname(__FILE__) . '/fixtures/ext/', self::$fixtures);
}
diff --git a/tests/functional/extension_global_lang_test.php b/tests/functional/extension_global_lang_test.php
index f615114c08..a1e2547745 100644
--- a/tests/functional/extension_global_lang_test.php
+++ b/tests/functional/extension_global_lang_test.php
@@ -30,7 +30,7 @@ class phpbb_functional_extension_global_lang_test extends phpbb_functional_test_
{
parent::setUpBeforeClass();
- self::$helper = new phpbb_test_case_helpers(self);
+ self::$helper = new phpbb_test_case_helpers(__CLASS__);
self::$helper->copy_ext_fixtures(dirname(__FILE__) . '/fixtures/ext/', self::$fixtures);
}
diff --git a/tests/functional/extension_module_test.php b/tests/functional/extension_module_test.php
index ee084720e4..d3a66b9b35 100644
--- a/tests/functional/extension_module_test.php
+++ b/tests/functional/extension_module_test.php
@@ -29,7 +29,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case
{
parent::setUpBeforeClass();
- self::$helper = new phpbb_test_case_helpers(self);
+ self::$helper = new phpbb_test_case_helpers(__CLASS__);
self::$helper->copy_ext_fixtures(dirname(__FILE__) . '/fixtures/ext/', self::$fixtures);
}
@@ -49,8 +49,9 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case
$this->phpbb_extension_manager = $this->get_extension_manager();
$this->phpbb_extension_manager->enable('foo/bar');
- $modules = new acp_modules();
$db = $this->get_db();
+ $cache = $this->get_cache_driver();
+ $modules = new \phpbb\module\module_manager($cache, $db, $this->phpbb_extension_manager, MODULES_TABLE, dirname(__FILE__) . '/../../phpBB/', 'php');
$sql = 'SELECT module_id
FROM ' . MODULES_TABLE . "
@@ -70,7 +71,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case
'module_mode' => '',
'module_auth' => '',
);
- $modules->update_module_data($parent_data, true);
+ $modules->update_module_data($parent_data);
$module_data = array(
'module_basename' => 'foo\\bar\\acp\\main_module',
@@ -82,7 +83,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case
'module_mode' => 'mode',
'module_auth' => '',
);
- $modules->update_module_data($module_data, true);
+ $modules->update_module_data($module_data);
$parent_data = array(
'module_basename' => '',
@@ -94,7 +95,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case
'module_mode' => '',
'module_auth' => '',
);
- $modules->update_module_data($parent_data, true);
+ $modules->update_module_data($parent_data);
$module_data = array(
'module_basename' => 'foo\\bar\\ucp\\main_module',
@@ -106,7 +107,7 @@ class phpbb_functional_extension_module_test extends phpbb_functional_test_case
'module_mode' => 'mode',
'module_auth' => '',
);
- $modules->update_module_data($module_data, true);
+ $modules->update_module_data($module_data);
$this->purge_cache();
}
diff --git a/tests/functional/extension_permission_lang_test.php b/tests/functional/extension_permission_lang_test.php
index 92d8d596c7..f570d45215 100644
--- a/tests/functional/extension_permission_lang_test.php
+++ b/tests/functional/extension_permission_lang_test.php
@@ -30,7 +30,7 @@ class phpbb_functional_extension_permission_lang_test extends phpbb_functional_t
{
parent::setUpBeforeClass();
- self::$helper = new phpbb_test_case_helpers(self);
+ self::$helper = new phpbb_test_case_helpers(__CLASS__);
self::$helper->copy_ext_fixtures(dirname(__FILE__) . '/fixtures/ext/', self::$fixtures);
}
diff --git a/tests/functional/feed_test.php b/tests/functional/feed_test.php
index e48dfc043a..725a44ae5e 100644
--- a/tests/functional/feed_test.php
+++ b/tests/functional/feed_test.php
@@ -30,9 +30,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
{
parent::__construct($name, $data, $dataName);
- $this->backupStaticAttributesBlacklist += array(
- 'phpbb_functional_feed_test' => array('init_values'),
- );
+ $this->backupStaticAttributesBlacklist['phpbb_functional_feed_test'] = array('init_values');
+
+ $this->purge_cache();
}
public function test_setup_config_before_state()
@@ -61,66 +61,64 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$form->setValues($values);
$crawler = self::submit($form);
- $this->assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text());
+ self::assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text());
// Special config (Guest can't see attachments)
$this->add_lang('acp/permissions');
$crawler = self::request('GET', "adm/index.php?i=acp_permissions&sid={$this->sid}&icat=16&mode=setting_group_global&group_id[0]=1");
- $this->assertContains($this->lang('ACL_SET'), $crawler->filter('h1')->eq(1)->text());
+ self::assertContains($this->lang('ACL_SET'), $crawler->filter('h1')->eq(1)->text());
$form = $crawler->selectButton($this->lang('APPLY_PERMISSIONS'))->form();
$form['setting[1][0][u_download]']->select(-1);
$crawler = self::submit($form);
- $this->assertContainsLang('AUTH_UPDATED', $crawler->filter('.successbox')->text());
+ self::assertContainsLang('AUTH_UPDATED', $crawler->filter('.successbox')->text());
}
public function test_dump_board_state()
{
- $crawler = self::request('GET', 'feed.php?mode=forums', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/forums', array(), false);
self::assert_response_xml();
self::$init_values['disapprove_user']['forums_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=overall', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/overall', array(), false);
self::assert_response_xml();
self::$init_values['disapprove_user']['overall_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=topics', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/topics', array(), false);
self::assert_response_xml();
self::$init_values['disapprove_user']['topics_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=topics_new', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/topics_new', array(), false);
self::assert_response_xml();
self::$init_values['disapprove_user']['topics_new_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=topics_active', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/topics_active', array(), false);
self::assert_response_xml();
self::$init_values['disapprove_user']['topics_active_value'] = $crawler->filterXPath('//entry')->count();
$this->login();
- $crawler = self::request('GET', 'feed.php?mode=forums', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/forums', array(), false);
self::assert_response_xml();
self::$init_values['admin']['forums_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=overall', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/overall', array(), false);
self::assert_response_xml();
self::$init_values['admin']['overall_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=topics', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/topics', array(), false);
self::assert_response_xml();
self::$init_values['admin']['topics_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=topics_new', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/topics_new', array(), false);
self::assert_response_xml();
self::$init_values['admin']['topics_new_value'] = $crawler->filterXPath('//entry')->count();
- $crawler = self::request('GET', 'feed.php?mode=topics_active', array(), false);
+ $crawler = self::request('GET', 'app.php/feed/topics_active', array(), false);
self::assert_response_xml();
self::$init_values['admin']['topics_active_value'] = $crawler->filterXPath('//entry')->count();
-
-
}
public function test_setup_forums()
@@ -138,7 +136,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$form = $crawler->selectButton('update')->form(array(
'forum_perm_from' => 2,
));
- $crawler = self::submit($form);
+ self::submit($form);
$this->load_ids(array(
'forums' => array(
@@ -155,7 +153,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$form = $crawler->selectButton('update')->form(array(
'forum_perm_from' => 2,
));
- $crawler = self::submit($form);
+ self::submit($form);
// 'Feeds #news' will be used for feed.php?mode=news
$crawler = self::request('GET', "adm/index.php?i=acp_forums&mode=manage&sid={$this->sid}");
@@ -166,9 +164,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$form = $crawler->selectButton('update')->form(array(
'forum_perm_from' => 2,
));
- $crawler = self::submit($form);
+ self::submit($form);
- // 'Feeds #exclude' will not be displayed on feed.php?mode=forums
+ // 'Feeds #exclude' will not be displayed on app.php/feed/forums
$crawler = self::request('GET', "adm/index.php?i=acp_forums&mode=manage&sid={$this->sid}");
$form = $crawler->selectButton('addforum')->form(array(
'forum_name' => 'Feeds #exclude',
@@ -177,7 +175,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$form = $crawler->selectButton('update')->form(array(
'forum_perm_from' => 2,
));
- $crawler = self::submit($form);
+ self::submit($form);
}
public function test_setup_config_after_forums()
@@ -201,7 +199,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$form['feed_exclude_id']->select(array($this->data['forums']['Feeds #exclude']));
$crawler = self::submit($form);
- $this->assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text());
+ self::assertContainsLang('CONFIG_UPDATED', $crawler->filter('.successbox')->text());
}
public function test_feeds_empty()
@@ -272,6 +270,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
'id' => $this->data['forums']['Feeds #exclude'],
'contents_lang' => array('NO_FEED'),
'invalid' => true,
+ 'response_code' => 404,
),
),
't' => array(
@@ -279,6 +278,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
'id' => $this->data['topics']['Feeds #exclude - Topic #1'],
'contents_lang' => array('NO_FEED'),
'invalid' => true,
+ 'response_code' => 404,
),
),
'overall' => array(
@@ -331,15 +331,15 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$post = $this->create_topic($this->data['forums']['Feeds #news'], 'Feeds #news - Topic #2', 'This is a test topic posted by the testing framework.');
$crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
- $this->assertContains('Feeds #news - Topic #2', $crawler->filter('html')->text());
+ self::assertContains('Feeds #news - Topic #2', $crawler->filter('html')->text());
$this->data['topics']['Feeds #news - Topic #2'] = (int) $post['topic_id'];
$this->data['posts']['Feeds #news - Topic #2'] = (int) $this->get_parameter_from_link($crawler->filter('.post')->selectLink($this->lang('POST', '', ''))->link()->getUri(), 'p');
// Test creating a reply
$post2 = $this->create_post($this->data['forums']['Feeds #news'], $post['topic_id'], 'Re: Feeds #news - Topic #2', 'This is a test post posted by the testing framework.');
- $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
- $this->assertContains('Re: Feeds #news - Topic #2', $crawler->filter('html')->text());
+ self::assertContains('Re: Feeds #news - Topic #2', $crawler->filter('html')->text());
$this->data['posts']['Re: Feeds #news - Topic #2'] = (int) $post2['post_id'];
}
@@ -493,9 +493,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
// Test creating a reply
$post2 = $this->create_post($this->data['forums']['Feeds #1'], $post['topic_id'], 'Re: Feeds #1 - Topic #2', 'This is a test post posted by the testing framework.');
- $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
- $this->assertContains('Re: Feeds #1 - Topic #2', $crawler->filter('html')->text());
+ self::assertContains('Re: Feeds #1 - Topic #2', $crawler->filter('html')->text());
$this->data['posts']['Re: Feeds #1 - Topic #2'] = (int) $post2['post_id'];
}
@@ -516,14 +516,14 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$this->add_lang('posting');
$crawler = self::request('GET', "posting.php?mode=delete&f={$this->data['forums']['Feeds #1']}&p={$this->data['posts']['Re: Feeds #1 - Topic #2']}&sid={$this->sid}");
- $this->assertContainsLang('DELETE_PERMANENTLY', $crawler->text());
+ self::assertContainsLang('DELETE_PERMANENTLY', $crawler->text());
$form = $crawler->selectButton('Yes')->form();
$crawler = self::submit($form);
- $this->assertContainsLang('POST_DELETED', $crawler->text());
+ self::assertContainsLang('POST_DELETED', $crawler->text());
$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Feeds #1 - Topic #2']}&sid={$this->sid}");
- $this->assertContains($this->lang('POST_DISPLAY', '', ''), $crawler->text());
+ self::assertContains($this->lang('POST_DISPLAY', '', ''), $crawler->text());
}
public function test_feeds_softdeleted_post_admin()
@@ -615,15 +615,15 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$this->add_lang('posting');
$crawler = $this->get_quickmod_page($this->data['topics']['Feeds #1 - Topic #2'], 'DELETE_TOPIC');
- $this->assertContainsLang('DELETE_PERMANENTLY', $crawler->text());
+ self::assertContainsLang('DELETE_PERMANENTLY', $crawler->text());
$this->add_lang('mcp');
$form = $crawler->selectButton('Yes')->form();
$crawler = self::submit($form);
- $this->assertContainsLang('TOPIC_DELETED_SUCCESS', $crawler->text());
+ self::assertContainsLang('TOPIC_DELETED_SUCCESS', $crawler->text());
$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Feeds #1 - Topic #2']}&sid={$this->sid}");
- $this->assertContains('Feeds #1 - Topic #2', $crawler->filter('h2')->text());
+ self::assertContains('Feeds #1 - Topic #2', $crawler->filter('h2')->text());
}
public function test_feeds_softdeleted_topic_admin()
@@ -716,8 +716,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
't' => array(
array(
'id' => $this->data['topics']['Feeds #1 - Topic #2'],
- 'contents_lang' => array('SORRY_AUTH_READ'),
+ 'contents_lang' => array('SORRY_AUTH_READ_TOPIC'),
'invalid' => true,
+ 'response_code' => 403,
),
),
'overall' => array(
@@ -758,10 +759,10 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
// Test creating a reply
$this->login('disapprove_user');
- $post2 = $this->create_post($this->data['forums']['Feeds #1.1'], $post['topic_id'], 'Re: Feeds #1.1 - Topic #2', 'This is a test post posted by the testing framework.', array(), 'POST_STORED_MOD');
+ $this->create_post($this->data['forums']['Feeds #1.1'], $post['topic_id'], 'Re: Feeds #1.1 - Topic #2', 'This is a test post posted by the testing framework.', array(), 'POST_STORED_MOD');
$crawler = self::request('GET', "viewtopic.php?t={$this->data['topics']['Feeds #1.1 - Topic #2']}&sid={$this->sid}");
- $this->assertNotContains('Re: Feeds #1.1 - Topic #2', $crawler->filter('html')->text());
+ self::assertNotContains('Re: Feeds #1.1 - Topic #2', $crawler->filter('html')->text());
}
public function test_feeds_unapproved_post_admin()
@@ -853,7 +854,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$this->data['topics']['Feeds #1 - Topic #3'] = (int) $post['topic_id'];
$crawler = self::request('GET', "viewforum.php?f={$this->data['forums']['Feeds #1.1']}&sid={$this->sid}");
- $this->assertNotContains('Feeds #1.1 - Topic #3', $crawler->filter('html')->text());
+ self::assertNotContains('Feeds #1.1 - Topic #3', $crawler->filter('html')->text());
$this->logout();
$this->set_flood_interval(15);
@@ -869,10 +870,10 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$form = $crawler->selectButton('Submit')->form();
$values = $form->getValues();
- $values["config[flood_interval]"] = $flood_interval;
+ $values['config[flood_interval]'] = $flood_interval;
$form->setValues($values);
$crawler = self::submit($form);
- $this->assertGreaterThan(0, $crawler->filter('.successbox')->count());
+ self::assertGreaterThan(0, $crawler->filter('.successbox')->count());
$this->logout();
}
@@ -964,8 +965,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
't' => array(
array(
'id' => $this->data['topics']['Feeds #1.1 - Topic #3'],
- 'contents_lang' => array('SORRY_AUTH_READ'),
+ 'contents_lang' => array('SORRY_AUTH_READ_TOPIC'),
'invalid' => true,
+ 'response_code' => 403,
),
),
'overall' => array(
@@ -1004,7 +1006,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$post = $this->create_topic($this->data['forums']['Feeds #1'], 'Feeds #1 - Topic #3', 'This is a test topic posted by the testing framework. [attachment=0]Attachment #0[/attachment]', array('upload_files' => 1));
$crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
- $this->assertContains('Feeds #1 - Topic #3', $crawler->filter('html')->text());
+ self::assertContains('Feeds #1 - Topic #3', $crawler->filter('html')->text());
$this->data['topics']['Feeds #1 - Topic #3'] = (int) $post['topic_id'];
}
@@ -1220,9 +1222,9 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
// Test creating a reply with 1 missing attachment
$post2 = $this->create_post($this->data['forums']['Feeds #1'], $this->data['topics']['Feeds #1 - Topic #3'], 'Re: Feeds #1 - Topic #3-1', 'This is a test post posted by the testing framework. [attachment=0]Attachment #0[/attachment]');
- $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
- $this->assertContains('Re: Feeds #1 - Topic #3-1', $crawler->filter('html')->text());
+ self::assertContains('Re: Feeds #1 - Topic #3-1', $crawler->filter('html')->text());
$this->data['posts']['Re: Feeds #1 - Topic #3-1'] = (int) $post2['post_id'];
}
@@ -1322,9 +1324,14 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
{
foreach ($feeds as $feed_data)
{
- if ($mode === 'f' || $mode === 't')
+ if ($mode === 'f')
+ {
+ $params = "/forum/{$feed_data['id']}";
+ $this->assert_feed($params, $feed_data);
+ }
+ else if ($mode === 't')
{
- $params = "?{$mode}={$feed_data['id']}";
+ $params = "/topic/{$feed_data['id']}";
$this->assert_feed($params, $feed_data);
}
else
@@ -1348,10 +1355,10 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
case 'news':
break;
default:
- $this->fail('Unsupported feed mode: ' . $mode);
+ self::fail('Unsupported feed mode: ' . $mode);
}
- $params = "?mode={$mode}";
+ $params = "/{$mode}";
$this->assert_feed($params, $feed_data);
}
}
@@ -1360,19 +1367,19 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
protected function assert_feed($params, $data)
{
- $crawler = self::request('GET', 'feed.php' . $params, array(), false);
+ $crawler = self::request('GET', 'app.php/feed' . $params, array(), false);
if (empty($data['invalid']))
{
self::assert_response_xml();
- $this->assertEquals($data['nb_entries'], $crawler->filter('entry')->count(), "Tested feed : 'feed.php{$params}'");
+ self::assertEquals($data['nb_entries'], $crawler->filter('entry')->count(), "Tested feed : 'app.php/feed{$params}'");
if (!empty($data['xpath']))
{
foreach($data['xpath'] as $xpath => $count_expected)
{
- $this->assertCount($count_expected, $crawler->filterXPath($xpath), "Tested feed : 'feed.php{$params}', Search for {$xpath}");
+ self::assertCount($count_expected, $crawler->filterXPath($xpath), "Tested feed : 'app.php/feed{$params}', Search for {$xpath}");
}
}
@@ -1381,7 +1388,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
foreach($data['contents'] as $entry_id => $string)
{
$content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text();
- $this->assertContains($string, $content, "Tested feed : 'feed.php{$params}'");
+ self::assertContains($string, $content, "Tested feed : 'app.php/feed{$params}'");
}
}
@@ -1390,7 +1397,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
foreach($data['contents_lang'] as $entry_id => $string)
{
$content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text();
- $this->assertContainsLang($string, $content, "Tested feed : 'feed.php{$params}'");
+ self::assertContainsLang($string, $content, "Tested feed : 'app.php/feed{$params}'");
}
}
@@ -1398,21 +1405,21 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
{
foreach($data['attachments'] as $entry_id => $attachments)
{
+ $content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text();
foreach ($attachments as $i => $attachment)
{
- $content = $crawler->filterXPath("//entry[{$entry_id}]/content")->text();
$url = self::$root_url . "download/file.php?id={$attachment['id']}";
$string = "Attachment #{$i}";
if ($attachment['displayed'])
{
- $this->assertContains($url, $content, "Tested feed : 'feed.php{$params}'");
- $this->assertNotContains($string, $content, "Tested feed : 'feed.php{$params}'");
+ self::assertContains($url, $content, "Tested feed : 'app.php/feed{$params}'");
+ self::assertNotContains($string, $content, "Tested feed : 'app.php/feed{$params}'");
}
else
{
- $this->assertContains($string, $content, "Tested feed : 'feed.php{$params}'");
- $this->assertNotContains($url, $content, "Tested feed : 'feed.php{$params}'");
+ self::assertContains($string, $content, "Tested feed : 'app.php/feed{$params}'");
+ self::assertNotContains($url, $content, "Tested feed : 'app.php/feed{$params}'");
}
}
}
@@ -1420,14 +1427,14 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
}
else
{
- self::assert_response_html();
+ self::assert_response_html($data['response_code'] ?: 202);
if (!empty($data['contents_lang']))
{
+ $content = $crawler->filter('html')->text();
foreach($data['contents_lang'] as $string)
{
- $content = $crawler->filter('html')->text();
- $this->assertContainsLang($string, $content, "Tested feed : 'feed.php{$params}'");
+ self::assertContainsLang($string, $content, "Tested feed : 'app.php/feed{$params}'");
}
}
}
@@ -1445,7 +1452,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
- if (in_array($row['forum_name'], $data['forums']))
+ if (in_array($row['forum_name'], $data['forums'], false))
{
$this->data['forums'][$row['forum_name']] = (int) $row['forum_id'];
}
@@ -1461,7 +1468,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
- if (in_array($row['topic_title'], $data['topics']))
+ if (in_array($row['topic_title'], $data['topics'], false))
{
$this->data['topics'][$row['topic_title']] = (int) $row['topic_id'];
}
@@ -1478,7 +1485,7 @@ class phpbb_functional_feed_test extends phpbb_functional_test_case
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
{
- if (in_array($row['post_subject'], $data['posts']))
+ if (in_array($row['post_subject'], $data['posts'], false))
{
$this->data['posts'][$row['post_subject']] = (int) $row['post_id'];
$post_ids[] = (int) $row['post_id'];
diff --git a/tests/functional/fileupload_form_test.php b/tests/functional/fileupload_form_test.php
index d381fa1ae2..ff9450be0d 100644
--- a/tests/functional/fileupload_form_test.php
+++ b/tests/functional/fileupload_form_test.php
@@ -46,6 +46,13 @@ class phpbb_functional_fileupload_form_test extends phpbb_functional_test_case
private function upload_file($filename, $mimetype)
{
+ $crawler = self::$client->request(
+ 'GET',
+ 'posting.php?mode=reply&f=2&t=1&sid=' . $this->sid
+ );
+
+ $file_form_data = array_merge(['add_file' => $this->lang('ADD_FILE')], $this->get_hidden_fields($crawler, 'posting.php?mode=reply&f=2&t=1&sid=' . $this->sid));
+
$file = array(
'tmp_name' => $this->path . $filename,
'name' => $filename,
@@ -57,7 +64,7 @@ class phpbb_functional_fileupload_form_test extends phpbb_functional_test_case
$crawler = self::$client->request(
'POST',
'posting.php?mode=reply&f=2&t=1&sid=' . $this->sid,
- array('add_file' => $this->lang('ADD_FILE')),
+ $file_form_data,
array('fileupload' => $file)
);
@@ -99,7 +106,6 @@ class phpbb_functional_fileupload_form_test extends phpbb_functional_test_case
$form = $crawler->selectButton('Submit')->form(array(
'config[check_attachment_content]' => 0,
- 'config[img_imagick]' => '',
));
self::submit($form);
diff --git a/tests/functional/fileupload_remote_test.php b/tests/functional/fileupload_remote_test.php
index 6ece150b23..426ebcee53 100644
--- a/tests/functional/fileupload_remote_test.php
+++ b/tests/functional/fileupload_remote_test.php
@@ -11,13 +11,29 @@
*
*/
-require_once __DIR__ . '/../../phpBB/includes/functions_upload.php';
-
/**
* @group functional
*/
class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case
{
+ /** @var \phpbb\filesystem\filesystem_interface */
+ protected $filesystem;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\request\request_interface */
+ protected $request;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
public function setUp()
{
parent::setUp();
@@ -25,19 +41,28 @@ class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case
// URL
// Global $config required by unique_id
- // Global $user required by fileupload::remote_upload
- global $config, $user;
+ global $config, $phpbb_root_path, $phpEx;
if (!is_array($config))
{
- $config = array();
+ $config = new \phpbb\config\config(array());
}
$config['rand_seed'] = '';
$config['rand_seed_last_update'] = time() + 600;
+ $config['remote_upload_verify'] = 0;
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->request = $this->getMock('\phpbb\request\request');
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
- $user = new phpbb_mock_user();
- $user->lang = new phpbb_mock_lang();
+ $container = new phpbb_mock_container_builder();
+ $container->set('files.filespec', new \phpbb\files\filespec($this->filesystem, $this->language, $this->php_ini, new \FastImageSize\FastImageSize(), $this->phpbb_root_path));
+ $this->factory = new \phpbb\files\factory($container);
+ $container->set('files.factory', $this->factory);
+ $container->set('files.types.remote', new \phpbb\files\types\remote($config, $this->factory, $this->language, $this->php_ini, $this->request, $phpbb_root_path));
+ $this->phpbb_root_path = $phpbb_root_path;
}
public function tearDown()
@@ -49,31 +74,48 @@ class phpbb_functional_fileupload_remote_test extends phpbb_functional_test_case
public function test_invalid_extension()
{
- $upload = new fileupload('', array('jpg'), 100);
- $file = $upload->remote_upload(self::$root_url . 'develop/blank.gif');
+ /** @var \phpbb\files\upload $upload */
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_error_prefix('')
+ ->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(100);
+ $file = $upload->handle_upload('files.types.remote', self::$root_url . 'develop/blank.gif');
$this->assertEquals('URL_INVALID', $file->error[0]);
}
public function test_empty_file()
{
- $upload = new fileupload('', array('jpg'), 100);
- $file = $upload->remote_upload(self::$root_url . 'develop/blank.jpg');
+ /** @var \phpbb\files\upload $upload */
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_error_prefix('')
+ ->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(100);
+ $file = $upload->handle_upload('files.types.remote', self::$root_url . 'develop/blank.jpg');
$this->assertEquals('EMPTY_REMOTE_DATA', $file->error[0]);
}
public function test_successful_upload()
{
- $upload = new fileupload('', array('gif'), 1000);
- $file = $upload->remote_upload(self::$root_url . 'styles/prosilver/theme/images/forum_read.gif');
- $this->assertEquals(0, sizeof($file->error));
- $this->assertTrue(file_exists($file->filename));
+ /** @var \phpbb\files\upload $upload */
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_error_prefix('')
+ ->set_allowed_extensions(array('gif'))
+ ->set_max_filesize(2000);
+ $file = $upload->handle_upload('files.types.remote', self::$root_url . 'develop/test.gif');
+ $this->assertEquals(0, count($file->error));
+ $this->assertTrue(file_exists($file->get('filename')));
+ $this->assertTrue($file->is_uploaded());
}
public function test_too_large()
{
- $upload = new fileupload('', array('gif'), 100);
- $file = $upload->remote_upload(self::$root_url . 'styles/prosilver/theme/images/forum_read.gif');
- $this->assertEquals(1, sizeof($file->error));
+ /** @var \phpbb\files\upload $upload */
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_error_prefix('')
+ ->set_allowed_extensions(array('gif'))
+ ->set_max_filesize(100);
+ $file = $upload->handle_upload('files.types.remote', self::$root_url . 'develop/test.gif');
+ $this->assertEquals(1, count($file->error));
$this->assertEquals('WRONG_FILESIZE', $file->error[0]);
}
}
diff --git a/tests/functional/fixtures/ext/foo/bar/acp/main_info.php b/tests/functional/fixtures/ext/foo/bar/acp/main_info.php
index ec378e0e75..371ab7c967 100644
--- a/tests/functional/fixtures/ext/foo/bar/acp/main_info.php
+++ b/tests/functional/fixtures/ext/foo/bar/acp/main_info.php
@@ -28,7 +28,6 @@ class main_info
return array(
'filename' => 'foo\bar\acp\main_module',
'title' => 'ACP_FOOBAR_TITLE',
- 'version' => '1.0.0',
'modes' => array(
'mode' => array('title' => 'ACP_FOOBAR_MODE', 'auth' => '', 'cat' => array('ACP_FOOBAR_TITLE')),
),
diff --git a/tests/functional/fixtures/ext/foo/bar/config/services.yml b/tests/functional/fixtures/ext/foo/bar/config/services.yml
index d35be7955a..495c775a1f 100644
--- a/tests/functional/fixtures/ext/foo/bar/config/services.yml
+++ b/tests/functional/fixtures/ext/foo/bar/config/services.yml
@@ -2,13 +2,13 @@ services:
foo_bar.controller:
class: foo\bar\controller\controller
arguments:
- - @controller.helper
- - @path_helper
- - @template
- - @config
- - @user
- - %core.root_path%
- - %core.php_ext%
+ - '@controller.helper'
+ - '@path_helper'
+ - '@template'
+ - '@config'
+ - '@user'
+ - '%core.root_path%'
+ - '%core.php_ext%'
foo_bar.listener.permission:
class: foo\bar\event\permission
diff --git a/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php b/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php
index d34244f800..4c74442639 100644
--- a/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php
+++ b/tests/functional/fixtures/ext/foo/bar/ucp/main_info.php
@@ -20,7 +20,6 @@ class main_info
return array(
'filename' => '\foo\bar\ucp\main_module',
'title' => 'ACP_FOOBAR_TITLE',
- 'version' => '1.0.0',
'modes' => array(
'mode' => array('title' => 'ACP_FOOBAR_MODE', 'auth' => '', 'cat' => array('ACP_FOOBAR_TITLE')),
),
diff --git a/tests/functional/forum_style_test.php b/tests/functional/forum_style_test.php
index 65be94f4d0..b3c1115b7f 100644
--- a/tests/functional/forum_style_test.php
+++ b/tests/functional/forum_style_test.php
@@ -16,16 +16,28 @@
*/
class phpbb_functional_forum_style_test extends phpbb_functional_test_case
{
+ public function test_font_awesome_style()
+ {
+ $crawler = self::request('GET', 'viewtopic.php?t=1&f=2');
+ $this->assertContains('font-awesome.min', $crawler->filter('head > link[rel=stylesheet]')->eq(0)->attr('href'));
+
+ $crawler = self::request('GET', 'viewtopic.php?t=1');
+ $this->assertContains('font-awesome.min', $crawler->filter('head > link[rel=stylesheet]')->eq(0)->attr('href'));
+
+ $crawler = self::request('GET', 'viewtopic.php?t=1&view=next');
+ $this->assertContains('font-awesome.min', $crawler->filter('head > link[rel=stylesheet]')->eq(0)->attr('href'));
+ }
+
public function test_default_forum_style()
{
$crawler = self::request('GET', 'viewtopic.php?t=1&f=2');
- $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->attr('href'));
+ $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href'));
$crawler = self::request('GET', 'viewtopic.php?t=1');
- $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->attr('href'));
+ $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href'));
$crawler = self::request('GET', 'viewtopic.php?t=1&view=next');
- $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->attr('href'));
+ $this->assertContains('styles/prosilver/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href'));
}
public function test_custom_forum_style()
@@ -35,13 +47,13 @@ class phpbb_functional_forum_style_test extends phpbb_functional_test_case
$db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET forum_style = 2 WHERE forum_id = 2');
$crawler = self::request('GET', 'viewtopic.php?t=1&f=2');
- $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->attr('href'));
+ $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href'));
$crawler = self::request('GET', 'viewtopic.php?t=1');
- $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->attr('href'));
+ $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href'));
$crawler = self::request('GET', 'viewtopic.php?t=1&view=next');
- $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->attr('href'));
+ $this->assertContains('styles/test_style/', $crawler->filter('head > link[rel=stylesheet]')->eq(1)->attr('href'));
$db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET forum_style = 0 WHERE forum_id = 2');
$this->delete_style(2, 'test_style');
diff --git a/tests/functional/metadata_manager_test.php b/tests/functional/metadata_manager_test.php
index 0d2fdf082e..8456c40f00 100644
--- a/tests/functional/metadata_manager_test.php
+++ b/tests/functional/metadata_manager_test.php
@@ -35,7 +35,7 @@ class phpbb_functional_metadata_manager_test extends phpbb_functional_test_case
{
parent::setUpBeforeClass();
- self::$helper = new phpbb_test_case_helpers(self);
+ self::$helper = new phpbb_test_case_helpers(__CLASS__);
self::$helper->copy_ext_fixtures(dirname(__FILE__) . '/fixtures/ext/', self::$fixtures);
}
diff --git a/tests/functional/notification_test.php b/tests/functional/notification_test.php
index f21d73817a..91fc962846 100644
--- a/tests/functional/notification_test.php
+++ b/tests/functional/notification_test.php
@@ -21,15 +21,15 @@ class phpbb_functional_notification_test extends phpbb_functional_test_case
return array(
// Rows inserted by phpBB/install/schemas/schema_data.sql
// Also see PHPBB3-11460
- array('notification.type.post_notification', true),
- array('notification.type.topic_notification', true),
+ array('notification.type.post_notification.method.board', true),
+ array('notification.type.topic_notification.method.board', true),
array('notification.type.post_notification.method.email', true),
array('notification.type.topic_notification.method.email', true),
// Default behaviour for in-board notifications:
// If user did not opt-out, in-board notifications are on.
- array('notification.type.bookmark_notification', true),
- array('notification.type.quote_notification', true),
+ array('notification.type.bookmark_notification.method.board', true),
+ array('notification.type.quote_notification.method.board', true),
// Default behaviour for email notifications:
// If user did not opt-in, email notifications are off.
diff --git a/tests/functional/permission_roles_test.php b/tests/functional/permission_roles_test.php
new file mode 100644
index 0000000000..e6506fb37c
--- /dev/null
+++ b/tests/functional/permission_roles_test.php
@@ -0,0 +1,84 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @group functional
+*/
+class functional_permission_roles_test extends phpbb_functional_test_case
+{
+ public function data_permission_roles()
+ {
+ return array(
+ array(
+ array(0, 14),
+ array(17, 17),
+ array(
+ 'role[5][1]' => 14,
+ )
+ ),
+ array(
+ array(14, 14),
+ array(17, 17),
+ array(
+ 'role[5][1]' => 0,
+ )
+ ),
+ array(
+ array(0, 14),
+ array(17, 17)
+ ),
+ );
+ }
+ /**
+ * @dataProvider data_permission_roles
+ */
+ public function test_permission_roles($admin_roles, $guest_roles, $set_values = array())
+ {
+ $this->login();
+ $this->admin_login();
+ $this->add_lang('acp/permissions');
+ $crawler = self::request('GET', 'adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid);
+
+ // Select forums
+ $form = $crawler->filter('form[id=select_victim]')->form();
+ $form['forum_id']->setValue(array(1,2));
+ $crawler = self::$client->submit($form);
+
+ // Select administrators and guests
+ $groups_form = $crawler->filter('form[id=groups]')->form();
+ $groups_form['group_id']->setValue(array(1,5));
+
+ $crawler = self::submit($groups_form);
+ $form = $crawler->filter('form')->form();
+ $values = $form->getValues();
+
+ // Check default settings
+ $this->assertEquals($admin_roles[0], $values['role[5][1]']);
+ $this->assertEquals($admin_roles[1], $values['role[5][2]']);
+ $this->assertEquals($guest_roles[0], $values['role[1][1]']);
+ $this->assertEquals($guest_roles[1], $values['role[1][2]']);
+
+ // Set admin to full access on category
+ foreach ($set_values as $key => $value)
+ {
+ $form[$key]->setValue($value);
+ }
+
+ $form_values = $form->getValues();
+ $form_values['action[apply_all_permissions]'] = true;
+ $crawler = self::request('POST', 'adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid, $form_values);
+ $this->assertContainsLang('AUTH_UPDATED', $crawler->text());
+
+ $this->logout();
+ }
+}
diff --git a/tests/functional/plupload_test.php b/tests/functional/plupload_test.php
index d358681ad1..4ab1c8e9e5 100644
--- a/tests/functional/plupload_test.php
+++ b/tests/functional/plupload_test.php
@@ -76,6 +76,10 @@ class phpbb_functional_plupload_test extends phpbb_functional_test_case
$chunk_size = ceil(filesize($this->path . 'valid.jpg') / self::CHUNKS);
$handle = fopen($this->path . 'valid.jpg', 'rb');
+ $crawler = self::$client->request('POST', $url . '&sid=' . $this->sid);
+
+ $file_form_data = $this->get_hidden_fields($crawler, $url);
+
for ($i = 0; $i < self::CHUNKS; $i++)
{
$chunk = fread($handle, $chunk_size);
@@ -94,24 +98,24 @@ class phpbb_functional_plupload_test extends phpbb_functional_test_case
$crawler = self::$client->request(
'POST',
$url . '&sid=' . $this->sid,
- array(
+ array_merge(array(
'chunk' => $i,
'chunks' => self::CHUNKS,
'name' => md5('valid') . '.jpg',
'real_filename' => 'valid.jpg',
'add_file' => $this->lang('ADD_FILE'),
- ),
+ ), $file_form_data),
array('fileupload' => $file),
array('X-PHPBB-USING-PLUPLOAD' => '1')
);
if ($i < self::CHUNKS - 1)
{
- $this->assertContains('{"jsonrpc":"2.0","id":"id","result":null}', self::$client->getResponse()->getContent());
+ $this->assertContains('{"jsonrpc":"2.0","id":"id","result":null}', self::get_content());
}
else
{
- $response = json_decode(self::$client->getResponse()->getContent(), true);
+ $response = json_decode(self::get_content(), true);
$this->assertEquals('valid.jpg', $response['data'][0]['real_filename']);
}
@@ -134,21 +138,23 @@ class phpbb_functional_plupload_test extends phpbb_functional_test_case
'error' => UPLOAD_ERR_OK,
);
- $crawler = self::$client->request(
+ $file_form_data = $this->get_hidden_fields(null, $url);
+
+ self::$client->setServerParameter('HTTP_X_PHPBB_USING_PLUPLOAD', '1');
+ self::$client->request(
'POST',
$url . '&sid=' . $this->sid,
- array(
+ array_merge(array(
'chunk' => '0',
'chunks' => '1',
'name' => md5('valid') . '.jpg',
'real_filename' => 'valid.jpg',
'add_file' => $this->lang('ADD_FILE'),
- ),
- array('fileupload' => $file),
- array('X-PHPBB-USING-PLUPLOAD' => '1')
+ ), $file_form_data),
+ array('fileupload' => $file)
);
- $response = json_decode(self::$client->getResponse()->getContent(), true);
+ $response = json_decode(self::get_content(), true);
$this->assertEquals('valid.jpg', $response['data'][0]['real_filename']);
}
}
diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php
index 914233240e..49447e1133 100644
--- a/tests/functional/posting_test.php
+++ b/tests/functional/posting_test.php
@@ -29,7 +29,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
// Test creating a reply with bbcode
$post2 = $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test [b]post[/b] posted by the testing framework.');
- $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
$this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text());
// Test quoting a message
@@ -41,23 +41,62 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
{
$this->login();
- $this->add_lang('posting');
+ $post = $this->create_topic(2, "Test Topic \xF0\x9F\xA4\x94 3\xF0\x9D\x94\xBB\xF0\x9D\x95\x9A", 'This is a test with emoji character in the topic title.');
+ $this->create_post(2, $post['topic_id'], "Re: Test Topic 1 \xF0\x9F\xA4\x94 3\xF0\x9D\x94\xBB\xF0\x9D\x95\x9A", 'This is a test with emoji characters in the topic title.');
+ $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
+ $this->assertContains("\xF0\x9F\xA4\x94 3\xF0\x9D\x94\xBB\xF0\x9D\x95\x9A", $crawler->text());
+ }
- self::create_post(2,
- 1,
- 'Unsupported characters',
- "This is a test with these weird characters: \xF0\x9F\x88\xB3 \xF0\x9F\x9A\xB6",
- array(),
- 'Your message contains the following unsupported characters'
- );
+ public function test_supported_unicode_characters()
+ {
+ $this->login();
- self::create_post(2,
- 1,
- "Unsupported: \xF0\x9F\x88\xB3 \xF0\x9F\x9A\xB6",
- 'This is a test with emoji characters in the topic title.',
- array(),
- 'Your subject contains the following unsupported characters'
- );
+ $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.');
+ $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', "This is a test with these weird characters: \xF0\x9F\x84\x90 \xF0\x9F\x84\x91");
+ $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
+ $this->assertContains("\xF0\x9F\x84\x90 \xF0\x9F\x84\x91", $crawler->text());
+ }
+
+ public function test_html_entities()
+ {
+ $this->login();
+
+ $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.');
+ $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', '&#128512;');
+ $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}");
+ $this->assertContains('&#128512;', $crawler->text());
+ }
+
+ public function test_quote()
+ {
+ $text = 'Test post </textarea>"\' &&amp;amp;';
+ $expected = "(\\[quote=admin[^\\]]*\\]\n" . preg_quote($text) . "\n\\[/quote\\])";
+
+ $this->login();
+ $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic');
+ $post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text);
+
+ $crawler = self::request('GET', "posting.php?mode=quote&f=2&t={$post['topic_id']}&p={$post['post_id']}&sid={$this->sid}");
+
+ $this->assertRegexp($expected, $crawler->filter('textarea#message')->text());
+ }
+
+ /**
+ * @see https://tracker.phpbb.com/browse/PHPBB3-14962
+ */
+ public function test_edit()
+ {
+ $this->login();
+ $this->create_topic(2, 'Test Topic post', 'Test topic post');
+
+ $url = self::$client->getCrawler()->selectLink('Edit')->link()->getUri();
+ $post_id = $this->get_parameter_from_link($url, 'p');
+ $crawler = self::request('GET', "posting.php?mode=edit&f=2&p={$post_id}&sid={$this->sid}");
+ $form = $crawler->selectButton('Submit')->form();
+ $form->setValues(array('message' => 'Edited post'));
+ $crawler = self::submit($form);
+
+ $this->assertContains('Edited post', $crawler->filter("#post_content{$post_id} .content")->text());
}
/**
@@ -67,10 +106,10 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
{
$text = '0[quote]1[quote]2[/quote]1[/quote]0';
$expected = array(
- 0 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]',
- 1 => '[quote="admin"]00[/quote]',
- 2 => '[quote="admin"]0[quote]11[/quote]0[/quote]',
- 3 => '[quote="admin"]0[quote]1[quote]2[/quote]1[/quote]0[/quote]',
+ 0 => '0[quote]1[quote]2[/quote]1[/quote]0',
+ 1 => '00',
+ 2 => '0[quote]11[/quote]0',
+ 3 => '0[quote]1[quote]2[/quote]1[/quote]0',
);
$this->login();
@@ -83,7 +122,10 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
{
$this->set_quote_depth($quote_depth);
$crawler = self::request('GET', $quote_url);
- $this->assertContains($expected_text, $crawler->filter('textarea#message')->text());
+ $this->assertRegexp(
+ "(\\[quote=admin[^\\]]*\\]\n?" . preg_quote($expected_text) . "\n?\\[/quote\\])",
+ $crawler->filter('textarea#message')->text()
+ );
}
}
@@ -114,7 +156,7 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
{
$this->set_quote_depth($quote_depth);
- $post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text);
+ $post = $this->create_post(2, $topic['topic_id'], "Re: Test Topic 1#$quote_depth", $text);
$url = "viewtopic.php?p={$post['post_id']}&sid={$this->sid}";
$crawler = self::request('GET', $url);
@@ -156,4 +198,106 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
$crawler = self::submit($form);
$this->assertEquals(1, $crawler->filter('.successbox')->count());
}
+
+ public function test_ticket_8420()
+ {
+ $text = '[b][url=http://example.org] :arrow: here[/url][/b]';
+
+ $this->login();
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2');
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'Test subject',
+ 'message' => $text
+ ));
+ $crawler = self::submit($form);
+ $this->assertEquals($text, $crawler->filter('#message')->text());
+ }
+
+ public function test_old_signature_in_preview()
+ {
+ $sql = 'UPDATE ' . USERS_TABLE . "
+ SET user_sig = '[b:2u8sdcwb]My signature[/b:2u8sdcwb]',
+ user_sig_bbcode_uid = '2u8sdcwb',
+ user_sig_bbcode_bitfield = 'QA=='
+ WHERE user_id = 2";
+ $this->get_db()->sql_query($sql);
+
+ $this->login();
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2');
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'Test subject',
+ 'message' => 'My post',
+ ));
+ $crawler = self::submit($form);
+ $this->assertContains(
+ '<strong class="text-strong">My signature</strong>',
+ $crawler->filter('#preview .signature')->html()
+ );
+ }
+
+ /**
+ * @ticket PHPBB3-10628
+ */
+ public function test_www_links_preview()
+ {
+ $text = 'www.example.org';
+ $url = 'http://' . $text;
+
+ $this->add_lang('posting');
+ $this->login();
+
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2');
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'Test subject',
+ 'message' => $text
+ ));
+ $crawler = self::submit($form);
+
+ // Test that the textarea remains unchanged
+ $this->assertEquals($text, $crawler->filter('#message')->text());
+
+ // Test that the preview contains the correct link
+ $this->assertEquals($url, $crawler->filter('#preview a')->attr('href'));
+ }
+
+ public function test_allowed_schemes_links()
+ {
+ $text = 'http://example.org/ tcp://localhost:22/ServiceName';
+
+ $this->login();
+ $this->admin_login();
+
+ // Post with default settings
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2');
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'Test subject',
+ 'message' => $text,
+ ));
+ $crawler = self::submit($form);
+ $this->assertContains(
+ '<a href="http://example.org/" class="postlink">http://example.org/</a> tcp://localhost:22/ServiceName',
+ $crawler->filter('#preview .content')->html()
+ );
+
+ // Update allowed schemes
+ $crawler = self::request('GET', 'adm/index.php?sid=' . $this->sid . '&i=acp_board&mode=post');
+ $form = $crawler->selectButton('Submit')->form();
+ $values = $form->getValues();
+ $values['config[allowed_schemes_links]'] = 'https,tcp';
+ $form->setValues($values);
+ $crawler = self::submit($form);
+ $this->assertEquals(1, $crawler->filter('.successbox')->count());
+
+ // Post with new settings
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2');
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'Test subject',
+ 'message' => $text,
+ ));
+ $crawler = self::submit($form);
+ $this->assertContains(
+ 'http://example.org/ <a href="tcp://localhost:22/ServiceName" class="postlink">tcp://localhost:22/ServiceName</a>',
+ $crawler->filter('#preview .content')->html()
+ );
+ }
}
diff --git a/tests/functional/private_messages_test.php b/tests/functional/private_messages_test.php
index 1f6dc3a979..ce709524a9 100644
--- a/tests/functional/private_messages_test.php
+++ b/tests/functional/private_messages_test.php
@@ -66,4 +66,45 @@ class phpbb_functional_private_messages_test extends phpbb_functional_test_case
$crawler = self::submit($form);
$this->assertContains($this->lang('CONFIG_UPDATED'), $crawler->filter('.successbox')->text());
}
+
+ public function test_quote_post()
+ {
+ $text = 'Test post';
+
+ $this->login();
+ $topic = $this->create_topic(2, 'Test Topic 1', 'Test topic');
+ $post = $this->create_post(2, $topic['topic_id'], 'Re: Test Topic 1', $text);
+
+ $expected = '(\\[quote=admin post_id=' . $post['post_id'] . ' time=\\d+ user_id=2\\]' . $text . '\\[/quote\\])';
+
+ $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=quotepost&p=' . $post['post_id'] . '&sid=' . $this->sid);
+
+ $this->assertRegexp($expected, $crawler->filter('textarea#message')->text());
+ }
+
+ public function test_quote_pm()
+ {
+ $text = 'This is a test private message sent by the testing framework.';
+ $expected = "(\\[quote=admin msg_id=\\d+ time=\\d+ user_id=2\\]\n" . $text . "\n\\[/quote\\])";
+
+ $this->login();
+ $message_id = $this->create_private_message('Test', $text, array(2));
+
+ $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=quote&p=' . $message_id . '&sid=' . $this->sid);
+
+ $this->assertRegexp($expected, $crawler->filter('textarea#message')->text());
+ }
+
+ public function test_quote_forward()
+ {
+ $text = 'This is a test private message sent by the testing framework.';
+ $expected = "[quote=admin]\n" . $text . "\n[/quote]";
+
+ $this->login();
+ $message_id = $this->create_private_message('Test', $text, array(2));
+
+ $crawler = self::request('GET', 'ucp.php?i=pm&mode=compose&action=forward&f=0&p=' . $message_id . '&sid=' . $this->sid);
+
+ $this->assertContains($expected, $crawler->filter('textarea#message')->text());
+ }
}
diff --git a/tests/functional/prune_shadow_topic_test.php b/tests/functional/prune_shadow_topic_test.php
index c014119b98..2bf0280d62 100644
--- a/tests/functional/prune_shadow_topic_test.php
+++ b/tests/functional/prune_shadow_topic_test.php
@@ -77,7 +77,7 @@ class phpbb_functional_prune_shadow_topic_test extends phpbb_functional_test_cas
// Test creating a reply
$post2 = $this->create_post($this->data['forums']['Prune Shadow'], $this->post['topic_id'], 'Re: Prune Shadow #1-#2', 'This is a test post posted by the testing framework.');
- $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
$this->assertContains('Re: Prune Shadow #1-#2', $crawler->filter('html')->text());
$this->data['posts']['Re: Prune Shadow #1-#2'] = (int) $post2['post_id'];
diff --git a/tests/functional/registration_test.php b/tests/functional/registration_test.php
index 690f4ae9f2..48982edc8c 100644
--- a/tests/functional/registration_test.php
+++ b/tests/functional/registration_test.php
@@ -36,6 +36,10 @@ class phpbb_functional_registration_test extends phpbb_functional_test_case
{
$this->add_lang('ucp');
+ // Check that we can't skip
+ self::request('GET', 'ucp.php?mode=register&agreed=1');
+ $this->assertContainsLang('AGREE', $this->get_content());
+
$crawler = self::request('GET', 'ucp.php?mode=register');
$this->assertContainsLang('REGISTRATION', $crawler->filter('div.content h2')->text());
@@ -64,4 +68,54 @@ class phpbb_functional_registration_test extends phpbb_functional_test_case
$this->assert_checkbox_is_checked($crawler, 'notification.type.post_notification.method.email');
$this->assert_checkbox_is_checked($crawler, 'notification.type.topic_notification.method.email');
}
+
+ /**
+ * @depends test_disable_captcha_on_registration
+ */
+ public function test_register_coppa_account()
+ {
+ $this->login();
+ $this->admin_login();
+
+ $crawler = self::request('GET', "adm/index.php?i=acp_board&mode=registration&sid={$this->sid}");
+ $form = $crawler->selectButton('Submit')->form();
+ $form['config[coppa_enable]']->setValue('1');
+ $crawler = self::submit($form);
+
+ $this->assertContainsLang('CONFIG_UPDATED', $crawler->filter('#main .successbox')->text());
+ $this->logout();
+
+ $this->add_lang('ucp');
+
+ // Check that we can't skip
+ $crawler = self::request('GET', 'ucp.php?mode=register&coppa=1');
+ $this->assertContainsLang('COPPA_BIRTHDAY', $crawler->html());
+
+ $form = $crawler->selectButton('coppa_yes')->form();
+ $crawler = self::submit($form);
+
+ $this->assertContainsLang('REGISTRATION', $crawler->filter('div.content h2')->text());
+
+ $form = $crawler->selectButton('I agree to these terms')->form();
+ $crawler = self::submit($form);
+
+ $form = $crawler->selectButton('Submit')->form(array(
+ 'username' => 'user-coppa-test',
+ 'email' => 'user-coppa-test@phpbb.com',
+ 'new_password' => 'user-coppa-testuser-coppa-test',
+ 'password_confirm' => 'user-coppa-testuser-coppa-test',
+ ));
+ $form['tz']->select('Europe/Berlin');
+ $crawler = self::submit($form);
+
+ $this->assertContainsLang('ACCOUNT_COPPA', $crawler->filter('#message')->text());
+
+ $this->login();
+ $this->admin_login();
+
+ $crawler = self::request('GET', "adm/index.php?i=acp_board&mode=registration&sid={$this->sid}");
+ $form = $crawler->selectButton('Submit')->form();
+ $form['config[coppa_enable]']->setValue('0');
+ $crawler = self::submit($form);
+ }
}
diff --git a/tests/functional/report_post_captcha_test.php b/tests/functional/report_post_captcha_test.php
index 93a03bd931..36a1a9ee4d 100644
--- a/tests/functional/report_post_captcha_test.php
+++ b/tests/functional/report_post_captcha_test.php
@@ -18,12 +18,13 @@ class phpbb_functional_report_post_captcha_test extends phpbb_functional_test_ca
{
public function test_guest_report_post()
{
- $crawler = self::request('GET', 'report.php?f=2&p=1');
+ $crawler = self::request('GET', 'app.php/post/1/report', array(), false);
+ $this->assert_response_html(403);
$this->add_lang('mcp');
$this->assertContains($this->lang('USER_CANNOT_REPORT'), $crawler->filter('html')->text());
$this->set_reporting_guest(1);
- $crawler = self::request('GET', 'report.php?f=2&p=1');
+ $crawler = self::request('GET', 'app.php/post/1/report');
$this->assertContains($this->lang('CONFIRM_CODE'), $crawler->filter('html')->text());
$this->set_reporting_guest(-1);
}
@@ -31,7 +32,7 @@ class phpbb_functional_report_post_captcha_test extends phpbb_functional_test_ca
public function test_user_report_post()
{
$this->login();
- $crawler = self::request('GET', 'report.php?f=2&p=1');
+ $crawler = self::request('GET', 'app.php/post/1/report');
$this->assertNotContains($this->lang('CONFIRM_CODE'), $crawler->filter('html')->text());
$this->add_lang('mcp');
diff --git a/tests/functional/search/base.php b/tests/functional/search/base.php
index f1e9b517d4..48c444fb76 100644
--- a/tests/functional/search/base.php
+++ b/tests/functional/search/base.php
@@ -36,6 +36,8 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case
$this->login();
$this->admin_login();
+ $this->create_search_index('\phpbb\search\fulltext_native');
+
$post = $this->create_topic(2, 'Test Topic 1 foosubject', 'This is a test topic posted by the barsearch testing framework.');
$crawler = self::request('GET', 'adm/index.php?i=acp_search&mode=settings&sid=' . $this->sid);
@@ -58,6 +60,7 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case
$this->delete_topic($post['topic_id']);
$this->markTestSkipped("Search backend is not supported/running");
}
+
$this->create_search_index();
}
@@ -72,7 +75,7 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case
$this->delete_topic($post['topic_id']);
}
- protected function create_search_index()
+ protected function create_search_index($backend = null)
{
$this->add_lang('acp/search');
$crawler = self::request('GET', 'adm/index.php?i=acp_search&mode=index&sid=' . $this->sid);
@@ -80,7 +83,7 @@ abstract class phpbb_functional_search_base extends phpbb_functional_test_case
$form_values = $form->getValues();
$form_values = array_merge($form_values,
array(
- 'search_type' => $this->search_backend,
+ 'search_type' => ( ($backend === null) ? $this->search_backend : $backend ),
'action' => 'create',
)
);
diff --git a/tests/functional/ucp_groups_test.php b/tests/functional/ucp_groups_test.php
index cd18a0fcae..445c124158 100644
--- a/tests/functional/ucp_groups_test.php
+++ b/tests/functional/ucp_groups_test.php
@@ -54,4 +54,72 @@ class phpbb_functional_ucp_groups_test extends phpbb_functional_common_groups_te
$this->assertContains($this->lang('GROUP_UPDATED'), $crawler->text());
$this->assertEquals($teampage_settings, $this->get_teampage_settings());
}
+
+ public function test_create_request_group()
+ {
+ $this->login();
+ $this->admin_login();
+ $this->add_lang('acp/groups');
+
+ $crawler = self::request('GET', 'adm/index.php?i=acp_groups&mode=manage&sid=' . $this->sid);
+ $form = $crawler->selectButton($this->lang('SUBMIT'))->form();
+ $crawler = self::submit($form, array('group_name' => 'request-group'));
+
+ $form = $crawler->selectButton($this->lang('SUBMIT'))->form();
+ $crawler = self::submit($form, array('group_name' => 'request-group'));
+
+ $this->assertContainsLang('GROUP_CREATED', $crawler->filter('#main')->text());
+
+ $group_id = $this->get_group_id('request-group');
+
+ // Make admin group leader
+ $crawler = self::request('GET', 'adm/index.php?i=acp_groups&mode=manage&action=list&g=' . $group_id . '&sid=' . $this->sid);
+ $form = $crawler->filter('input[name=addusers]')->selectButton($this->lang('SUBMIT'))->form();
+ $crawler = self::submit($form, [
+ 'leader' => 1,
+ 'usernames' => 'admin',
+ ]);
+
+ $this->assertContainsLang('GROUP_MODS_ADDED', $crawler->filter('#main')->text());
+ }
+
+ /**
+ * @depends test_create_request_group
+ */
+ public function test_request_group_membership()
+ {
+ $this->create_user('request-group-user');
+ $this->login('request-group-user');
+ $this->add_lang('groups');
+
+ $group_id = $this->get_group_id('request-group');
+
+ $crawler = self::request('GET', 'ucp.php?i=ucp_groups&mode=membership&sid=' . $this->sid);
+ $form = $crawler->selectButton($this->lang('SUBMIT'))->form();
+ $crawler = self::submit($form, ['selected' => $group_id, 'action' => 'join']);
+ $this->assertContainsLang('GROUP_JOIN_PENDING_CONFIRM', $crawler->text());
+
+ $form = $crawler->selectButton($this->lang('YES'))->form();
+ $crawler = self::submit($form);
+ $this->assertContainsLang('GROUP_JOINED_PENDING', $crawler->text());
+ }
+
+ /**
+ * @depends test_request_group_membership
+ */
+ public function test_approve_group_membership()
+ {
+ $this->login();
+ $this->add_lang('acp/groups');
+
+ $group_id = $this->get_group_id('request-group');
+ $crawler = self::request('GET', 'ucp.php?i=ucp_groups&mode=manage&action=list&g=' . $group_id . '&sid=' . $this->sid);
+ $form = $crawler->filter('input[name=update]')->selectButton($this->lang('SUBMIT'))->form();
+ $crawler = self::submit($form, [
+ 'mark' => [$crawler->filter('input[name="mark[]"]')->first()->attr('value')],
+ 'action' => 'approve',
+ ]);
+
+ $this->assertContainsLang('USERS_APPROVED', $crawler->text());
+ }
}
diff --git a/tests/functional/user_password_reset_test.php b/tests/functional/user_password_reset_test.php
index 3da78407cf..2361eed066 100644
--- a/tests/functional/user_password_reset_test.php
+++ b/tests/functional/user_password_reset_test.php
@@ -21,25 +21,56 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
public function test_password_reset()
{
$this->add_lang('ucp');
- $user_id = $this->create_user('reset-password-test-user');
+ $user_id = $this->create_user('reset-password-test-user', 'reset-password-test-user@test.com');
+ // test without email
+ $crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}");
+ $form = $crawler->selectButton('submit')->form();
+ $crawler = self::submit($form);
+ $this->assertContainsLang('NO_EMAIL_USER', $crawler->text());
+
+ // test with non-existent email
$crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}");
$form = $crawler->selectButton('submit')->form(array(
- 'username' => 'reset-password-test-user',
+ 'email' => 'non-existent@email.com',
));
$crawler = self::submit($form);
- $this->assertContainsLang('NO_EMAIL_USER', $crawler->text());
+ $this->assertContainsLang('PASSWORD_UPDATED_IF_EXISTED', $crawler->text());
+ // test with correct email
$crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}");
$form = $crawler->selectButton('submit')->form(array(
- 'username' => 'reset-password-test-user',
- 'email' => 'nobody@example.com',
+ 'email' => 'reset-password-test-user@test.com',
+ ));
+ $crawler = self::submit($form);
+ $this->assertContainsLang('PASSWORD_UPDATED_IF_EXISTED', $crawler->text());
+
+ // Check if columns in database were updated for password reset
+ $this->get_user_data('reset-password-test-user');
+ $this->assertNotNull($this->user_data['user_actkey']);
+ $this->assertNotNull($this->user_data['user_newpasswd']);
+
+ // Create another user with the same email
+ $this->create_user('reset-password-test-user1', 'reset-password-test-user@test.com');
+
+ // Test that username is now also required
+ $crawler = self::request('GET', "ucp.php?mode=sendpassword&sid={$this->sid}");
+ $form = $crawler->selectButton('submit')->form(array(
+ 'email' => 'reset-password-test-user@test.com',
+ ));
+ $crawler = self::submit($form);
+ $this->assertContainsLang('EMAIL_NOT_UNIQUE', $crawler->text());
+
+ // Provide both username and email
+ $form = $crawler->selectButton('submit')->form(array(
+ 'email' => 'reset-password-test-user@test.com',
+ 'username' => 'reset-password-test-user1',
));
$crawler = self::submit($form);
- $this->assertContainsLang('PASSWORD_UPDATED', $crawler->text());
+ $this->assertContainsLang('PASSWORD_UPDATED_IF_EXISTED', $crawler->text());
// Check if columns in database were updated for password reset
- $this->get_user_data();
+ $this->get_user_data('reset-password-test-user1');
$this->assertNotNull($this->user_data['user_actkey']);
$this->assertNotNull($this->user_data['user_newpasswd']);
@@ -73,7 +104,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
public function test_activate_new_password($expected, $user_id, $act_key)
{
$this->add_lang('ucp');
- $this->get_user_data();
+ $this->get_user_data('reset-password-test-user');
$user_id = (!$user_id) ? $this->user_data['user_id'] : $user_id;
$act_key = (!$act_key) ? $this->user_data['user_actkey'] : $act_key;
@@ -119,7 +150,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
public function test_acivateAfterDeactivate()
{
// User is active, actkey should not exist
- $this->get_user_data();
+ $this->get_user_data('reset-password-test-user');
$this->assertEmpty($this->user_data['user_actkey']);
$this->login();
@@ -143,7 +174,7 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
$crawler = self::request('GET', preg_replace('#(.+)(adm/index.php.+)#', '$2', $link->getUri()));
// Ensure again that actkey is empty after deactivation
- $this->get_user_data();
+ $this->get_user_data('reset-password-test-user');
$this->assertEmpty($this->user_data['user_actkey']);
// Force reactivation of account and check that act key is not empty anymore
@@ -152,16 +183,16 @@ class phpbb_functional_user_password_reset_test extends phpbb_functional_test_ca
$crawler = self::submit($form, array('action' => 'reactivate'));
$this->assertContainsLang('FORCE_REACTIVATION_SUCCESS', $crawler->filter('html')->text());
- $this->get_user_data();
+ $this->get_user_data('reset-password-test-user');
$this->assertNotEmpty($this->user_data['user_actkey']);
}
- protected function get_user_data()
+ protected function get_user_data($username)
{
$db = $this->get_db();
$sql = 'SELECT user_id, username, user_type, user_email, user_newpasswd, user_lang, user_notify_type, user_actkey, user_inactive_reason
FROM ' . USERS_TABLE . "
- WHERE username = 'reset-password-test-user'";
+ WHERE username = '" . $db->sql_escape($username) . "'";
$result = $db->sql_query($sql);
$this->user_data = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
diff --git a/tests/functional/visibility_softdelete_test.php b/tests/functional/visibility_softdelete_test.php
index 6450c00c1e..fd994361a5 100644
--- a/tests/functional/visibility_softdelete_test.php
+++ b/tests/functional/visibility_softdelete_test.php
@@ -97,7 +97,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_
// Test creating a reply
$post2 = $this->create_post($this->data['forums']['Soft Delete #1'], $post['topic_id'], 'Re: Soft Delete Topic #1-#2', 'This is a test post posted by the testing framework.');
- $crawler = self::request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post2['post_id']}&sid={$this->sid}");
$this->assertContains('Re: Soft Delete Topic #1-#2', $crawler->filter('html')->text());
$this->data['posts']['Re: Soft Delete Topic #1-#2'] = (int) $post2['post_id'];
@@ -114,7 +114,7 @@ class phpbb_functional_visibility_softdelete_test extends phpbb_functional_test_
// Test creating another reply
$post3 = $this->create_post($this->data['forums']['Soft Delete #1'], $post['topic_id'], 'Re: Soft Delete Topic #1-#3', 'This is another test post posted by the testing framework.');
- $crawler = self::request('GET', "viewtopic.php?t={$post3['topic_id']}&sid={$this->sid}");
+ $crawler = self::request('GET', "viewtopic.php?p={$post3['post_id']}&sid={$this->sid}");
$this->assertContains('Re: Soft Delete Topic #1-#3', $crawler->filter('html')->text());
$this->data['posts']['Re: Soft Delete Topic #1-#3'] = (int) $post3['post_id'];
diff --git a/tests/functional/visit_installer_test.php b/tests/functional/visit_installer_test.php
new file mode 100644
index 0000000000..b4a75c0b51
--- /dev/null
+++ b/tests/functional/visit_installer_test.php
@@ -0,0 +1,30 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @group functional
+*/
+class phpbb_functional_visit_installer_test extends phpbb_functional_test_case
+{
+ public function test_visit_installer()
+ {
+ self::request('GET', 'install/', [], false);
+ $this->assertContains('<meta http-equiv="refresh" content="0; url=./app.php" />', $this->get_content());
+
+ self::request('GET', 'install/index.html', [], false);
+ $this->assertContains('<meta http-equiv="refresh" content="0; url=./app.php" />', $this->get_content());
+
+ self::request('GET', 'install/app.php');
+ $this->assertContains('installation system', $this->get_content());
+ }
+}
diff --git a/tests/functions/build_hidden_fields_for_query_params_test.php b/tests/functions/build_hidden_fields_for_query_params_test.php
index 14cb4b9a94..aee7a569d4 100644
--- a/tests/functions/build_hidden_fields_for_query_params_test.php
+++ b/tests/functions/build_hidden_fields_for_query_params_test.php
@@ -11,8 +11,6 @@
*
*/
-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()
diff --git a/tests/functions/build_url_test.php b/tests/functions/build_url_test.php
index a59b94c744..91a4a9ec66 100644
--- a/tests/functions/build_url_test.php
+++ b/tests/functions/build_url_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_build_url_test extends phpbb_test_case
{
protected function setUp()
@@ -29,7 +27,7 @@ class phpbb_build_url_test extends phpbb_test_case
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ new \phpbb\filesystem\filesystem(),
$this->getMock('\phpbb\request\request'),
$phpbb_root_path,
'php'
diff --git a/tests/functions/convert_30_dbms_to_31_test.php b/tests/functions/convert_30_dbms_to_31_test.php
index 729c0a82f0..456eb64461 100644
--- a/tests/functions/convert_30_dbms_to_31_test.php
+++ b/tests/functions/convert_30_dbms_to_31_test.php
@@ -11,21 +11,17 @@
*
*/
-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('mssql'),
array('mssql_odbc'),
array('mssqlnative'),
array('mysql'),
array('mysqli'),
array('oracle'),
array('postgres'),
- array('sqlite'),
);
}
diff --git a/tests/functions/fixtures/validate_email.xml b/tests/functions/fixtures/validate_email.xml
index eb4fd90217..fa139f6f18 100644
--- a/tests/functions/fixtures/validate_email.xml
+++ b/tests/functions/fixtures/validate_email.xml
@@ -1,5 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
+ <table name="phpbb_banlist">
+ <column>ban_id</column>
+ <column>ban_userid</column>
+ <column>ban_exclude</column>
+ <column>ban_end</column>
+ <column>ban_email</column>
+ <column>ban_give_reason</column>
+ <row>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ <value>0</value>
+ <value>banned@example.com</value>
+ <value></value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>0</value>
+ <value>0</value>
+ <value>0</value>
+ <value>banned2@example.com</value>
+ <value>just because</value>
+ </row>
+ </table>
<table name="phpbb_users">
<column>user_id</column>
<column>username</column>
diff --git a/tests/functions/fixtures/validate_username.xml b/tests/functions/fixtures/validate_username.xml
index 1b85a2f06d..add8f76553 100644
--- a/tests/functions/fixtures/validate_username.xml
+++ b/tests/functions/fixtures/validate_username.xml
@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_groups">
+ <column>group_id</column>
<column>group_name</column>
<column>group_desc</column>
<row>
+ <value>10</value>
<value>foobar_group</value>
<value>test123</value>
</row>
diff --git a/tests/functions/generate_string_list.php b/tests/functions/generate_string_list.php
index cd1e37618a..6eddb1395e 100644
--- a/tests/functions/generate_string_list.php
+++ b/tests/functions/generate_string_list.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_generate_string_list_test extends phpbb_test_case
{
public $user;
@@ -22,7 +19,12 @@ class phpbb_generate_string_list_test extends phpbb_test_case
{
parent::setUp();
- $this->user = new \phpbb\user('\phpbb\datetime');
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $this->user = $user;
$this->user->data = array('user_lang' => 'en');
$this->user->add_lang('common');
}
@@ -36,7 +38,7 @@ class phpbb_generate_string_list_test extends phpbb_test_case
),
array(
array('A'),
- 'A',
+ 'A',
),
array(
array(2 => 'A', 3 => 'B'),
diff --git a/tests/functions/get_formatted_filesize_test.php b/tests/functions/get_formatted_filesize_test.php
index 635753d737..290515b64f 100644
--- a/tests/functions/get_formatted_filesize_test.php
+++ b/tests/functions/get_formatted_filesize_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_get_formatted_filesize_test extends phpbb_test_case
{
public function get_formatted_filesize_test_data()
diff --git a/tests/functions/get_preg_expression_test.php b/tests/functions/get_preg_expression_test.php
index e74017d315..b8254b03ea 100644
--- a/tests/functions/get_preg_expression_test.php
+++ b/tests/functions/get_preg_expression_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_functions_get_preg_expression_test extends phpbb_test_case
{
public function data_path_remove_dot_trailing_slash()
diff --git a/tests/functions/get_remote_file_test.php b/tests/functions/get_remote_file_test.php
index 612d82273e..75e5a6dc61 100644
--- a/tests/functions/get_remote_file_test.php
+++ b/tests/functions/get_remote_file_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php';
-
/**
* @group slow
*/
@@ -61,7 +58,7 @@ class phpbb_functions_get_remote_file extends phpbb_test_case
$this->assertGreaterThanOrEqual(
2,
- sizeof($lines),
+ count($lines),
'Failed asserting that the version file has at least two lines.'
);
diff --git a/tests/functions/is_absolute_test.php b/tests/functions/is_absolute_test.php
deleted file mode 100644
index afa4b9b59f..0000000000
--- a/tests/functions/is_absolute_test.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
-class phpbb_functions_is_absolute_test extends phpbb_test_case
-{
- static public function is_absolute_data()
- {
- return array(
- // Empty
- array('', false),
-
- // Absolute unix style
- array('/etc/phpbb', true),
- // Unix does not support \ so that is not an absolute path
- array('\etc\phpbb', false),
-
- // Absolute windows style
- array('c:\windows', true),
- array('C:\Windows', true),
- array('c:/windows', true),
- array('C:/Windows', true),
-
- // Executable
- array('etc/phpbb', false),
- array('explorer.exe', false),
-
- // Relative subdir
- array('Windows\System32', false),
- array('Windows\System32\explorer.exe', false),
- array('Windows/System32', false),
- array('Windows/System32/explorer.exe', false),
-
- // Relative updir
- array('..\Windows\System32', false),
- array('..\Windows\System32\explorer.exe', false),
- array('../Windows/System32', false),
- array('../Windows/System32/explorer.exe', false),
- );
- }
-
- /**
- * @dataProvider is_absolute_data
- */
- public function test_is_absolute($path, $expected)
- {
- $this->assertEquals($expected, phpbb_is_absolute($path));
- }
-}
diff --git a/tests/functions/language_select_test.php b/tests/functions/language_select_test.php
index 6762ead5a1..2d1296d72f 100644
--- a/tests/functions/language_select_test.php
+++ b/tests/functions/language_select_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_functions_language_select_test extends phpbb_database_test_case
{
public function getDataSet()
diff --git a/tests/functions/make_clickable_email_test.php b/tests/functions/make_clickable_email_test.php
index 4c802d0487..d481bde80d 100644
--- a/tests/functions/make_clickable_email_test.php
+++ b/tests/functions/make_clickable_email_test.php
@@ -11,18 +11,16 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_functions_make_clickable_email_test extends phpbb_test_case
{
protected function setUp()
{
parent::setUp();
- global $config, $user, $request;
+ global $config, $user, $request, $symfony_request;
$user = new phpbb_mock_user();
$request = new phpbb_mock_request();
+ $symfony_request = new \phpbb\symfony_request($request);
}
/**
@@ -171,7 +169,7 @@ class phpbb_functions_make_clickable_email_test extends phpbb_test_case
array('abc,def@example.com'), // invalid character ,
array('abc<def@example.com'), // invalid character <
array('abc>def@example.com', 'abc><!-- e --><a href="mailto:def@example.com">def@example.com</a><!-- e -->'), // invalid character >
-
+
// http://fightingforalostcause.net/misc/2006/compare-email-regex.php
array('missingDomain@.com'),
array('@missingLocal.org'),
diff --git a/tests/functions/make_clickable_test.php b/tests/functions/make_clickable_test.php
index 63beeb06b2..a6af12b624 100644
--- a/tests/functions/make_clickable_test.php
+++ b/tests/functions/make_clickable_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_functions_make_clickable_test extends phpbb_test_case
{
/**
@@ -56,6 +53,14 @@ class phpbb_functions_make_clickable_test extends phpbb_test_case
'<!-- l --><a class="postlink-local" href="http://testhost/viewtopic.php?t=1">viewtopic.php?t=1</a><!-- l -->'
),
array(
+ 'javascript://testhost/viewtopic.php?t=1',
+ 'javascript://testhost/viewtopic.php?t=1'
+ ),
+ array(
+ "java\nscri\npt://testhost/viewtopic.php?t=1",
+ "java\nscri\n<!-- m --><a class=\"postlink\" href=\"pt://testhost/viewtopic.php?t=1\">pt://testhost/viewtopic.php?t=1</a><!-- m -->"
+ ),
+ array(
'email@domain.com',
'<!-- e --><a href="mailto:email@domain.com">email@domain.com</a><!-- e -->'
),
@@ -93,6 +98,10 @@ class phpbb_functions_make_clickable_test extends phpbb_test_case
'<!-- m --><a class="postlink" href="ftp://ftp.täst.de/">ftp://ftp.täst.de/</a><!-- m -->'
),
array(
+ 'javascript://täst.de/',
+ 'javascript://täst.de/'
+ ),
+ array(
'sip://bantu@täst.de',
'<!-- m --><a class="postlink" href="sip://bantu@täst.de">sip://bantu@täst.de</a><!-- m -->'
),
@@ -149,9 +158,10 @@ class phpbb_functions_make_clickable_test extends phpbb_test_case
{
parent::setUp();
- global $config, $user, $request;
+ global $config, $user, $request, $symfony_request;
$user = new phpbb_mock_user();
$request = new phpbb_mock_request();
+ $symfony_request = new \phpbb\symfony_request($request);
}
/**
diff --git a/tests/functions/obtain_online_test.php b/tests/functions/obtain_online_test.php
index e793a4eb82..778753e5d2 100644
--- a/tests/functions/obtain_online_test.php
+++ b/tests/functions/obtain_online_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_functions_obtain_online_test extends phpbb_database_test_case
{
public function getDataSet()
diff --git a/tests/functions/parse_cfg_file_test.php b/tests/functions/parse_cfg_file_test.php
index b47e25fbc1..017a931f28 100644
--- a/tests/functions/parse_cfg_file_test.php
+++ b/tests/functions/parse_cfg_file_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_functions_parse_cfg_file extends phpbb_test_case
{
public function parse_cfg_file_data()
diff --git a/tests/functions/quoteattr_test.php b/tests/functions/quoteattr_test.php
index 6e191f9610..dbad7a99d8 100644
--- a/tests/functions/quoteattr_test.php
+++ b/tests/functions/quoteattr_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_quoteattr_test extends phpbb_test_case
{
public function quoteattr_test_data()
diff --git a/tests/functions/style_select_test.php b/tests/functions/style_select_test.php
index a918f83155..27f0e68c88 100644
--- a/tests/functions/style_select_test.php
+++ b/tests/functions/style_select_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_functions_style_select_test extends phpbb_database_test_case
{
public function getDataSet()
diff --git a/tests/functions/user_delete_test.php b/tests/functions/user_delete_test.php
index c224323273..f419c90e9e 100644
--- a/tests/functions/user_delete_test.php
+++ b/tests/functions/user_delete_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
class phpbb_functions_user_delete_test extends phpbb_database_test_case
@@ -28,10 +27,12 @@ class phpbb_functions_user_delete_test extends phpbb_database_test_case
{
parent::setUp();
- global $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $user;
+ global $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $user, $phpbb_root_path, $phpEx;
$this->db = $db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$phpbb_container = new phpbb_mock_container_builder();
$config = new \phpbb\config\config(array(
@@ -39,8 +40,7 @@ class phpbb_functions_user_delete_test extends phpbb_database_test_case
'auth_oauth_google_key' => 'foo',
'auth_oauth_google_secret' => 'bar',
));
- set_config_count('foobar', 0, false, $config);
- $cache = new \phpbb\cache\driver\null();
+ $cache = new \phpbb\cache\driver\dummy();
$request = new phpbb_mock_request();
$notification_manager = new phpbb_mock_notification_manager();
$provider_collection = new \phpbb\auth\provider_collection($phpbb_container, $config);
@@ -67,6 +67,7 @@ class phpbb_functions_user_delete_test extends phpbb_database_test_case
$request,
$user,
'phpbb_oauth_tokens',
+ 'phpbb_oauth_states',
'phpbb_oauth_accounts',
$oauth_provider_collection,
'phpbb_users',
@@ -81,6 +82,12 @@ class phpbb_functions_user_delete_test extends phpbb_database_test_case
$phpbb_container->set('auth.provider.oauth.service.google', $oauth_provider_google);
$phpbb_container->set('auth.provider_collection', $provider_collection);
$phpbb_container->set('notification_manager', $notification_manager);
+
+ $phpbb_container->setParameter('tables.auth_provider_oauth_token_storage', 'phpbb_oauth_tokens');
+ $phpbb_container->setParameter('tables.auth_provider_oauth_states', 'phpbb_oauth_states');
+ $phpbb_container->setParameter('tables.auth_provider_oauth_account_assoc', 'phpbb_oauth_accounts');
+
+ $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications');
}
public function test_user_delete()
diff --git a/tests/functions/validate_email_test.php b/tests/functions/validate_email_test.php
index b46509fda7..7f8b2679d4 100644
--- a/tests/functions/validate_email_test.php
+++ b/tests/functions/validate_email_test.php
@@ -7,7 +7,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
require_once dirname(__FILE__) . '/../mock/user.php';
require_once dirname(__FILE__) . '/validate_data_helper.php';
diff --git a/tests/functions/validate_password_test.php b/tests/functions/validate_password_test.php
index c5942e79bf..5e34c8baba 100644
--- a/tests/functions/validate_password_test.php
+++ b/tests/functions/validate_password_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
require_once dirname(__FILE__) . '/validate_data_helper.php';
diff --git a/tests/functions/validate_string_test.php b/tests/functions/validate_string_test.php
index 24026e4c9f..7aca14c334 100644
--- a/tests/functions/validate_string_test.php
+++ b/tests/functions/validate_string_test.php
@@ -12,7 +12,6 @@
*/
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
require_once dirname(__FILE__) . '/validate_data_helper.php';
class phpbb_functions_validate_string_test extends phpbb_test_case
diff --git a/tests/functions/validate_user_email_test.php b/tests/functions/validate_user_email_test.php
index 951d5794e6..d23ffc0503 100644
--- a/tests/functions/validate_user_email_test.php
+++ b/tests/functions/validate_user_email_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
require_once dirname(__FILE__) . '/../mock/user.php';
require_once dirname(__FILE__) . '/validate_data_helper.php';
@@ -29,10 +28,16 @@ class phpbb_functions_validate_user_email_test extends phpbb_database_test_case
protected function setUp()
{
+ global $cache, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
+
parent::setUp();
+ $cache = new \phpbb\cache\driver\file();
+ $cache->purge();
$this->db = $this->new_dbal();
- $this->user = new phpbb_mock_user;
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
+ $language = new phpbb\language\language(new phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $this->user = new phpbb\user($language, '\phpbb\datetime');
$this->helper = new phpbb_functions_validate_data_helper($this);
}
@@ -48,7 +53,6 @@ class phpbb_functions_validate_user_email_test extends phpbb_database_test_case
$config['email_check_mx'] = $check_mx;
$db = $this->db;
$user = $this->user;
- $user->optionset('banned_users', array('banned@example.com'));
}
public static function validate_user_email_data()
@@ -59,7 +63,8 @@ class phpbb_functions_validate_user_email_test extends phpbb_database_test_case
array('valid_complex', array(), "'%$~test@example.com"),
array('invalid', array('EMAIL_INVALID'), 'fööbar@example.com'),
array('taken', array('EMAIL_TAKEN'), 'admin@example.com'),
- array('banned', array('EMAIL_BANNED'), 'banned@example.com'),
+ array('banned', ['just because'], 'banned2@example.com'),
+ array('banned', ['EMAIL_BANNED'], 'banned@example.com')
);
}
diff --git a/tests/functions/validate_username_test.php b/tests/functions/validate_username_test.php
index 4fa5af7ff3..cee5d38400 100644
--- a/tests/functions/validate_username_test.php
+++ b/tests/functions/validate_username_test.php
@@ -11,9 +11,7 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
require_once dirname(__FILE__) . '/../mock/cache.php';
require_once dirname(__FILE__) . '/validate_data_helper.php';
@@ -49,6 +47,7 @@ class phpbb_functions_validate_data_test extends phpbb_database_test_case
'foobar_letter_num' => array(),
'foobar_letter_num_sp' => array(),
'foobar_quot' => array('INVALID_CHARS'),
+ 'foobar_emoji' => array('INVALID_EMOJIS'),
'barfoo_disallow' => array('USERNAME_DISALLOWED'),
'admin_taken' => array('USERNAME_TAKEN'),
'group_taken' => array('USERNAME_TAKEN'),
@@ -62,6 +61,7 @@ class phpbb_functions_validate_data_test extends phpbb_database_test_case
'foobar_letter_num' => array(),
'foobar_letter_num_sp' => array('INVALID_CHARS'),
'foobar_quot' => array('INVALID_CHARS'),
+ 'foobar_emoji' => array('INVALID_EMOJIS'),
'barfoo_disallow' => array('USERNAME_DISALLOWED'),
'admin_taken' => array('USERNAME_TAKEN'),
'group_taken' => array('INVALID_CHARS'),
@@ -75,6 +75,7 @@ class phpbb_functions_validate_data_test extends phpbb_database_test_case
'foobar_letter_num' => array(),
'foobar_letter_num_sp' => array('INVALID_CHARS'),
'foobar_quot' => array('INVALID_CHARS'),
+ 'foobar_emoji' => array('INVALID_EMOJIS'),
'barfoo_disallow' => array('USERNAME_DISALLOWED'),
'admin_taken' => array('USERNAME_TAKEN'),
'group_taken' => array('USERNAME_TAKEN'),
@@ -88,6 +89,7 @@ class phpbb_functions_validate_data_test extends phpbb_database_test_case
'foobar_letter_num' => array(),
'foobar_letter_num_sp' => array('INVALID_CHARS'),
'foobar_quot' => array('INVALID_CHARS'),
+ 'foobar_emoji' => array('INVALID_EMOJIS'),
'barfoo_disallow' => array('USERNAME_DISALLOWED'),
'admin_taken' => array('USERNAME_TAKEN'),
'group_taken' => array('INVALID_CHARS'),
@@ -101,6 +103,7 @@ class phpbb_functions_validate_data_test extends phpbb_database_test_case
'foobar_letter_num' => array(),
'foobar_letter_num_sp' => array(),
'foobar_quot' => array('INVALID_CHARS'),
+ 'foobar_emoji' => array('INVALID_EMOJIS'),
'barfoo_disallow' => array('USERNAME_DISALLOWED'),
'admin_taken' => array('USERNAME_TAKEN'),
'group_taken' => array('USERNAME_TAKEN'),
@@ -114,6 +117,7 @@ class phpbb_functions_validate_data_test extends phpbb_database_test_case
'foobar_letter_num' => array(),
'foobar_letter_num_sp' => array('INVALID_CHARS'),
'foobar_quot' => array('INVALID_CHARS'),
+ 'foobar_emoji' => array('INVALID_EMOJIS'),
'barfoo_disallow' => array('USERNAME_DISALLOWED'),
'admin_taken' => array('USERNAME_TAKEN'),
'group_taken' => array('USERNAME_TAKEN'),
@@ -175,6 +179,11 @@ class phpbb_functions_validate_data_test extends phpbb_database_test_case
'"foobar"',
array('username'),
),
+ 'foobar_emoji' => array(
+ $expected['foobar_emoji'],
+ 'username😮',
+ array('username'),
+ ),
'barfoo_disallow' => array(
$expected['barfoo_disallow'],
'barfoo',
diff --git a/tests/functions_acp/validate_config_vars_test.php b/tests/functions_acp/validate_config_vars_test.php
index 32738e4351..3bd2204de9 100644
--- a/tests/functions_acp/validate_config_vars_test.php
+++ b/tests/functions_acp/validate_config_vars_test.php
@@ -12,7 +12,6 @@
*/
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_acp.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
class phpbb_functions_acp_validate_config_vars_test extends phpbb_test_case
{
@@ -20,10 +19,11 @@ class phpbb_functions_acp_validate_config_vars_test extends phpbb_test_case
{
parent::setUp();
- global $user;
+ global $language, $user;
$user = new phpbb_mock_user();
$user->lang = new phpbb_mock_lang();
+ $language = $user->lang;
}
/**
@@ -45,6 +45,7 @@ class phpbb_functions_acp_validate_config_vars_test extends phpbb_test_case
'test_int_32' => array('lang' => 'TEST_INT', 'validate' => 'int:32'),
'test_int_32_64' => array('lang' => 'TEST_INT', 'validate' => 'int:32:64'),
'test_lang' => array('lang' => 'TEST_LANG', 'validate' => 'lang'),
+ 'test_url' => array('lang' => 'TEST_URL', 'validate' => 'url'),
/*
'test_sp' => array('lang' => 'TEST_SP', 'validate' => 'script_path'),
'test_rpath' => array('lang' => 'TEST_RPATH', 'validate' => 'rpath'),
@@ -65,6 +66,7 @@ class phpbb_functions_acp_validate_config_vars_test extends phpbb_test_case
'test_int_32' => 32,
'test_int_32_64' => 48,
'test_lang' => 'en',
+ 'test_url' => 'http://foobar.com',
),
),
);
@@ -149,6 +151,11 @@ class phpbb_functions_acp_validate_config_vars_test extends phpbb_test_case
array('test_lang' => 'this_is_no_language'),
array('WRONG_DATA_LANG'),
),
+ array(
+ array('test_url' => array('lang' => 'TEST_URL', 'validate' => 'url')),
+ array('test_url' => 'javascript://foobar.com'),
+ array('URL_INVALID TEST_URL'),
+ ),
);
}
@@ -162,100 +169,4 @@ class phpbb_functions_acp_validate_config_vars_test extends phpbb_test_case
$this->assertEquals($expected, $phpbb_error);
}
-
- public function data_validate_path_linux()
- {
- return array(
- array('/usr/bin', 'absolute_path', true),
- array('/usr/bin/', 'absolute_path:50:200', true),
- array('/usr/bin/which', 'absolute_path', 'DIRECTORY_NOT_DIR'),
- array('/foo/bar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- array('C:\Windows', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- array('.', 'absolute_path', true),
- array('', 'absolute_path', true),
- array('mkdir /foo/bar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- // Make sure above command didn't do anything
- array('/foo/bar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- );
- }
-
- /**
- * @dataProvider data_validate_path_linux
- */
- public function test_validate_path_linux($path, $validation_type, $expected)
- {
- if (strtolower(substr(PHP_OS, 0, 5)) !== 'linux')
- {
- $this->markTestSkipped('Unable to test linux specific paths on other OS.');
- }
-
- $error = array();
- $config_ary = array(
- 'path' => $path,
- );
-
- validate_config_vars(array(
- 'path' => array('lang' => 'FOOBAR', 'validate' => $validation_type),
- ),
- $config_ary,
- $error
- );
-
- if ($expected === true)
- {
- $this->assertEmpty($error);
- }
- else
- {
- $this->assertEquals(array($expected), $error);
- }
- }
-
- public function data_validate_path_windows()
- {
- return array(
- array('C:\Windows', 'absolute_path', true),
- array('C:\Windows\\', 'absolute_path:50:200', true),
- array('C:\Windows\explorer.exe', 'absolute_path', 'DIRECTORY_NOT_DIR'),
- array('C:\foobar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- array('/usr/bin', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- array('.', 'absolute_path', true),
- array('', 'absolute_path', true),
- array('mkdir C:\Windows\foobar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- // Make sure above command didn't do anything
- array('C:\Windows\foobar', 'absolute_path', 'DIRECTORY_DOES_NOT_EXIST'),
- );
- }
-
- /**
- * @dataProvider data_validate_path_windows
- */
- public function test_validate_path_windows($path, $validation_type, $expected)
- {
- if (strtolower(substr(PHP_OS, 0, 3)) !== 'win')
- {
- $this->markTestSkipped('Unable to test windows specific paths on other OS.');
- }
-
- $error = array();
- $config_ary = array(
- 'path' => $path,
- );
-
- validate_config_vars(array(
- 'path' => array('lang' => 'FOOBAR', 'validate' => $validation_type),
- ),
- $config_ary,
- $error
- );
-
- if ($expected === true)
- {
- $this->assertEmpty($error);
- }
- else
- {
- $this->assertEquals(array($expected), $error);
- }
- }
}
diff --git a/tests/functions_acp/validate_range_test.php b/tests/functions_acp/validate_range_test.php
index 6408e29a26..9e9154a43c 100644
--- a/tests/functions_acp/validate_range_test.php
+++ b/tests/functions_acp/validate_range_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_acp.php';
class phpbb_functions_acp_validate_range_test extends phpbb_test_case
diff --git a/tests/functions_content/get_username_string_test.php b/tests/functions_content/get_username_string_test.php
index 01ec97f6a4..e79342d05d 100644
--- a/tests/functions_content/get_username_string_test.php
+++ b/tests/functions_content/get_username_string_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_functions_content_get_username_string_test extends phpbb_test_case
{
public function setUp()
diff --git a/tests/functions_content/phpbb_clean_search_string_test.php b/tests/functions_content/phpbb_clean_search_string_test.php
index abd107097c..34ae0575c5 100644
--- a/tests/functions_content/phpbb_clean_search_string_test.php
+++ b/tests/functions_content/phpbb_clean_search_string_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_functions_content_phpbb_clean_search_string_test extends phpbb_test_case
{
public function phpbb_clean_search_string_data()
diff --git a/tests/functions_content/phpbb_format_quote_test.php b/tests/functions_content/phpbb_format_quote_test.php
new file mode 100644
index 0000000000..cbbd46d0a9
--- /dev/null
+++ b/tests/functions_content/phpbb_format_quote_test.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+require_once dirname(__FILE__) . '/../../phpBB/includes/message_parser.php';
+
+class phpbb_functions_content_phpbb_format_quote_test extends phpbb_test_case
+{
+ /** @var \phpbb\language\language */
+ protected $lang;
+
+ public function setUp()
+ {
+ global $cache, $user, $phpbb_root_path, $phpEx;
+
+ $lang_file_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $this->lang = new \phpbb\language\language($lang_file_loader);
+ $user = new \phpbb\user($this->lang, '\phpbb\datetime');
+ $cache = new phpbb_mock_cache();
+
+ parent::setUp();
+ }
+
+ public function data_phpbb_format_quote()
+ {
+ return [
+ [true, ['author' => 'admin', 'user_id' => 2], '[quote=&quot;username&quot;]quoted[/quote]', '', "[quote=admin user_id=2][quote=&quot;username&quot;]quoted[/quote][/quote]\n\n"],
+ [false, ['author' => 'admin', 'user_id' => 2], '[quote=&quot;username&quot;]quoted[/quote]', '', "admin wrote:\n&gt; [quote=&quot;username&quot;]quoted[/quote]\n"],
+ [true, ['author' => 'admin', 'user_id' => 2], '[quote=&quot;username&quot;]quoted[/quote]', "[url=http://viewtopic.php?p=1#p1]Subject: Foo[/url]\n\n", "[url=http://viewtopic.php?p=1#p1]Subject: Foo[/url]\n\n[quote=admin user_id=2][quote=&quot;username&quot;]quoted[/quote][/quote]\n\n"],
+ [false, ['author' => 'admin', 'user_id' => 2], '[quote=&quot;username&quot;]quoted[/quote]', "http://viewtopic.php?p=1#p1 - Subject: Foo\n\n", "http://viewtopic.php?p=1#p1 - Subject: Foo\n\nadmin wrote:\n&gt; [quote=&quot;username&quot;]quoted[/quote]\n"],
+ ];
+ }
+
+
+ /**
+ * @dataProvider data_phpbb_format_quote
+ */
+ public function test_phpbb_format_quote($bbcode_status, $quote_attributes, $message, $message_link, $expected)
+ {
+ $text_formatter_utils = new \phpbb\textformatter\s9e\utils();
+
+ $message_parser = new parse_message($message);
+
+ phpbb_format_quote($this->lang, $message_parser, $text_formatter_utils, $bbcode_status, $quote_attributes, $message_link);
+
+ $this->assertEquals($expected, $message_parser->message);
+ }
+}
diff --git a/tests/functions_install/ignore_new_file_on_update_test.php b/tests/functions_install/ignore_new_file_on_update_test.php
deleted file mode 100644
index 822c5e6789..0000000000
--- a/tests/functions_install/ignore_new_file_on_update_test.php
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_install.php';
-
-class phpbb_functions_install_ignore_new_file_on_update_test extends phpbb_test_case
-{
- static public function ignore_new_file_on_update_data()
- {
- return array(
- array('willneverexist.php', false),
- array('includes/dirwillneverexist/newfile.php', false),
-
- array('language/en/email/short/bookmark.txt', false),
- array('language/languagewillneverexist/email/short/bookmark.txt', true),
-
- array('styles/prosilver/template/bbcode.html', false),
- array('styles/stylewillneverexist/template/bbcode.html', true),
-
- array('styles/prosilver/theme/en/icon_user_online.gif', false),
- array('styles/prosilver/theme/languagewillneverexist/icon_user_online.gif', true),
-
- array('styles/prosilver/theme/imageset.css', false),
- );
- }
-
- /**
- * @dataProvider ignore_new_file_on_update_data
- */
- public function test_ignore_new_file_on_update($file, $expected)
- {
- global $phpbb_root_path;
- $this->assertEquals($expected, phpbb_ignore_new_file_on_update($phpbb_root_path, $file));
- }
-}
diff --git a/tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml b/tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml
new file mode 100644
index 0000000000..c78d63f7cb
--- /dev/null
+++ b/tests/functions_privmsgs/fixtures/get_max_setting_from_group.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_groups">
+ <column>group_id</column>
+ <column>group_desc</column>
+ <column>group_message_limit</column>
+ <column>group_max_recipients</column>
+ <row>
+ <value>1</value>
+ <value></value>
+ <value>1</value>
+ <value>3</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value></value>
+ <value>2</value>
+ <value>4</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value></value>
+ <value>0</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value></value>
+ <value>0</value>
+ <value>5</value>
+ </row>
+ </table>
+ <table name="phpbb_user_group">
+ <column>user_id</column>
+ <column>group_id</column>
+ <column>user_pending</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>2</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>3</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>2</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>3</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>4</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>3</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>2</value>
+ <value>0</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/functions_privmsgs/get_max_setting_from_group_test.php b/tests/functions_privmsgs/get_max_setting_from_group_test.php
new file mode 100644
index 0000000000..fbabf1222a
--- /dev/null
+++ b/tests/functions_privmsgs/get_max_setting_from_group_test.php
@@ -0,0 +1,64 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once dirname(__FILE__) . '/../../phpBB/includes/functions_privmsgs.php';
+
+class phpbb_functions_privmsgs_get_max_setting_from_group_test extends phpbb_database_test_case
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/get_max_setting_from_group.xml');
+ }
+
+ /** @var \phpbb\db\driver\driver_interface */
+ protected $db;
+
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $this->db = $this->new_dbal();
+ }
+
+ static public function get_max_setting_from_group_data()
+ {
+ return array(
+ array(1, 2, 'message_limit'),
+ array(2, 2, 'message_limit'),
+ array(3, 0, 'message_limit'),
+ array(4, 0, 'message_limit'),
+ array(5, 2, 'message_limit'),
+ array(1, 4, 'max_recipients'),
+ array(2, 4, 'max_recipients'),
+ array(3, 0, 'max_recipients'),
+ array(4, 5, 'max_recipients'),
+ array(5, 4, 'max_recipients'),
+ );
+ }
+
+ /**
+ * @dataProvider get_max_setting_from_group_data
+ */
+ public function test_get_max_setting_from_group($user_id, $expected, $setting)
+ {
+ $this->assertEquals($expected, phpbb_get_max_setting_from_group($this->db, $user_id, $setting));
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function test_get_max_setting_from_group_throws()
+ {
+ phpbb_get_max_setting_from_group($this->db, ANONYMOUS, 'not_a_setting');
+ }
+}
diff --git a/tests/functions_user/delete_user_test.php b/tests/functions_user/delete_user_test.php
index 7db69e332c..09ed51890c 100644
--- a/tests/functions_user/delete_user_test.php
+++ b/tests/functions_user/delete_user_test.php
@@ -7,9 +7,7 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
class phpbb_functions_user_delete_user_test extends phpbb_database_test_case
{
@@ -25,19 +23,19 @@ class phpbb_functions_user_delete_user_test extends phpbb_database_test_case
{
parent::setUp();
- global $cache, $config, $db, $phpbb_dispatcher, $phpbb_container;
+ global $cache, $config, $db, $phpbb_dispatcher, $phpbb_container, $phpbb_root_path;
$db = $this->db = $this->new_dbal();
$config = new \phpbb\config\config(array(
'load_online_time' => 5,
'search_type' => '\phpbb\search\fulltext_mysql',
));
- set_config(false, false, false, $config);
- set_config_count(false, false, false, $config);
$cache = new phpbb_mock_null_cache();
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
+ // Works as a workaround for tests
+ $phpbb_container->set('attachment.manager', new \phpbb\attachment\delete($config, $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path));
$phpbb_container->set(
'auth.provider.db',
new phpbb_mock_auth_provider()
@@ -48,6 +46,11 @@ class phpbb_functions_user_delete_user_test extends phpbb_database_test_case
'auth.provider_collection',
$provider_collection
);
+ $phpbb_container->setParameter('tables.auth_provider_oauth_token_storage', 'phpbb_oauth_tokens');
+ $phpbb_container->setParameter('tables.auth_provider_oauth_states', 'phpbb_oauth_states');
+ $phpbb_container->setParameter('tables.auth_provider_oauth_account_assoc', 'phpbb_oauth_accounts');
+
+ $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications');
}
public function first_last_post_data()
diff --git a/tests/functions_user/fixtures/delete_user.xml b/tests/functions_user/fixtures/delete_user.xml
index 56014b35d1..8de2659722 100644
--- a/tests/functions_user/fixtures/delete_user.xml
+++ b/tests/functions_user/fixtures/delete_user.xml
@@ -515,35 +515,44 @@
</table>
<table name="phpbb_privmsgs_folder">
<column>user_id</column>
+ <column>folder_id</column>
<row>
<value>2</value>
+ <value>1</value>
</row>
<row>
<value>3</value>
+ <value>2</value>
</row>
</table>
<table name="phpbb_privmsgs_rules">
<column>user_id</column>
<column>rule_string</column>
+ <column>rule_id</column>
<row>
<value>2</value>
<value></value>
+ <value>1</value>
</row>
<row>
<value>3</value>
<value></value>
+ <value>2</value>
</row>
</table>
<table name="phpbb_drafts">
<column>user_id</column>
<column>draft_message</column>
+ <column>draft_id</column>
<row>
<value>2</value>
<value></value>
+ <value>1</value>
</row>
<row>
<value>3</value>
<value></value>
+ <value>2</value>
</row>
</table>
</dataset>
diff --git a/tests/functions_user/group_user_attributes_test.php b/tests/functions_user/group_user_attributes_test.php
index 99a15b32bf..3124d57ba0 100644
--- a/tests/functions_user/group_user_attributes_test.php
+++ b/tests/functions_user/group_user_attributes_test.php
@@ -11,9 +11,7 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
class phpbb_functions_user_group_user_attributes_test extends phpbb_database_test_case
{
@@ -139,7 +137,7 @@ class phpbb_functions_user_group_user_attributes_test extends phpbb_database_tes
$auth = $this->getMock('\phpbb\auth\auth');
$auth->expects($this->any())
->method('acl_clear_prefetch');
- $cache_driver = new \phpbb\cache\driver\null();
+ $cache_driver = new \phpbb\cache\driver\dummy();
$phpbb_container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$phpbb_container
->expects($this->any())
diff --git a/tests/group/helper_get_name_string_test.php b/tests/group/helper_get_name_string_test.php
new file mode 100644
index 0000000000..c626328dcc
--- /dev/null
+++ b/tests/group/helper_get_name_string_test.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+require_once dirname(__FILE__) . '/helper_test_case.php';
+
+class phpbb_group_helper_get_name_string_test extends phpbb_group_helper_test_case
+{
+
+ public function get_name_string_profile_data()
+ {
+ global $phpbb_root_path, $phpEx;
+
+ return array(
+ array(0, 'Non existing group', '', false, ''),
+ array(2, 'Administrators', 'AA0000', false, "{$phpbb_root_path}memberlist.$phpEx?mode=group&amp;g=2"),
+ array(42, 'Example Group', '', 'http://www.example.org/group.php?mode=show', 'http://www.example.org/group.php?mode=show&amp;g=42'),
+ );
+ }
+
+ /**
+ * @dataProvider get_name_string_profile_data
+ */
+ public function test_get_name_string_profile($group_id, $group_name, $group_colour, $custom_profile_url, $expected)
+ {
+ $this->assertEquals($expected, $this->group_helper->get_name_string('profile', $group_id, $group_name, $group_colour, $custom_profile_url));
+ }
+
+ public function get_name_string_group_name_data()
+ {
+ return array(
+ // Should be fine
+ array(0, 'BOTS', 'AA0000', false, 'Bots'),
+ array(1, 'new_group', '', false, 'Some new group'),
+ array(2, 'group_with_ümlauts', '', 'http://www.example.org/group.php?mode=show', 'Should work'),
+
+ // Should fail and thus return the same
+ array(3, 'not_uppercase', 'FFFFFF', false, 'not_uppercase'),
+ array(4, 'Awesome group', '', false, 'Awesome group'),
+ );
+ }
+
+ /**
+ * @dataProvider get_name_string_group_name_data
+ */
+ public function test_get_name_string_group_name($group_id, $group_name, $group_colour, $custom_profile_url, $expected)
+ {
+ $this->assertEquals($expected, $this->group_helper->get_name_string('group_name', $group_id, $group_name, $group_colour, $custom_profile_url));
+ }
+
+ public function get_name_string_colour_data()
+ {
+ return array(
+ array(0, '', '', false, ''),
+ array(0, '', 'F0F0F0', false, '#F0F0F0'),
+ array(1, 'Guests', '000000', false, '#000000'),
+ array(2, 'Administrators', '', false, ''),
+ );
+ }
+
+ /**
+ * @dataProvider get_name_string_colour_data
+ */
+ public function test_get_name_string_colour($group_id, $group_name, $group_colour, $custom_profile_url, $expected)
+ {
+ $this->assertEquals($expected, $this->group_helper->get_name_string('colour', $group_id, $group_name, $group_colour, $custom_profile_url));
+ }
+
+ public function get_name_string_full_data()
+ {
+ global $phpbb_root_path, $phpEx;
+
+ return array(
+ array(0, 'BOTS', '000000', false, '<span class="username-coloured" style="color: #000000;">Bots</span>'),
+ array(1, 'BOTS', '111111', false, '<span class="username-coloured" style="color: #111111;">Bots</span>'),
+ array(7, 'new_group', 'FFA500', false, '<a class="username-coloured" href="' . $phpbb_root_path . 'memberlist.' . $phpEx . '?mode=group&amp;g=7" style="color: #FFA500;">Some new group</a>'),
+ array(14, 'Awesome group', '', 'http://www.example.org/group.php?mode=show', '<a class="username" href="http://www.example.org/group.php?mode=show&amp;g=14">Awesome group</a>'),
+ );
+ }
+
+ /**
+ * @dataProvider get_name_string_full_data
+ */
+ public function test_get_name_string_full($group_id, $group_name, $group_colour, $custom_profile_url, $expected)
+ {
+ $this->assertEquals($expected, $this->group_helper->get_name_string('full', $group_id, $group_name, $group_colour, $custom_profile_url));
+ }
+
+ public function get_name_string_no_profile_data()
+ {
+ return array(
+ array(0, 'BOTS', '000000', false, '<span class="username-coloured" style="color: #000000;">Bots</span>'),
+ array(1, 'new_group', '', false, '<span class="username">Some new group</span>'),
+ array(2, 'not_uppercase', 'FF0000', false, '<span class="username-coloured" style="color: #FF0000;">not_uppercase</span>'),
+ array(5, 'Awesome group', '', 'http://www.example.org/group.php?mode=show', '<span class="username">Awesome group</span>'),
+ );
+ }
+
+ /**
+ * @dataProvider get_name_string_no_profile_data
+ */
+ public function test_get_name_string_no_profile($group_id, $group_name, $group_colour, $custom_profile_url, $expected)
+ {
+ $this->assertEquals($expected, $this->group_helper->get_name_string('no_profile', $group_id, $group_name, $group_colour, $custom_profile_url));
+ }
+}
diff --git a/tests/group/helper_get_name_test.php b/tests/group/helper_get_name_test.php
new file mode 100644
index 0000000000..b39b2cbedd
--- /dev/null
+++ b/tests/group/helper_get_name_test.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+require_once dirname(__FILE__) . '/helper_test_case.php';
+
+class phpbb_group_helper_get_name_test extends phpbb_group_helper_test_case
+{
+ public function test_get_name()
+ {
+ // They should be totally fine
+ $this->assertEquals('Bots', $this->group_helper->get_name('Bots'));
+ $this->assertEquals('Some new group', $this->group_helper->get_name('new_group'));
+ $this->assertEquals('Should work', $this->group_helper->get_name('group_with_ümlauts'));
+
+ // This should fail (obviously)
+ $this->assertNotEquals('The key does not contain uppercase letters', $this->group_helper->get_name('not_uppercase'));
+
+ // The key doesn't exist so just return group name...
+ $this->assertEquals('Awesome group', $this->group_helper->get_name('Awesome group'));
+ }
+}
diff --git a/tests/group/helper_get_rank_test.php b/tests/group/helper_get_rank_test.php
new file mode 100644
index 0000000000..5efd8ad95e
--- /dev/null
+++ b/tests/group/helper_get_rank_test.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+require_once dirname(__FILE__) . '/helper_test_case.php';
+
+class phpbb_group_helper_get_rank_test extends phpbb_group_helper_test_case
+{
+ public function get_rank_data()
+ {
+ global $phpbb_root_path;
+
+ return array(
+ array(
+ array('group_id' => 0, 'group_rank' => 1),
+ array(
+ 'title' => 'Site admin',
+ 'img' => '<img src="' . $phpbb_root_path . 'images/ranks/siteadmin.png' . '" alt="Site admin" title="Site admin" />',
+ 'img_src' => $phpbb_root_path . 'images/ranks/siteadmin.png',
+ )
+ ),
+ array(array('group_id' => 1, 'group_rank' => 0), array('title' => null, 'img' => null, 'img_src' => null)),
+ array(array('group_id' => 2, 'group_rank' => 2), array('title' => 'Test member', 'img' => '', 'img_src' => '')),
+ );
+ }
+
+ /**
+ * @dataProvider get_rank_data
+ */
+ public function test_get_rank($group_data, $expected)
+ {
+ $this->assertEquals($expected, $this->group_helper->get_rank($group_data));
+ }
+}
diff --git a/tests/group/helper_test_case.php b/tests/group/helper_test_case.php
new file mode 100644
index 0000000000..e298770331
--- /dev/null
+++ b/tests/group/helper_test_case.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_group_helper_test_case extends phpbb_test_case
+{
+ /** @var \phpbb\group\helper */
+ protected $group_helper;
+
+ protected function config_defaults()
+ {
+ $defaults = array(
+ 'ranks_path' => 'images/ranks'
+ );
+ return $defaults;
+ }
+
+ protected function get_test_language_data_set()
+ {
+ return array(
+ 'G_BOTS' => 'Bots',
+ 'G_NEW_GROUP' => 'Some new group',
+ 'G_not_uppercase' => 'The key does not contain uppercase letters',
+ 'G_GROUP_WITH_ÃœMLAUTS' => 'Should work',
+ );
+ }
+
+ protected function get_test_rank_data_set()
+ {
+ return array(
+ 'special' => array(
+ 1 => array(
+ 'rank_id' => 1,
+ 'rank_title' => 'Site admin',
+ 'rank_special' => 1,
+ 'rank_image' => 'siteadmin.png',
+ ),
+ 2 => array(
+ 'rank_id' => 2,
+ 'rank_title' => 'Test member',
+ 'rank_special' => 1,
+ 'rank_image' => '',
+ )
+ )
+ );
+ }
+
+ protected function setup_engine(array $new_config = array())
+ {
+ global $phpbb_dispatcher, $phpbb_root_path, $phpEx;
+
+ // Set up authentication data for testing
+ $auth = $this->getMock('\phpbb\auth\auth');
+ $auth->expects($this->any())
+ ->method('acl_get')
+ ->with($this->stringContains('_'), $this->anything())
+ ->will($this->returnValueMap(array(
+ array('u_viewprofile', true),
+ )));
+
+ // Set up cache service
+ $cache_service = $this->getMockBuilder('\phpbb\cache\service')->disableOriginalConstructor()->getMock();
+ $cache_service->expects($this->any())
+ ->method('obtain_ranks')
+ ->will($this->returnValue($this->get_test_rank_data_set()));
+
+ // Set up configuration
+ $defaults = $this->config_defaults();
+ $config = new \phpbb\config\config(array_merge($defaults, $new_config));
+
+ // Set up language service
+ $lang = new \phpbb\language\language(
+ new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)
+ );
+
+ // Set up language data for testing
+ $reflection_class = new ReflectionClass('\phpbb\language\language');
+
+ // Set default language files loaded flag to true
+ $loaded_flag = $reflection_class->getProperty('common_language_files_loaded');
+ $loaded_flag->setAccessible(true);
+ $loaded_flag->setValue($lang, true);
+
+ // Set up test language data
+ $lang_array = $reflection_class->getProperty('lang');
+ $lang_array->setAccessible(true);
+ $lang_array->setValue($lang, $this->get_test_language_data_set());
+
+ // Set up event dispatcher
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
+
+ // Set up path helper
+ $path_helper = $this->getMockBuilder('\phpbb\path_helper')
+ ->disableOriginalConstructor()
+ ->setMethods(array())
+ ->getMock();
+ $path_helper->method('get_phpbb_root_path')
+ ->willReturn($phpbb_root_path);
+ $path_helper->method('get_php_ext')
+ ->willReturn($phpEx);
+ $path_helper->method('update_web_root_path')
+ ->will($this->returnArgument(0));
+
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->data['user_id'] = ANONYMOUS;
+
+ $this->group_helper = new \phpbb\group\helper($auth, $cache_service, $config, $lang, $phpbb_dispatcher, $path_helper, $user);
+ }
+
+ public function setUp()
+ {
+ $this->setup_engine();
+ }
+}
diff --git a/tests/groupposition/legend_test.php b/tests/groupposition/legend_test.php
index fe003e93a7..02ddb7cbce 100644
--- a/tests/groupposition/legend_test.php
+++ b/tests/groupposition/legend_test.php
@@ -11,7 +11,6 @@
*
*/
-
class phpbb_groupposition_legend_test extends phpbb_database_test_case
{
public function getDataSet()
@@ -33,11 +32,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case
*/
public function test_get_group_value($group_id, $expected, $throws_exception)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
if ($throws_exception)
@@ -51,11 +52,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case
public function test_get_group_count()
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\legend($db, $user);
@@ -91,11 +94,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case
*/
public function test_add_group($group_id, $expected_added, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\legend($db, $user);
@@ -179,11 +184,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case
*/
public function test_delete_group($group_id, $skip_group, $expected_deleted, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\legend($db, $user);
@@ -234,11 +241,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case
*/
public function test_move_up($group_id, $excepted_moved, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\legend($db, $user);
@@ -289,11 +298,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case
*/
public function test_move_down($group_id, $excepted_moved, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\legend($db, $user);
@@ -387,11 +398,13 @@ class phpbb_groupposition_legend_test extends phpbb_database_test_case
*/
public function test_move($group_id, $increment, $excepted_moved, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\legend($db, $user);
diff --git a/tests/groupposition/teampage_test.php b/tests/groupposition/teampage_test.php
index 1e61e3ebfb..3b916670f7 100644
--- a/tests/groupposition/teampage_test.php
+++ b/tests/groupposition/teampage_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_groupposition_teampage_test extends phpbb_database_test_case
{
public function getDataSet()
@@ -35,11 +32,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
*/
public function test_get_group_value($group_id, $expected, $throws_exception)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
if ($throws_exception)
@@ -53,11 +52,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
public function test_get_group_count()
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\teampage($db, $user, $cache);
@@ -137,11 +138,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
*/
public function test_add_group_teampage($group_id, $parent_id, $expected_added, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\teampage($db, $user, $cache);
@@ -180,11 +183,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
*/
public function test_add_category_teampage($group_name, $expected_added, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\teampage($db, $user, $cache);
@@ -247,11 +252,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
*/
public function test_delete_group($group_id, $expected_deleted, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\teampage($db, $user, $cache);
@@ -299,11 +306,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
*/
public function test_delete_teampage($teampage_id, $expected_deleted, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\teampage($db, $user, $cache);
@@ -462,11 +471,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
*/
public function test_move($group_id, $move_delta, $excepted_moved, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\teampage($db, $user, $cache);
@@ -625,11 +636,13 @@ class phpbb_groupposition_teampage_test extends phpbb_database_test_case
*/
public function test_move_teampage($teampage_id, $move_delta, $excepted_moved, $expected)
{
- global $cache;
+ global $cache, $phpbb_root_path, $phpEx;
$cache = new phpbb_mock_cache;
$db = $this->new_dbal();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = array();
$test_class = new \phpbb\groupposition\teampage($db, $user, $cache);
diff --git a/tests/help/manager_test.php b/tests/help/manager_test.php
new file mode 100644
index 0000000000..68534d9a32
--- /dev/null
+++ b/tests/help/manager_test.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_help_manager_test extends phpbb_test_case
+{
+ /** @var \phpbb\help\manager */
+ protected $manager;
+ /** @var \phpbb\template\template */
+ protected $template;
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ public function setUp()
+ {
+ $this->template = $this->getMockBuilder('\phpbb\template\template')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->language = $this->getMockBuilder('\phpbb\language\language')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->manager = new \phpbb\help\manager(
+ new \phpbb_mock_event_dispatcher(),
+ $this->language,
+ $this->template
+ );
+ }
+
+ public function add_block_data()
+ {
+ return array(
+ array('abc', false, array(), false),
+ array('def', true, array(), true),
+ array(
+ 'abc',
+ false,
+ array(
+ 'question1' => 'answer1',
+ 'question2' => 'answer2',
+ 'question3' => 'answer3',
+ ),
+ false
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider add_block_data
+ *
+ * @param string $block_name
+ * @param bool $switch
+ * @param array $questions
+ * @param bool $switch_expected
+ */
+ public function test_add_block($block_name, $switch, $questions, $switch_expected)
+ {
+ $this->language->expects($this->at(0))
+ ->method('lang')
+ ->with($block_name)
+ ->willReturn(strtoupper($block_name));
+ $lang_call_count = 1;
+ foreach ($questions as $question => $answer)
+ {
+ $this->language->expects($this->at($lang_call_count))
+ ->method('lang')
+ ->with($question)
+ ->willReturn(strtoupper($question));
+ $lang_call_count++;
+
+ $this->language->expects($this->at($lang_call_count))
+ ->method('lang')
+ ->with($answer)
+ ->willReturn(strtoupper($answer));
+ $lang_call_count++;
+ }
+
+ $this->template->expects($this->at(0))
+ ->method('assign_block_vars')
+ ->with('faq_block', array(
+ 'BLOCK_TITLE' => strtoupper($block_name),
+ 'SWITCH_COLUMN' => $switch_expected,
+ ));
+ $template_call_count = 1;
+ foreach ($questions as $question => $answer)
+ {
+ $this->template->expects($this->at($template_call_count))
+ ->method('assign_block_vars')
+ ->with('faq_block.faq_row', array(
+ 'FAQ_QUESTION' => strtoupper($question),
+ 'FAQ_ANSWER' => strtoupper($answer),
+ ));
+ $template_call_count++;
+ }
+
+ $this->manager->add_block($block_name, $switch, $questions);
+
+ $this->assertEquals($switch_expected, $this->manager->switched_column());
+ }
+
+ public function add_question_data()
+ {
+ return array(
+ array('abc', false, false),
+ array('def', true, true),
+ );
+ }
+
+ /**
+ * @dataProvider add_question_data
+ *
+ * @param string $question
+ * @param string $answer
+ */
+ public function test_add_question($question, $answer)
+ {
+ $this->language->expects($this->at(0))
+ ->method('lang')
+ ->with($question)
+ ->willReturn(strtoupper($question));
+ $this->language->expects($this->at(1))
+ ->method('lang')
+ ->with($answer)
+ ->willReturn(strtoupper($answer));
+
+ $this->template->expects($this->once())
+ ->method('assign_block_vars')
+ ->with('faq_block.faq_row', array(
+ 'FAQ_QUESTION' => strtoupper($question),
+ 'FAQ_ANSWER' => strtoupper($answer),
+ ));
+
+ $this->manager->add_question($question, $answer);
+ }
+
+ public function test_add_block_double_switch()
+ {
+ $block_name = 'abc';
+ $switch_expected = true;
+
+ $this->language->expects($this->at(0))
+ ->method('lang')
+ ->with($block_name)
+ ->willReturn(strtoupper($block_name));
+
+ $this->template->expects($this->at(0))
+ ->method('assign_block_vars')
+ ->with('faq_block', array(
+ 'BLOCK_TITLE' => strtoupper($block_name),
+ 'SWITCH_COLUMN' => $switch_expected,
+ ));
+
+ $this->manager->add_block($block_name, true);
+ $this->assertTrue($this->manager->switched_column());
+
+ // Add a second block with switch
+ $block_name = 'def';
+ $switch_expected = false;
+
+ $this->language->expects($this->at(0))
+ ->method('lang')
+ ->with($block_name)
+ ->willReturn(strtoupper($block_name));
+
+ $this->template->expects($this->at(0))
+ ->method('assign_block_vars')
+ ->with('faq_block', array(
+ 'BLOCK_TITLE' => strtoupper($block_name),
+ 'SWITCH_COLUMN' => $switch_expected,
+ ));
+
+ $this->manager->add_block($block_name, true);
+ $this->assertTrue($this->manager->switched_column());
+ }
+}
diff --git a/tests/installer/database_helper_test.php b/tests/installer/database_helper_test.php
new file mode 100644
index 0000000000..ed355884f6
--- /dev/null
+++ b/tests/installer/database_helper_test.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_installer_database_helper_test extends phpbb_test_case
+{
+ /**
+ * @var phpbb\install\helper\database
+ */
+ private $database_helper;
+
+ public function setUp()
+ {
+ $filesystem = new \phpbb\filesystem\filesystem();
+ $phpbb_root_path = '';
+ $this->database_helper = new \phpbb\install\helper\database($filesystem, $phpbb_root_path);
+ }
+
+ /**
+ * @param string $input
+ * @param string $expected
+ *
+ * @dataProvider comment_string_provider
+ */
+ public function test_remove_comments($input, $expected)
+ {
+ $this->assertEquals($expected, $this->database_helper->remove_comments($input));
+ }
+
+ /**
+ * @param array $expected
+ * @param string $sql
+ * @param string $delimiter
+ *
+ * @dataProvider sql_file_string_provider
+ */
+ public function test_split_sql($expected, $sql, $delimiter)
+ {
+ $this->assertEquals($expected, $this->database_helper->split_sql_file($sql, $delimiter));
+ }
+
+ /**
+ * @param bool|array $expected
+ * @param string $test_string
+ *
+ * @dataProvider prefix_test_case_provider
+ */
+ public function test_validate_table_prefix($expected, $test_string)
+ {
+ $db_helper_mock = $this->getMockBuilder('\phpbb\install\helper\database')
+ ->setMethods(array('get_available_dbms'))
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $db_helper_mock->method('get_available_dbms')
+ ->willReturn(array('sqlite3' => array(
+ 'LABEL' => 'SQLite3',
+ 'SCHEMA' => 'sqlite',
+ 'MODULE' => 'sqlite3',
+ 'DELIM' => ';',
+ 'DRIVER' => 'phpbb\db\driver\sqlite3',
+ 'AVAILABLE' => true,
+ '2.0.x' => false,
+ )));
+
+ $this->assertEquals($expected, $db_helper_mock->validate_table_prefix('sqlite3', $test_string));
+ }
+
+ // Data provider for the remove comments function
+ public function comment_string_provider()
+ {
+ return array(
+ array(
+ 'abc',
+ 'abc',
+ ),
+ array(
+ 'abc /* asdf */',
+ "abc \n",
+ ),
+ array(
+ 'abc /* asdf */ f',
+ "abc \n f",
+ ),
+ array(
+ '# abc',
+ "\n",
+ ),
+ );
+ }
+
+ // Data provider for the sql file splitter function
+ public function sql_file_string_provider()
+ {
+ return array(
+ array(
+ array(
+ 'abcd "efgh"' . "\n" . 'qwerty',
+ 'SELECT * FROM table',
+ ),
+ 'abcd "efgh"' . "\n" .
+ 'qwerty;' . "\n" .
+ 'SELECT * FROM table',
+ ';',
+ ),
+ );
+ }
+
+ // Test data for prefix test
+ public function prefix_test_case_provider()
+ {
+ return array(
+ array(
+ true,
+ 'phpbb_',
+ ),
+ array(
+ true,
+ 'phpbb',
+ ),
+ array(
+ array(
+ array('title' => 'INST_ERR_DB_INVALID_PREFIX'),
+ ),
+ '1hpbb_',
+ ),
+ array(
+ array(
+ array('title' => 'INST_ERR_DB_INVALID_PREFIX'),
+ ),
+ '?hpbb_',
+ ),
+ array(
+ array(
+ array('title' => array('INST_ERR_PREFIX_TOO_LONG', 200)),
+ ),
+ 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ ),
+ array(
+ array(
+ array('title' => 'INST_ERR_DB_INVALID_PREFIX'),
+ array('title' => array('INST_ERR_PREFIX_TOO_LONG', 200)),
+ ),
+ '_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+ ),
+ );
+ }
+}
diff --git a/tests/installer/installer_config_test.php b/tests/installer/installer_config_test.php
new file mode 100644
index 0000000000..13ac325a79
--- /dev/null
+++ b/tests/installer/installer_config_test.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+use phpbb\install\helper\config;
+
+class phpbb_installer_config_test extends phpbb_test_case
+{
+ /**
+ * @var \phpbb\install\helper\config
+ */
+ private $config;
+
+ public function setUp()
+ {
+ $phpbb_root_path = __DIR__ . './../../phpBB/';
+ $filesystem = $this->getMock('\phpbb\filesystem\filesystem');
+ $php_ini = $this->getMockBuilder('\bantu\IniGetWrapper\IniGetWrapper')
+ ->getMock();
+ $php_ini->method('getInt')
+ ->willReturn(-1);
+ $php_ini->method('getBytes')
+ ->willReturn(-1);
+
+ $this->config = new config($filesystem, $php_ini, $phpbb_root_path);
+ }
+
+ public function test_set_get_var()
+ {
+ $this->config->set('foo', 'bar');
+ $this->assertEquals('bar', $this->config->get('foo'));
+ }
+
+ public function test_get_time_remaining()
+ {
+ $this->assertGreaterThan(0, $this->config->get_time_remaining());
+ }
+
+ public function test_get_memory_remaining()
+ {
+ $this->assertGreaterThan(0, $this->config->get_memory_remaining());
+ }
+
+ public function test_progress_tracking()
+ {
+ $this->config->set_finished_task(0);
+ $this->config->set_active_module('bar', 5);
+ $this->config->set_task_progress_count(10);
+ $this->config->increment_current_task_progress();
+
+ $progress_data = $this->config->get_progress_data();
+ $this->assertEquals(1, $progress_data['current_task_progress']);
+
+ $this->config->increment_current_task_progress(2);
+
+ // We only want to check these values
+ $result = $this->config->get_progress_data();
+ $expected_result = array(
+ 'last_task_module_name' => 'bar',
+ 'last_task_module_index' => 5,
+ 'last_task_index' => 0,
+ 'max_task_progress' => 10,
+ 'current_task_progress' => 3,
+ );
+
+ foreach ($expected_result as $key => $value)
+ {
+ $this->assertEquals($value, $result[$key]);
+ }
+ }
+}
diff --git a/tests/installer/mocks/test_installer_module.php b/tests/installer/mocks/test_installer_module.php
new file mode 100644
index 0000000000..e6ebbba263
--- /dev/null
+++ b/tests/installer/mocks/test_installer_module.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class test_installer_module extends \phpbb\install\module_base
+{
+ public function get_navigation_stage_path()
+ {
+ return array();
+ }
+}
diff --git a/tests/installer/mocks/test_installer_task_mock.php b/tests/installer/mocks/test_installer_task_mock.php
new file mode 100644
index 0000000000..ccd62b3bf4
--- /dev/null
+++ b/tests/installer/mocks/test_installer_task_mock.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class test_installer_task_mock extends \phpbb\install\task_base
+{
+ private $task_was_runned;
+
+ public function __construct()
+ {
+ $this->task_was_runned = false;
+
+ parent::__construct();
+ }
+
+ public function run()
+ {
+ $this->task_was_runned = true;
+ }
+
+ public function was_task_runned()
+ {
+ return $this->task_was_runned;
+ }
+
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+
+ public static function get_step_count()
+ {
+ return 2;
+ }
+}
diff --git a/tests/installer/module_base_test.php b/tests/installer/module_base_test.php
new file mode 100644
index 0000000000..9578010047
--- /dev/null
+++ b/tests/installer/module_base_test.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+require_once __DIR__ . '/mocks/test_installer_task_mock.php';
+require_once __DIR__ . '/mocks/test_installer_module.php';
+
+class module_base_test extends phpbb_test_case
+{
+ /**
+ * @var \phpbb\install\module_interface
+ */
+ protected $module;
+
+ /**
+ * @var phpbb_mock_container_builder
+ */
+ protected $container;
+
+ public function setUp()
+ {
+ // DI container mock
+ $this->container = new phpbb_mock_container_builder();
+ $this->container->set('task_one', new test_installer_task_mock());
+ $this->container->set('task_two', new test_installer_task_mock());
+
+ // the collection
+ $module_collection = new \phpbb\di\ordered_service_collection($this->container);
+ $module_collection->add('task_one');
+ $module_collection->add('task_two');
+ $module_collection->add_service_class('task_one', 'test_installer_task_mock');
+ $module_collection->add_service_class('task_two', 'test_installer_task_mock');
+
+ $this->module = new test_installer_module($module_collection, true, false);
+
+ $iohandler = $this->getMock('\phpbb\install\helper\iohandler\iohandler_interface');
+ $config = new \phpbb\install\helper\config(new \phpbb\filesystem\filesystem(), new \bantu\IniGetWrapper\IniGetWrapper(), '', 'php');
+ $this->module->setup($config, $iohandler);
+ }
+
+ public function test_run()
+ {
+ $this->module->run();
+
+ $task = $this->container->get('task_one');
+ $this->assertTrue($task->was_task_runned());
+
+ $task = $this->container->get('task_two');
+ $this->assertTrue($task->was_task_runned());
+ }
+
+ public function test_step_count()
+ {
+ $this->assertEquals(4, $this->module->get_step_count());
+ }
+}
diff --git a/tests/installer/navigation_provider_test.php b/tests/installer/navigation_provider_test.php
new file mode 100644
index 0000000000..ea39af66cd
--- /dev/null
+++ b/tests/installer/navigation_provider_test.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_installer_navigation_provider_test extends phpbb_test_case
+{
+ public function test_navigation()
+ {
+ // Mock nav interface
+ $nav_stub = $this->getMockBuilder('\phpbb\install\helper\navigation\navigation_interface')
+ ->getMock();
+ $nav_stub->method('get')
+ ->willReturn(array('foo' => 'bar'));
+
+ // Set up dependencies
+ $container = new phpbb_mock_container_builder();
+ $container->set('foo', $nav_stub);
+ $nav_collection = new \phpbb\di\service_collection($container);
+ $nav_collection->add('foo');
+
+ // Let's test
+ $nav_provider = new \phpbb\install\helper\navigation\navigation_provider($nav_collection);
+ $this->assertEquals(array('foo' => 'bar'), $nav_provider->get());
+ }
+}
diff --git a/tests/language/language_test.php b/tests/language/language_test.php
new file mode 100644
index 0000000000..29b4873dcb
--- /dev/null
+++ b/tests/language/language_test.php
@@ -0,0 +1,243 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_language_test extends phpbb_test_case
+{
+ /** @var \phpbb\language\language */
+ protected $lang;
+
+ public function setUp()
+ {
+ global $phpbb_root_path, $phpEx;
+
+ // Set up language service
+ $this->lang = new \phpbb\language\language(
+ new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)
+ );
+
+ // Set up language data for testing
+ $reflection_class = new ReflectionClass('\phpbb\language\language');
+
+ // Set default language files loaded flag to true
+ $loaded_flag = $reflection_class->getProperty('common_language_files_loaded');
+ $loaded_flag->setAccessible(true);
+ $loaded_flag->setValue($this->lang, true);
+
+ // Set up test language data
+ $lang_array = $reflection_class->getProperty('lang');
+ $lang_array->setAccessible(true);
+ $lang_array->setValue($this->lang, $this->get_test_data_set());
+ }
+
+ public function test_is_set()
+ {
+ // Check for non-existing key
+ $this->assertFalse($this->lang->is_set('VALUE'));
+ $this->assertFalse($this->lang->is_set(array('dateformat', 'MAYBE')));
+
+ // Check for existing key
+ $this->assertTrue($this->lang->is_set('FOO'));
+ $this->assertTrue($this->lang->is_set(array('dateformat', 'AGO')));
+
+ // Array doesn't exist at all...
+ $this->assertFalse($this->lang->is_set(array('PHPBB', 'PHP')));
+ }
+
+ public function test_lang_raw()
+ {
+ $this->assertEquals($this->lang->lang_raw('FOO'), 'BAR');
+ $this->assertEquals($this->lang->lang_raw('VOID'), 'VOID');
+ $this->assertEquals($this->lang->lang_raw('ARRY'), array(
+ 0 => 'No posts', // 0
+ 1 => '1 post', // 1
+ 2 => '%d posts', // 2+
+ ));
+ }
+
+ public function test_lang_array()
+ {
+ $this->assertEquals($this->lang->lang_array('FOO'), 'BAR');
+ $this->assertEquals($this->lang->lang_array('VOID'), 'VOID');
+ $this->assertEquals($this->lang->lang_array('ARRY', [0]), 'No posts');
+ $this->assertEquals($this->lang->lang_array('FOO', [2, 3, 'BARZ']), 'BAR');
+ }
+
+ public function test_lang()
+ {
+ // No param
+ $this->assertEquals($this->lang->lang('FOO'), 'BAR');
+ $this->assertEquals($this->lang->lang('EMPTY'), '');
+ $this->assertEquals($this->lang->lang('ZERO'), '0');
+
+ // Invalid index
+ $this->assertEquals($this->lang->lang('VOID'), 'VOID');
+
+ // Unnecessary param
+ $this->assertEquals($this->lang->lang('FOO', 2), 'BAR');
+ $this->assertEquals($this->lang->lang('FOO', 2, 3), 'BAR');
+ $this->assertEquals($this->lang->lang('FOO', 2, 3, 'BARZ'), 'BAR');
+
+ // String
+ $this->assertEquals($this->lang->lang('STR', 24, 'x', 42), '24 x, 42 topics');
+ $this->assertEquals($this->lang->lang('STR2', 64), '64 foos');
+
+ // Array
+ $this->assertEquals($this->lang->lang('ARRY', 0), 'No posts');
+ $this->assertEquals($this->lang->lang('ARRY', 1), '1 post');
+ $this->assertEquals($this->lang->lang('ARRY', 2), '2 posts');
+ $this->assertEquals($this->lang->lang('ARRY', 123), '123 posts');
+
+ // Empty array returns the language key
+ $this->assertEquals($this->lang->lang('ARRY_EMPTY', 123), 'ARRY_EMPTY');
+
+ // No 0 key defined
+ $this->assertEquals($this->lang->lang('ARRY_NO_ZERO', 0), '0 posts');
+ $this->assertEquals($this->lang->lang('ARRY_NO_ZERO', 1), '1 post');
+ $this->assertEquals($this->lang->lang('ARRY_NO_ZERO', 2), '2 posts');
+
+ // Array with missing keys
+ $this->assertEquals($this->lang->lang('ARRY_MISSING', 2), '2 post');
+
+ // Floats as array key
+ $this->assertEquals($this->lang->lang('ARRY_FLOAT', 1.3), '1 post');
+ $this->assertEquals($this->lang->lang('ARRY_FLOAT', 2.0), '2.0 posts');
+ $this->assertEquals($this->lang->lang('ARRY_FLOAT', 2.51), '2.5 posts');
+
+ // Use sub key, if first paramenter is an array
+ $this->assertEquals($this->lang->lang(array('dateformat', 'AGO'), 2), '2 seconds');
+
+ // ticket PHPBB3-9949 - use first int to determinate the plural-form to use
+ $this->assertEquals($this->lang->lang('ARRY', 1, 2), '1 post');
+ $this->assertEquals($this->lang->lang('ARRY', 1, 's', 2), '1 post');
+ }
+
+ public function test_lang_plural_rules()
+ {
+ $this->assertEquals($this->lang->lang('PLURAL_ARRY', 0), '0 is 0');
+ $this->assertEquals($this->lang->lang('PLURAL_ARRY', 1), '1 is 1');
+ $this->assertEquals($this->lang->lang('PLURAL_ARRY', 103), '103 ends with 01-10');
+ $this->assertEquals($this->lang->lang('PLURAL_ARRY', 15), '15 ends with 11-19');
+ $this->assertEquals($this->lang->lang('PLURAL_ARRY', 300), '300 is part of the last rule');
+ }
+
+ public function test_lang_bc()
+ {
+ $user = new \phpbb\user($this->lang, '\phpbb\datetime');
+
+ // Test lang array access
+ $this->assertEquals($user->lang['FOO'], 'BAR');
+
+ // No param
+ $this->assertEquals($user->lang('FOO'), 'BAR');
+ $this->assertEquals($user->lang('EMPTY'), '');
+ $this->assertEquals($user->lang('ZERO'), '0');
+
+ // Invalid index
+ $this->assertEquals($user->lang('VOID'), 'VOID');
+
+ // Unnecessary param
+ $this->assertEquals($user->lang('FOO', 2), 'BAR');
+ $this->assertEquals($user->lang('FOO', 2, 3), 'BAR');
+ $this->assertEquals($user->lang('FOO', 2, 3, 'BARZ'), 'BAR');
+
+ // String
+ $this->assertEquals($user->lang('STR', 24, 'x', 42), '24 x, 42 topics');
+ $this->assertEquals($user->lang('STR2', 64), '64 foos');
+
+ // Array
+ $this->assertEquals($user->lang('ARRY', 0), 'No posts');
+ $this->assertEquals($user->lang('ARRY', 1), '1 post');
+ $this->assertEquals($user->lang('ARRY', 2), '2 posts');
+ $this->assertEquals($user->lang('ARRY', 123), '123 posts');
+
+ // Empty array returns the language key
+ $this->assertEquals($user->lang('ARRY_EMPTY', 123), 'ARRY_EMPTY');
+
+ // No 0 key defined
+ $this->assertEquals($user->lang('ARRY_NO_ZERO', 0), '0 posts');
+ $this->assertEquals($user->lang('ARRY_NO_ZERO', 1), '1 post');
+ $this->assertEquals($user->lang('ARRY_NO_ZERO', 2), '2 posts');
+
+ // Array with missing keys
+ $this->assertEquals($user->lang('ARRY_MISSING', 2), '2 post');
+
+ // Floats as array key
+ $this->assertEquals($user->lang('ARRY_FLOAT', 1.3), '1 post');
+ $this->assertEquals($user->lang('ARRY_FLOAT', 2.0), '2.0 posts');
+ $this->assertEquals($user->lang('ARRY_FLOAT', 2.51), '2.5 posts');
+
+ // Use sub key, if first paramenter is an array
+ $this->assertEquals($user->lang(array('dateformat', 'AGO'), 2), '2 seconds');
+
+ // ticket PHPBB3-9949 - use first int to determinate the plural-form to use
+ $this->assertEquals($user->lang('ARRY', 1, 2), '1 post');
+ $this->assertEquals($user->lang('ARRY', 1, 's', 2), '1 post');
+ }
+
+ public function test_lang_plural_rules_bc()
+ {
+ $user = new \phpbb\user($this->lang, '\phpbb\datetime');
+
+ // ticket PHPBB3-10345 - different plural rules, not just 0/1/2+
+ $this->assertEquals($user->lang('PLURAL_ARRY', 0), '0 is 0');
+ $this->assertEquals($user->lang('PLURAL_ARRY', 1), '1 is 1');
+ $this->assertEquals($user->lang('PLURAL_ARRY', 103), '103 ends with 01-10');
+ $this->assertEquals($user->lang('PLURAL_ARRY', 15), '15 ends with 11-19');
+ $this->assertEquals($user->lang('PLURAL_ARRY', 300), '300 is part of the last rule');
+ }
+
+ protected function get_test_data_set()
+ {
+ return array(
+ 'FOO' => 'BAR',
+ 'BARZ' => 'PENG',
+ 'EMPTY' => '',
+ 'ZERO' => '0',
+ 'STR' => '%d %s, %d topics',
+ 'STR2' => '%d foos',
+ 'ARRY' => array(
+ 0 => 'No posts', // 0
+ 1 => '1 post', // 1
+ 2 => '%d posts', // 2+
+ ),
+ 'ARRY_NO_ZERO' => array(
+ 1 => '1 post', // 1
+ 2 => '%d posts', // 0, 2+
+ ),
+ 'ARRY_MISSING' => array(
+ 1 => '%d post', // 1
+ //Missing second plural
+ ),
+ 'ARRY_FLOAT' => array(
+ 1 => '1 post', // 1.x
+ 2 => '%1$.1f posts', // 0.x, 2+.x
+ ),
+ 'ARRY_EMPTY' => array(
+ ),
+ 'dateformat' => array(
+ 'AGO' => array(
+ 1 => '%d second',
+ 2 => '%d seconds',
+ ),
+ ),
+ 'PLURAL_RULE' => 13,
+ 'PLURAL_ARRY' => array(
+ 0 => '%d is 0', // 0
+ 1 => '%d is 1', // 1
+ 2 => '%d ends with 01-10', // ending with 01-10
+ 3 => '%d ends with 11-19', // ending with 11-19
+ 4 => '%d is part of the last rule', // everything else
+ ),
+ );
+ }
+}
diff --git a/tests/lint_test.php b/tests/lint_test.php
index 70046bdfd2..8ab31f976c 100644
--- a/tests/lint_test.php
+++ b/tests/lint_test.php
@@ -67,6 +67,12 @@ class phpbb_lint_test extends phpbb_test_case
{
$files = array();
$dh = opendir($root);
+
+ if ($dh === false)
+ {
+ return $files;
+ }
+
while (($filename = readdir($dh)) !== false)
{
if ($filename == '.' || $filename == '..')
@@ -89,6 +95,7 @@ class phpbb_lint_test extends phpbb_test_case
// PHP Fatal error: Cannot declare class Container because the name is already in use in /var/www/projects/phpbb3/tests/../phpBB/vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services1-1.php on line 20
// https://gist.github.com/e003913ffd493da63cbc
dirname(__FILE__) . '/../phpBB/vendor',
+ dirname(__FILE__) . '/../node_modules',
)))
{
$files = array_merge($files, $this->check($path));
diff --git a/tests/lock/db_test.php b/tests/lock/db_test.php
index 6fc813cb38..5fbfa26554 100644
--- a/tests/lock/db_test.php
+++ b/tests/lock/db_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_lock_db_test extends phpbb_database_test_case
{
private $db;
@@ -30,7 +28,6 @@ class phpbb_lock_db_test extends phpbb_database_test_case
$db = $this->db = $this->new_dbal();
$config = $this->config = new \phpbb\config\config(array('rand_seed' => '', 'rand_seed_last_update' => '0'));
- set_config(null, null, null, $this->config);
$this->lock = new \phpbb\lock\db('test_lock', $this->config, $this->db);
}
diff --git a/tests/log/add_test.php b/tests/log/add_test.php
index 29d3adaeb6..604c8364dc 100644
--- a/tests/log/add_test.php
+++ b/tests/log/add_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_log_add_test extends phpbb_database_test_case
{
public function getDataSet()
@@ -27,7 +25,9 @@ class phpbb_log_add_test extends phpbb_database_test_case
$db = $this->new_dbal();
$cache = new phpbb_mock_cache;
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$auth = $this->getMock('\phpbb\auth\auth');
$log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE);
@@ -56,7 +56,9 @@ class phpbb_log_add_test extends phpbb_database_test_case
$db = $this->new_dbal();
$cache = new phpbb_mock_cache;
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$auth = $this->getMock('\phpbb\auth\auth');
$log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE);
diff --git a/tests/log/delete_test.php b/tests/log/delete_test.php
index ec43182a0c..e8b75d01d9 100644
--- a/tests/log/delete_test.php
+++ b/tests/log/delete_test.php
@@ -11,10 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_log_delete_test extends phpbb_database_test_case
{
protected $log;
@@ -30,7 +26,9 @@ class phpbb_log_delete_test extends phpbb_database_test_case
$db = $this->new_dbal();
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->data['user_id'] = 1;
$auth = $this->getMock('\phpbb\auth\auth');
diff --git a/tests/log/fixtures/delete_log.xml b/tests/log/fixtures/delete_log.xml
index 4b2402102e..393c686f0c 100644
--- a/tests/log/fixtures/delete_log.xml
+++ b/tests/log/fixtures/delete_log.xml
@@ -6,6 +6,7 @@
<column>user_id</column>
<column>forum_id</column>
<column>topic_id</column>
+ <column>post_id</column>
<column>reportee_id</column>
<column>log_ip</column>
<column>log_time</column>
@@ -18,6 +19,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_INSTALL_INSTALLED</value>
@@ -30,6 +32,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_KEY_NOT_EXISTS</value>
@@ -42,6 +45,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_CRITICAL</value>
@@ -54,6 +58,7 @@
<value>12</value>
<value>34</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD</value>
@@ -66,6 +71,7 @@
<value>12</value>
<value>45</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD</value>
@@ -78,6 +84,7 @@
<value>23</value>
<value>56</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD</value>
@@ -90,6 +97,7 @@
<value>12</value>
<value>45</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD2</value>
@@ -101,6 +109,7 @@
<value>1</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>2</value>
<value>127.0.0.1</value>
<value>1</value>
@@ -113,6 +122,7 @@
<value>1</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>1</value>
<value>127.0.0.1</value>
<value>1</value>
@@ -126,6 +136,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_SINGULAR_PLURAL</value>
@@ -138,6 +149,7 @@
<value>15</value>
<value>3</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD3</value>
@@ -150,6 +162,7 @@
<value>13</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value></value>
@@ -162,6 +175,7 @@
<value>14</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value></value>
@@ -174,6 +188,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value></value>
@@ -186,6 +201,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value></value>
diff --git a/tests/log/fixtures/empty_log.xml b/tests/log/fixtures/empty_log.xml
index 261b6a622a..47fd639b17 100644
--- a/tests/log/fixtures/empty_log.xml
+++ b/tests/log/fixtures/empty_log.xml
@@ -6,6 +6,7 @@
<column>user_id</column>
<column>forum_id</column>
<column>topic_id</column>
+ <column>post_id</column>
<column>reportee_id</column>
<column>log_ip</column>
<column>log_time</column>
diff --git a/tests/log/fixtures/full_log.xml b/tests/log/fixtures/full_log.xml
index ef35884444..5b9ded9ffb 100644
--- a/tests/log/fixtures/full_log.xml
+++ b/tests/log/fixtures/full_log.xml
@@ -6,6 +6,7 @@
<column>user_id</column>
<column>forum_id</column>
<column>topic_id</column>
+ <column>post_id</column>
<column>reportee_id</column>
<column>log_ip</column>
<column>log_time</column>
@@ -18,6 +19,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_INSTALL_INSTALLED</value>
@@ -30,6 +32,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_KEY_NOT_EXISTS</value>
@@ -42,6 +45,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_CRITICAL</value>
@@ -54,6 +58,7 @@
<value>12</value>
<value>34</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD</value>
@@ -66,6 +71,7 @@
<value>12</value>
<value>45</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD</value>
@@ -78,6 +84,7 @@
<value>23</value>
<value>56</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD</value>
@@ -90,6 +97,7 @@
<value>12</value>
<value>45</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD2</value>
@@ -101,6 +109,7 @@
<value>1</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>2</value>
<value>127.0.0.1</value>
<value>1</value>
@@ -113,6 +122,7 @@
<value>1</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>1</value>
<value>127.0.0.1</value>
<value>1</value>
@@ -126,6 +136,7 @@
<value>0</value>
<value>0</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_SINGULAR_PLURAL</value>
@@ -138,6 +149,7 @@
<value>15</value>
<value>3</value>
<value>0</value>
+ <value>0</value>
<value>127.0.0.1</value>
<value>1</value>
<value>LOG_MOD3</value>
diff --git a/tests/log/function_add_log_test.php b/tests/log/function_add_log_test.php
index 63e468498e..3b5537fc13 100644
--- a/tests/log/function_add_log_test.php
+++ b/tests/log/function_add_log_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_log_function_add_log_test extends phpbb_database_test_case
{
public function getDataSet()
@@ -161,7 +159,10 @@ class phpbb_log_function_add_log_test extends phpbb_database_test_case
$db = $this->new_dbal();
$cache = new phpbb_mock_cache;
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$auth = $this->getMock('\phpbb\auth\auth');
$phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE);
diff --git a/tests/log/function_view_log_test.php b/tests/log/function_view_log_test.php
index 02e0b3912f..ee9c3e5893 100644
--- a/tests/log/function_view_log_test.php
+++ b/tests/log/function_view_log_test.php
@@ -11,10 +11,7 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_admin.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
require_once dirname(__FILE__) . '/../mock/user.php';
require_once dirname(__FILE__) . '/../mock/cache.php';
@@ -46,6 +43,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 0,
'topic_id' => 0,
+ 'post_id' => 0,
'viewforum' => '',
'action' => 'LOG_INSTALL_INSTALLED 3.1.0-dev',
@@ -65,6 +63,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 0,
'topic_id' => 0,
+ 'post_id' => 0,
'viewforum' => '',
'action' => '{LOG KEY NOT EXISTS}<br />additional_data',
@@ -84,6 +83,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 0,
'topic_id' => 0,
+ 'post_id' => 0,
'viewforum' => '',
'action' => '{LOG CRITICAL}<br />critical data',
@@ -103,10 +103,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 12,
'topic_id' => 34,
+ 'post_id' => 0,
'viewforum' => '',
'action' => '{LOG MOD}',
'viewtopic' => '',
+ 'viewpost' => '',
'viewlogs' => '',
),
5 => array(
@@ -124,10 +126,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 12,
'topic_id' => 45,
+ 'post_id' => 0,
'viewforum' => '',
'action' => '{LOG MOD}',
'viewtopic' => '',
+ 'viewpost' => '',
'viewlogs' => '',
),
6 => array(
@@ -145,10 +149,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 23,
'topic_id' => 56,
+ 'post_id' => 0,
'viewforum' => append_sid("phpBB/viewforum.$phpEx", 'f=23'),
'action' => '{LOG MOD}',
'viewtopic' => append_sid("phpBB/viewtopic.$phpEx", 'f=23&amp;t=56'),
+ 'viewpost' => '',
'viewlogs' => append_sid("phpBB/mcp.$phpEx", 'i=logs&amp;mode=topic_logs&amp;t=56'),
),
7 => array(
@@ -166,10 +172,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 12,
'topic_id' => 45,
+ 'post_id' => 0,
'viewforum' => '',
'action' => 'LOG_MOD2',
'viewtopic' => '',
+ 'viewpost' => '',
'viewlogs' => '',
),
8 => array(
@@ -187,6 +195,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 0,
'topic_id' => 0,
+ 'post_id' => 0,
'viewforum' => '',
'action' => 'LOG_USER admin',
@@ -206,6 +215,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 0,
'topic_id' => 0,
+ 'post_id' => 0,
'viewforum' => '',
'action' => 'LOG_USER guest',
@@ -225,6 +235,7 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 0,
'topic_id' => 0,
+ 'post_id' => 0,
'viewforum' => '',
'action' => 'LOG_SINGULAR_PLURAL 2',
@@ -244,10 +255,12 @@ class phpbb_log_function_view_log_test extends phpbb_database_test_case
'time' => 1,
'forum_id' => 15,
'topic_id' => 3,
+ 'post_id' => 0,
'viewforum' => '',
'action' => 'LOG_MOD3 guest ',
'viewtopic' => '',
+ 'viewpost' => '',
'viewlogs' => '',
),
);
diff --git a/tests/migrator/convert_timezones_test.php b/tests/migrator/convert_timezones_test.php
index 7501ed2ed0..f8d780da0c 100644
--- a/tests/migrator/convert_timezones_test.php
+++ b/tests/migrator/convert_timezones_test.php
@@ -18,7 +18,8 @@ class phpbb_migrator_convert_timezones_test extends phpbb_database_test_case
public function getDataSet()
{
$this->db = $this->new_dbal();
- $db_tools = new \phpbb\db\tools($this->db);
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($this->db);
// user_dst doesn't exist anymore, must re-add it to test this
$db_tools->sql_column_add('phpbb_users', 'user_dst', array('BOOL', 1));
@@ -55,11 +56,12 @@ class phpbb_migrator_convert_timezones_test extends phpbb_database_test_case
global $phpbb_root_path, $phpEx;
$this->db = $this->new_dbal();
+ $factory = new \phpbb\db\tools\factory();
$this->migration = new \phpbb\db\migration\data\v310\timezone(
new \phpbb\config\config(array()),
$this->db,
- new \phpbb\db\tools($this->db),
+ $factory->get($this->db),
$phpbb_root_path,
$phpEx,
'phpbb_'
@@ -90,7 +92,8 @@ class phpbb_migrator_convert_timezones_test extends phpbb_database_test_case
}
$this->db->sql_freeresult($result);
- $db_tools = new \phpbb\db\tools($this->db);
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($this->db);
// Remove the user_dst field again
$db_tools->sql_column_remove('phpbb_users', 'user_dst');
diff --git a/tests/migrator/get_callable_from_step_test.php b/tests/migrator/get_callable_from_step_test.php
new file mode 100644
index 0000000000..af636f5d21
--- /dev/null
+++ b/tests/migrator/get_callable_from_step_test.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class get_callable_from_step_test extends phpbb_database_test_case
+{
+ public function setUp()
+ {
+ global $phpbb_root_path, $php_ext, $table_prefix, $phpbb_log;
+
+ parent::setUp();
+
+ $phpbb_log = $this->getMockBuilder('\phpbb\log\log')->disableOriginalConstructor()->getMock();
+ $db = $this->new_dbal();
+ $factory = new \phpbb\db\tools\factory();
+ $cache_service = $this->getMockBuilder('\phpbb\cache\service')->disableOriginalConstructor()->getMock();
+ $user = $this->getMockBuilder('\phpbb\user')->disableOriginalConstructor()->getMock();
+ $module_manager = new \phpbb\module\module_manager(
+ $this->getMockBuilder('\phpbb\cache\driver\dummy')->disableOriginalConstructor()->getMock(),
+ $db,
+ new phpbb_mock_extension_manager($phpbb_root_path),
+ 'phpbb_modules',
+ $phpbb_root_path,
+ $php_ext
+ );
+ $module_tools = new \phpbb\db\migration\tool\module($db, $cache_service, $user, $module_manager, $phpbb_root_path, $php_ext, 'phpbb_modules');
+ $this->migrator = new \phpbb\db\migrator(
+ new phpbb_mock_container_builder(),
+ new \phpbb\config\config(array()),
+ $db,
+ $factory->get($db),
+ 'phpbb_migrations',
+ $phpbb_root_path,
+ $php_ext,
+ $table_prefix,
+ array($module_tools),
+ new \phpbb\db\migration\helper()
+ );
+
+ if (!$module_tools->exists('acp', 0, 'new_module_langname'))
+ {
+ $module_tools->add('acp', 0, array(
+ 'module_basename' => 'new_module_basename',
+ 'module_langname' => 'new_module_langname',
+ 'module_mode' => 'settings',
+ 'module_auth' => '',
+ 'module_display' => true,
+ 'before' => false,
+ 'after' => false,
+ ));
+ $this->module_added = true;
+ }
+ }
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__).'/../dbal/fixtures/migrator.xml');
+ }
+
+ public function get_callable_from_step_provider()
+ {
+ return array(
+ array(
+ array('if', array(
+ false,
+ array('permission.add', array('some_data')),
+ )),
+ true, // expects false
+ ),
+ array(
+ array('if', array(
+ array('module.exists', array(
+ 'mcp',
+ 'RANDOM_PARENT',
+ 'RANDOM_MODULE'
+ )),
+ array('permission.add', array('some_data')),
+ )),
+ true, // expects false
+ ),
+ array(
+ array('if', array(
+ array('module.exists', array(
+ 'acp',
+ 0,
+ 'new_module_langname'
+ )),
+ array('module.add', array(
+ 'acp',
+ 0,
+ 'module_basename' => 'new_module_basename2',
+ 'module_langname' => 'new_module_langname2',
+ 'module_mode' => 'settings',
+ 'module_auth' => '',
+ 'module_display' => true,
+ 'before' => false,
+ 'after' => false,
+ )),
+ )),
+ false, // expects false
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider get_callable_from_step_provider
+ */
+ public function test_get_callable_from_step($step, $expects_false)
+ {
+ if ($expects_false)
+ {
+ $this->assertFalse($this->call_get_callable_from_step($step));
+ }
+ else
+ {
+ $this->assertNotFalse($this->call_get_callable_from_step($step));
+ }
+ }
+
+ protected function call_get_callable_from_step($step)
+ {
+ $class = new ReflectionClass($this->migrator);
+ $method = $class->getMethod('get_callable_from_step');
+ $method->setAccessible(true);
+ return $method->invokeArgs($this->migrator, array($step));
+ }
+}
diff --git a/tests/migrator/schema_generator_test.php b/tests/migrator/schema_generator_test.php
index 9adf518a5d..1996d207ea 100644
--- a/tests/migrator/schema_generator_test.php
+++ b/tests/migrator/schema_generator_test.php
@@ -29,8 +29,9 @@ class schema_generator_test extends phpbb_test_case
parent::setUp();
$this->config = new \phpbb\config\config(array());
- $this->db = new \phpbb\db\driver\sqlite();
- $this->db_tools = new \phpbb\db\tools($this->db);
+ $this->db = new \phpbb\db\driver\sqlite3();
+ $factory = new \phpbb\db\tools\factory();
+ $this->db_tools = $factory->get($this->db);
$this->table_prefix = 'phpbb_';
}
diff --git a/tests/mock/container_builder.php b/tests/mock/container_builder.php
index 297e3a65e6..134589b0b8 100644
--- a/tests/mock/container_builder.php
+++ b/tests/mock/container_builder.php
@@ -52,7 +52,15 @@ class phpbb_mock_container_builder implements ContainerInterface
{
if ($this->has($id))
{
- return $this->services[$id];
+ $service = $this->services[$id];
+ if (is_array($service) && is_callable($service[0]))
+ {
+ return call_user_func_array($service[0], $service[1]);
+ }
+ else
+ {
+ return $service;
+ }
}
throw new Exception('Could not find service: ' . $id);
@@ -180,4 +188,9 @@ class phpbb_mock_container_builder implements ContainerInterface
public function isScopeActive($name)
{
}
+
+ public function isFrozen()
+ {
+ return false;
+ }
}
diff --git a/tests/mock/controller_helper.php b/tests/mock/controller_helper.php
index ae3e7bf432..0116dced49 100644
--- a/tests/mock/controller_helper.php
+++ b/tests/mock/controller_helper.php
@@ -13,20 +13,6 @@
class phpbb_mock_controller_helper extends \phpbb\controller\helper
{
- public function __construct(\phpbb\template\template $template, \phpbb\user $user, \phpbb\config\config $config, \phpbb\controller\provider $provider, \phpbb\extension\manager $manager, \phpbb\symfony_request $symfony_request, \phpbb\request\request_interface $request, \phpbb\filesystem $filesystem, $phpbb_root_path, $php_ext, $phpbb_root_path_ext)
- {
- $this->template = $template;
- $this->user = $user;
- $this->config = $config;
- $this->symfony_request = $symfony_request;
- $this->request = $request;
- $this->filesystem = $filesystem;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $provider->find_routing_files($manager->get_finder());
- $this->route_collection = $provider->find($phpbb_root_path_ext)->get_routes();
- }
-
public function get_current_url()
{
return '';
diff --git a/tests/mock/extension_manager.php b/tests/mock/extension_manager.php
index 94268159a8..0d6d110647 100644
--- a/tests/mock/extension_manager.php
+++ b/tests/mock/extension_manager.php
@@ -15,12 +15,15 @@ class phpbb_mock_extension_manager extends \phpbb\extension\manager
{
public function __construct($phpbb_root_path, $extensions = array(), $container = null)
{
+ global $phpEx;
+
+ $lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
$this->phpbb_root_path = $phpbb_root_path;
$this->php_ext = 'php';
$this->extensions = $extensions;
- $this->filesystem = new \phpbb\filesystem();
+ $this->filesystem = new \phpbb\filesystem\filesystem();
$this->container = $container;
$this->config = new \phpbb\config\config(array());
- $this->user = new \phpbb\user('\phpbb\datetime');
+ $this->user = new \phpbb\user($lang,'\phpbb\datetime');
}
}
diff --git a/tests/mock/fileupload.php b/tests/mock/fileupload.php
index 8cc4d77ea1..5a0afc6cd3 100644
--- a/tests/mock/fileupload.php
+++ b/tests/mock/fileupload.php
@@ -19,9 +19,10 @@ class phpbb_mock_fileupload
{
public $max_filesize = 100;
public $error_prefix = '';
+ public $valid_dimensions = true;
public function valid_dimensions($filespec)
{
- return true;
+ return $this->valid_dimensions;
}
}
diff --git a/tests/mock/migrator.php b/tests/mock/migrator.php
index 293f115335..4d1aca0a0a 100644
--- a/tests/mock/migrator.php
+++ b/tests/mock/migrator.php
@@ -21,10 +21,6 @@ class phpbb_mock_migrator extends \phpbb\db\migrator
{
}
- public function set_migrations($class_names)
- {
- }
-
public function update()
{
}
diff --git a/tests/mock/notification_manager.php b/tests/mock/notification_manager.php
index 6a590bc0ca..952c0db489 100644
--- a/tests/mock/notification_manager.php
+++ b/tests/mock/notification_manager.php
@@ -32,19 +32,18 @@ class phpbb_mock_notification_manager
);
}
- public function mark_notifications_read()
+ public function mark_notifications()
{
}
- public function mark_notifications_read_by_parent()
+ public function mark_notifications_by_parent()
{
}
- public function mark_notifications_read_by_id()
+ public function mark_notifications_by_id()
{
}
-
public function add_notifications()
{
return array();
diff --git a/tests/mock/notification_type_post.php b/tests/mock/notification_type_post.php
index 6d8f6dc504..4116fecf5e 100644
--- a/tests/mock/notification_type_post.php
+++ b/tests/mock/notification_type_post.php
@@ -21,11 +21,12 @@ if (!defined('IN_PHPBB'))
class phpbb_mock_notification_type_post extends \phpbb\notification\type\post
{
- public function __construct($user_loader, $db, $cache, $user, $auth, $config, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
+ public function __construct($user_loader, $db, $cache, $language, $user, $auth, $config, $phpbb_root_path, $php_ext, $notification_types_table, $user_notifications_table)
{
$this->user_loader = $user_loader;
$this->db = $db;
$this->cache = $cache;
+ $this->language = $language;
$this->user = $user;
$this->auth = $auth;
$this->config = $config;
@@ -34,7 +35,6 @@ class phpbb_mock_notification_type_post extends \phpbb\notification\type\post
$this->php_ext = $php_ext;
$this->notification_types_table = $notification_types_table;
- $this->notifications_table = $notifications_table;
- $this->user_notifications_table = $user_notifications_table;
+ $this->user_notifications_table = $user_notifications_table;
}
}
diff --git a/tests/mock/phpbb_di_container_builder.php b/tests/mock/phpbb_di_container_builder.php
index 59cdf0bb2b..c78b41d8ec 100644
--- a/tests/mock/phpbb_di_container_builder.php
+++ b/tests/mock/phpbb_di_container_builder.php
@@ -17,4 +17,22 @@ class phpbb_mock_phpbb_di_container_builder extends \phpbb\di\container_builder
{
return $this->phpbb_root_path . '../../tmp/container.' . $this->php_ext;
}
+
+ /**
+ * Get the filename under which the dumped extensions autoloader will be stored.
+ *
+ * @return string Path for dumped extensions autoloader
+ */
+ protected function get_autoload_filename()
+ {
+ return $this->phpbb_root_path . '../../tmp/autoload.' . $this->php_ext;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function inject_dbal_driver()
+ {
+ return;
+ }
}
diff --git a/tests/mock/request.php b/tests/mock/request.php
index e7217a94a9..6a32ba0cf1 100644
--- a/tests/mock/request.php
+++ b/tests/mock/request.php
@@ -34,6 +34,11 @@ class phpbb_mock_request implements \phpbb\request\request_interface
$this->data[$super_global][$var_name] = $value;
}
+ public function raw_variable($var_name, $default, $super_global = \phpbb\request\request_interface::REQUEST)
+ {
+ return $this->variable($var_name, $default, true, $super_global);
+ }
+
public function variable($var_name, $default, $multibyte = false, $super_global = \phpbb\request\request_interface::REQUEST)
{
return isset($this->data[$super_global][$var_name]) ? $this->data[$super_global][$var_name] : $default;
diff --git a/tests/mock/router.php b/tests/mock/router.php
new file mode 100644
index 0000000000..01faa338c5
--- /dev/null
+++ b/tests/mock/router.php
@@ -0,0 +1,27 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_mock_router extends \phpbb\routing\router
+{
+ public function get_matcher()
+ {
+ $this->create_new_url_matcher();
+ return parent::get_matcher();
+ }
+
+ public function get_generator()
+ {
+ $this->create_new_url_generator();
+ return parent::get_generator();
+ }
+}
diff --git a/tests/mock/session_testable.php b/tests/mock/session_testable.php
index 29dd2a5bff..2f24978ba8 100644
--- a/tests/mock/session_testable.php
+++ b/tests/mock/session_testable.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
/**
* Extends the session class to overwrite the setting of cookies.
*
diff --git a/tests/mock/sql_insert_buffer.php b/tests/mock/sql_insert_buffer.php
index c751764d45..e57983684d 100644
--- a/tests/mock/sql_insert_buffer.php
+++ b/tests/mock/sql_insert_buffer.php
@@ -15,7 +15,7 @@ class phpbb_mock_sql_insert_buffer extends \phpbb\db\sql_insert_buffer
{
public function flush()
{
- return (sizeof($this->buffer)) ? true : false;
+ return (count($this->buffer)) ? true : false;
}
public function get_buffer()
diff --git a/tests/network/checkdnsrr_test.php b/tests/network/checkdnsrr_test.php
index a3852b2656..8cbd4f7e97 100644
--- a/tests/network/checkdnsrr_test.php
+++ b/tests/network/checkdnsrr_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
/**
* @group slow
*/
@@ -40,7 +38,7 @@ class phpbb_network_checkdnsrr_test extends phpbb_test_case
array('does-not-exist.phpbb.com', 'AAAA', false),
// Existing CNAME record
- array('news.cnet.com', 'CNAME', true),
+ array('area51.phpbb.com', 'CNAME', true),
// Non-existing CNAME record
array('does-not-exist.phpbb.com', 'CNAME', false),
diff --git a/tests/network/ftp_fsock_pasv_epsv_test.php b/tests/network/ftp_fsock_pasv_epsv_test.php
index 6ed9d61dc0..4ec21b6f75 100644
--- a/tests/network/ftp_fsock_pasv_epsv_test.php
+++ b/tests/network/ftp_fsock_pasv_epsv_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_transfer.php';
/**
diff --git a/tests/network/inet_ntop_pton_test.php b/tests/network/inet_ntop_pton_test.php
index fae40ad74e..dbd58ce783 100644
--- a/tests/network/inet_ntop_pton_test.php
+++ b/tests/network/inet_ntop_pton_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_network_inet_ntop_pton_test extends phpbb_test_case
{
public function data_provider()
diff --git a/tests/network/ip_normalise_test.php b/tests/network/ip_normalise_test.php
index 1acfd4521d..52e594e115 100644
--- a/tests/network/ip_normalise_test.php
+++ b/tests/network/ip_normalise_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_network_ip_normalise_test extends phpbb_test_case
{
public function data_provider()
diff --git a/tests/notification/base.php b/tests/notification/base.php
index 162feae557..80b9a0d777 100644
--- a/tests/notification/base.php
+++ b/tests/notification/base.php
@@ -11,6 +11,10 @@
*
*/
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
+
require_once dirname(__FILE__) . '/manager_helper.php';
abstract class phpbb_tests_notification_base extends phpbb_database_test_case
@@ -39,6 +43,13 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
);
}
+ protected function get_notification_methods()
+ {
+ return array(
+ 'notification.method.board',
+ );
+ }
+
protected function setUp()
{
parent::setUp();
@@ -55,55 +66,83 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
'allow_bookmarks' => true,
'allow_topic_notify' => true,
'allow_forum_notify' => true,
+ 'allow_board_notifications' => true,
));
- $user = $this->user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $this->user = $user;
$this->user_loader = new \phpbb\user_loader($this->db, $phpbb_root_path, $phpEx, 'phpbb_users');
$auth = $this->auth = new phpbb_mock_notifications_auth();
+ $cache_driver = new \phpbb\cache\driver\dummy();
$cache = $this->cache = new \phpbb\cache\service(
- new \phpbb\cache\driver\null(),
+ $cache_driver,
$this->config,
$this->db,
$phpbb_root_path,
$phpEx
);
-
+
$this->phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $phpbb_container = $this->container = new phpbb_mock_container_builder();
+ $phpbb_container = $this->container = new ContainerBuilder();
+ $loader = new YamlFileLoader($phpbb_container, new FileLocator(__DIR__ . '/fixtures'));
+ $loader->load('services_notification.yml');
+ $phpbb_container->set('user_loader', $this->user_loader);
+ $phpbb_container->set('user', $user);
+ $phpbb_container->set('language', $lang);
+ $phpbb_container->set('config', $this->config);
+ $phpbb_container->set('dbal.conn', $this->db);
+ $phpbb_container->set('auth', $auth);
+ $phpbb_container->set('cache.driver', $cache_driver);
+ $phpbb_container->set('cache', $cache);
+ $phpbb_container->set('text_formatter.utils', new \phpbb\textformatter\s9e\utils());
+ $phpbb_container->set('dispatcher', $this->phpbb_dispatcher);
+ $phpbb_container->setParameter('core.root_path', $phpbb_root_path);
+ $phpbb_container->setParameter('core.php_ext', $phpEx);
+ $phpbb_container->setParameter('tables.notifications', 'phpbb_notifications');
+ $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications');
+ $phpbb_container->setParameter('tables.notification_types', 'phpbb_notification_types');
$this->notifications = new phpbb_notification_manager_helper(
array(),
array(),
$this->container,
$this->user_loader,
- $this->config,
$this->phpbb_dispatcher,
$this->db,
$this->cache,
+ $lang,
$this->user,
- $phpbb_root_path,
- $phpEx,
'phpbb_notification_types',
- 'phpbb_notifications',
'phpbb_user_notifications'
);
$phpbb_container->set('notification_manager', $this->notifications);
+ $phpbb_container->compile();
$this->notifications->setDependencies($this->auth, $this->config);
$types = array();
foreach ($this->get_notification_types() as $type)
{
- $type_parts = explode('.', $type);
- $class = $this->build_type('phpbb\notification\type\\' . array_pop($type_parts));
+ $class = $this->build_type($type);
$types[$type] = $class;
- $this->container->set($type, $class);
}
$this->notifications->set_var('notification_types', $types);
+ $methods = array();
+ foreach ($this->get_notification_methods() as $method)
+ {
+ $class = $this->container->get($method);
+
+ $methods[$method] = $class;
+ }
+
+ $this->notifications->set_var('notification_methods', $methods);
+
$this->db->sql_query('DELETE FROM phpbb_notification_types');
$this->db->sql_query('DELETE FROM phpbb_notifications');
$this->db->sql_query('DELETE FROM phpbb_user_notifications');
@@ -111,20 +150,20 @@ abstract class phpbb_tests_notification_base extends phpbb_database_test_case
protected function build_type($type)
{
- global $phpbb_root_path, $phpEx;
+ $instance = $this->container->get($type);
- return new $type($this->user_loader, $this->db, $this->cache->get_driver(), $this->user, $this->auth, $this->config, $phpbb_root_path, $phpEx, 'phpbb_notification_types', 'phpbb_notifications', 'phpbb_user_notifications');
+ return $instance;
}
protected function assert_notifications($expected, $options = array())
{
- $notifications = $this->notifications->load_notifications(array_merge(array(
+ $notifications = $this->notifications->load_notifications('notification.method.board', array_merge(array(
'count_unread' => true,
'order_by' => 'notification_time',
'order_dir' => 'ASC',
), $options));
- $this->assertEquals(sizeof($expected), $notifications['unread_count']);
+ $this->assertEquals(count($expected), $notifications['unread_count']);
$i = 0;
foreach ($notifications['notifications'] as $notification)
diff --git a/tests/notification/convert_test.php b/tests/notification/convert_test.php
index 32ab34c9bc..4a7fd89409 100644
--- a/tests/notification/convert_test.php
+++ b/tests/notification/convert_test.php
@@ -28,11 +28,12 @@ class phpbb_notification_convert_test extends phpbb_database_test_case
global $phpbb_root_path, $phpEx;
$this->db = $this->new_dbal();
+ $factory = new \phpbb\db\tools\factory();
$this->migration = new \phpbb\db\migration\data\v310\notification_options_reconvert(
new \phpbb\config\config(array()),
$this->db,
- new \phpbb\db\tools($this->db),
+ $factory->get($this->db),
$phpbb_root_path,
$phpEx,
'phpbb_'
diff --git a/tests/notification/ext/test/notification/type/test.php b/tests/notification/ext/test/notification/type/test.php
index b02a563f06..7f3b4a4ef1 100644
--- a/tests/notification/ext/test/notification/type/test.php
+++ b/tests/notification/ext/test/notification/type/test.php
@@ -47,12 +47,13 @@ class test extends \phpbb\notification\type\base
{
$this->notification_time = $post['post_time'];
- return parent::create_insert_array($post, $pre_create_data);
+ parent::create_insert_array($post, $pre_create_data);
}
public function create_update_array($type_data)
{
- $data = $this->create_insert_array($type_data);
+ $this->create_insert_array($type_data);
+ $data = $this->get_insert_array();
// Unset data unique to each row
unset(
diff --git a/tests/notification/fixtures/services_notification.yml b/tests/notification/fixtures/services_notification.yml
new file mode 100644
index 0000000000..6e68cccff6
--- /dev/null
+++ b/tests/notification/fixtures/services_notification.yml
@@ -0,0 +1,76 @@
+imports:
+ - { resource: ../../../phpBB/config/default/container/services_notification.yml }
+
+services:
+ notification_manager:
+ synthetic: true
+
+ user_loader:
+ synthetic: true
+
+ user:
+ synthetic: true
+
+ config:
+ synthetic: true
+
+ dbal.conn:
+ synthetic: true
+
+ language:
+ synthetic: true
+
+ auth:
+ synthetic: true
+
+ cache.driver:
+ synthetic: true
+
+ group_helper:
+ synthetic: true
+
+ path_helper:
+ synthetic: true
+
+ groupposition.legend:
+ synthetic: true
+
+ groupposition.teampage:
+ synthetic: true
+
+ groupposition.teampage:
+ synthetic: true
+
+ text_formatter.s9e.factory:
+ synthetic: true
+
+ text_formatter.s9e.quote_helper:
+ synthetic: true
+
+ text_formatter.parser:
+ synthetic: true
+
+ text_formatter.s9e.parser:
+ synthetic: true
+
+ text_formatter.renderer:
+ synthetic: true
+
+ text_formatter.s9e.renderer:
+ synthetic: true
+
+ text_formatter.utils:
+ synthetic: true
+
+ text_formatter.s9e.utils:
+ synthetic: true
+
+ text_formatter.data_access:
+ synthetic: true
+
+ test:
+ class: phpbb\notification\type\test
+ scope: prototype
+ parent: notification.type.base
+ tags:
+ - { name: notification.type }
diff --git a/tests/notification/fixtures/submit_post_notification.type.bookmark.xml b/tests/notification/fixtures/submit_post_notification.type.bookmark.xml
index a1413e2cf8..db1cef2ef6 100644
--- a/tests/notification/fixtures/submit_post_notification.type.bookmark.xml
+++ b/tests/notification/fixtures/submit_post_notification.type.bookmark.xml
@@ -29,6 +29,7 @@
</row>
</table>
<table name="phpbb_notifications">
+ <column>notification_id</column>
<column>notification_type_id</column>
<column>user_id</column>
<column>item_id</column>
@@ -37,6 +38,7 @@
<column>notification_data</column>
<row>
<value>1</value>
+ <value>1</value>
<value>5</value>
<value>1</value>
<value>1</value>
@@ -126,35 +128,35 @@
<value>notification.type.bookmark</value>
<value>0</value>
<value>2</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.bookmark</value>
<value>0</value>
<value>3</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.bookmark</value>
<value>0</value>
<value>4</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.bookmark</value>
<value>0</value>
<value>5</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.bookmark</value>
<value>0</value>
<value>6</value>
- <value></value>
+ <value>notification.method.board</value>
<value>0</value>
</row>
</table>
diff --git a/tests/notification/fixtures/submit_post_notification.type.post.xml b/tests/notification/fixtures/submit_post_notification.type.post.xml
index ed75787c70..920b271525 100644
--- a/tests/notification/fixtures/submit_post_notification.type.post.xml
+++ b/tests/notification/fixtures/submit_post_notification.type.post.xml
@@ -21,6 +21,7 @@
</row>
</table>
<table name="phpbb_notifications">
+ <column>notification_id</column>
<column>notification_type_id</column>
<column>user_id</column>
<column>item_id</column>
@@ -29,6 +30,7 @@
<column>notification_data</column>
<row>
<value>1</value>
+ <value>1</value>
<value>5</value>
<value>1</value>
<value>1</value>
@@ -36,6 +38,7 @@
<value></value>
</row>
<row>
+ <value>2</value>
<value>1</value>
<value>8</value>
<value>1</value>
@@ -156,49 +159,49 @@
<value>notification.type.post</value>
<value>0</value>
<value>2</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.post</value>
<value>0</value>
<value>3</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.post</value>
<value>0</value>
<value>4</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.post</value>
<value>0</value>
<value>5</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.post</value>
<value>0</value>
<value>6</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.post</value>
<value>0</value>
<value>7</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.post</value>
<value>0</value>
<value>8</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
</table>
diff --git a/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml b/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml
index 2dea8e34dd..12e73b0ff2 100644
--- a/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml
+++ b/tests/notification/fixtures/submit_post_notification.type.post_in_queue.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_notifications">
+ <column>notification_id</column>
<column>notification_type_id</column>
<column>user_id</column>
<column>item_id</column>
@@ -9,6 +10,7 @@
<column>notification_data</column>
<row>
<value>1</value>
+ <value>1</value>
<value>6</value>
<value>1</value>
<value>1</value>
@@ -110,49 +112,49 @@
<value>notification.type.needs_approval</value>
<value>0</value>
<value>2</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.needs_approval</value>
<value>0</value>
<value>3</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.needs_approval</value>
<value>0</value>
<value>4</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.needs_approval</value>
<value>0</value>
<value>5</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.needs_approval</value>
<value>0</value>
<value>6</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.needs_approval</value>
<value>0</value>
<value>7</value>
- <value></value>
+ <value>notification.method.board</value>
<value>0</value>
</row>
<row>
<value>notification.type.needs_approval</value>
<value>0</value>
<value>9</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
</table>
diff --git a/tests/notification/fixtures/submit_post_notification.type.quote.xml b/tests/notification/fixtures/submit_post_notification.type.quote.xml
index dd5bc620cd..9f4ba91475 100644
--- a/tests/notification/fixtures/submit_post_notification.type.quote.xml
+++ b/tests/notification/fixtures/submit_post_notification.type.quote.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_notifications">
+ <column>notification_id</column>
<column>notification_type_id</column>
<column>user_id</column>
<column>item_id</column>
@@ -9,6 +10,7 @@
<column>notification_data</column>
<row>
<value>1</value>
+ <value>1</value>
<value>5</value>
<value>1</value>
<value>1</value>
@@ -98,35 +100,35 @@
<value>notification.type.quote</value>
<value>0</value>
<value>2</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.quote</value>
<value>0</value>
<value>3</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.quote</value>
<value>0</value>
<value>4</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.quote</value>
<value>0</value>
<value>5</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.quote</value>
<value>0</value>
<value>6</value>
- <value></value>
+ <value>notification.method.board</value>
<value>0</value>
</row>
</table>
diff --git a/tests/notification/fixtures/submit_post_notification.type.topic.xml b/tests/notification/fixtures/submit_post_notification.type.topic.xml
index 1ba8d05699..1f96ed2ee7 100644
--- a/tests/notification/fixtures/submit_post_notification.type.topic.xml
+++ b/tests/notification/fixtures/submit_post_notification.type.topic.xml
@@ -21,6 +21,7 @@
</row>
</table>
<table name="phpbb_notifications">
+ <column>notification_id</column>
<column>notification_type_id</column>
<column>user_id</column>
<column>item_id</column>
@@ -29,6 +30,7 @@
<column>notification_data</column>
<row>
<value>1</value>
+ <value>1</value>
<value>8</value>
<value>1</value>
<value>1</value>
@@ -106,28 +108,28 @@
<value>notification.type.topic</value>
<value>0</value>
<value>2</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.topic</value>
<value>0</value>
<value>6</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.topic</value>
<value>0</value>
<value>7</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
<row>
<value>notification.type.topic</value>
<value>0</value>
<value>8</value>
- <value></value>
+ <value>notification.method.board</value>
<value>1</value>
</row>
</table>
diff --git a/tests/notification/group_request_test.php b/tests/notification/group_request_test.php
index 0d1bda95ce..e849c66fa5 100644
--- a/tests/notification/group_request_test.php
+++ b/tests/notification/group_request_test.php
@@ -12,7 +12,6 @@
*/
require_once dirname(__FILE__) . '/base.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_notification_group_request_test extends phpbb_tests_notification_base
{
@@ -40,8 +39,6 @@ class phpbb_notification_group_request_test extends phpbb_tests_notification_bas
include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx);
include_once($phpbb_root_path . 'includes/functions_content.' . $phpEx);
- set_config(false, false, false, $this->config);
-
$this->container->set('groupposition.legend', new \phpbb\groupposition\legend(
$this->db,
$this->user
@@ -51,8 +48,28 @@ class phpbb_notification_group_request_test extends phpbb_tests_notification_bas
$this->user,
$this->cache->get_driver()
));
+ $this->container->set('group_helper', new \phpbb\group\helper(
+ $this->getMock('\phpbb\auth\auth'),
+ $this->cache,
+ $this->config,
+ new \phpbb\language\language(
+ new phpbb\language\language_file_loader($phpbb_root_path, $phpEx)
+ ),
+ new phpbb_mock_event_dispatcher(),
+ new \phpbb\path_helper(
+ new \phpbb\symfony_request(
+ new phpbb_mock_request()
+ ),
+ new \phpbb\filesystem\filesystem(),
+ $this->getMock('\phpbb\request\request'),
+ $phpbb_root_path,
+ $phpEx
+ ),
+ $this->user
+ ));
$phpbb_dispatcher = new phpbb_mock_event_dispatcher;
- $phpbb_log = new \phpbb\log\null();
+ $phpbb_log = new \phpbb\log\dummy();
+ $this->get_test_case_helpers()->set_s9e_services();
// Now on to the actual test
diff --git a/tests/notification/manager_helper.php b/tests/notification/manager_helper.php
index 75b7275d3a..2e8699e1e0 100644
--- a/tests/notification/manager_helper.php
+++ b/tests/notification/manager_helper.php
@@ -37,35 +37,4 @@ class phpbb_notification_manager_helper extends \phpbb\notification\manager
$this->auth = $auth;
$this->config = $config;
}
-
- /**
- * Helper to get the notifications item type class and set it up
- */
- public function get_item_type_class($item_type, $data = array())
- {
- $item_parts = explode('.', $item_type);
- $item_type = 'phpbb\notification\type\\' . array_pop($item_parts);
-
- $item = new $item_type($this->user_loader, $this->db, $this->cache->get_driver(), $this->user, $this->auth, $this->config, $this->phpbb_root_path, $this->php_ext, $this->notification_types_table, $this->notifications_table, $this->user_notifications_table);
-
- $item->set_notification_manager($this);
-
- $item->set_initial_data($data);
-
- return $item;
- }
-
- /**
- * Helper to get the notifications method class and set it up
- */
- public function get_method_class($method_name)
- {
- $method_name = 'phpbb\notification\method\\' . $method_name;
-
- $method = new $method_name($this->user_loader, $this->db, $this->cache->get_driver(), $this->user, $this->auth, $this->config, $this->phpbb_root_path, $this->php_ext, $this->notification_types_table, $this->notifications_table, $this->user_notifications_table);
-
- $method->set_notification_manager($this);
-
- return $method;
- }
}
diff --git a/tests/notification/notification_test.php b/tests/notification/notification_test.php
index 79fa5338c4..6bbabfc602 100644
--- a/tests/notification/notification_test.php
+++ b/tests/notification/notification_test.php
@@ -29,7 +29,7 @@ class phpbb_notification_test extends phpbb_tests_notification_base
$quote_type_id = $this->notifications->get_notification_type_id('notification.type.quote');
$test_type_id = $this->notifications->get_notification_type_id('test');
- $this->assertEquals(array(
+ self::assertEquals(array(
'test' => $test_type_id,
'notification.type.quote' => $quote_type_id,
'notification.type.post' => $post_type_id,
@@ -40,13 +40,13 @@ class phpbb_notification_test extends phpbb_tests_notification_base
'notification.type.post',
)
));
- $this->assertEquals($quote_type_id, $this->notifications->get_notification_type_id('notification.type.quote'));
+ self::assertEquals($quote_type_id, $this->notifications->get_notification_type_id('notification.type.quote'));
try
{
- $this->assertEquals(false, $this->notifications->get_notification_type_id('fail'));
+ self::assertEquals(false, $this->notifications->get_notification_type_id('fail'));
- $this->fail('Non-existent type should throw an exception');
+ self::fail('Non-existent type should throw an exception');
}
catch (Exception $e) {}
}
@@ -55,15 +55,15 @@ class phpbb_notification_test extends phpbb_tests_notification_base
{
$subscription_types = $this->notifications->get_subscription_types();
- $this->assertArrayHasKey('NOTIFICATION_GROUP_MISCELLANEOUS', $subscription_types);
- $this->assertArrayHasKey('NOTIFICATION_GROUP_POSTING', $subscription_types);
+ self::assertArrayHasKey('NOTIFICATION_GROUP_MISCELLANEOUS', $subscription_types);
+ self::assertArrayHasKey('NOTIFICATION_GROUP_POSTING', $subscription_types);
- $this->assertArrayHasKey('notification.type.bookmark', $subscription_types['NOTIFICATION_GROUP_POSTING']);
- $this->assertArrayHasKey('notification.type.post', $subscription_types['NOTIFICATION_GROUP_POSTING']);
- $this->assertArrayHasKey('notification.type.quote', $subscription_types['NOTIFICATION_GROUP_POSTING']);
- $this->assertArrayHasKey('notification.type.topic', $subscription_types['NOTIFICATION_GROUP_POSTING']);
+ self::assertArrayHasKey('notification.type.bookmark', $subscription_types['NOTIFICATION_GROUP_POSTING']);
+ self::assertArrayHasKey('notification.type.post', $subscription_types['NOTIFICATION_GROUP_POSTING']);
+ self::assertArrayHasKey('notification.type.quote', $subscription_types['NOTIFICATION_GROUP_POSTING']);
+ self::assertArrayHasKey('notification.type.topic', $subscription_types['NOTIFICATION_GROUP_POSTING']);
- $this->assertArrayHasKey('notification.type.pm', $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']);
+ self::assertArrayHasKey('notification.type.pm', $subscription_types['NOTIFICATION_GROUP_MISCELLANEOUS']);
//get_subscription_types
//get_subscription_methods
@@ -72,33 +72,33 @@ class phpbb_notification_test extends phpbb_tests_notification_base
public function test_subscriptions()
{
$expected_subscriptions = array(
- 'notification.type.post' => array(''),
- 'notification.type.topic' => array(''),
- 'notification.type.quote' => array(''),
- 'notification.type.bookmark' => array(''),
- 'test' => array(''),
- 'notification.type.pm' => array(''),
+ 'notification.type.post' => array('notification.method.board'),
+ 'notification.type.topic' => array('notification.method.board'),
+ 'notification.type.quote' => array('notification.method.board'),
+ 'notification.type.bookmark' => array('notification.method.board'),
+ 'test' => array('notification.method.board'),
+ 'notification.type.pm' => array('notification.method.board'),
);
$subscriptions = $this->notifications->get_global_subscriptions(2);
-
foreach ($expected_subscriptions as $item_type => $methods)
{
+ self::assertArrayHasKey($item_type, $subscriptions);
$this->assert_array_content_equals($methods, $subscriptions[$item_type]);
}
foreach ($subscriptions as $item_type => $methods)
{
- $this->assert_array_content_equals($methods, $expected_subscriptions[$item_type]);
+ $this->assert_array_content_equals($methods, $expected_subscriptions[$item_type]);
}
- $this->notifications->delete_subscription('notification.type.post', 0, '', 2);
+ $this->notifications->delete_subscription('notification.type.post', 0, 'notification.method.board', 2);
- $this->assertArrayNotHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2));
+ self::assertArrayNotHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2));
- $this->notifications->add_subscription('notification.type.post', 0, '', 2);
+ $this->notifications->add_subscription('notification.type.post', 0, 'notification.method.board', 2);
- $this->assertArrayHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2));
+ self::assertArrayHasKey('notification.type.post', $this->notifications->get_global_subscriptions(2));
}
public function test_notifications()
@@ -108,7 +108,7 @@ class phpbb_notification_test extends phpbb_tests_notification_base
$types = array('notification.type.quote', 'notification.type.bookmark', 'notification.type.post', 'test');
foreach ($types as $id => $type)
{
- $this->db->sql_query('INSERT INTO phpbb_notification_types ' .
+ $this->getConnection()->createQueryTable('insertNotification', 'INSERT INTO phpbb_notification_types ' .
$this->db->sql_build_array('INSERT', array(
'notification_type_id' => ($id + 1),
'notification_type_name' => $type,
@@ -124,11 +124,11 @@ class phpbb_notification_test extends phpbb_tests_notification_base
'user_id' => 0,
)));
- $this->assertEquals(array(
+ self::assertEquals(array(
'notifications' => array(),
'unread_count' => 0,
'total_count' => 0,
- ), $this->notifications->load_notifications(array(
+ ), $this->notifications->load_notifications('notification.method.board', array(
'count_unread' => true,
)));
diff --git a/tests/notification/submit_post_base.php b/tests/notification/submit_post_base.php
index 5e770f71c9..21559c42a5 100644
--- a/tests/notification/submit_post_base.php
+++ b/tests/notification/submit_post_base.php
@@ -11,10 +11,11 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
+
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_posting.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
abstract class phpbb_notification_submit_post_base extends phpbb_database_test_case
{
@@ -50,7 +51,7 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
{
parent::setUp();
- global $auth, $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $user, $request, $phpEx, $phpbb_root_path;
+ global $auth, $cache, $config, $db, $phpbb_container, $phpbb_dispatcher, $lang, $user, $request, $phpEx, $phpbb_root_path, $user_loader;
// Database
$this->db = $this->new_dbal();
@@ -69,12 +70,15 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
)));
// Config
- $config = new \phpbb\config\config(array('num_topics' => 1,'num_posts' => 1,));
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
+ $config = new \phpbb\config\config(array(
+ 'num_topics' => 1,
+ 'num_posts' => 1,
+ 'allow_board_notifications' => true,
+ ));
+ $cache_driver = new \phpbb\cache\driver\dummy();
$cache = new \phpbb\cache\service(
- new \phpbb\cache\driver\null(),
+ $cache_driver,
$config,
$db,
$phpbb_root_path,
@@ -84,8 +88,14 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
// Event dispatcher
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
+ // Language
+ $lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+
// User
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $user = $this->getMock('\phpbb\user', array(), array(
+ $lang,
+ '\phpbb\datetime'
+ ));
$user->ip = '';
$user->data = array(
'user_id' => 2,
@@ -98,34 +108,47 @@ abstract class phpbb_notification_submit_post_base extends phpbb_database_test_c
$type_cast_helper = $this->getMock('\phpbb\request\type_cast_helper_interface');
$request = $this->getMock('\phpbb\request\request');
- // Container
- $phpbb_container = new phpbb_mock_container_builder();
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE));
-
$user_loader = new \phpbb\user_loader($db, $phpbb_root_path, $phpEx, USERS_TABLE);
+ // Container
+ $phpbb_container = new ContainerBuilder();
+ $loader = new YamlFileLoader($phpbb_container, new FileLocator(__DIR__ . '/fixtures'));
+ $loader->load('services_notification.yml');
+ $phpbb_container->set('user_loader', $user_loader);
+ $phpbb_container->set('user', $user);
+ $phpbb_container->set('language', $lang);
+ $phpbb_container->set('config', $config);
+ $phpbb_container->set('dbal.conn', $db);
+ $phpbb_container->set('auth', $auth);
+ $phpbb_container->set('cache.driver', $cache_driver);
+ $phpbb_container->set('cache', $cache);
+ $phpbb_container->set('text_formatter.utils', new \phpbb\textformatter\s9e\utils());
+ $phpbb_container->set('dispatcher', $phpbb_dispatcher);
+ $phpbb_container->setParameter('core.root_path', $phpbb_root_path);
+ $phpbb_container->setParameter('core.php_ext', $phpEx);
+ $phpbb_container->setParameter('tables.notifications', 'phpbb_notifications');
+ $phpbb_container->setParameter('tables.user_notifications', 'phpbb_user_notifications');
+ $phpbb_container->setParameter('tables.notification_types', 'phpbb_notification_types');
+ $phpbb_container->set('content.visibility', new \phpbb\content_visibility($auth, $config, $phpbb_dispatcher, $db, $user, $phpbb_root_path, $phpEx, FORUMS_TABLE, POSTS_TABLE, TOPICS_TABLE, USERS_TABLE));
+ $phpbb_container->compile();
+
// Notification Types
$notification_types = array('quote', 'bookmark', 'post', 'post_in_queue', 'topic', 'topic_in_queue', 'approve_topic', 'approve_post');
$notification_types_array = array();
foreach ($notification_types as $type)
{
- $class_name = '\phpbb\notification\type\\' . $type;
- $class = new $class_name(
- $user_loader, $db, $cache->get_driver(), $user, $auth, $config,
- $phpbb_root_path, $phpEx,
- NOTIFICATION_TYPES_TABLE, NOTIFICATIONS_TABLE, USER_NOTIFICATIONS_TABLE);
-
- $phpbb_container->set('notification.type.' . $type, $class);
-
+ $class = $phpbb_container->get('notification.type.' . $type);
$notification_types_array['notification.type.' . $type] = $class;
}
+ // Methods Types
+ $notification_methods_array = array('notification.method.board' => $phpbb_container->get('notification.method.board'));
+
// Notification Manager
- $phpbb_notifications = new \phpbb\notification\manager($notification_types_array, array(),
- $phpbb_container, $user_loader, $config, $phpbb_dispatcher, $db, $cache, $user,
- $phpbb_root_path, $phpEx,
- NOTIFICATION_TYPES_TABLE, NOTIFICATIONS_TABLE, USER_NOTIFICATIONS_TABLE);
+ $phpbb_notifications = new \phpbb\notification\manager($notification_types_array, $notification_methods_array,
+ $phpbb_container, $user_loader, $phpbb_dispatcher, $db, $cache, $lang, $user,
+ NOTIFICATION_TYPES_TABLE, USER_NOTIFICATIONS_TABLE);
$phpbb_container->set('notification_manager', $phpbb_notifications);
}
diff --git a/tests/notification/submit_post_type_quote_test.php b/tests/notification/submit_post_type_quote_test.php
index 61e3840773..3fab8c05ba 100644
--- a/tests/notification/submit_post_type_quote_test.php
+++ b/tests/notification/submit_post_type_quote_test.php
@@ -51,6 +51,9 @@ class phpbb_notification_submit_post_type_quote_test extends phpbb_notification_
*/
public function submit_post_data()
{
+ // The new mock container is needed because the data providers may be executed before phpunit call setUp()
+ $parser = $this->get_test_case_helpers()->set_s9e_services(new phpbb_mock_container_builder())->get('text_formatter.parser');
+
return array(
/**
* Normal post
@@ -65,15 +68,15 @@ class phpbb_notification_submit_post_type_quote_test extends phpbb_notification_
*/
array(
array(
- 'message' => implode(' ', array(
- '[quote=&quot;poster&quot;:uid]poster should not be notified[/quote:uid]',
- '[quote=&quot;test&quot;:uid]test should be notified[/quote:uid]',
- '[quote=&quot;unauthorized&quot;:uid]unauthorized to read, should not receive a notification[/quote:uid]',
- '[quote=&quot;notified&quot;:uid]already notified, should not receive a new notification[/quote:uid]',
- '[quote=&quot;disabled&quot;:uid]option disabled, should not receive a notification[/quote:uid]',
- '[quote=&quot;default&quot;:uid]option set to default, should receive a notification[/quote:uid]',
- '[quote=&quot;doesn\'t exist&quot;:uid]user does not exist, should not receive a notification[/quote:uid]',
- )),
+ 'message' => $parser->parse(implode(' ', array(
+ '[quote="poster"]poster should not be notified[/quote]',
+ '[quote="test"]test should be notified[/quote]',
+ '[quote="unauthorized"]unauthorized to read, should not receive a notification[/quote]',
+ '[quote="notified"]already notified, should not receive a new notification[/quote]',
+ '[quote="disabled"]option disabled, should not receive a notification[/quote]',
+ '[quote="default"]option set to default, should receive a notification[/quote]',
+ '[quote="doesn\'t exist"]user does not exist, should not receive a notification[/quote]',
+ ))),
'bbcode_uid' => 'uid',
),
array(
@@ -94,15 +97,15 @@ class phpbb_notification_submit_post_type_quote_test extends phpbb_notification_
*/
array(
array(
- 'message' => implode(' ', array(
- '[quote=&quot;poster&quot;:uid]poster should not be notified[/quote:uid]',
- '[quote=&quot;test&quot;:uid]test should be notified[/quote:uid]',
- '[quote=&quot;unauthorized&quot;:uid]unauthorized to read, should not receive a notification[/quote:uid]',
- '[quote=&quot;notified&quot;:uid]already notified, should not receive a new notification[/quote:uid]',
- '[quote=&quot;disabled&quot;:uid]option disabled, should not receive a notification[/quote:uid]',
- '[quote=&quot;default&quot;:uid]option set to default, should receive a notification[/quote:uid]',
- '[quote=&quot;doesn\'t exist&quot;:uid]user does not exist, should not receive a notification[/quote:uid]',
- )),
+ 'message' => $parser->parse(implode(' ', array(
+ '[quote="poster"]poster should not be notified[/quote]',
+ '[quote="test"]test should be notified[/quote]',
+ '[quote="unauthorized"]unauthorized to read, should not receive a notification[/quote]',
+ '[quote="notified"]already notified, should not receive a new notification[/quote]',
+ '[quote="disabled"]option disabled, should not receive a notification[/quote]',
+ '[quote="default"]option set to default, should receive a notification[/quote]',
+ '[quote="doesn\'t exist"]user does not exist, should not receive a notification[/quote]',
+ ))),
'bbcode_uid' => 'uid',
'force_approved_state' => false,
),
diff --git a/tests/notification/submit_post_type_topic_test.php b/tests/notification/submit_post_type_topic_test.php
index c095fbc4ba..f14f305517 100644
--- a/tests/notification/submit_post_type_topic_test.php
+++ b/tests/notification/submit_post_type_topic_test.php
@@ -42,7 +42,7 @@ class phpbb_notification_submit_post_type_topic_test extends phpbb_notification_
),
)));
- $phpbb_log = $this->getMock('\phpbb\log\null');
+ $phpbb_log = $this->getMock('\phpbb\log\dummy');
}
/**
diff --git a/tests/notification/user_list_trim_test.php b/tests/notification/user_list_trim_test.php
index c43eff729c..7d4dff6024 100644
--- a/tests/notification/user_list_trim_test.php
+++ b/tests/notification/user_list_trim_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
{
protected $notification;
@@ -33,11 +30,9 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
$db = $this->new_dbal();
$config = new \phpbb\config\config(array());
- set_config(null, null, null, $config);
- set_config_count(null, null, null, $config);
$cache = new \phpbb\cache\service(
- new \phpbb\cache\driver\null(),
+ new \phpbb\cache\driver\dummy(),
$config,
$db,
$phpbb_root_path,
@@ -53,15 +48,17 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
array('u_viewprofile', 1, false),
)));
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->data = array('user_lang' => 'en');
- $user->add_lang('common');
+ $lang->add_lang('common');
$user_loader = new phpbb\user_loader($db, $phpbb_root_path, $phpEx, USERS_TABLE);
$user_loader->load_users(array(2, 3, 4, 5, 6));
$this->notification = new phpbb_mock_notification_type_post(
- $user_loader, null, null, $user, null, null, $phpbb_root_path, $phpEx, null, null, null
+ $user_loader, null, null, $lang, $user, null, null, $phpbb_root_path, $phpEx, null, null
);
}
@@ -73,7 +70,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
'topic_title' => 'Test',
'poster_id' => 2,
'post_username' => 'A',
- 'responders' => null,
+ 'responders' => null,
),
'<strong>Reply</strong> from A in topic:',
),
@@ -84,7 +81,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
'post_username' => 'A',
'responders' => array(
array('username' => '', 'poster_id' => 3),
- ),
+ ),
),
'<strong>Reply</strong> from A and <span class="username">B</span> in topic:',
),
@@ -96,7 +93,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
'responders' => array(
array('username' => '', 'poster_id' => 3),
array('username' => '', 'poster_id' => 4),
- ),
+ ),
),
'<strong>Reply</strong> from A, <span class="username">B</span>, and <span class="username">C</span> in topic:',
),
@@ -109,7 +106,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
array('username' => '', 'poster_id' => 3),
array('username' => '', 'poster_id' => 4),
array('username' => '', 'poster_id' => 5),
- ),
+ ),
),
'<strong>Reply</strong> from A, <span class="username">B</span>, <span class="username">C</span>, and <span class="username">D</span> in topic:',
),
@@ -123,7 +120,7 @@ class phpbb_notification_user_list_trim_test extends phpbb_database_test_case
array('username' => '', 'poster_id' => 4),
array('username' => '', 'poster_id' => 5),
array('username' => '', 'poster_id' => 6),
- ),
+ ),
),
'<strong>Reply</strong> from A, <span class="username">B</span>, <span class="username">C</span>, and 2 others in topic:',
),
diff --git a/tests/pagination/config/routing.yml b/tests/pagination/config/test/routing/environment.yml
index 2ce082c9d1..2ce082c9d1 100644
--- a/tests/pagination/config/routing.yml
+++ b/tests/pagination/config/test/routing/environment.yml
diff --git a/tests/pagination/pagination_test.php b/tests/pagination/pagination_test.php
index ea6dd999c3..2d7d1671a8 100644
--- a/tests/pagination/pagination_test.php
+++ b/tests/pagination/pagination_test.php
@@ -26,27 +26,28 @@ class phpbb_pagination_pagination_test extends phpbb_template_template_test_case
{
parent::setUp();
- global $phpbb_dispatcher;
+ global $phpbb_dispatcher, $phpbb_root_path, $phpEx;
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $this->user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$this->user->expects($this->any())
->method('lang')
->will($this->returnCallback(array($this, 'return_callback_implode')));
- $filesystem = new \phpbb\filesystem();
+ $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1'));
+
+ $filesystem = new \phpbb\filesystem\filesystem();
$manager = new phpbb_mock_extension_manager(dirname(__FILE__) . '/', array());
- $finder = new \phpbb\finder(
- $filesystem,
- dirname(__FILE__) . '/',
- new phpbb_mock_cache()
- );
- $finder->set_extensions(array_keys($manager->all_enabled()));
- $this->config = new \phpbb\config\config(array('enable_mod_rewrite' => '1'));
- $provider = new \phpbb\controller\provider();
- $provider->find_routing_files($finder);
- $provider->find(dirname(__FILE__) . '/');
+
+ $loader = new \Symfony\Component\Routing\Loader\YamlFileLoader(
+ new \phpbb\routing\file_locator($filesystem, dirname(__FILE__) . '/')
+ );
+ $resources_locator = new \phpbb\routing\resources_locator\default_resources_locator(dirname(__FILE__) . '/', PHPBB_ENVIRONMENT, $manager);
+ $router = new phpbb_mock_router(new phpbb_mock_container_builder(), $resources_locator, $loader, dirname(__FILE__) . '/', 'php');
$request = new phpbb_mock_request();
$request->overwrite('SCRIPT_NAME', '/app.php', \phpbb\request\request_interface::SERVER);
@@ -57,7 +58,8 @@ class phpbb_pagination_pagination_test extends phpbb_template_template_test_case
$request
);
- $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $provider, $manager, $symfony_request, $request, $filesystem, '', 'php', dirname(__FILE__) . '/');
+ $this->routing_helper = new \phpbb\routing\helper($this->config, $router, $symfony_request, $request, $filesystem, '', 'php');
+ $this->helper = new phpbb_mock_controller_helper($this->template, $this->user, $this->config, $symfony_request, $request, $this->routing_helper);
$this->pagination = new \phpbb\pagination($this->template, $this->user, $this->helper, $phpbb_dispatcher);
}
@@ -217,6 +219,12 @@ class phpbb_pagination_pagination_test extends phpbb_template_template_test_case
0,
'PAGE_OF-1-1',
),
+ array(
+ '10',
+ '10',
+ '0',
+ 'PAGE_OF-1-1',
+ ),
);
}
diff --git a/tests/passwords/drivers_test.php b/tests/passwords/drivers_test.php
index 5f9fd523c9..01c69a38bb 100644
--- a/tests/passwords/drivers_test.php
+++ b/tests/passwords/drivers_test.php
@@ -23,8 +23,8 @@ class phpbb_passwords_helper_test extends \phpbb_test_case
$php_ext = 'php';
$this->passwords_drivers = array(
- 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $this->driver_helper),
- 'passwords.driver.bcrypt' => new \phpbb\passwords\driver\bcrypt($config, $this->driver_helper),
+ 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $this->driver_helper, 10),
+ 'passwords.driver.bcrypt' => new \phpbb\passwords\driver\bcrypt($config, $this->driver_helper, 10),
'passwords.driver.salted_md5' => new \phpbb\passwords\driver\salted_md5($config, $this->driver_helper),
'passwords.driver.phpass' => new \phpbb\passwords\driver\phpass($config, $this->driver_helper),
'passwords.driver.sha1_smf' => new \phpbb\passwords\driver\sha1_smf($config, $this->driver_helper),
@@ -413,4 +413,23 @@ class phpbb_passwords_helper_test extends \phpbb_test_case
);
return strtr($string, $transform);
}
+
+ public function data_needs_rehash()
+ {
+ return array(
+ array('passwords.driver.bcrypt_2y', '$2y$10$somerandomhash', false),
+ array('passwords.driver.bcrypt', '$2a$10$somerandomhash', false),
+ array('passwords.driver.salted_md5', 'foobar', false),
+ array('passwords.driver.bcrypt_2y', '$2y$9$somerandomhash', true),
+ array('passwords.driver.bcrypt', '$2a$04$somerandomhash', true),
+ );
+ }
+
+ /**
+ * @dataProvider data_needs_rehash
+ */
+ public function test_needs_rehash($driver, $hash, $expected)
+ {
+ $this->assertSame($this->passwords_drivers[$driver]->needs_rehash($hash), $expected);
+ }
}
diff --git a/tests/passwords/manager_test.php b/tests/passwords/manager_test.php
index 333834ee07..0410d7035f 100644
--- a/tests/passwords/manager_test.php
+++ b/tests/passwords/manager_test.php
@@ -29,8 +29,8 @@ class phpbb_passwords_manager_test extends \phpbb_test_case
$php_ext = 'php';
$this->passwords_drivers = array(
- 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $this->driver_helper),
- 'passwords.driver.bcrypt' => new \phpbb\passwords\driver\bcrypt($config, $this->driver_helper),
+ 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $this->driver_helper, 10),
+ 'passwords.driver.bcrypt' => new \phpbb\passwords\driver\bcrypt($config, $this->driver_helper, 10),
'passwords.driver.salted_md5' => new \phpbb\passwords\driver\salted_md5($config, $this->driver_helper),
'passwords.driver.phpass' => new \phpbb\passwords\driver\phpass($config, $this->driver_helper),
'passwords.driver.convert_password' => new \phpbb\passwords\driver\convert_password($config, $this->driver_helper),
@@ -344,4 +344,54 @@ class phpbb_passwords_manager_test extends \phpbb_test_case
{
$this->assertSame($expected, $this->driver_helper->string_compare($a, $b));
}
+
+ public function data_driver_interface_driver()
+ {
+ return array(
+ array(false, false, false),
+ array(true, false, false),
+ array(true, true, true),
+ );
+ }
+
+ /**
+ * @dataProvider data_driver_interface_driver
+ */
+ public function test_driver_interface_driver($use_new_interface, $needs_rehash, $expected)
+ {
+ if ($use_new_interface)
+ {
+ $test_driver = $this->getMock('\phpbb\passwords\driver\rehashable_driver_interface', array('needs_rehash', 'get_prefix', 'check', 'is_supported', 'is_legacy', 'hash', 'get_settings_only'));
+ $test_driver->method('needs_rehash')
+ ->willReturn($needs_rehash);
+ }
+ else
+ {
+ $test_driver = $this->getMock('\phpbb\passwords\driver\driver_interface', array('get_prefix', 'check', 'is_supported', 'is_legacy', 'hash', 'get_settings_only'));
+ }
+ $config = new \phpbb\config\config(array());
+
+ $test_driver->method('is_supported')
+ ->willReturn(true);
+ $test_driver->method('get_prefix')
+ ->willReturn('$test$');
+ $test_driver->method('check')
+ ->with($this->anything())
+ ->willReturn(true);
+ $passwords_drivers = array(
+ 'passwords.driver.foobar' => $test_driver,
+ 'passwords.driver.bcrypt_2y' => new \phpbb\passwords\driver\bcrypt_2y($config, $this->driver_helper, 10),
+ );
+ // Set up another manager
+ $foobar_manager = new \phpbb\passwords\manager($config, $passwords_drivers, $this->helper, array('passwords.driver.foobar'));
+
+ $this->assertTrue($foobar_manager->check('foobar', '$test$somerandomstuff'));
+ $this->assertEquals($expected, $foobar_manager->convert_flag);
+
+ // Should always return true in case a different driver is default
+ $foobar_manager = new \phpbb\passwords\manager($config, $passwords_drivers, $this->helper, array('passwords.driver.bcrypt_2y', 'passwords.driver.foobar'));
+
+ $this->assertTrue($foobar_manager->check('foobar', '$test$somerandomstuff'));
+ $this->assertTrue($foobar_manager->convert_flag);
+ }
}
diff --git a/tests/path_helper/path_helper_test.php b/tests/path_helper/path_helper_test.php
index 73f0e6bafc..49dd40fbec 100644
--- a/tests/path_helper/path_helper_test.php
+++ b/tests/path_helper/path_helper_test.php
@@ -21,14 +21,14 @@ class phpbb_path_helper_test extends phpbb_test_case
{
parent::setUp();
- $filesystem = new \phpbb\filesystem();
+ $filesystem = new \phpbb\filesystem\filesystem();
$this->set_phpbb_root_path($filesystem);
$this->path_helper = new \phpbb\path_helper(
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ new \phpbb\filesystem\filesystem(),
$this->getMock('\phpbb\request\request'),
$this->phpbb_root_path,
'php'
@@ -56,7 +56,7 @@ class phpbb_path_helper_test extends phpbb_test_case
public function basic_update_web_root_path_data()
{
- $filesystem = new \phpbb\filesystem();
+ $filesystem = new \phpbb\filesystem\filesystem();
$this->set_phpbb_root_path($filesystem);
return array(
@@ -90,7 +90,7 @@ class phpbb_path_helper_test extends phpbb_test_case
public function update_web_root_path_data()
{
- $this->set_phpbb_root_path(new \phpbb\filesystem());
+ $this->set_phpbb_root_path(new \phpbb\filesystem\filesystem());
return array(
array(
@@ -135,6 +135,43 @@ class phpbb_path_helper_test extends phpbb_test_case
'/phpbb3-fork/phpBB/app.php',
'./../',
),
+
+ // No correction if the path is already prepend by the web root path
+ array(
+ './../' . $this->phpbb_root_path . 'test.php',
+ '//',
+ null,
+ null,
+ '',
+ ),
+ array(
+ './../' . $this->phpbb_root_path . 'test.php',
+ '//',
+ 'foo/bar.php',
+ 'bar.php',
+ '',
+ ),
+ array(
+ './../../' . $this->phpbb_root_path . 'test.php',
+ '/foo/template',
+ '/phpbb3-fork/phpBB/app.php/foo/template',
+ '/phpbb3-fork/phpBB/app.php',
+ '',
+ ),
+ array(
+ './../' . $this->phpbb_root_path . 'test.php',
+ '/foo/template',
+ '/phpbb3-fork/phpBB/foo/template',
+ '/phpbb3-fork/phpBB/app.php',
+ '',
+ ),
+ array(
+ './../'.$this->phpbb_root_path . 'test.php',
+ '/',
+ '/phpbb3-fork/phpBB/app.php/',
+ '/phpbb3-fork/phpBB/app.php',
+ '',
+ ),
);
}
@@ -158,7 +195,7 @@ class phpbb_path_helper_test extends phpbb_test_case
$path_helper = new \phpbb\path_helper(
$symfony_request,
- new \phpbb\filesystem(),
+ new \phpbb\filesystem\filesystem(),
$this->getMock('\phpbb\request\request'),
$this->phpbb_root_path,
'php'
diff --git a/tests/plupload/plupload_test.php b/tests/plupload/plupload_test.php
index c3fa2b9bad..eb4657afbc 100644
--- a/tests/plupload/plupload_test.php
+++ b/tests/plupload/plupload_test.php
@@ -34,6 +34,10 @@ class phpbb_plupload_test extends phpbb_test_case
*/
public function test_generate_resize_string($config_width, $config_height, $expected)
{
+ global $phpbb_root_path, $phpEx;
+
+ $lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+
$config = new \phpbb\config\config(array(
'img_max_width' => $config_width,
'img_max_height' => $config_height,
@@ -43,11 +47,84 @@ class phpbb_plupload_test extends phpbb_test_case
'',
$config,
new phpbb_mock_request,
- new \phpbb\user('\phpbb\datetime'),
- new \phpbb\php\ini,
+ new \phpbb\user($lang, '\phpbb\datetime'),
+ new \bantu\IniGetWrapper\IniGetWrapper,
new \phpbb\mimetype\guesser(array(new \phpbb\mimetype\extension_guesser))
);
$this->assertEquals($expected, $plupload->generate_resize_string());
}
+
+ public function data_get_chunk_size()
+ {
+ return [
+ [[
+ 'memory_limit' => -1,
+ 'upload_max_filesize' => 0,
+ 'post_max_size' => 0,
+ ], 0],
+ [[
+ 'memory_limit' => -1,
+ 'upload_max_filesize' => 500,
+ 'post_max_size' => 400,
+ ], 200],
+ [[
+ 'memory_limit' => 100,
+ 'upload_max_filesize' => 0,
+ 'post_max_size' => 300,
+ ], 50],
+ [[
+ 'memory_limit' => 300,
+ 'upload_max_filesize' => 200,
+ 'post_max_size' => 0,
+ ], 100],
+ [[
+ 'memory_limit' => 3000,
+ 'upload_max_filesize' => 800,
+ 'post_max_size' => 900,
+ ], 400],
+ [[
+ 'memory_limit' => 2000,
+ 'upload_max_filesize' => 1000,
+ 'post_max_size' => 600,
+ ], 300],
+ [[
+ 'memory_limit' => 1000,
+ 'upload_max_filesize' => 2000,
+ 'post_max_size' => 3000,
+ ], 500],
+ ];
+ }
+
+ /**
+ * @dataProvider data_get_chunk_size
+ */
+ public function test_get_chunk_size($limits_ary, $expected)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $config = new \phpbb\config\config([]);
+
+ $ini_wrapper = $this->getMockBuilder('\bantu\IniGetWrapper\IniGetWrapper')
+ ->setMethods(['getBytes'])
+ ->getMock();
+ $ini_wrapper->method('getBytes')
+ ->will($this->returnValueMap([
+ ['memory_limit', $limits_ary['memory_limit']],
+ ['upload_max_filesize', $limits_ary['upload_max_filesize']],
+ ['post_max_size', $limits_ary['post_max_size']]
+ ]));
+
+ $plupload = new \phpbb\plupload\plupload(
+ '',
+ $config,
+ new phpbb_mock_request,
+ new \phpbb\user($lang, '\phpbb\datetime'),
+ $ini_wrapper,
+ new \phpbb\mimetype\guesser(array(new \phpbb\mimetype\extension_guesser))
+ );
+
+ $this->assertEquals($expected, $plupload->get_chunk_size());
+ }
}
diff --git a/tests/privmsgs/delete_user_pms_test.php b/tests/privmsgs/delete_user_pms_test.php
index 0f061e9784..9d6ba7a917 100644
--- a/tests/privmsgs/delete_user_pms_test.php
+++ b/tests/privmsgs/delete_user_pms_test.php
@@ -85,12 +85,14 @@ class phpbb_privmsgs_delete_user_pms_test extends phpbb_database_test_case
*/
public function test_delete_user_pms($delete_user, $remaining_privmsgs, $remaining_privmsgs_to)
{
- global $db, $phpbb_container;
+ global $db, $phpbb_container, $phpbb_root_path;
$db = $this->new_dbal();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
+ // Works as a workaround for tests
+ $phpbb_container->set('attachment.manager', new \phpbb\attachment\delete(new \phpbb\config\config(array()), $db, new \phpbb_mock_event_dispatcher(), new \phpbb\filesystem\filesystem(), new \phpbb\attachment\resync($db), $phpbb_root_path));
phpbb_delete_user_pms($delete_user);
diff --git a/tests/profilefields/type_bool_test.php b/tests/profilefields/type_bool_test.php
index 41c40ddb4b..10239172c3 100644
--- a/tests/profilefields/type_bool_test.php
+++ b/tests/profilefields/type_bool_test.php
@@ -25,7 +25,12 @@ class phpbb_profilefield_type_bool_test extends phpbb_test_case
*/
public function setUp()
{
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ global $phpbb_root_path, $phpEx;
+
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$user->expects($this->any())
->method('lang')
->will($this->returnCallback(array($this, 'return_callback_implode')));
diff --git a/tests/profilefields/type_date_test.php b/tests/profilefields/type_date_test.php
index 123955198e..e0807b2f9b 100644
--- a/tests/profilefields/type_date_test.php
+++ b/tests/profilefields/type_date_test.php
@@ -25,7 +25,12 @@ class phpbb_profilefield_type_date_test extends phpbb_test_case
*/
public function setUp()
{
- $this->user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ global $phpbb_root_path, $phpEx;
+
+ $this->user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$this->user->expects($this->any())
->method('lang')
->will($this->returnCallback(array($this, 'return_callback_implode')));
diff --git a/tests/profilefields/type_dropdown_test.php b/tests/profilefields/type_dropdown_test.php
index 3845a8e96b..ab02353fb9 100644
--- a/tests/profilefields/type_dropdown_test.php
+++ b/tests/profilefields/type_dropdown_test.php
@@ -25,7 +25,12 @@ class phpbb_profilefield_type_dropdown_test extends phpbb_test_case
*/
public function setUp()
{
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ global $phpbb_root_path, $phpEx;
+
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$user->expects($this->any())
->method('lang')
->will($this->returnCallback(array($this, 'return_callback_implode')));
diff --git a/tests/profilefields/type_googleplus_test.php b/tests/profilefields/type_googleplus_test.php
index f3db6ef01f..9222362214 100644
--- a/tests/profilefields/type_googleplus_test.php
+++ b/tests/profilefields/type_googleplus_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_profilefield_type_googleplus_test extends phpbb_test_case
{
protected $field;
@@ -21,7 +19,11 @@ class phpbb_profilefield_type_googleplus_test extends phpbb_test_case
{
parent::setUp();
- $user = new \phpbb\user('\phpbb\datetime');
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->add_lang('ucp');
$request = $this->getMock('\phpbb\request\request');
$template = $this->getMock('\phpbb\template\template');
diff --git a/tests/profilefields/type_int_test.php b/tests/profilefields/type_int_test.php
index 07b22525e2..33f3f575c8 100644
--- a/tests/profilefields/type_int_test.php
+++ b/tests/profilefields/type_int_test.php
@@ -24,7 +24,12 @@ class phpbb_profilefield_type_int_test extends phpbb_test_case
*/
public function setUp()
{
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ global $phpbb_root_path, $phpEx;
+
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$user->expects($this->any())
->method('lang')
->will($this->returnCallback(array($this, 'return_callback_implode')));
diff --git a/tests/profilefields/type_string_test.php b/tests/profilefields/type_string_test.php
index 0417afbfab..54bb406838 100644
--- a/tests/profilefields/type_string_test.php
+++ b/tests/profilefields/type_string_test.php
@@ -11,10 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_profilefield_type_string_test extends phpbb_test_case
{
protected $cp;
@@ -28,13 +24,17 @@ class phpbb_profilefield_type_string_test extends phpbb_test_case
*/
public function setUp()
{
- global $request, $user, $cache;
+ global $config, $request, $user, $cache, $phpbb_root_path, $phpEx;
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$cache = new phpbb_mock_cache;
$user->expects($this->any())
->method('lang')
->will($this->returnCallback(array($this, 'return_callback_implode')));
+ $config = new \phpbb\config\config([]);
$request = $this->getMock('\phpbb\request\request');
$template = $this->getMock('\phpbb\template\template');
@@ -270,6 +270,18 @@ class phpbb_profilefield_type_string_test extends phpbb_test_case
null,
'Field should simply output null for empty vlaue',
),
+ array(
+ 'http://foobar.com',
+ array('field_show_novalue' => false),
+ '<!-- l --><a class="postlink-local" href="http://foobar.com">foobar.com</a><!-- l -->',
+ 'Field should output the given value and make it clickable',
+ ),
+ array(
+ 'javascript://foobar.com',
+ array('field_show_novalue' => true),
+ 'javascript://foobar.com',
+ 'Field should output the given value but not make it clickable',
+ ),
);
}
diff --git a/tests/profilefields/type_url_test.php b/tests/profilefields/type_url_test.php
index cc37f04f30..3bb5d52899 100644
--- a/tests/profilefields/type_url_test.php
+++ b/tests/profilefields/type_url_test.php
@@ -12,6 +12,8 @@
*/
require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
+require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
+require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
class phpbb_profilefield_type_url_test extends phpbb_test_case
{
@@ -26,7 +28,14 @@ class phpbb_profilefield_type_url_test extends phpbb_test_case
*/
public function setUp()
{
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ global $config, $request, $user, $cache, $phpbb_root_path, $phpEx;
+
+ $config = new \phpbb\config\config([]);
+ $cache = new phpbb_mock_cache;
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$user->expects($this->any())
->method('lang')
->will($this->returnCallback(array($this, 'return_callback_implode')));
@@ -89,6 +98,19 @@ class phpbb_profilefield_type_url_test extends phpbb_test_case
'FIELD_INVALID_URL-field',
'Field should reject invalid URL having multi value parameters',
),
+ // Not allowed schemes
+ array(
+ 'ftp://example.com/',
+ array(),
+ 'FIELD_INVALID_URL-field',
+ 'Field should reject invalid URL having multi value parameters',
+ ),
+ array(
+ 'javascript://alert.com',
+ array(),
+ 'FIELD_INVALID_URL-field',
+ 'Field should reject invalid URL having multi value parameters',
+ ),
// IDN url type profilefields
array(
@@ -162,6 +184,55 @@ class phpbb_profilefield_type_url_test extends phpbb_test_case
);
}
+ public function profile_value_data()
+ {
+ return array(
+ array(
+ 'http://foobar.com',
+ array('field_show_novalue' => true),
+ '<!-- l --><a class="postlink-local" href="http://foobar.com">foobar.com</a><!-- l -->',
+ 'Field should output the given value',
+ ),
+ array(
+ 'http://foobar.com',
+ array('field_show_novalue' => false),
+ '<!-- l --><a class="postlink-local" href="http://foobar.com">foobar.com</a><!-- l -->',
+ 'Field should output the given value',
+ ),
+ array(
+ 'test',
+ array('field_show_novalue' => true),
+ null,
+ 'Field should output nothing for empty value',
+ ),
+ array(
+ 'test',
+ array('field_show_novalue' => false),
+ null,
+ 'Field should simply output null for empty value',
+ ),
+ array(
+ 'javascript://foobar.com',
+ array('field_show_novalue' => true),
+ null,
+ 'Field should output nothing for empty value',
+ ),
+ );
+ }
+
+
+ /**
+ * @dataProvider profile_value_data
+ */
+ public function test_get_profile_value($value, $field_options, $expected, $description)
+ {
+ $field_options = array_merge($this->field_options, $field_options);
+
+ $result = $this->cp->get_profile_value($value, $field_options);
+
+ $this->assertSame($expected, $result, $description);
+ }
+
/**
* @dataProvider profile_value_raw_data
*/
diff --git a/tests/random/gen_rand_string_test.php b/tests/random/gen_rand_string_test.php
index 1d12d0622c..428db6ac98 100644
--- a/tests/random/gen_rand_string_test.php
+++ b/tests/random/gen_rand_string_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_random_gen_rand_string_test extends phpbb_test_case
{
const TEST_COUNT = 100;
@@ -42,7 +40,10 @@ class phpbb_random_gen_rand_string_test extends phpbb_test_case
$random_string_length = strlen($random_string);
$this->assertTrue($random_string_length >= self::MIN_STRING_LENGTH);
- $this->assertTrue($random_string_length <= $num_chars);
+ $this->assertTrue(
+ $random_string_length == $num_chars,
+ sprintf('Failed asserting that random string length matches expected length. Expected %1$u, Actual %2$u', $num_chars, $random_string_length)
+ );
$this->assertRegExp('#^[A-Z0-9]+$#', $random_string);
}
}
@@ -58,7 +59,10 @@ class phpbb_random_gen_rand_string_test extends phpbb_test_case
$random_string_length = strlen($random_string);
$this->assertTrue($random_string_length >= self::MIN_STRING_LENGTH);
- $this->assertTrue($random_string_length <= $num_chars);
+ $this->assertTrue(
+ $random_string_length == $num_chars,
+ sprintf('Failed asserting that random string length matches expected length. Expected %1$u, Actual %2$u', $num_chars, $random_string_length)
+ );
$this->assertRegExp('#^[A-NP-Z1-9]+$#', $random_string);
}
}
diff --git a/tests/regex/censor_test.php b/tests/regex/censor_test.php
index 50c6778c8c..5a516b71de 100644
--- a/tests/regex/censor_test.php
+++ b/tests/regex/censor_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_regex_censor_test extends phpbb_test_case
{
public function censor_test_data()
@@ -37,18 +35,8 @@ class phpbb_regex_censor_test extends phpbb_test_case
*/
public function test_censor_unicode($pattern, $subject)
{
- $regex = get_censor_preg_expression($pattern, true);
-
- $this->assertRegExp($regex, $subject);
- }
-
- /**
- * @dataProvider censor_test_data
- */
- public function test_censor_no_unicode($pattern, $subject)
- {
- $regex = get_censor_preg_expression($pattern, false);
+ $regex = get_censor_preg_expression($pattern);
$this->assertRegExp($regex, $subject);
}
-} \ No newline at end of file
+}
diff --git a/tests/regex/email_test.php b/tests/regex/email_test.php
index ede35c49bc..5187b8bda6 100644
--- a/tests/regex/email_test.php
+++ b/tests/regex/email_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_regex_email_test extends phpbb_test_case
{
protected $regex;
diff --git a/tests/regex/ipv4_test.php b/tests/regex/ipv4_test.php
index 62c2567517..e21a2d77fa 100644
--- a/tests/regex/ipv4_test.php
+++ b/tests/regex/ipv4_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_regex_ipv4_test extends phpbb_test_case
{
protected $regex;
diff --git a/tests/regex/ipv6_test.php b/tests/regex/ipv6_test.php
index 41039c819d..223161df7f 100644
--- a/tests/regex/ipv6_test.php
+++ b/tests/regex/ipv6_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_regex_ipv6_test extends phpbb_test_case
{
protected $regex;
diff --git a/tests/regex/password_complexity_test.php b/tests/regex/password_complexity_test.php
index 8a1a9edd41..933dc1ac91 100644
--- a/tests/regex/password_complexity_test.php
+++ b/tests/regex/password_complexity_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../../phpBB/includes/functions_user.php';
class phpbb_password_complexity_test extends phpbb_test_case
diff --git a/tests/regex/table_prefix_test.php b/tests/regex/table_prefix_test.php
index c593085b25..bf7b59ccc6 100644
--- a/tests/regex/table_prefix_test.php
+++ b/tests/regex/table_prefix_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_regex_table_prefix_test extends phpbb_test_case
{
public function table_prefix_test_data()
diff --git a/tests/regex/url_test.php b/tests/regex/url_test.php
index e5d7c3256a..5e2a22bf73 100644
--- a/tests/regex/url_test.php
+++ b/tests/regex/url_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_regex_url_test extends phpbb_test_case
{
public function url_test_data()
diff --git a/tests/request/request_var_test.php b/tests/request/request_var_test.php
index 67712eb6c8..84c81c4e84 100644
--- a/tests/request/request_var_test.php
+++ b/tests/request/request_var_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_request_var_test extends phpbb_test_case
{
/**
diff --git a/tests/request/type_cast_helper_test.php b/tests/request/type_cast_helper_test.php
index d6ee1dc728..6407dca894 100644
--- a/tests/request/type_cast_helper_test.php
+++ b/tests/request/type_cast_helper_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_type_cast_helper_test extends phpbb_test_case
{
private $type_cast_helper;
@@ -22,16 +20,6 @@ class phpbb_type_cast_helper_test extends phpbb_test_case
$this->type_cast_helper = new \phpbb\request\type_cast_helper();
}
- public function test_addslashes_recursively()
- {
- $data = array('some"string' => array('that"' => 'really"', 'needs"' => '"escaping'));
- $expected = array('some\\"string' => array('that\\"' => 'really\\"', 'needs\\"' => '\\"escaping'));
-
- $this->type_cast_helper->addslashes_recursively($data);
-
- $this->assertEquals($expected, $data);
- }
-
public function test_simple_recursive_set_var()
{
$data = 'eviL<3';
diff --git a/tests/search/fixtures/posts.xml b/tests/search/fixtures/posts.xml
index 16232b8f39..4916cd188b 100644
--- a/tests/search/fixtures/posts.xml
+++ b/tests/search/fixtures/posts.xml
@@ -1,25 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<table name="phpbb_posts">
+ <column>post_id</column>
<column>post_username</column>
<column>post_subject</column>
<column>post_text</column>
<row>
+ <value>1</value>
<value>foo</value>
<value>foo</value>
<value>foo</value>
</row>
<row>
+ <value>2</value>
<value>bar</value>
<value>bar</value>
<value>bar</value>
</row>
<row>
+ <value>3</value>
<value>commonword</value>
<value>commonword</value>
<value>commonword</value>
</row>
<row>
+ <value>4</value>
<value>baaz</value>
<value>baaz</value>
<value>baaz</value>
diff --git a/tests/search/native_test.php b/tests/search/native_test.php
index 29d0d0a8d3..0e6f719cef 100644
--- a/tests/search/native_test.php
+++ b/tests/search/native_test.php
@@ -70,7 +70,7 @@ class phpbb_search_native_test extends phpbb_search_test_case
'ba*az',
'all',
true,
- array('\'ba%az\''),
+ array(4),
array(),
array(),
),
@@ -78,7 +78,7 @@ class phpbb_search_native_test extends phpbb_search_test_case
'ba*z',
'all',
true,
- array('\'ba%z\''),
+ array(), // <= 3 chars after removing *
array(),
array(),
),
@@ -86,7 +86,7 @@ class phpbb_search_native_test extends phpbb_search_test_case
'baa* baaz*',
'all',
true,
- array('\'baa%\'', '\'baaz%\''),
+ array('\'baa%\'', 4),
array(),
array(),
),
@@ -94,7 +94,7 @@ class phpbb_search_native_test extends phpbb_search_test_case
'ba*z baa*',
'all',
true,
- array('\'ba%z\'', '\'baa%\''),
+ array('\'baa%\''), // baz is <= 3 chars, only baa* is left
array(),
array(),
),
diff --git a/tests/security/base.php b/tests/security/base.php
index 330408b448..d2abdbc362 100644
--- a/tests/security/base.php
+++ b/tests/security/base.php
@@ -46,10 +46,12 @@ abstract class phpbb_security_test_base extends phpbb_test_case
$request = new phpbb_mock_request(array(), array(), array(), $this->server);
$symfony_request = new \phpbb\symfony_request($request);
- $phpbb_filesystem = new \phpbb\filesystem();
+ $phpbb_filesystem = new \phpbb\filesystem\filesystem();
// Set no user and trick a bit to circumvent errors
- $user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
$user->lang = true;
$user->browser = $this->server['HTTP_USER_AGENT'];
$user->referer = '';
diff --git a/tests/security/extract_current_page_test.php b/tests/security/extract_current_page_test.php
index 767b901a43..f764449eca 100644
--- a/tests/security/extract_current_page_test.php
+++ b/tests/security/extract_current_page_test.php
@@ -13,7 +13,6 @@
require_once dirname(__FILE__) . '/base.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_security_extract_current_page_test extends phpbb_security_test_base
{
diff --git a/tests/security/hash_test.php b/tests/security/hash_test.php
index 0494c55c6d..84d4fcf479 100644
--- a/tests/security/hash_test.php
+++ b/tests/security/hash_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_compatibility.php';
-
class phpbb_security_hash_test extends phpbb_test_case
{
public function setUp()
diff --git a/tests/security/redirect_test.php b/tests/security/redirect_test.php
index a88fc63858..0177eb4259 100644
--- a/tests/security/redirect_test.php
+++ b/tests/security/redirect_test.php
@@ -13,7 +13,6 @@
require_once dirname(__FILE__) . '/base.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_security_redirect_test extends phpbb_security_test_base
{
@@ -67,7 +66,7 @@ class phpbb_security_redirect_test extends phpbb_security_test_base
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ new \phpbb\filesystem\filesystem(),
$this->getMock('\phpbb\request\request'),
$this->phpbb_root_path,
'php'
@@ -110,7 +109,7 @@ class phpbb_security_redirect_test extends phpbb_security_test_base
if ($expected_error !== false)
{
- $this->setExpectedTriggerError(E_USER_ERROR, $user->lang[$expected_error]);
+ $this->setExpectedTriggerError(E_USER_WARNING, $user->lang[$expected_error]);
}
$result = redirect($test, true, $disable_cd_check);
diff --git a/tests/session/append_sid_test.php b/tests/session/append_sid_test.php
index 2a1d94514f..4e5a238644 100644
--- a/tests/session/append_sid_test.php
+++ b/tests/session/append_sid_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_session_append_sid_test extends phpbb_test_case
{
diff --git a/tests/session/check_ban_test.php b/tests/session/check_ban_test.php
index 561b7faf49..16a65b0ade 100644
--- a/tests/session/check_ban_test.php
+++ b/tests/session/check_ban_test.php
@@ -42,7 +42,10 @@ class phpbb_session_check_ban_test extends phpbb_session_test_case
parent::setUp();
// Get session here so that config is mocked correctly
$this->session = $this->session_factory->get_session($this->db);
- global $cache, $config, $phpbb_root_path, $phpEx;
+ global $cache, $config, $phpbb_root_path, $phpEx, $phpbb_filesystem;
+
+ $phpbb_filesystem = new \phpbb\filesystem\filesystem();
+
$this->backup_cache = $cache;
// Change the global cache object for this test because
// the mock cache object does not hit the database as is needed
@@ -69,7 +72,8 @@ class phpbb_session_check_ban_test extends phpbb_session_test_case
{
try
{
- $is_banned = $this->session->check_ban($user_id, $user_ips, $user_email, $return);
+ $ban = $this->session->check_ban($user_id, $user_ips, $user_email, $return);
+ $is_banned = !empty($ban);
}
catch (PHPUnit_Framework_Error_Notice $e)
{
diff --git a/tests/session/extract_page_test.php b/tests/session/extract_page_test.php
index f0d1cdb60e..f8aa3d27a5 100644
--- a/tests/session/extract_page_test.php
+++ b/tests/session/extract_page_test.php
@@ -12,7 +12,6 @@
*/
require_once dirname(__FILE__) . '/../test_framework/phpbb_session_test_case.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_session_extract_page_test extends phpbb_session_test_case
{
@@ -137,6 +136,22 @@ class phpbb_session_extract_page_test extends phpbb_session_test_case
'forum' => 0,
),
),
+ array(
+ './community',
+ '/app.php',
+ '',
+ '/',
+ '/kb',
+ array(
+ 'page_name' => 'app.php/kb',
+ 'page_dir' => '..',
+ 'query_string' => '',
+ 'script_path' => '/',
+ 'root_script_path' => '/community/',
+ 'page' => '../app.php/kb',
+ 'forum' => 0,
+ ),
+ ),
);
}
@@ -145,7 +160,7 @@ class phpbb_session_extract_page_test extends phpbb_session_test_case
{
global $symfony_request, $request, $phpbb_filesystem;
- $phpbb_filesystem = new \phpbb\filesystem();
+ $phpbb_filesystem = new \phpbb\filesystem\filesystem();
$server['HTTP_HOST'] = 'localhost';
$server['SERVER_NAME'] = 'localhost';
diff --git a/tests/session/garbage_collection_test.php b/tests/session/garbage_collection_test.php
index 3fad81c68b..3dc591a328 100644
--- a/tests/session/garbage_collection_test.php
+++ b/tests/session/garbage_collection_test.php
@@ -12,7 +12,6 @@
*/
require_once dirname(__FILE__) . '/../test_framework/phpbb_session_test_case.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_session_garbage_collection_test extends phpbb_session_test_case
{
diff --git a/tests/session/session_key_test.php b/tests/session/session_key_test.php
index bf3dfcaa3c..2499ea1d55 100644
--- a/tests/session/session_key_test.php
+++ b/tests/session/session_key_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../test_framework/phpbb_session_test_case.php';
class phpbb_session_login_keys_test extends phpbb_session_test_case
diff --git a/tests/session/testable_factory.php b/tests/session/testable_factory.php
index 3e25286480..6f8b49122b 100644
--- a/tests/session/testable_factory.php
+++ b/tests/session/testable_factory.php
@@ -73,7 +73,7 @@ class phpbb_session_testable_factory
public function get_session(\phpbb\db\driver\driver_interface $dbal)
{
// set up all the global variables used by session
- global $SID, $_SID, $db, $config, $cache, $request, $phpbb_container;
+ global $SID, $_SID, $db, $config, $cache, $request, $phpbb_container, $phpbb_root_path;
$request = $this->request = new phpbb_mock_request(
array(),
@@ -81,10 +81,8 @@ class phpbb_session_testable_factory
$this->cookies,
$this->server_data
);
- request_var(null, null, null, null, $request);
$config = $this->config = new \phpbb\config\config($this->get_config_data());
- set_config(null, null, null, $config);
$db = $dbal;
@@ -96,6 +94,8 @@ class phpbb_session_testable_factory
'auth.provider.db',
new phpbb_mock_auth_provider()
);
+ $phpbb_container->setParameter('core.environment', PHPBB_ENVIRONMENT);
+ $phpbb_container->setParameter('core.cache_dir', $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/');
$provider_collection = new \phpbb\auth\provider_collection($phpbb_container, $config);
$provider_collection->add('auth.provider.db');
$phpbb_container->set(
diff --git a/tests/template/asset_test.php b/tests/template/asset_test.php
new file mode 100644
index 0000000000..3d2fdd8959
--- /dev/null
+++ b/tests/template/asset_test.php
@@ -0,0 +1,49 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+use phpbb\template\asset;
+
+class phpbb_template_asset_test extends phpbb_test_case
+{
+ public function set_path_data()
+ {
+ return array(
+ // array(phpbb_root_path, given path, expected path),
+ array('.', 'foo/bar', 'foo/bar'),
+ array('../', 'foo/bar', 'foo/bar'),
+ array('./phpBB/', 'foo/bar', 'foo/bar'),
+ array('../', __DIR__ . '/foo/bar', '../' . basename(dirname(dirname(__DIR__))) . '/tests/template/foo/bar'),
+ array('./', __DIR__ . '/foo/bar', './tests/template/foo/bar'),
+ array('./phpBB/', __DIR__ . '/foo/bar', 'tests/template/foo/bar'),
+ );
+ }
+
+ /**
+ * @dataProvider set_path_data
+ */
+ public function test_set_path($phpbb_root_path, $path, $expected)
+ {
+ $path_helper = $this->getMockBuilder('\phpbb\path_helper')
+ ->disableOriginalConstructor()
+ ->setMethods(array())
+ ->getMock();
+
+ $path_helper->method('get_phpbb_root_path')
+ ->willReturn($phpbb_root_path);
+
+ $asset = new asset('', $path_helper, new phpbb\filesystem\filesystem());
+
+ $asset->set_path($path, true);
+ $this->assertEquals($expected, $asset->get_path());
+ }
+}
diff --git a/tests/template/context_test.php b/tests/template/context_test.php
new file mode 100644
index 0000000000..52ce6c8fde
--- /dev/null
+++ b/tests/template/context_test.php
@@ -0,0 +1,96 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class context_test extends phpbb_test_case
+{
+ protected $context;
+ protected function setUp()
+ {
+ $this->context = new \phpbb\template\context();
+
+ for ($i = 0; $i < 10; $i++)
+ {
+ $this->context->assign_block_vars('block' . $i, array(
+ 'FOO' . $i => 'foo' . $i,
+ 'BAR' . $i => 'bar' . $i,
+ ));
+
+ for ($j = 0; $j < 10; $j++)
+ {
+ $this->context->assign_block_vars('block' . $i . '.subblock', array(
+ 'SUBFOO' => 'subfoo' . $j,
+ 'SUBBAR' => 'subbar' . $j,
+ ));
+
+ for ($k = 0; $k < 10; $k++)
+ {
+ $this->context->assign_block_vars('block' . $i . '.subblock.subsubblock', array(
+ 'SUBSUBFOO' => 'subsubfoo' . $k,
+ 'SUBSUBBAR' => 'subsubbar' . $k,
+ ));
+ }
+ }
+ }
+ }
+
+ public function retrieve_block_vars_data()
+ {
+ return array(
+ array('foo', array(), array()), // non-existent top-level block
+ array('block1.foo', array(), array()), // non-existent sub-level block
+ array('block1', array(), array( // top-level block, all vars
+ 'FOO1' => 'foo1',
+ 'BAR1' => 'bar1',
+ )),
+ array('block1', array('FOO1'), array( // top-level block, one var
+ 'FOO1' => 'foo1',
+ )),
+ array('block2.subblock', array(), array( // sub-level block, all vars
+ 'SUBFOO' => 'subfoo9',
+ 'SUBBAR' => 'subbar9',
+ )),
+ array('block2.subblock', array('SUBBAR'), array( // sub-level block, one var
+ 'SUBBAR' => 'subbar9',
+ )),
+ array('block2.subblock.subsubblock', array(), array( // sub-sub-level block, all vars
+ 'SUBSUBFOO' => 'subsubfoo9',
+ 'SUBSUBBAR' => 'subsubbar9',
+ )),
+ array('block2.subblock.subsubblock', array('SUBSUBBAR'), array( // sub-sub-level block, one var
+ 'SUBSUBBAR' => 'subsubbar9',
+ )),
+ array('block3.subblock[2]', array(), array( // sub-level, exact index, all vars
+ 'SUBFOO' => 'subfoo2',
+ 'SUBBAR' => 'subbar2',
+ )),
+ array('block3.subblock[2]', array('SUBBAR'), array( // sub-level, exact index, one var
+ 'SUBBAR' => 'subbar2',
+ )),
+ array('block3.subblock[3].subsubblock[5]', array(), array( // sub-sub-level, exact index, all vars
+ 'SUBSUBFOO' => 'subsubfoo5',
+ 'SUBSUBBAR' => 'subsubbar5',
+ )),
+ array('block3.subblock[4].subsubblock[6]', array('SUBSUBFOO'), array( // sub-sub-level, exact index, one var
+ 'SUBSUBFOO' => 'subsubfoo6',
+ )),
+ );
+ }
+
+ /**
+ * @dataProvider retrieve_block_vars_data
+ */
+ public function test_retrieve_block_vars($blockname, $vararray, $result)
+ {
+ $this->assertEquals($result, $this->context->retrieve_block_vars($blockname, $vararray));
+ }
+}
diff --git a/tests/template/includephp_test.php b/tests/template/includephp_test.php
index fdddbef4f2..722e10e42d 100644
--- a/tests/template/includephp_test.php
+++ b/tests/template/includephp_test.php
@@ -39,8 +39,9 @@ class phpbb_template_includephp_test extends phpbb_template_template_test_case
{
global $phpbb_root_path;
+ $filesystem = new \phpbb\filesystem\filesystem();
$path_to_php = str_replace('\\', '/', dirname(__FILE__)) . '/templates/_dummy_include.php.inc';
- $this->assertTrue(phpbb_is_absolute($path_to_php));
+ $this->assertTrue($filesystem->is_absolute_path($path_to_php));
$template_text = "Path is absolute.\n<!-- INCLUDEPHP $path_to_php -->";
$cache_dir = $phpbb_root_path . 'cache/';
diff --git a/tests/template/template_allfolder_test.php b/tests/template/template_allfolder_test.php
index b4ad84e9c3..63a6ef08ea 100644
--- a/tests/template/template_allfolder_test.php
+++ b/tests/template/template_allfolder_test.php
@@ -28,13 +28,18 @@ class phpbb_template_allfolder_test extends phpbb_template_template_test_case
$defaults = $this->config_defaults();
$config = new \phpbb\config\config(array_merge($defaults, $new_config));
- $this->user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $this->user = $user;
+
+ $filesystem = new \phpbb\filesystem\filesystem();
$path_helper = new \phpbb\path_helper(
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ $filesystem,
$this->getMock('\phpbb\request\request'),
$phpbb_root_path,
$phpEx
@@ -51,9 +56,30 @@ class phpbb_template_allfolder_test extends phpbb_template_template_test_case
)
);
+ $container = new phpbb_mock_container_builder();
+ $cache_path = $phpbb_root_path . 'cache/twig';
+ $context = new \phpbb\template\context();
+ $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), '');
+ $twig = new \phpbb\template\twig\environment(
+ $config,
+ $filesystem,
+ $path_helper,
+ $cache_path,
+ $this->extension_manager,
+ $loader,
+ new \phpbb\event\dispatcher($container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
+ );
+ $this->template = new \phpbb\template\twig\twig($path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)), $this->extension_manager);
+ $twig->setLexer(new \phpbb\template\twig\lexer($twig));
+
$this->template_path = $this->test_path . '/templates';
$this->ext_template_path = 'tests/extension/ext/vendor4/bar/styles/all/template';
- $this->template = new \phpbb\template\twig\twig($path_helper, $config, $this->user, new \phpbb\template\context(), $this->extension_manager);
$this->template->set_custom_style('all', array($this->template_path, $this->ext_template_path));
}
}
diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php
index c415c969fe..3a93c91e11 100644
--- a/tests/template/template_events_test.php
+++ b/tests/template/template_events_test.php
@@ -138,16 +138,40 @@ Zeta test event in all',
$this->extension_manager = new phpbb_mock_filesystem_extension_manager(
dirname(__FILE__) . "/datasets/$dataset/"
);
+
+ $filesystem = new \phpbb\filesystem\filesystem();
$path_helper = new \phpbb\path_helper(
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ new \phpbb\filesystem\filesystem(),
$this->getMock('\phpbb\request\request'),
$phpbb_root_path,
$phpEx
);
- $this->template = new \phpbb\template\twig\twig($path_helper, $config, $user, new \phpbb\template\context, $this->extension_manager);
+
+ $container = new phpbb_mock_container_builder();
+ $cache_path = $phpbb_root_path . 'cache/twig';
+ $context = new \phpbb\template\context();
+ $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), '');
+ $twig = new \phpbb\template\twig\environment(
+ $config,
+ $filesystem,
+ $path_helper,
+ $cache_path,
+ $this->extension_manager,
+ $loader,
+ new \phpbb\event\dispatcher($container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
+ );
+ $this->template = new \phpbb\template\twig\twig($path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)), $this->extension_manager);
+ $twig->setLexer(new \phpbb\template\twig\lexer($twig));
+
$this->template->set_custom_style(((!empty($style_names)) ? $style_names : 'silver'), array($this->template_path));
}
}
diff --git a/tests/template/template_includecss_test.php b/tests/template/template_includecss_test.php
index b025cd21d5..4eb30eda1e 100644
--- a/tests/template/template_includecss_test.php
+++ b/tests/template/template_includecss_test.php
@@ -15,6 +15,12 @@ require_once dirname(__FILE__) . '/template_test_case_with_tree.php';
class phpbb_template_template_includecss_test extends phpbb_template_template_test_case_with_tree
{
+ /** @var \phpbb\path_helper */
+ protected $phpbb_path_helper;
+
+ /** @var string */
+ protected $parent_template_path;
+
protected function setup_engine(array $new_config = array())
{
global $phpbb_root_path, $phpEx, $user;
@@ -22,11 +28,13 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te
$defaults = $this->config_defaults();
$config = new \phpbb\config\config(array_merge($defaults, $new_config));
+ $filesystem = new \phpbb\filesystem\filesystem();
+
$this->phpbb_path_helper = new \phpbb\path_helper(
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ $filesystem,
$this->getMock('\phpbb\request\request'),
$phpbb_root_path,
$phpEx
@@ -34,11 +42,33 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te
$this->template_path = $this->test_path . '/templates';
$this->parent_template_path = $this->test_path . '/parent_templates';
+ $container = new phpbb_mock_container_builder();
+ $cache_path = $phpbb_root_path . 'cache/twig';
+ $context = new \phpbb\template\context();
+ $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), '');
+ $twig = new \phpbb\template\twig\environment(
+ $config,
+ $filesystem,
+ $this->phpbb_path_helper,
+ $cache_path,
+ null,
+ $loader,
+ new \phpbb\event\dispatcher($container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
+ );
$this->template = new phpbb\template\twig\twig(
$this->phpbb_path_helper,
$config,
- $user,
- new phpbb\template\context(),
+ $context,
+ $twig,
+ $cache_path,
+ $this->user,
+ array(new \phpbb\template\twig\extension($context, $this->user)),
new phpbb_mock_extension_manager(
dirname(__FILE__) . '/',
array(
@@ -50,6 +80,7 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te
)
)
);
+ $twig->setLexer(new \phpbb\template\twig\lexer($twig));
$this->template->set_custom_style('tests', array($this->template_path, $this->parent_template_path));
}
@@ -64,19 +95,19 @@ class phpbb_template_template_includecss_test extends phpbb_template_template_te
*/
array(
array('TEST' => 1),
- '<link href="tests/template/templates/child_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
+ '<link href="tests/template/templates/child_only.css?assets_version=1" rel="stylesheet" media="screen" />',
),
array(
array('TEST' => 2),
- '<link href="tests/template/parent_templates/parent_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
+ '<link href="tests/template/parent_templates/parent_only.css?assets_version=1" rel="stylesheet" media="screen" />',
),
array(
array('TEST' => 3),
- '<link href="tests/template/ext/include/css/styles/all/theme/test.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
+ '<link href="tests/template/ext/include/css/styles/all/theme/test.css?assets_version=1" rel="stylesheet" media="screen" />',
),
array(
array('TEST' => 4),
- '<link href="tests/template/ext/include/css/styles/all/theme/child_only.css?assets_version=1" rel="stylesheet" type="text/css" media="screen" />',
+ '<link href="tests/template/ext/include/css/styles/all/theme/child_only.css?assets_version=1" rel="stylesheet" media="screen" />',
),
);
}
diff --git a/tests/template/template_includejs_test.php b/tests/template/template_includejs_test.php
index 232f551b4a..19c016ae5e 100644
--- a/tests/template/template_includejs_test.php
+++ b/tests/template/template_includejs_test.php
@@ -28,67 +28,67 @@ class phpbb_template_template_includejs_test extends phpbb_template_template_tes
*/
array(
array('TEST' => 1),
- '<script type="text/javascript" src="tests/template/templates/parent_and_child.js?assets_version=1"></script>',
+ '<script src="tests/template/templates/parent_and_child.js?assets_version=1"></script>',
),
array(
array('TEST' => 2),
- '<script type="text/javascript" src="tests/template/templates/parent_and_child.js?assets_version=0"></script>',
+ '<script src="tests/template/templates/parent_and_child.js?assets_version=0"></script>',
),
array(
array('TEST' => 3),
- '<script type="text/javascript" src="tests/template/templates/parent_and_child.js?test=1&assets_version=0"></script>',
+ '<script src="tests/template/templates/parent_and_child.js?test=1&assets_version=0"></script>',
),
array(
array('TEST' => 4),
- '<script type="text/javascript" src="tests/template/templates/parent_and_child.js?test=1&amp;assets_version=0"></script>',
+ '<script src="tests/template/templates/parent_and_child.js?test=1&amp;assets_version=0"></script>',
),
array(
array('TEST' => 6),
- '<script type="text/javascript" src="tests/template/parent_templates/parent_only.js?assets_version=1"></script>',
+ '<script src="tests/template/parent_templates/parent_only.js?assets_version=1"></script>',
),
array(
array('TEST' => 7),
- '<script type="text/javascript" src="tests/template/templates/child_only.js?assets_version=1"></script>',
+ '<script src="tests/template/templates/child_only.js?assets_version=1"></script>',
),
array(
array('TEST' => 8),
- '<script type="text/javascript" src="tests/template/templates/subdir/parent_only.js?assets_version=1"></script>',
+ '<script src="tests/template/templates/subdir/parent_only.js?assets_version=1"></script>',
),
array(
array('TEST' => 9),
- '<script type="text/javascript" src="tests/template/templates/subdir/subsubdir/parent_only.js?assets_version=1"></script>',
+ '<script src="tests/template/templates/subdir/subsubdir/parent_only.js?assets_version=1"></script>',
),
array(
array('TEST' => 10),
- '<script type="text/javascript" src="tests/template/templates/subdir/parent_only.js?assets_version=1"></script>',
+ '<script src="tests/template/templates/subdir/parent_only.js?assets_version=1"></script>',
),
array(
array('TEST' => 11),
- '<script type="text/javascript" src="tests/template/templates/child_only.js?test1=1&amp;test2=2&amp;assets_version=1#test3"></script>',
+ '<script src="tests/template/templates/child_only.js?test1=1&amp;test2=2&amp;assets_version=1#test3"></script>',
),
array(
array('TEST' => 12),
- '<script type="text/javascript" src="tests/template/parent_templates/parent_only.js?test1=1&amp;test2=2&amp;assets_version=1#test3"></script>',
+ '<script src="tests/template/parent_templates/parent_only.js?test1=1&amp;test2=2&amp;assets_version=1#test3"></script>',
),
array(
array('TEST' => 14),
- '<script type="text/javascript" src="tests/template/parent_templates/parent_only.js?test1=&quot;&amp;assets_version=1#test3"></script>',
+ '<script src="tests/template/parent_templates/parent_only.js?test1=&quot;&amp;assets_version=1#test3"></script>',
),
array(
array('TEST' => 15),
- '<script type="text/javascript" src="http://phpbb.com/b.js?c=d#f"></script>',
+ '<script src="http://phpbb.com/b.js?c=d#f"></script>',
),
array(
array('TEST' => 16),
- '<script type="text/javascript" src="http://phpbb.com/b.js?c=d&assets_version=2#f"></script>',
+ '<script src="http://phpbb.com/b.js?c=d&assets_version=2#f"></script>',
),
array(
array('TEST' => 17),
- '<script type="text/javascript" src="//phpbb.com/b.js"></script>',
+ '<script src="//phpbb.com/b.js"></script>',
),
array(
array('TEST' => 18),
- '<script type="text/javascript" src="tests/template/templates/parent_and_child.js?test=1&test2=0&amp;assets_version=1"></script>',
+ '<script src="tests/template/templates/parent_and_child.js?test=1&test2=0&amp;assets_version=1"></script>',
),
);
}
diff --git a/tests/template/template_parser_test.php b/tests/template/template_parser_test.php
index d32fe78391..938b1bc8b8 100644
--- a/tests/template/template_parser_test.php
+++ b/tests/template/template_parser_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/template_test_case.php';
class phpbb_template_template_parser_test extends phpbb_template_template_test_case
diff --git a/tests/template/template_test.php b/tests/template/template_test.php
index 69546cc227..727f35e9d2 100644
--- a/tests/template/template_test.php
+++ b/tests/template/template_test.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/template_test_case.php';
class phpbb_template_template_test extends phpbb_template_template_test_case
@@ -130,6 +129,34 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"loop\nloop\nloop\nloop\nloop#0-block#0\nloop#0-block#1\nloop#1-block#0\nloop#1-block#1",
),
array(
+ 'loop_twig.html',
+ array(),
+ array(),
+ array(),
+ "noloop\nnoloop",
+ ),
+ array(
+ 'loop_twig.html',
+ array(),
+ array('test_loop' => array(array())),
+ array(),
+ "loop\nloop",
+ ),
+ array(
+ 'loop_twig.html',
+ array(),
+ array('test_loop' => array(array(), array()), 'test_loop.block' => array(array())),
+ array(),
+ "loop\nloop\nloop\nloop",
+ ),
+ array(
+ 'loop_twig.html',
+ array(),
+ array('test_loop' => array(array(), array()), 'test_loop.block' => array(array()), 'block' => array(array(), array())),
+ array(),
+ "loop\nloop\nloop\nloop\nloop#0-block#0\nloop#0-block#1\nloop#1-block#0\nloop#1-block#1",
+ ),
+ array(
'loop_vars.html',
array(),
array('test_loop' => array(array('VARIABLE' => 'x'))),
@@ -151,6 +178,27 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast\n0 - c\n1 - c\nlast inner",
),
array(
+ 'loop_vars_twig.html',
+ array(),
+ array('test_loop' => array(array('VARIABLE' => 'x'))),
+ array(),
+ "first\n0 - a\nx - b\nset\nlast",
+ ),
+ array(
+ 'loop_vars_twig.html',
+ array(),
+ array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y'))),
+ array(),
+ "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast",
+ ),
+ array(
+ 'loop_vars_twig.html',
+ array(),
+ array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())),
+ array(),
+ "first\n0 - a\nx - b\nset\n1 - a\ny - b\nset\nlast\n0 - c\n1 - c\nlast inner",
+ ),
+ array(
'loop_advanced.html',
array(),
array('test_loop' => array(array(), array(), array(), array(), array(), array(), array())),
@@ -158,6 +206,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"101234561\nx\n101234561\nx\n101234561\nx\n1234561\nx\n1\nx\n101\nx\n234\nx\n10\nx\n561\nx\n561",
),
array(
+ 'loop_advanced_twig.html',
+ array(),
+ array('test_loop' => array(array(), array(), array(), array(), array(), array(), array())),
+ array(),
+ "101234561\nx\n101234561\nx\n101234561\nx\n1234561\nx\n1\nx\n101\nx\n234\nx\n10\nx\n561\nx\n561",
+ ),
+ array(
'loop_nested2.html',
array(),
array('outer' => array(array(), array()), 'outer.middle' => array(array(), array())),
@@ -165,6 +220,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"o0o1m01m11",
),
array(
+ 'loop_nested2_twig.html',
+ array(),
+ array('outer' => array(array(), array()), 'outer.middle' => array(array(), array())),
+ array(),
+ "o0o1m01m11",
+ ),
+ array(
'define.html',
array(),
array('test_loop' => array(array(), array(), array(), array(), array(), array(), array()), 'test' => array(array()), 'test.deep' => array(array()), 'test.deep.defines' => array(array())),
@@ -244,6 +306,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
'',
),
array(
+ 'loop_vars_twig.html',
+ array(),
+ array('test_loop' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'test_loop.inner' => array(array(), array())),
+ array('test_loop'),
+ '',
+ ),
+ array(
'include_define_variable.html',
array('VARIABLE' => 'variable.html'),
array(),
@@ -275,6 +344,15 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"noloop\nnoloop",
),
array(
+ // Just like a regular loop but the name begins
+ // with an underscore
+ 'loop_underscore_twig.html',
+ array(),
+ array(),
+ array(),
+ "noloop\nnoloop",
+ ),
+ array(
'lang.html',
array(),
array(),
@@ -286,7 +364,7 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
array(),
array(),
array(),
- "Value'\n1 O'Clock\nValue\'\n1 O\'Clock",
+ "Value'\n1 O'Clock\nValue\\u0027\n1\\u0020O\\u0027Clock",
array('VARIABLE' => "Value'", '1_VARIABLE' => "1 O'Clock"),
),
array(
@@ -297,6 +375,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"top-level content",
),
array(
+ 'loop_nested_multilevel_ref_twig.html',
+ array(),
+ array(),
+ array(),
+ "top-level content",
+ ),
+ array(
'loop_nested_multilevel_ref.html',
array(),
array('outer' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'outer.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
@@ -304,6 +389,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"top-level content\nouter x\nouter y\ninner z\nfirst row\n\ninner zz",
),
array(
+ 'loop_nested_multilevel_ref_twig.html',
+ array(),
+ array('outer' => array(array('VARIABLE' => 'x'), array('VARIABLE' => 'y')), 'outer.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
+ array(),
+ "top-level content\nouter x\nouter y\ninner z\nfirst row\n\ninner zz",
+ ),
+ array(
'loop_nested_deep_multilevel_ref.html',
array(),
array('outer' => array(array()), 'outer.middle' => array(array()), 'outer.middle.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
@@ -311,6 +403,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"top-level content\nouter\nmiddle\ninner z\nfirst row of 2 in inner\n\ninner zz",
),
array(
+ 'loop_nested_deep_multilevel_ref_twig.html',
+ array(),
+ array('outer' => array(array()), 'outer.middle' => array(array()), 'outer.middle.inner' => array(array('VARIABLE' => 'z'), array('VARIABLE' => 'zz'))),
+ array(),
+ "top-level content\nouter\nmiddle\ninner z\nfirst row of 2 in inner\n\ninner zz",
+ ),
+ array(
'loop_size.html',
array(),
array('test_loop' => array(array()), 'empty_loop' => array()),
@@ -318,6 +417,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"nonexistent = 0\n! nonexistent\n\nempty = 0\n! empty\nloop\n\nin loop",
),
array(
+ 'loop_size_twig.html',
+ array(),
+ array('test_loop' => array(array()), 'empty_loop' => array()),
+ array(),
+ "nonexistent = 0\n! nonexistent\n\nempty = 0\n! empty\nloop\n\nin loop",
+ ),
+ array(
'loop_include.html',
array(),
array('test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1'))),
@@ -325,6 +431,13 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"barbarbar1bar1",
),
array(
+ 'loop_include_twig.html',
+ array(),
+ array('test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1'))),
+ array(),
+ "barbarbar1bar1",
+ ),
+ array(
'loop_nested_include.html',
array(),
array(
@@ -335,6 +448,17 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
"[bar|[bar|]][bar1|[bar1|[bar1|works]]]",
array(),
),
+ array(
+ 'loop_nested_include_twig.html',
+ array(),
+ array(
+ 'test_loop' => array(array('foo' => 'bar'), array('foo' => 'bar1')),
+ 'test_loop.inner' => array(array('myinner' => 'works')),
+ ),
+ array(),
+ "[bar|[bar|]][bar1|[bar1|[bar1|works]]]",
+ array(),
+ ),
/* Does not pass with the current implementation.
array(
'loop_reuse.html',
@@ -343,8 +467,15 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
array(),
// Not entirely sure what should be outputted but the current output of "a" is most certainly wrong
"a\nb\nc\nd",
+ ),*/
+ array(
+ 'loop_reuse_twig.html',
+ array(),
+ array('one' => array(array('VAR' => 'a'), array('VAR' => 'b')), 'one.one' => array(array('VAR' => 'c'), array('VAR' => 'd'))),
+ array(),
+ // Not entirely sure what should be outputted but the current output of "a" is most certainly wrong
+ "a\nb\nc\nd",
),
- */
array(
'twig.html',
array('VARIABLE' => 'FOObar',),
@@ -359,6 +490,27 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
array(),
'inner_value',
),
+ array(
+ 'loop_expressions.html',
+ array(),
+ array('loop' => array(array(),array(),array(),array(),array(),array()),),
+ array(),
+ 'yesnononoyesnoyesnonoyesnono',
+ ),
+ array(
+ 'loop_expressions_twig.html',
+ array(),
+ array('loop' => array(array(),array(),array(),array(),array(),array()),),
+ array(),
+ 'yesnononoyesnoyesnonoyesnono',
+ ),
+ array(
+ 'loop_expressions_twig2.html',
+ array('loop' => array(array(),array(),array(),array(),array(),array()),),
+ array(),
+ array(),
+ 'yesnononoyesnoyesnonoyesnono',
+ ),
);
}
@@ -406,7 +558,7 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
$this->template->assign_display('test', 'VARIABLE', false);
- $this->assertEquals("pass\npass\npass\n<!-- DUMMY var -->", $this->display('container'), "Testing assign_display($file)");
+ $this->assertEquals("pass\npass\npass\n<!-- DUMMY var -->", $this->display('container'), "Testing assign_display(\$file)");
}
public function test_append_var_without_assign_var()
@@ -445,6 +597,37 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
$this->assertEquals($expecting, $this->display('append_var'));
}
+ public function test_retrieve_data()
+ {
+ $this->template->set_filenames(array('test' => 'loop_nested.html'));
+
+ $this->template->assign_var('TEST_MORE', false);
+
+ // @todo Change this
+ $this->template->assign_vars(array('ONE' => true, 'TWO' => 'two', 'THREE' => 3));
+ $this->template->assign_block_vars('outer', array('POSITION' => 'O1'));
+ $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O1M1'));
+ $this->template->assign_block_vars('outer', array('POSITION' => 'O2'));
+ $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O2M1'));
+ $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O2M2'));
+ $this->template->assign_block_vars('outer', array('POSITION' => 'O3'));
+ $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O3M1'));
+ $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O3M2', 'ONE' => true, 'TWO' => 'two', 'THREE' => 3));
+ $this->template->assign_block_vars('outer.middle', array('POSITION' => 'O3M3'));
+
+ $expect = 'outer - 0middle - 0outer - 1middle - 0middle - 1outer - 2middle - 0middle - 1middle - 2';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
+
+ $this->assertEquals(true, $this->template->retrieve_var('ONE'), 'Retrieve a single value from the template');
+ $this->assertEquals(null, $this->template->retrieve_var('FOUR'), 'Retrieve a non_existent value from the template');
+ $this->assertEquals(array('TWO' => 'two', 'THREE' => 3, 'FOUR' => null), $this->template->retrieve_vars(array('TWO','THREE', 'FOUR')), 'Retrieve several variables from the template');
+
+ $this->assertEquals(array('POSITION' => 'O3', 'SIZE' => null), $this->template->retrieve_block_vars('outer', array('POSITION', 'SIZE')), 'Retrieve vars from a block in the template');
+ $this->assertEquals(array('POSITION' => 'O2M1'), $this->template->retrieve_block_vars('outer[1].middle[0]', array('POSITION')), 'Retrieve single var from a nested indexed block in the template');
+ $this->assertEquals(array('S_ROW_NUM' => 2), $this->template->retrieve_block_vars('outer.middle', array('S_ROW_NUM')), 'Retrieve automatic var from a block in the template');
+ $this->assertEquals(array('POSITION' => 'O3M2', 'ONE' => true, 'TWO' => 'two', 'THREE' => 3), $this->template->retrieve_block_vars('outer[2].middle[1]', array()), 'Retrieve all vars from a block in the template');
+ }
+
public function test_php()
{
global $phpbb_root_path;
@@ -767,6 +950,95 @@ EOT
$this->assertEquals(false, $this->template->find_key_index('outer.wrong', true), 'Wrong middle block name');
$this->assertEquals(false, $this->template->find_key_index('wrong.middle', false), 'Wrong outer block name');
}
+
+ public function test_delete_alter_block_array()
+ {
+ $this->template->set_filenames(array('test' => 'loop_nested.html'));
+
+ $this->template->assign_var('TEST_MORE', true);
+
+ // @todo Change this
+ $this->template->assign_block_vars('outer', array('VARIABLE' => 'zero'));
+ $this->template->assign_block_vars('outer', array('VARIABLE' => 'one'));
+ $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '1A'));
+ $this->template->assign_block_vars('outer', array('VARIABLE' => 'two'));
+ $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2A'));
+ $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2B'));
+ $this->template->assign_block_vars('outer', array('VARIABLE' => 'three'));
+ $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3A'));
+ $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3B'));
+ $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3C'));
+
+ $expect = 'outer - 0 - zero[outer|4]outer - 1 - one[outer|4]middle - 0 - 1A[middle|1]outer - 2 - two[outer|4]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 3 - three[outer|4]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
+
+ $this->template->alter_block_array('outer', array(), false, 'delete');
+
+ $expect = 'outer - 0 - one[outer|3]middle - 0 - 1A[middle|1]outer - 1 - two[outer|3]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 2 - three[outer|3]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting at the beginning of outer loop');
+
+ $this->template->alter_block_array('outer[0].middle', array(), true, 'delete');
+
+ $expect = 'outer - 0 - one[outer|3]outer - 1 - two[outer|3]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 2 - three[outer|3]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting at the end of first middle loop, delete complete loop');
+
+ $this->template->alter_block_array('outer', array(), 1, 'delete');
+
+ $expect = 'outer - 0 - one[outer|2]outer - 1 - three[outer|2]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting by index at top level');
+
+ $this->template->alter_block_array('outer.middle', array(), 1, 'delete');
+
+ $expect = 'outer - 0 - one[outer|2]outer - 1 - three[outer|2]middle - 0 - 3A[middle|2]middle - 1 - 3C[middle|2]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting by index at middle level');
+
+ $this->template->alter_block_array('outer', array(), 4, 'delete');
+
+ $expect = 'outer - 0 - one[outer|2]outer - 1 - three[outer|2]middle - 0 - 3A[middle|2]middle - 1 - 3C[middle|2]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Deleting by index out of bounds, ignored');
+ }
+
+ public function test_indexed_assign_block_vars()
+ {
+ $this->template->set_filenames(array('test' => 'loop_nested.html'));
+
+ $this->template->assign_var('TEST_MORE', true);
+
+ // @todo Change this
+ $this->template->assign_block_vars('outer', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer.middle', array());
+ $this->template->assign_block_vars('outer.middle', array());
+
+ $expect = 'outer - 0[outer|3]middle - 0[middle|1]outer - 1[outer|3]middle - 0[middle|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification');
+
+ $this->template->assign_block_vars('outer[0].middle', array('VARIABLE' => 'test'));
+
+ $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Inserting at the first outer block');
+
+ $this->template->assign_block_vars('outer[1].middle[0].inner', array());
+
+ $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]inner - 0[inner|1]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Creating an inner block at the first middle block in the second outer block');
+
+ $this->template->assign_block_vars('outer[1].middle[0].inner', array());
+
+ $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]inner - 0[inner|2]inner - 1[inner|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]middle - 2[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Inserting another inner block in the same place');
+
+ $this->template->assign_block_vars('outer.middle[1].inner', array('VARIABLE' => 'test'));
+
+ $expect = 'outer - 0[outer|3]middle - 0[middle|2]middle - 1 - test[middle|2]outer - 1[outer|3]middle - 0[middle|2]inner - 0[inner|2]inner - 1[inner|2]middle - 1[middle|2]outer - 2[outer|3]middle - 0[middle|3]middle - 1[middle|3]inner - 0 - test[inner|1]middle - 2[middle|3]';
+ $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Inserting another inner block in the same place');
+ }
+
public function assign_block_vars_array_data()
{
return array(
diff --git a/tests/template/template_test_case.php b/tests/template/template_test_case.php
index 1250397401..8adbafb1b2 100644
--- a/tests/template/template_test_case.php
+++ b/tests/template/template_test_case.php
@@ -11,10 +11,9 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_template_template_test_case extends phpbb_test_case
{
+ protected $lang;
protected $template;
protected $template_path;
protected $user;
@@ -24,6 +23,17 @@ class phpbb_template_template_test_case extends phpbb_test_case
// Keep the contents of the cache for debugging?
const PRESERVE_CACHE = true;
+ static protected $language_reflection_lang;
+
+ static public function setUpBeforeClass()
+ {
+ parent::setUpBeforeClass();
+
+ $reflection = new ReflectionClass('\phpbb\language\language');
+ self::$language_reflection_lang = $reflection->getProperty('lang');
+ self::$language_reflection_lang->setAccessible(true);
+ }
+
protected function display($handle)
{
ob_start();
@@ -65,20 +75,46 @@ class phpbb_template_template_test_case extends phpbb_test_case
$defaults = $this->config_defaults();
$config = new \phpbb\config\config(array_merge($defaults, $new_config));
- $this->user = new \phpbb\user('\phpbb\datetime');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $this->lang = $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $this->user = $user;
+
+ $filesystem = new \phpbb\filesystem\filesystem();
$path_helper = new \phpbb\path_helper(
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ $filesystem,
$this->getMock('\phpbb\request\request'),
$phpbb_root_path,
$phpEx
);
$this->template_path = $this->test_path . '/templates';
- $this->template = new \phpbb\template\twig\twig($path_helper, $config, $this->user, new \phpbb\template\context());
+
+ $container = new phpbb_mock_container_builder();
+ $cache_path = $phpbb_root_path . 'cache/twig';
+ $context = new \phpbb\template\context();
+ $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), '');
+ $twig = new \phpbb\template\twig\environment(
+ $config,
+ $filesystem,
+ $path_helper,
+ $cache_path,
+ null,
+ $loader,
+ new \phpbb\event\dispatcher($container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
+ );
+ $this->template = new phpbb\template\twig\twig($path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)));
+ $twig->setLexer(new \phpbb\template\twig\lexer($twig));
$this->template->set_custom_style('tests', $this->template_path);
}
@@ -88,6 +124,10 @@ class phpbb_template_template_test_case extends phpbb_test_case
$this->setup_engine();
$this->template->clear_cache();
+
+ global $phpbb_filesystem;
+
+ $phpbb_filesystem = new \phpbb\filesystem\filesystem();
}
protected function tearDown()
@@ -121,12 +161,16 @@ class phpbb_template_template_test_case extends phpbb_test_case
{
foreach ($lang_vars as $name => $value)
{
- $this->user->lang[$name] = $value;
+ self::$language_reflection_lang->setValue($this->lang, array_merge(
+ self::$language_reflection_lang->getValue($this->lang),
+ array($name => $value)
+ ));
}
}
$expected = str_replace(array("\n", "\r", "\t"), '', $expected);
$output = str_replace(array("\n", "\r", "\t"), '', $this->display('test'));
+
$this->assertEquals($expected, $output, "Testing $file");
}
}
diff --git a/tests/template/template_test_case_with_tree.php b/tests/template/template_test_case_with_tree.php
index 68ecc4b706..75e3918f44 100644
--- a/tests/template/template_test_case_with_tree.php
+++ b/tests/template/template_test_case_with_tree.php
@@ -22,11 +22,13 @@ class phpbb_template_template_test_case_with_tree extends phpbb_template_templat
$defaults = $this->config_defaults();
$config = new \phpbb\config\config(array_merge($defaults, $new_config));
+ $filesystem = new \phpbb\filesystem\filesystem();
+
$this->phpbb_path_helper = new \phpbb\path_helper(
new \phpbb\symfony_request(
new phpbb_mock_request()
),
- new \phpbb\filesystem(),
+ $filesystem,
$this->getMock('\phpbb\request\request'),
$phpbb_root_path,
$phpEx
@@ -34,7 +36,28 @@ class phpbb_template_template_test_case_with_tree extends phpbb_template_templat
$this->template_path = $this->test_path . '/templates';
$this->parent_template_path = $this->test_path . '/parent_templates';
- $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $config, $user, new phpbb\template\context());
+
+ $container = new phpbb_mock_container_builder();
+ $cache_path = $phpbb_root_path . 'cache/twig';
+ $context = new \phpbb\template\context();
+ $loader = new \phpbb\template\twig\loader(new \phpbb\filesystem\filesystem(), '');
+ $twig = new \phpbb\template\twig\environment(
+ $config,
+ $filesystem,
+ $this->phpbb_path_helper,
+ $cache_path,
+ null,
+ $loader,
+ new \phpbb\event\dispatcher($container),
+ array(
+ 'cache' => false,
+ 'debug' => false,
+ 'auto_reload' => true,
+ 'autoescape' => false,
+ )
+ );
+ $this->template = new phpbb\template\twig\twig($this->phpbb_path_helper, $config, $context, $twig, $cache_path, $this->user, array(new \phpbb\template\twig\extension($context, $this->user)));
+ $twig->setLexer(new \phpbb\template\twig\lexer($twig));
$this->template->set_custom_style('tests', array($this->template_path, $this->parent_template_path));
}
}
diff --git a/tests/template/templates/loop_advanced_twig.html b/tests/template/templates/loop_advanced_twig.html
new file mode 100644
index 0000000000..fd9fcae045
--- /dev/null
+++ b/tests/template/templates/loop_advanced_twig.html
@@ -0,0 +1,19 @@
+{% for test_loop_inner in test_loop %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(0) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(0,-1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(1,1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(0,1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(2,4) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(0,-7) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(-2,6) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
+x
+{% for test_loop_inner in test_loop|subset(-2,-1) %}{{ test_loop_inner.S_FIRST_ROW }}{{ test_loop_inner.S_ROW_COUNT }}{{ test_loop_inner.S_LAST_ROW }}{% endfor %}
diff --git a/tests/template/templates/loop_expressions.html b/tests/template/templates/loop_expressions.html
index 6bff53f388..ddb9fd52fa 100644
--- a/tests/template/templates/loop_expressions.html
+++ b/tests/template/templates/loop_expressions.html
@@ -1,11 +1,11 @@
<!-- BEGIN loop -->
-<!-- IF loop.S_ROW_NUM is even by 4 -->on<!-- ELSE -->off<!-- ENDIF -->
+<!-- IF loop.S_ROW_NUM is divisible by(4) -->yes<!-- ELSE -->no<!-- ENDIF -->
<!-- END loop -->
<!-- BEGIN loop -->
-<!-- IF loop.S_ROW_NUM is odd by 3 -->on<!-- ELSE -->off<!-- ENDIF -->
+<!-- IF loop.S_ROW_NUM is divisible by(3) -->yes<!-- ELSE -->no<!-- ENDIF -->
<!-- END loop -->
diff --git a/tests/template/templates/loop_expressions_twig.html b/tests/template/templates/loop_expressions_twig.html
new file mode 100644
index 0000000000..5ca8cc3601
--- /dev/null
+++ b/tests/template/templates/loop_expressions_twig.html
@@ -0,0 +1,11 @@
+{% for loop_inner in loop %}
+
+{% if loop_inner.S_ROW_NUM is divisible by(4) %}yes{% else %}no{% endif %}
+
+{% endfor %}
+
+{% for loop_inner in loop %}
+
+{% if loop_inner.S_ROW_NUM is divisible by(3) %}yes{% else %}no{% endif %}
+
+{% endfor %}
diff --git a/tests/template/templates/loop_expressions_twig2.html b/tests/template/templates/loop_expressions_twig2.html
new file mode 100644
index 0000000000..16159ead4c
--- /dev/null
+++ b/tests/template/templates/loop_expressions_twig2.html
@@ -0,0 +1,11 @@
+{% for loop_inner in loop %}
+
+{% if loop.index0 is divisible by(4) %}yes{% else %}no{% endif %}
+
+{% endfor %}
+
+{% for loop_inner in loop %}
+
+{% if loop.index0 is divisible by(3) %}yes{% else %}no{% endif %}
+
+{% endfor %}
diff --git a/tests/template/templates/loop_include1_twig.html b/tests/template/templates/loop_include1_twig.html
new file mode 100644
index 0000000000..2ff9f61b02
--- /dev/null
+++ b/tests/template/templates/loop_include1_twig.html
@@ -0,0 +1 @@
+{{ test_loop_inner.foo }}
diff --git a/tests/template/templates/loop_include_twig.html b/tests/template/templates/loop_include_twig.html
new file mode 100644
index 0000000000..1a534e2dbc
--- /dev/null
+++ b/tests/template/templates/loop_include_twig.html
@@ -0,0 +1,4 @@
+{% for test_loop_inner in test_loop %}
+ {{ test_loop_inner.foo }}
+ {% INCLUDE 'loop_include1_twig.html' %}
+{% endfor %}
diff --git a/tests/template/templates/loop_nested.html b/tests/template/templates/loop_nested.html
index cf099ecc15..5763262781 100644
--- a/tests/template/templates/loop_nested.html
+++ b/tests/template/templates/loop_nested.html
@@ -2,5 +2,8 @@
outer - {outer.S_ROW_COUNT}<!-- IF outer.VARIABLE --> - {outer.VARIABLE}<!-- ENDIF --><!-- IF TEST_MORE -->[{outer.S_BLOCK_NAME}|{outer.S_NUM_ROWS}]<!-- ENDIF -->
<!-- BEGIN middle -->
middle - {outer.middle.S_ROW_COUNT}<!-- IF outer.middle.VARIABLE --> - {outer.middle.VARIABLE}<!-- ENDIF --><!-- IF TEST_MORE -->[{outer.middle.S_BLOCK_NAME}|{outer.middle.S_NUM_ROWS}]<!-- ENDIF -->
+<!-- BEGIN inner -->
+inner - {outer.middle.inner.S_ROW_COUNT}<!-- IF outer.middle.inner.VARIABLE --> - {outer.middle.inner.VARIABLE}<!-- ENDIF --><!-- IF TEST_MORE -->[{outer.middle.inner.S_BLOCK_NAME}|{outer.middle.inner.S_NUM_ROWS}]<!-- ENDIF -->
+<!-- END inner -->
<!-- END middle -->
<!-- END outer -->
diff --git a/tests/template/templates/loop_nested2_twig.html b/tests/template/templates/loop_nested2_twig.html
new file mode 100644
index 0000000000..cf802dc69f
--- /dev/null
+++ b/tests/template/templates/loop_nested2_twig.html
@@ -0,0 +1,6 @@
+{% for outer_inner in outer %}
+ o{{ outer_inner.S_ROW_COUNT }}
+ {% for middle in outer_inner.middle %}
+ m{{ middle.S_ROW_COUNT }}{{ outer_inner.S_ROW_COUNT }}
+ {% endfor %}
+{% endfor %}
diff --git a/tests/template/templates/loop_nested_deep_multilevel_ref_twig.html b/tests/template/templates/loop_nested_deep_multilevel_ref_twig.html
new file mode 100644
index 0000000000..9bc68e6e2e
--- /dev/null
+++ b/tests/template/templates/loop_nested_deep_multilevel_ref_twig.html
@@ -0,0 +1,13 @@
+top-level content
+{% for outer_inner in outer %}
+ outer
+ {% for middle in outer_inner.middle %}
+ {{ middle.S_BLOCK_NAME }}
+ {% for inner in middle.inner %}
+ inner {{ inner.VARIABLE }}
+ {% if inner.S_FIRST_ROW %}
+ first row of {{ inner.S_NUM_ROWS }} in {{ inner.S_BLOCK_NAME }}
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+{% endfor %}
diff --git a/tests/template/templates/loop_nested_include1_twig.html b/tests/template/templates/loop_nested_include1_twig.html
new file mode 100644
index 0000000000..4c2ebb5f15
--- /dev/null
+++ b/tests/template/templates/loop_nested_include1_twig.html
@@ -0,0 +1,5 @@
+[{{ test_loop_inner.foo }}|
+{% for inner in test_loop_inner.inner %}
+ [{{ test_loop_inner.foo }}|
+ {{ inner.myinner }}]
+{% endfor %}]
diff --git a/tests/template/templates/loop_nested_include_twig.html b/tests/template/templates/loop_nested_include_twig.html
new file mode 100644
index 0000000000..c92ac922d1
--- /dev/null
+++ b/tests/template/templates/loop_nested_include_twig.html
@@ -0,0 +1,4 @@
+{% for test_loop_inner in test_loop %}
+ [{{ test_loop_inner.foo }}
+ |{% INCLUDE 'loop_nested_include1_twig.html' %}]
+{% endfor %}
diff --git a/tests/template/templates/loop_nested_multilevel_ref_twig.html b/tests/template/templates/loop_nested_multilevel_ref_twig.html
new file mode 100644
index 0000000000..336a57d0bc
--- /dev/null
+++ b/tests/template/templates/loop_nested_multilevel_ref_twig.html
@@ -0,0 +1,10 @@
+top-level content
+{% for outer_inner in outer %}
+ outer {{ outer_inner.VARIABLE }}
+ {% for inner in outer_inner.inner %}
+ inner {{ inner.VARIABLE }}
+ {% if inner.S_FIRST_ROW %}
+ first row
+ {% endif %}
+ {% endfor %}
+{% endfor %}
diff --git a/tests/template/templates/loop_nested_twig.html b/tests/template/templates/loop_nested_twig.html
new file mode 100644
index 0000000000..b294226b3a
--- /dev/null
+++ b/tests/template/templates/loop_nested_twig.html
@@ -0,0 +1,6 @@
+{% for outer_inner in outer %}
+outer - {{ outer_inner.S_ROW_COUNT }}{% if outer_inner.VARIABLE %} - {{ outer_inner.VARIABLE }}{% endif %}{% if TEST_MORE %}[{{ outer_inner.S_BLOCK_NAME }}|{{ outer_inner.S_NUM_ROWS }}]{% endif %}
+{% for middle in outer_inner.middle %}
+middle - {{ middle.S_ROW_COUNT }}{% if middle.VARIABLE %} - {{ middle.VARIABLE }}{% endif %}{% if TEST_MORE %}[{{ middle.S_BLOCK_NAME }}|{{ middle.S_NUM_ROWS }}]{% endif %}
+{% endfor %}
+{% endfor %}
diff --git a/tests/template/templates/loop_reuse_twig.html b/tests/template/templates/loop_reuse_twig.html
new file mode 100644
index 0000000000..67452a737f
--- /dev/null
+++ b/tests/template/templates/loop_reuse_twig.html
@@ -0,0 +1,6 @@
+{% for one_inner in one %}
+ {{ one_inner.VAR }}
+ {% for one_one_inner in one_inner.one %}
+ {{ one_one_inner.VAR }}
+ {% endfor %}
+{% endfor %}
diff --git a/tests/template/templates/loop_size_twig.html b/tests/template/templates/loop_size_twig.html
new file mode 100644
index 0000000000..f6d2571e11
--- /dev/null
+++ b/tests/template/templates/loop_size_twig.html
@@ -0,0 +1,39 @@
+{% if nonexistent_loop|length %}
+nonexistent
+{% endif %}
+
+{% if nonexistent_loop|length == 0 %}
+nonexistent = 0
+{% endif %}
+
+{% if ! nonexistent_loop|length %}
+! nonexistent
+{% endif %}
+
+{% if empty_loop|length %}
+empty
+{% endif %}
+
+{% if empty_loop|length == 0 %}
+empty = 0
+{% endif %}
+
+{% if ! empty_loop|length %}
+! empty
+{% endif %}
+
+{% if test_loop|length %}
+loop
+{% endif %}
+
+{% if test_loop|length == 0 %}
+loop = 0
+{% endif %}
+
+{% if ! test_loop|length %}
+! loop
+{% endif %}
+
+{% for test_loop_inner in test_loop %}
+in loop
+{% endfor %}
diff --git a/tests/template/templates/loop_twig.html b/tests/template/templates/loop_twig.html
new file mode 100644
index 0000000000..fb24f331b3
--- /dev/null
+++ b/tests/template/templates/loop_twig.html
@@ -0,0 +1,21 @@
+{% for test_loop_inner in test_loop %}
+loop
+{% else %}
+noloop
+{% endfor %}
+
+{% if test_loop|length %}
+loop
+{% else %}
+noloop
+{% endif %}
+
+{% if test_loop|length == 2 %}
+loop
+{% endif %}
+
+{% for test_loop_inner in test_loop %}
+{% for block_inner in block %}
+loop#{{ test_loop_inner.S_ROW_COUNT }}-block#{{ block_inner.S_ROW_COUNT }}
+{% endfor %}
+{% endfor %}
diff --git a/tests/template/templates/loop_underscore_twig.html b/tests/template/templates/loop_underscore_twig.html
new file mode 100644
index 0000000000..44b095c882
--- /dev/null
+++ b/tests/template/templates/loop_underscore_twig.html
@@ -0,0 +1,21 @@
+{% for _underscore_loop_inner in _underscore_loop %}
+loop
+{% else %}
+noloop
+{% endfor %}
+
+{% if _underscore_loop|length %}
+loop
+{% else %}
+noloop
+{% endif %}
+
+{% if _underscore_loop|length == 2 %}
+loop
+{% endif %}
+
+{% for _underscore_loop_inner in _underscore_loop %}
+{% for block_inner in block %}
+loop#{{ loop.S_ROW_COUNT }}-block#{{ block_inner.S_ROW_COUNT }}
+{% endfor %}
+{% endfor %}
diff --git a/tests/template/templates/loop_vars_twig.html b/tests/template/templates/loop_vars_twig.html
new file mode 100644
index 0000000000..af6c63d8e3
--- /dev/null
+++ b/tests/template/templates/loop_vars_twig.html
@@ -0,0 +1,13 @@
+{% for test_loop_inner in test_loop %}
+{% if test_loop_inner.S_FIRST_ROW %}first{% endif %}
+{{ test_loop_inner.S_ROW_NUM }} - a
+{{ test_loop_inner.VARIABLE }} - b
+{% if test_loop_inner.VARIABLE %}set{% endif %}
+{% if test_loop_inner.S_LAST_ROW %}
+last
+{% endif %}
+{% for inner_inner in test_loop_inner.inner %}
+{{ inner_inner.S_ROW_NUM }} - c
+{% if inner_inner.S_LAST_ROW and inner_inner.S_ROW_COUNT and inner_inner.S_NUM_ROWS %}last inner{% endif %}
+{% endfor %}
+{% endfor %}
diff --git a/tests/test_framework/mock/phpbb_mock_null_installer_task.php b/tests/test_framework/mock/phpbb_mock_null_installer_task.php
new file mode 100644
index 0000000000..c1b880d967
--- /dev/null
+++ b/tests/test_framework/mock/phpbb_mock_null_installer_task.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_mock_null_installer_task extends \phpbb\install\task_base
+{
+ public function run()
+ {
+
+ }
+
+ static public function get_step_count()
+ {
+ return 0;
+ }
+
+ public function get_task_lang_name()
+ {
+ return '';
+ }
+}
diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php
index fc1a3632f4..606c40a623 100644
--- a/tests/test_framework/phpbb_database_test_case.php
+++ b/tests/test_framework/phpbb_database_test_case.php
@@ -58,7 +58,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
$setup_extensions = static::setup_extensions();
- $finder = new \phpbb\finder(new \phpbb\filesystem(), $phpbb_root_path, null, $phpEx);
+ $finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), $phpbb_root_path, null, $phpEx);
$finder->core_path('phpbb/db/migration/data/');
if (!empty($setup_extensions))
{
@@ -76,8 +76,11 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
global $table_prefix;
- $db = new \phpbb\db\driver\sqlite();
- $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, new \phpbb\db\tools($db, true), $phpbb_root_path, $phpEx, $table_prefix);
+ $db = new \phpbb\db\driver\sqlite3();
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($db, true);
+
+ $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, $db_tools, $phpbb_root_path, $phpEx, $table_prefix);
file_put_contents(self::$schema_file, json_encode($schema_generator->get_schema()));
}
@@ -139,9 +142,86 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
$manager->database_synchronisation($table_column_map);
}
+ /**
+ * Create xml data set for insertion into database
+ *
+ * @param string $path Path to fixture XML
+ * @return PHPUnit_Extensions_Database_DataSet_DefaultDataSet|PHPUnit_Extensions_Database_DataSet_XmlDataSet
+ */
public function createXMLDataSet($path)
{
$this->fixture_xml_data = parent::createXMLDataSet($path);
+
+ // Extend XML data set on MSSQL
+ if (strpos($this->get_database_config()['dbms'], 'mssql') !== false)
+ {
+ $newXmlData = new PHPUnit_Extensions_Database_DataSet_DefaultDataSet();
+ $db = $this->new_dbal();
+ foreach ($this->fixture_xml_data as $key => $value)
+ {
+ /** @var \PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData $tableMetaData */
+ $tableMetaData = $value->getTableMetaData();
+ $columns = $tableMetaData->getColumns();
+ $primaryKeys = $tableMetaData->getPrimaryKeys();
+
+ $sql = "SELECT COLUMN_NAME AS identity_column
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE COLUMNPROPERTY(object_id(TABLE_SCHEMA + '.' + TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
+ AND TABLE_NAME = '$key'
+ ORDER BY TABLE_NAME";
+ $result = $db->sql_query($sql);
+ $identity_columns = $db->sql_fetchrowset($result);
+ $has_default_identity = false;
+ $add_primary_keys = false;
+
+ // Iterate over identity columns to check for missing primary
+ // keys in data set and special identity column 'mssqlindex'
+ // that might have been added when no default identity column
+ // exists in the current table.
+ foreach ($identity_columns as $column)
+ {
+ if (in_array($column['identity_column'], $columns) && !in_array($column['identity_column'], $primaryKeys))
+ {
+ $primaryKeys[] = $column['identity_column'];
+ $add_primary_keys = true;
+ }
+
+ if ($column['identity_column'] === 'mssqlindex')
+ {
+ $has_default_identity = true;
+ break;
+ }
+ }
+
+ if ($has_default_identity || $add_primary_keys)
+ {
+ // Add default identity column to columns list
+ if ($has_default_identity)
+ {
+ $columns[] = 'mssqlindex';
+ }
+
+ $newMetaData = new PHPUnit_Extensions_Database_DataSet_DefaultTableMetaData($key, $columns, $primaryKeys);
+ $newTable = new PHPUnit_Extensions_Database_DataSet_DefaultTable($newMetaData);
+ for ($i = 0; $i < $value->getRowCount(); $i++)
+ {
+ $dataRow = $value->getRow($i);
+ if ($has_default_identity)
+ {
+ $dataRow['mssqlindex'] = $i + 1;
+ }
+ $newTable->addRow($dataRow);
+ }
+ $newXmlData->addTable($newTable);
+ }
+ else
+ {
+ $newXmlData->addTable($value);
+ }
+ }
+
+ $this->fixture_xml_data = $newXmlData;
+ }
return $this->fixture_xml_data;
}
@@ -226,7 +306,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
{
// http://stackoverflow.com/questions/3838288/phpunit-assert-two-arrays-are-equal-but-order-of-elements-not-important
// but one array_diff is not enough!
- if (sizeof(array_diff($one, $two)) || sizeof(array_diff($two, $one)))
+ if (count(array_diff($one, $two)) || count(array_diff($two, $one)))
{
// get a nice error message
$this->assertEquals($one, $two);
diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php
index 3b5bab749e..f3adbefc1b 100644
--- a/tests/test_framework/phpbb_database_test_connection_manager.php
+++ b/tests/test_framework/phpbb_database_test_connection_manager.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_install.php';
require_once dirname(__FILE__) . '/phpbb_database_connection_odbc_pdo_wrapper.php';
class phpbb_database_test_connection_manager
@@ -56,7 +55,6 @@ class phpbb_database_test_connection_manager
switch ($this->dbms['PDO'])
{
- case 'sqlite2':
case 'sqlite': // SQLite3 driver
$dsn .= $this->config['dbhost'];
break;
@@ -194,7 +192,6 @@ class phpbb_database_test_connection_manager
{
switch ($this->config['dbms'])
{
- case 'phpbb\db\driver\sqlite':
case 'phpbb\db\driver\sqlite3':
$this->connect();
// Drop all of the tables
@@ -225,6 +222,14 @@ class phpbb_database_test_connection_manager
$this->purge_extras();
break;
+ case 'phpbb\db\driver\mssql':
+ case 'phpbb\db\driver\mssqlnative':
+ $this->connect();
+ // Drop all tables
+ $this->pdo->exec("EXEC sp_MSforeachtable 'DROP TABLE ?'");
+ $this->purge_extras();
+ break;
+
default:
$this->connect(false);
@@ -270,12 +275,6 @@ class phpbb_database_test_connection_manager
$sql = 'SHOW TABLES';
break;
- case 'phpbb\db\driver\sqlite':
- $sql = 'SELECT name
- FROM sqlite_master
- WHERE type = "table"';
- break;
-
case 'phpbb\db\driver\sqlite3':
$sql = 'SELECT name
FROM sqlite_master
@@ -351,10 +350,13 @@ class phpbb_database_test_connection_manager
if (file_exists($filename))
{
+ global $phpbb_root_path;
+
$queries = file_get_contents($filename);
- $sql = phpbb_remove_comments($queries);
- $sql = split_sql_file($sql, $this->dbms['DELIM']);
+ $db_helper = new \phpbb\install\helper\database(new \phpbb\filesystem\filesystem(), $phpbb_root_path);
+ $sql = $db_helper->remove_comments($queries);
+ $sql = $db_helper->split_sql_file($sql, $this->dbms['DELIM']);
foreach ($sql as $query)
{
@@ -372,16 +374,20 @@ class phpbb_database_test_connection_manager
{
global $phpbb_root_path, $phpEx, $table_prefix;
- $finder = new \phpbb\finder(new \phpbb\filesystem(), $phpbb_root_path, null, $phpEx);
+ $finder = new \phpbb\finder(new \phpbb\filesystem\filesystem(), $phpbb_root_path, null, $phpEx);
$classes = $finder->core_path('phpbb/db/migration/data/')
->get_classes();
- $db = new \phpbb\db\driver\sqlite();
- $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, new \phpbb\db\tools($db, true), $phpbb_root_path, $phpEx, $table_prefix);
+ $db = new \phpbb\db\driver\sqlite3();
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($db, true);
+
+ $schema_generator = new \phpbb\db\migration\schema_generator($classes, new \phpbb\config\config(array()), $db, $db_tools, $phpbb_root_path, $phpEx, $table_prefix);
$db_table_schema = $schema_generator->get_schema();
}
- $db_tools = new \phpbb\db\tools($db, true);
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($db, true);
foreach ($db_table_schema as $table_name => $table_data)
{
$queries = $db_tools->sql_create_table(
@@ -448,11 +454,6 @@ class phpbb_database_test_connection_manager
'DELIM' => ';',
'PDO' => 'pgsql',
),
- 'phpbb\db\driver\sqlite' => array(
- 'SCHEMA' => 'sqlite',
- 'DELIM' => ';',
- 'PDO' => 'sqlite2',
- ),
'phpbb\db\driver\sqlite3' => array(
'SCHEMA' => 'sqlite',
'DELIM' => ';',
@@ -628,7 +629,7 @@ class phpbb_database_test_connection_manager
}
// Combine all of the SETVALs into one query
- if (sizeof($setval_queries))
+ if (count($setval_queries))
{
$queries[] = 'SELECT ' . implode(', ', $setval_queries);
}
diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php
index 8107e45dc7..f1b30f0fed 100644
--- a/tests/test_framework/phpbb_functional_test_case.php
+++ b/tests/test_framework/phpbb_functional_test_case.php
@@ -12,13 +12,15 @@
*/
use Symfony\Component\BrowserKit\CookieJar;
-require_once __DIR__ . '/../../phpBB/includes/functions_install.php';
+require_once __DIR__ . '/mock/phpbb_mock_null_installer_task.php';
class phpbb_functional_test_case extends phpbb_test_case
{
+ /** @var \Goutte\Client */
static protected $client;
static protected $cookieJar;
static protected $root_url;
+ static protected $install_success = false;
protected $cache = null;
protected $db = null;
@@ -77,13 +79,15 @@ class phpbb_functional_test_case extends phpbb_test_case
{
parent::setUp();
+ if (!self::$install_success)
+ {
+ $this->fail('Installing phpBB has failed.');
+ }
+
$this->bootstrap();
self::$cookieJar = new CookieJar;
self::$client = new Goutte\Client(array(), null, self::$cookieJar);
- // Reset the curl handle because it is 0 at this point and not a valid
- // resource
- self::$client->getClient()->getCurlMulti()->reset(true);
// Clear the language array so that things
// that were added in other tests are gone
@@ -169,7 +173,7 @@ class phpbb_functional_test_case extends phpbb_test_case
*/
static public function get_content()
{
- return self::$client->getResponse()->getContent();
+ return (string) self::$client->getResponse()->getContent();
}
// bootstrap, called after board is set up
@@ -205,6 +209,12 @@ class phpbb_functional_test_case extends phpbb_test_case
{
if (!$this->cache)
{
+ global $phpbb_container, $phpbb_root_path;
+
+ $phpbb_container = new phpbb_mock_container_builder();
+ $phpbb_container->setParameter('core.environment', PHPBB_ENVIRONMENT);
+ $phpbb_container->setParameter('core.cache_dir', $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/');
+
$this->cache = new \phpbb\cache\driver\file;
}
@@ -226,7 +236,8 @@ class phpbb_functional_test_case extends phpbb_test_case
$config = new \phpbb\config\config(array());
$db = $this->get_db();
- $db_tools = new \phpbb\db\tools($db);
+ $factory = new \phpbb\db\tools\factory();
+ $db_tools = $factory->get($db);
$container = new phpbb_mock_container_builder();
$migrator = new \phpbb\db\migrator(
@@ -243,18 +254,16 @@ class phpbb_functional_test_case extends phpbb_test_case
);
$container->set('migrator', $migrator);
$container->set('dispatcher', new phpbb_mock_event_dispatcher());
- $user = new \phpbb\user('\phpbb\datetime');
$extension_manager = new \phpbb\extension\manager(
$container,
$db,
$config,
- new phpbb\filesystem(),
- $user,
+ new phpbb\filesystem\filesystem(),
self::$config['table_prefix'] . 'ext',
dirname(__FILE__) . '/',
$phpEx,
- $this->get_cache_driver()
+ new \phpbb\cache\service($this->get_cache_driver(), $config, $this->db, $phpbb_root_path, $phpEx)
);
return $extension_manager;
@@ -282,120 +291,129 @@ class phpbb_functional_test_case extends phpbb_test_case
}
}
- self::$cookieJar = new CookieJar;
- self::$client = new Goutte\Client(array(), null, self::$cookieJar);
- // Set client manually so we can increase the cURL timeout
- self::$client->setClient(new Guzzle\Http\Client('', array(
- Guzzle\Http\Client::DISABLE_REDIRECTS => true,
- 'curl.options' => array(
- CURLOPT_TIMEOUT => 120,
- ),
- )));
-
- // Reset the curl handle because it is 0 at this point and not a valid
- // resource
- self::$client->getClient()->getCurlMulti()->reset(true);
+ $install_config_file = $phpbb_root_path . 'store/install_config.php';
- $parseURL = parse_url(self::$config['phpbb_functional_url']);
+ if (file_exists($install_config_file))
+ {
+ unlink($install_config_file);
+ }
- $crawler = self::request('GET', 'install/index.php?mode=install&language=en');
- self::assertContains('Welcome to Installation', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form();
+ $container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+ $container = $container_builder
+ ->with_environment('installer')
+ ->without_extensions()
+ ->without_cache()
+ ->with_custom_parameters([
+ 'core.disable_super_globals' => false,
+ 'installer.create_config_file.options' => [
+ 'debug' => true,
+ 'environment' => 'test',
+ ],
+ 'cache.driver.class' => 'phpbb\cache\driver\file'
+ ])
+ ->with_config(new \phpbb\config_php_file($phpbb_root_path, $phpEx))
+ ->without_compiled_container()
+ ->get_container();
+
+ $container->register('installer.install_finish.notify_user')->setSynthetic(true);
+ $container->set('installer.install_finish.notify_user', new phpbb_mock_null_installer_task());
+ $container->register('installer.install_finish.install_extensions')->setSynthetic(true);
+ $container->set('installer.install_finish.install_extensions', new phpbb_mock_null_installer_task());
+ $container->compile();
+
+ $language = $container->get('language');
+ $language->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
+
+ $iohandler_factory = $container->get('installer.helper.iohandler_factory');
+ $iohandler_factory->set_environment('cli');
+ $iohandler = $iohandler_factory->get();
- // install/index.php?mode=install&sub=requirements
- $crawler = self::submit($form);
- self::assertContains('Installation compatibility', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form();
+ $parseURL = parse_url(self::$config['phpbb_functional_url']);
- // install/index.php?mode=install&sub=database
- $crawler = self::submit($form);
- self::assertContains('Database configuration', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form(array(
- // Installer uses 3.0-style dbms name
- 'dbms' => str_replace('phpbb\db\driver\\', '', self::$config['dbms']),
- 'dbhost' => self::$config['dbhost'],
- 'dbport' => self::$config['dbport'],
- 'dbname' => self::$config['dbname'],
- 'dbuser' => self::$config['dbuser'],
- 'dbpasswd' => self::$config['dbpasswd'],
- 'table_prefix' => self::$config['table_prefix'],
- ));
+ $output = new \Symfony\Component\Console\Output\NullOutput();
+ $style = new \Symfony\Component\Console\Style\SymfonyStyle(
+ new \Symfony\Component\Console\Input\ArrayInput(array()),
+ $output
+ );
+ $iohandler->set_style($style, $output);
+
+ $installer = $container->get('installer.installer.install');
+ $installer->set_iohandler($iohandler);
+
+ // Set data
+ $iohandler->set_input('admin_name', 'admin');
+ $iohandler->set_input('admin_pass1', 'adminadmin');
+ $iohandler->set_input('admin_pass2', 'adminadmin');
+ $iohandler->set_input('board_email', 'nobody@example.com');
+ $iohandler->set_input('submit_admin', 'submit');
+
+ $iohandler->set_input('default_lang', 'en');
+ $iohandler->set_input('board_name', 'yourdomain.com');
+ $iohandler->set_input('board_description', 'A short text to describe your forum');
+ $iohandler->set_input('submit_board', 'submit');
+
+ $iohandler->set_input('dbms', str_replace('phpbb\db\driver\\', '', self::$config['dbms']));
+ $iohandler->set_input('dbhost', self::$config['dbhost']);
+ $iohandler->set_input('dbport', self::$config['dbport']);
+ $iohandler->set_input('dbuser', self::$config['dbuser']);
+ $iohandler->set_input('dbpasswd', self::$config['dbpasswd']);
+ $iohandler->set_input('dbname', self::$config['dbname']);
+ $iohandler->set_input('table_prefix', self::$config['table_prefix']);
+ $iohandler->set_input('submit_database', 'submit');
+
+ $iohandler->set_input('email_enable', true);
+ $iohandler->set_input('smtp_delivery', '1');
+ $iohandler->set_input('smtp_host', 'nxdomain.phpbb.com');
+ $iohandler->set_input('smtp_auth', 'PLAIN');
+ $iohandler->set_input('smtp_user', 'nxuser');
+ $iohandler->set_input('smtp_pass', 'nxpass');
+ $iohandler->set_input('submit_email', 'submit');
+
+ $iohandler->set_input('cookie_secure', '0');
+ $iohandler->set_input('server_protocol', '0');
+ $iohandler->set_input('force_server_vars', $parseURL['scheme'] . '://');
+ $iohandler->set_input('server_name', $parseURL['host']);
+ $iohandler->set_input('server_port', isset($parseURL['port']) ? (int) $parseURL['port'] : 80);
+ $iohandler->set_input('script_path', $parseURL['path']);
+ $iohandler->set_input('submit_server', 'submit');
+
+ $installer->run();
- // install/index.php?mode=install&sub=database
- $crawler = self::submit($form);
- self::assertContains('Successful connection', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form();
+ copy($config_file, $config_file_test);
- // install/index.php?mode=install&sub=administrator
- $crawler = self::submit($form);
- self::assertContains('Administrator configuration', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form(array(
- 'default_lang' => 'en',
- 'admin_name' => 'admin',
- 'admin_pass1' => 'adminadmin',
- 'admin_pass2' => 'adminadmin',
- 'board_email' => 'nobody@example.com',
- ));
+ self::$install_success = true;
- // install/index.php?mode=install&sub=administrator
- $crawler = self::submit($form);
- self::assertContains('Tests passed', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form();
-
- // We have to skip install/index.php?mode=install&sub=config_file
- // because that step will create a config.php file if phpBB has the
- // permission to do so. We have to create the config file on our own
- // in order to get the DEBUG constants defined.
- $config_php_data = phpbb_create_config_file_data(self::$config, self::$config['dbms'], true, false, true);
- $config_created = file_put_contents($config_file, $config_php_data) !== false;
- if (!$config_created)
+ if (file_exists($phpbb_root_path . 'store/install_config.php'))
{
- self::markTestSkipped("Could not write $config_file file.");
+ self::$install_success = false;
+ @unlink($phpbb_root_path . 'store/install_config.php');
}
- // We also have to create a install lock that is normally created by
- // the installer. The file will be removed by the final step of the
- // installer.
- $install_lock_file = $phpbb_root_path . 'cache/install_lock';
- $lock_created = file_put_contents($install_lock_file, '') !== false;
- if (!$lock_created)
+ if (file_exists($phpbb_root_path . 'cache/install_lock'))
{
- self::markTestSkipped("Could not create $lock_created file.");
+ @unlink($phpbb_root_path . 'cache/install_lock');
}
- @chmod($install_lock_file, 0666);
-
- // install/index.php?mode=install&sub=advanced
- $form_data = $form->getValues();
- unset($form_data['submit']);
-
- $crawler = self::request('POST', 'install/index.php?mode=install&sub=advanced', $form_data);
- self::assertContains('The settings on this page are only necessary to set if you know that you require something different from the default.', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form(array(
- 'email_enable' => true,
- 'smtp_delivery' => true,
- 'smtp_host' => 'nxdomain.phpbb.com',
- 'smtp_auth' => 'PLAIN',
- 'smtp_user' => 'nxuser',
- 'smtp_pass' => 'nxpass',
- 'cookie_secure' => false,
- 'force_server_vars' => false,
- 'server_protocol' => $parseURL['scheme'] . '://',
- 'server_name' => 'localhost',
- 'server_port' => isset($parseURL['port']) ? (int) $parseURL['port'] : 80,
- 'script_path' => $parseURL['path'],
- ));
- // install/index.php?mode=install&sub=create_table
- $crawler = self::submit($form);
- self::assertContains('The database tables used by phpBB', $crawler->filter('#main')->text());
- self::assertContains('have been created and populated with some initial data.', $crawler->filter('#main')->text());
- $form = $crawler->selectButton('submit')->form();
+ global $phpbb_container;
+ $phpbb_container->reset();
- // install/index.php?mode=install&sub=final
- $crawler = self::submit($form);
- self::assertContains('You have successfully installed', $crawler->text());
+ // Purge cache to remove cached files
+ $phpbb_container = new phpbb_mock_container_builder();
+ $phpbb_container->setParameter('core.environment', PHPBB_ENVIRONMENT);
+ $phpbb_container->setParameter('core.cache_dir', $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/');
- copy($config_file, $config_file_test);
+ $cache = new \phpbb\cache\driver\file;
+ $cache->purge();
+
+ $blacklist = ['phpbb_class_loader_mock', 'phpbb_class_loader_ext', 'phpbb_class_loader'];
+
+ foreach (array_keys($GLOBALS) as $key)
+ {
+ if (is_object($GLOBALS[$key]) && !in_array($key, $blacklist, true))
+ {
+ unset($GLOBALS[$key]);
+ }
+ }
}
public function install_ext($extension)
@@ -415,7 +433,7 @@ class phpbb_functional_test_case extends phpbb_test_case
$meta_refresh = $crawler->filter('meta[http-equiv="refresh"]');
// Wait for extension to be fully enabled
- while (sizeof($meta_refresh))
+ while (count($meta_refresh))
{
preg_match('#url=.+/(adm+.+)#', $meta_refresh->attr('content'), $match);
$url = $match[1];
@@ -490,7 +508,7 @@ class phpbb_functional_test_case extends phpbb_test_case
));
$db->sql_query($sql);
- if ($style_path != 'prosilver' && $style_path != 'subsilver2')
+ if ($style_path != 'prosilver')
{
@mkdir($phpbb_root_path . 'styles/' . $style_path, 0777);
@mkdir($phpbb_root_path . 'styles/' . $style_path . '/template', 0777);
@@ -499,7 +517,6 @@ class phpbb_functional_test_case extends phpbb_test_case
else
{
$db->sql_multi_insert(STYLES_TABLE, array(array(
- 'style_id' => $style_id,
'style_name' => $style_path,
'style_copyright' => '',
'style_active' => 1,
@@ -529,7 +546,7 @@ class phpbb_functional_test_case extends phpbb_test_case
$db->sql_query('DELETE FROM ' . STYLES_TEMPLATE_TABLE . ' WHERE template_id = ' . $style_id);
$db->sql_query('DELETE FROM ' . STYLES_THEME_TABLE . ' WHERE theme_id = ' . $style_id);
- if ($style_path != 'prosilver' && $style_path != 'subsilver2')
+ if ($style_path != 'prosilver')
{
@rmdir($phpbb_root_path . 'styles/' . $style_path . '/template');
@rmdir($phpbb_root_path . 'styles/' . $style_path);
@@ -541,9 +558,10 @@ class phpbb_functional_test_case extends phpbb_test_case
* Creates a new user with limited permissions
*
* @param string $username Also doubles up as the user's password
+ * @param string $email User email (defaults to nobody@example.com)
* @return int ID of created user
*/
- protected function create_user($username)
+ protected function create_user($username, $email = 'nobody@example.com')
{
// Required by unique_id
global $config;
@@ -562,6 +580,9 @@ class phpbb_functional_test_case extends phpbb_test_case
$config['rand_seed'] = '';
$config['rand_seed_last_update'] = time() + 600;
+ // Prevent new user to have an invalid style
+ $config['default_style'] = 1;
+
// Required by user_add
global $db, $cache, $phpbb_dispatcher, $phpbb_container;
$db = $this->get_db();
@@ -571,7 +592,7 @@ class phpbb_functional_test_case extends phpbb_test_case
}
$cache = new phpbb_mock_null_cache;
- $cache_driver = new \phpbb\cache\driver\null();
+ $cache_driver = new \phpbb\cache\driver\dummy();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('cache.driver', $cache_driver);
$phpbb_notifications = new phpbb_mock_notification_manager();
@@ -585,15 +606,14 @@ class phpbb_functional_test_case extends phpbb_test_case
{
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();
$passwords_manager = $this->get_passwords_manager();
$user_row = array(
'username' => $username,
'group_id' => 2,
- 'user_email' => 'nobody@example.com',
+ 'user_email' => $email,
'user_type' => 0,
'user_lang' => 'en',
'user_timezone' => 'UTC',
@@ -603,6 +623,25 @@ class phpbb_functional_test_case extends phpbb_test_case
return user_add($user_row);
}
+ /**
+ * Get group ID
+ *
+ * @param string $group_name Group name
+ * @return int Group id of specified group name
+ */
+ protected function get_group_id($group_name)
+ {
+ $db = $this->get_db();
+ $sql = 'SELECT group_id
+ FROM ' . GROUPS_TABLE . "
+ WHERE group_name = '" . $db->sql_escape($group_name) . "'";
+ $result = $db->sql_query($sql);
+ $group_id = (int) $db->sql_fetchfield('group_id');
+ $db->sql_freeresult($result);
+
+ return $group_id;
+ }
+
protected function remove_user_group($group_name, $usernames)
{
global $db, $cache, $auth, $config, $phpbb_dispatcher, $phpbb_log, $phpbb_container, $phpbb_root_path, $phpEx;
@@ -612,13 +651,16 @@ class phpbb_functional_test_case extends phpbb_test_case
$db = $this->get_db();
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$auth = $this->getMock('\phpbb\auth\auth');
$phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE);
$cache = new phpbb_mock_null_cache;
- $cache_driver = new \phpbb\cache\driver\null();
+ $cache_driver = new \phpbb\cache\driver\dummy();
$phpbb_container = new phpbb_mock_container_builder();
$phpbb_container->set('cache.driver', $cache_driver);
$phpbb_container->set('notification_manager', new phpbb_mock_notification_manager());
@@ -632,12 +674,7 @@ class phpbb_functional_test_case extends phpbb_test_case
require_once(__DIR__ . '/../../phpBB/includes/functions_user.php');
}
- $sql = 'SELECT group_id
- FROM ' . GROUPS_TABLE . "
- WHERE group_name = '" . $db->sql_escape($group_name) . "'";
- $result = $db->sql_query($sql);
- $group_id = (int) $db->sql_fetchfield('group_id');
- $db->sql_freeresult($result);
+ $group_id = $this->get_group_id($group_name);
return group_user_del($group_id, false, $usernames, $group_name);
}
@@ -651,13 +688,16 @@ class phpbb_functional_test_case extends phpbb_test_case
$db = $this->get_db();
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
- $user = $this->getMock('\phpbb\user', array(), array('\phpbb\datetime'));
+ $user = $this->getMock('\phpbb\user', array(), array(
+ new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx)),
+ '\phpbb\datetime'
+ ));
$auth = $this->getMock('\phpbb\auth\auth');
$phpbb_log = new \phpbb\log\log($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, 'adm/', $phpEx, LOG_TABLE);
$cache = new phpbb_mock_null_cache;
- $cache_driver = new \phpbb\cache\driver\null();
+ $cache_driver = new \phpbb\cache\driver\dummy();
$phpbb_container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$phpbb_container
->expects($this->any())
@@ -674,12 +714,7 @@ class phpbb_functional_test_case extends phpbb_test_case
require_once(__DIR__ . '/../../phpBB/includes/functions_user.php');
}
- $sql = 'SELECT group_id
- FROM ' . GROUPS_TABLE . "
- WHERE group_name = '" . $db->sql_escape($group_name) . "'";
- $result = $db->sql_query($sql);
- $group_id = (int) $db->sql_fetchfield('group_id');
- $db->sql_freeresult($result);
+ $group_id = $this->get_group_id($group_name);
return group_user_add($group_id, false, $usernames, $group_name, $default, $leader);
}
@@ -856,7 +891,7 @@ class phpbb_functional_test_case extends phpbb_test_case
static public function assert_response_html($status_code = 200)
{
// Any output before the doc type means there was an error
- $content = self::$client->getResponse()->getContent();
+ $content = self::get_content();
self::assertNotContains('[phpBB Debug]', $content);
self::assertStringStartsWith('<!DOCTYPE', trim($content), 'Output found before DOCTYPE specification.');
@@ -877,7 +912,7 @@ class phpbb_functional_test_case extends phpbb_test_case
static public function assert_response_xml($status_code = 200)
{
// Any output before the xml opening means there was an error
- $content = self::$client->getResponse()->getContent();
+ $content = self::get_content();
self::assertNotContains('[phpBB Debug]', $content);
self::assertStringStartsWith('<?xml', trim($content), 'Output found before XML specification.');
@@ -894,10 +929,15 @@ class phpbb_functional_test_case extends phpbb_test_case
* status code. This assertion tries to catch that.
*
* @param int $status_code Expected status code
- * @return null
+ * @return void
*/
static public function assert_response_status_code($status_code = 200)
{
+ if ($status_code != self::$client->getResponse()->getStatus() &&
+ preg_match('/^5[0-9]{2}/', self::$client->getResponse()->getStatus()))
+ {
+ self::fail("Encountered unexpected server error:\n" . self::$client->getResponse()->getContent());
+ }
self::assertEquals($status_code, self::$client->getResponse()->getStatus(), 'HTTP status code does not match');
}
@@ -948,8 +988,7 @@ class phpbb_functional_test_case extends phpbb_test_case
*/
public function assert_checkbox_is_unchecked($crawler, $name, $message = '')
{
- $this->assertSame(
- '',
+ $this->assertNull(
$this->assert_find_one_checkbox($crawler, $name)->attr('checked'),
$message ?: "Failed asserting that checkbox $name is unchecked."
);
@@ -973,7 +1012,7 @@ class phpbb_functional_test_case extends phpbb_test_case
$this->assertEquals(
1,
- sizeof($result),
+ count($result),
$message ?: 'Failed asserting that exactly one checkbox with name' .
" $name exists in crawler scope."
);
@@ -1136,28 +1175,14 @@ class phpbb_functional_test_case extends phpbb_test_case
'error' => UPLOAD_ERR_OK,
);
- $crawler = self::$client->request('POST', $posting_url, array('add_file' => $this->lang('ADD_FILE')), array('fileupload' => $file));
- }
- unset($form_data['upload_files']);
- }
-
- $hidden_fields = array(
- $crawler->filter('[type="hidden"]')->each(function ($node, $i) {
- return array('name' => $node->attr('name'), 'value' => $node->attr('value'));
- }),
- );
+ $file_form_data = array_merge(['add_file' => $this->lang('ADD_FILE')], $this->get_hidden_fields($crawler, $posting_url));
- foreach ($hidden_fields as $fields)
- {
- foreach($fields as $field)
- {
- $form_data[$field['name']] = $field['value'];
+ $crawler = self::$client->request('POST', $posting_url, $file_form_data, array('fileupload' => $file));
}
+ unset($form_data['upload_files']);
}
- // 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;
+ $form_data = array_merge($form_data, $this->get_hidden_fields($crawler, $posting_url));
// 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)
@@ -1288,4 +1313,37 @@ class phpbb_functional_test_case extends phpbb_test_case
return self::request('GET', substr($link, strpos($link, 'mcp.')));
}
+
+ /**
+ * Get hidden fields for URL
+ *
+ * @param Symfony\Component\DomCrawler\Crawler|null $crawler Crawler instance or null
+ * @param string $url Request URL
+ *
+ * @return array Hidden form fields array
+ */
+ protected function get_hidden_fields($crawler, $url)
+ {
+ if (!$crawler)
+ {
+ $crawler = self::$client->request('GET', $url);
+ }
+ $hidden_fields = [
+ $crawler->filter('[type="hidden"]')->each(function ($node, $i) {
+ return ['name' => $node->attr('name'), 'value' => $node->attr('value')];
+ }),
+ ];
+
+ $file_form_data = [];
+
+ foreach ($hidden_fields as $fields)
+ {
+ foreach($fields as $field)
+ {
+ $file_form_data[$field['name']] = $field['value'];
+ }
+ }
+
+ return $file_form_data;
+ }
}
diff --git a/tests/test_framework/phpbb_session_test_case.php b/tests/test_framework/phpbb_session_test_case.php
index 1bf0277fe0..b3d7780d14 100644
--- a/tests/test_framework/phpbb_session_test_case.php
+++ b/tests/test_framework/phpbb_session_test_case.php
@@ -11,7 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
require_once dirname(__FILE__) . '/../session/testable_factory.php';
require_once dirname(__FILE__) . '/../session/testable_facade.php';
@@ -34,7 +33,7 @@ abstract class phpbb_session_test_case extends phpbb_database_test_case
$symfony_request = new \phpbb\symfony_request(
new phpbb_mock_request()
);
- $phpbb_filesystem = new \phpbb\filesystem();
+ $phpbb_filesystem = new \phpbb\filesystem\filesystem();
$phpbb_path_helper = new \phpbb\path_helper(
$symfony_request,
$phpbb_filesystem,
diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php
index dee70ad016..c792976b1e 100644
--- a/tests/test_framework/phpbb_test_case_helpers.php
+++ b/tests/test_framework/phpbb_test_case_helpers.php
@@ -11,6 +11,8 @@
*
*/
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
class phpbb_test_case_helpers
{
protected $expectedTriggerError = false;
@@ -120,17 +122,6 @@ class phpbb_test_case_helpers
'dbpasswd' => '',
));
}
- else if (extension_loaded('sqlite'))
- {
- $config = array_merge($config, array(
- 'dbms' => 'phpbb\db\driver\sqlite',
- 'dbhost' => dirname(__FILE__) . '/../phpbb_unit_tests.sqlite2', // filename
- 'dbport' => '',
- 'dbname' => '',
- 'dbuser' => '',
- 'dbpasswd' => '',
- ));
- }
if (isset($_SERVER['PHPBB_TEST_CONFIG']))
{
@@ -298,4 +289,298 @@ class phpbb_test_case_helpers
}
}
}
+
+ /**
+ * Set working instances of the text_formatter.* services
+ *
+ * If no container is passed, the global $phpbb_container will be used and/or
+ * created if applicable
+ *
+ * @param ContainerInterface $container Service container
+ * @param string $fixture Path to the XML fixture
+ * @param string $styles_path Path to the styles dir
+ * @return ContainerInterface
+ */
+ public function set_s9e_services(ContainerInterface $container = null, $fixture = null, $styles_path = null)
+ {
+ static $first_run;
+ global $config, $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx, $request, $user;
+
+ $cache_dir = __DIR__ . '/../tmp/';
+
+ // Remove old cache files on first run
+ if (!isset($first_run))
+ {
+ $first_run = 1;
+
+ array_map('unlink', array_merge(
+ glob($cache_dir . 'data_s9e_*'),
+ glob($cache_dir . 's9e_*')
+ ));
+ }
+
+ if (!isset($container))
+ {
+ if (!isset($phpbb_container))
+ {
+ $phpbb_container = new phpbb_mock_container_builder;
+ }
+
+ $container = $phpbb_container;
+ }
+
+ if (!isset($fixture))
+ {
+ $fixture = __DIR__ . '/../text_formatter/s9e/fixtures/default_formatting.xml';
+ }
+
+ if (!isset($styles_path))
+ {
+ $styles_path = $phpbb_root_path . 'styles/';
+ }
+
+ $dataset = new DOMDocument;
+ $dataset->load($fixture);
+
+ $tables = array(
+ 'phpbb_bbcodes' => array(),
+ 'phpbb_smilies' => array(),
+ 'phpbb_styles' => array(),
+ 'phpbb_words' => array()
+ );
+ foreach ($dataset->getElementsByTagName('table') as $table)
+ {
+ $name = $table->getAttribute('name');
+ $columns = array();
+
+ foreach ($table->getElementsByTagName('column') as $column)
+ {
+ $columns[] = $column->textContent;
+ }
+
+ foreach ($table->getElementsByTagName('row') as $row)
+ {
+ $values = array();
+
+ foreach ($row->getElementsByTagName('value') as $value)
+ {
+ $values[] = $value->textContent;
+ }
+
+ $tables[$name][] = array_combine($columns, $values);
+ }
+ }
+
+ // Set up a default style if there's none set
+ if (empty($tables['phpbb_styles']))
+ {
+ $tables['phpbb_styles'][] = array(
+ 'style_id' => 1,
+ 'style_path' => 'prosilver',
+ 'bbcode_bitfield' => 'kNg='
+ );
+ }
+
+ // Mock the DAL, make it return data from the fixture
+ $mb = $this->test_case->getMockBuilder('phpbb\\textformatter\\data_access');
+ $mb->setMethods(array('get_bbcodes', 'get_censored_words', 'get_smilies', 'get_styles'));
+ $mb->setConstructorArgs(array(
+ $this->test_case->getMockBuilder('phpbb\\db\\driver\\driver')->getMock(),
+ 'phpbb_bbcodes',
+ 'phpbb_smilies',
+ 'phpbb_styles',
+ 'phpbb_words',
+ $styles_path
+ ));
+
+ $dal = $mb->getMock();
+ $container->set('text_formatter.data_access', $dal);
+
+ $dal->expects($this->test_case->any())
+ ->method('get_bbcodes')
+ ->will($this->test_case->returnValue($tables['phpbb_bbcodes']));
+ $dal->expects($this->test_case->any())
+ ->method('get_smilies')
+ ->will($this->test_case->returnValue($tables['phpbb_smilies']));
+ $dal->expects($this->test_case->any())
+ ->method('get_styles')
+ ->will($this->test_case->returnValue($tables['phpbb_styles']));
+ $dal->expects($this->test_case->any())
+ ->method('get_censored_words')
+ ->will($this->test_case->returnValue($tables['phpbb_words']));
+
+ // Cache the parser and renderer with a key based on this method's arguments
+ $cache = new \phpbb\cache\driver\file($cache_dir);
+ $prefix = '_s9e_' . md5(serialize(func_get_args()));
+ $cache_key_parser = $prefix . '_parser';
+ $cache_key_renderer = $prefix . '_renderer';
+ $container->set('cache.driver', $cache);
+
+ if (!$container->isFrozen())
+ {
+ $container->setParameter('cache.dir', $cache_dir);
+ }
+
+ // Create a path_helper
+ if (!$container->has('path_helper') || $container->getDefinition('path_helper')->isSynthetic())
+ {
+ $path_helper = $this->test_case->getMockBuilder('phpbb\\path_helper')
+ ->disableOriginalConstructor()
+ ->setMethods(array('get_web_root_path'))
+ ->getMock();
+ $path_helper->expects($this->test_case->any())
+ ->method('get_web_root_path')
+ ->will($this->test_case->returnValue('phpBB/'));
+
+ $container->set('path_helper', $path_helper);
+ }
+ else
+ {
+ $path_helper = $container->get('path_helper');
+ }
+
+ // Create an event dispatcher
+ if ($container->has('dispatcher'))
+ {
+ $dispatcher = $container->get('dispatcher');
+ }
+ else if (isset($phpbb_dispatcher))
+ {
+ $dispatcher = $phpbb_dispatcher;
+ }
+ else
+ {
+ $dispatcher = new phpbb_mock_event_dispatcher;
+ }
+ if (!isset($phpbb_dispatcher))
+ {
+ $phpbb_dispatcher = $dispatcher;
+ }
+
+ // Set up the a minimum config
+ if ($container->has('config'))
+ {
+ $config = $container->get('config');
+ }
+ elseif (!isset($config))
+ {
+ $config = new \phpbb\config\config(array());
+ }
+ $default_config = array(
+ 'allow_nocensors' => false,
+ 'allowed_schemes_links' => 'http,https,ftp',
+ 'script_path' => '/phpbb',
+ 'server_name' => 'localhost',
+ 'server_port' => 80,
+ 'server_protocol' => 'http://',
+ 'smilies_path' => 'images/smilies',
+ );
+ foreach ($default_config as $config_name => $config_value)
+ {
+ if (!isset($config[$config_name]))
+ {
+ $config[$config_name] = $config_value;
+ }
+ }
+
+ // Create a fake request
+ if (!isset($request))
+ {
+ $request = new phpbb_mock_request;
+ }
+
+ // Get a log interface
+ $log = ($container->has('log')) ? $container->get('log') : $this->test_case->getMockBuilder('phpbb\\log\\log_interface')->getMock();
+
+ // Create and register the text_formatter.s9e.factory service
+ $factory = new \phpbb\textformatter\s9e\factory($dal, $cache, $dispatcher, $config, new \phpbb\textformatter\s9e\link_helper, $log, $cache_dir, $cache_key_parser, $cache_key_renderer);
+ $container->set('text_formatter.s9e.factory', $factory);
+
+ // Create a user if none was provided, and add the common lang strings
+ if ($container->has('user'))
+ {
+ $user = $container->get('user');
+ }
+ else
+ {
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+
+ $user = $this->test_case->getMockBuilder('\phpbb\user')
+ ->setConstructorArgs(array($lang, '\phpbb\datetime'))
+ ->setMethods(array('format_date'))
+ ->getMock();
+ $user->expects($this->test_case->any())
+ ->method('format_date')
+ ->will($this->test_case->returnCallback(__CLASS__ . '::format_date'));
+
+ $user->date_format = 'Y-m-d H:i:s';
+ $user->optionset('viewcensors', true);
+ $user->optionset('viewflash', true);
+ $user->optionset('viewimg', true);
+ $user->optionset('viewsmilies', true);
+ $user->timezone = new \DateTimeZone('UTC');
+ $container->set('user', $user);
+ }
+ $user->add_lang('common');
+
+ if (!isset($user->style))
+ {
+ $user->style = array('style_id' => 1);
+ }
+
+ // Create and register a quote_helper
+ $quote_helper = new \phpbb\textformatter\s9e\quote_helper(
+ $container->get('user'),
+ $phpbb_root_path,
+ $phpEx
+ );
+ $container->set('text_formatter.s9e.quote_helper', $quote_helper);
+
+ // Create and register the text_formatter.s9e.parser service and its alias
+ $parser = new \phpbb\textformatter\s9e\parser(
+ $cache,
+ $cache_key_parser,
+ $factory,
+ $dispatcher
+ );
+ $container->set('text_formatter.parser', $parser);
+ $container->set('text_formatter.s9e.parser', $parser);
+
+ // Create and register the text_formatter.s9e.renderer service and its alias
+ $renderer = new \phpbb\textformatter\s9e\renderer(
+ $cache,
+ $cache_dir,
+ $cache_key_renderer,
+ $factory,
+ $dispatcher
+ );
+
+ // Calls configured in services.yml
+ $auth = ($container->has('auth')) ? $container->get('auth') : new \phpbb\auth\auth;
+ $renderer->configure_quote_helper($quote_helper);
+ $renderer->configure_smilies_path($config, $path_helper);
+ $renderer->configure_user($user, $config, $auth);
+
+ $container->set('text_formatter.renderer', $renderer);
+ $container->set('text_formatter.s9e.renderer', $renderer);
+
+ // Create and register the text_formatter.s9e.utils service and its alias
+ $utils = new \phpbb\textformatter\s9e\utils;
+ $container->set('text_formatter.utils', $utils);
+ $container->set('text_formatter.s9e.utils', $utils);
+
+ return $container;
+ }
+
+ /**
+ * Mocked replacement for \phpbb\user::format_date()
+ *
+ * @param integer $gmepoch unix timestamp
+ * @return string
+ */
+ static public function format_date($gmepoch)
+ {
+ return gmdate('Y-m-d H:i:s', $gmepoch);
+ }
}
diff --git a/tests/test_framework/phpbb_ui_test_case.php b/tests/test_framework/phpbb_ui_test_case.php
index e8b230ecbe..48e510abe3 100644
--- a/tests/test_framework/phpbb_ui_test_case.php
+++ b/tests/test_framework/phpbb_ui_test_case.php
@@ -11,12 +11,13 @@
*
*/
+use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Exception\WebDriverCurlException;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
-require_once __DIR__ . '/../../phpBB/includes/functions_install.php';
+require_once __DIR__ . '/mock/phpbb_mock_null_installer_task.php';
class phpbb_ui_test_case extends phpbb_test_case
{
@@ -32,7 +33,6 @@ class phpbb_ui_test_case extends phpbb_test_case
static protected $root_url;
static protected $already_installed = false;
static protected $install_success = false;
-
protected $cache = null;
protected $db = null;
protected $extension_manager = null;
@@ -79,14 +79,18 @@ class phpbb_ui_test_case extends phpbb_test_case
self::markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.');
}
- if (!self::$webDriver)
- {
- try {
- $capabilities = DesiredCapabilities::firefox();
- self::$webDriver = RemoteWebDriver::create(self::$host . ':' . self::$port, $capabilities);
- } catch (WebDriverCurlException $e) {
- self::markTestSkipped('PhantomJS webserver is not running.');
- }
+ try {
+ $capabilities = DesiredCapabilities::chrome();
+ $chromeOptions = (new ChromeOptions)->addArguments(['headless', 'disable-gpu']);
+ $capabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions);
+ self::$webDriver = RemoteWebDriver::create(
+ self::$host . ':' . self::$port,
+ $capabilities,
+ 30 * 1000, // 30 seconds connection timeout
+ 30 * 1000 // 30 seconds request timeout
+ );
+ } catch (WebDriverCurlException $e) {
+ self::markTestSkipped('PhantomJS webserver is not running.');
}
if (!self::$already_installed)
@@ -147,9 +151,33 @@ class phpbb_ui_test_case extends phpbb_test_case
}
}
- static public function visit($path)
+ public function getDriver()
{
- self::$webDriver->get(self::$root_url . $path);
+ return self::$webDriver;
+ }
+
+ public function visit($path)
+ {
+ // Retry three times on curl issues, e.g. timeout
+ $attempts = 0;
+ $retries = 3;
+
+ while (true)
+ {
+ $attempts++;
+ try
+ {
+ $this->getDriver()->get(self::$root_url . $path);
+ break;
+ }
+ catch (Facebook\WebDriver\Exception\WebDriverCurlException $exception)
+ {
+ if ($attempts >= $retries)
+ {
+ throw $exception;
+ }
+ }
+ }
}
static protected function recreate_database($config)
@@ -158,14 +186,14 @@ class phpbb_ui_test_case extends phpbb_test_case
$db_conn_mgr->recreate_db();
}
- static public function find_element($type, $value)
+ public function find_element($type, $value)
{
- return self::$webDriver->findElement(WebDriverBy::$type($value));
+ return $this->getDriver()->findElement(WebDriverBy::$type($value));
}
- static public function submit($type = 'id', $value = 'submit')
+ public function submit($type = 'id', $value = 'submit')
{
- $element = self::find_element($type, $value);
+ $element = $this->find_element($type, $value);
$element->click();
}
@@ -191,90 +219,121 @@ class phpbb_ui_test_case extends phpbb_test_case
}
}
+ $install_config_file = $phpbb_root_path . 'store/install_config.php';
+
+ if (file_exists($install_config_file))
+ {
+ unlink($install_config_file);
+ }
+
+ $container_builder = new \phpbb\di\container_builder($phpbb_root_path, $phpEx);
+ $container = $container_builder
+ ->with_environment('installer')
+ ->without_extensions()
+ ->without_cache()
+ ->with_custom_parameters([
+ 'core.disable_super_globals' => false,
+ 'installer.create_config_file.options' => [
+ 'debug' => true,
+ 'environment' => 'test',
+ ],
+ 'cache.driver.class' => 'phpbb\cache\driver\file'
+ ])
+ ->with_config(new \phpbb\config_php_file($phpbb_root_path, $phpEx))
+ ->without_compiled_container()
+ ->get_container();
+
+ $container->register('installer.install_finish.notify_user')->setSynthetic(true);
+ $container->set('installer.install_finish.notify_user', new phpbb_mock_null_installer_task());
+ $container->register('installer.install_finish.install_extensions')->setSynthetic(true);
+ $container->set('installer.install_finish.install_extensions', new phpbb_mock_null_installer_task());
+ $container->compile();
+
+ $language = $container->get('language');
+ $language->add_lang(array('common', 'acp/common', 'acp/board', 'install', 'posting'));
+
+ $iohandler_factory = $container->get('installer.helper.iohandler_factory');
+ $iohandler_factory->set_environment('cli');
+ $iohandler = $iohandler_factory->get();
+
$parseURL = parse_url(self::$config['phpbb_functional_url']);
- self::visit('install/index.php?mode=install&language=en');
- self::assertContains('Welcome to Installation', self::find_element('id', 'main')->getText());
-
- // install/index.php?mode=install&sub=requirements
- self::submit();
- self::assertContains('Installation compatibility', self::find_element('id', 'main')->getText());
-
- // install/index.php?mode=install&sub=database
- self::submit();
- self::assertContains('Database configuration', self::find_element('id', 'main')->getText());
-
- self::find_element('id','dbms')->sendKeys(str_replace('phpbb\db\driver\\', '', self::$config['dbms']));
- self::find_element('id','dbhost')->sendKeys(self::$config['dbhost']);
- self::find_element('id','dbport')->sendKeys(self::$config['dbport']);
- self::find_element('id','dbname')->sendKeys(self::$config['dbname']);
- self::find_element('id','dbuser')->sendKeys(self::$config['dbuser']);
- self::find_element('id','dbpasswd')->sendKeys(self::$config['dbpasswd']);
-
- // Need to clear default phpbb_ prefix
- self::find_element('id','table_prefix')->clear();
- self::find_element('id','table_prefix')->sendKeys(self::$config['table_prefix']);
-
- // install/index.php?mode=install&sub=database
- self::submit();
- self::assertContains('Successful connection', self::find_element('id','main')->getText());
-
- // install/index.php?mode=install&sub=administrator
- self::submit();
- self::assertContains('Administrator configuration', self::find_element('id','main')->getText());
-
- self::find_element('id','admin_name')->sendKeys('admin');
- self::find_element('id','admin_pass1')->sendKeys('adminadmin');
- self::find_element('id','admin_pass2')->sendKeys('adminadmin');
- self::find_element('id','board_email')->sendKeys('nobody@example.com');
-
- // install/index.php?mode=install&sub=administrator
- self::submit();
- self::assertContains('Tests passed', self::find_element('id','main')->getText());
-
- // install/index.php?mode=install&sub=config_file
- self::submit();
-
- // Installer has created a config.php file, we will overwrite it with a
- // config file of our own in order to get the DEBUG constants defined
- $config_php_data = phpbb_create_config_file_data(self::$config, self::$config['dbms'], true, false, true);
- $config_created = file_put_contents($config_file, $config_php_data) !== false;
- if (!$config_created)
+ $output = new \Symfony\Component\Console\Output\NullOutput();
+ $style = new \Symfony\Component\Console\Style\SymfonyStyle(
+ new \Symfony\Component\Console\Input\ArrayInput(array()),
+ $output
+ );
+ $iohandler->set_style($style, $output);
+
+ $installer = $container->get('installer.installer.install');
+ $installer->set_iohandler($iohandler);
+
+ // Set data
+ $iohandler->set_input('admin_name', 'admin');
+ $iohandler->set_input('admin_pass1', 'adminadmin');
+ $iohandler->set_input('admin_pass2', 'adminadmin');
+ $iohandler->set_input('board_email', 'nobody@example.com');
+ $iohandler->set_input('submit_admin', 'submit');
+
+ $iohandler->set_input('default_lang', 'en');
+ $iohandler->set_input('board_name', 'yourdomain.com');
+ $iohandler->set_input('board_description', 'A short text to describe your forum');
+ $iohandler->set_input('submit_board', 'submit');
+
+ $iohandler->set_input('dbms', str_replace('phpbb\db\driver\\', '', self::$config['dbms']));
+ $iohandler->set_input('dbhost', self::$config['dbhost']);
+ $iohandler->set_input('dbport', self::$config['dbport']);
+ $iohandler->set_input('dbuser', self::$config['dbuser']);
+ $iohandler->set_input('dbpasswd', self::$config['dbpasswd']);
+ $iohandler->set_input('dbname', self::$config['dbname']);
+ $iohandler->set_input('table_prefix', self::$config['table_prefix']);
+ $iohandler->set_input('submit_database', 'submit');
+
+ $iohandler->set_input('email_enable', true);
+ $iohandler->set_input('smtp_delivery', '1');
+ $iohandler->set_input('smtp_host', 'nxdomain.phpbb.com');
+ $iohandler->set_input('smtp_auth', 'PLAIN');
+ $iohandler->set_input('smtp_user', 'nxuser');
+ $iohandler->set_input('smtp_pass', 'nxpass');
+ $iohandler->set_input('submit_email', 'submit');
+
+ $iohandler->set_input('cookie_secure', '0');
+ $iohandler->set_input('server_protocol', '0');
+ $iohandler->set_input('force_server_vars', $parseURL['scheme'] . '://');
+ $iohandler->set_input('server_name', $parseURL['host']);
+ $iohandler->set_input('server_port', isset($parseURL['port']) ? (int) $parseURL['port'] : 80);
+ $iohandler->set_input('script_path', $parseURL['path']);
+ $iohandler->set_input('submit_server', 'submit');
+
+ $installer->run();
+
+ copy($config_file, $config_file_test);
+
+ self::$install_success = true;
+
+ if (file_exists($phpbb_root_path . 'store/install_config.php'))
{
- self::markTestSkipped("Could not write $config_file file.");
+ self::$install_success = false;
+ @unlink($phpbb_root_path . 'store/install_config.php');
}
- if (strpos(self::find_element('id','main')->getText(), 'The configuration file has been written') === false)
+ if (file_exists($phpbb_root_path . 'cache/install_lock'))
{
- self::submit('id', 'dldone');
+ @unlink($phpbb_root_path . 'cache/install_lock');
}
- self::assertContains('The configuration file has been written', self::find_element('id','main')->getText());
-
- // install/index.php?mode=install&sub=advanced
- self::submit();
- self::assertContains('The settings on this page are only necessary to set if you know that you require something different from the default.', self::find_element('id','main')->getText());
-
- self::find_element('id','smtp_delivery')->sendKeys('1');
- self::find_element('id','smtp_host')->sendKeys('nxdomain.phpbb.com');
- self::find_element('id','smtp_user')->sendKeys('nxuser');
- self::find_element('id','smtp_pass')->sendKeys('nxpass');
- self::find_element('id','server_protocol')->sendKeys($parseURL['scheme'] . '://');
- self::find_element('id','server_name')->sendKeys('localhost');
- self::find_element('id','server_port')->sendKeys(isset($parseURL['port']) ? $parseURL['port'] : 80);
- self::find_element('id','script_path')->sendKeys($parseURL['path']);
-
- // install/index.php?mode=install&sub=create_table
- self::submit();
- self::assertContains('The database tables used by phpBB', self::find_element('id','main')->getText());
- self::assertContains('have been created and populated with some initial data.', self::find_element('id','main')->getText());
-
- // install/index.php?mode=install&sub=final
- self::submit();
- self::assertContains('You have successfully installed', self::find_element('id', 'main')->getText());
- copy($config_file, $config_file_test);
+ global $phpbb_container;
+ $phpbb_container->reset();
- self::$install_success = true;
+ $blacklist = ['phpbb_class_loader_mock', 'phpbb_class_loader_ext', 'phpbb_class_loader'];
+
+ foreach (array_keys($GLOBALS) as $key)
+ {
+ if (is_object($GLOBALS[$key]) && !in_array($key, $blacklist, true))
+ {
+ unset($GLOBALS[$key]);
+ }
+ }
}
public function install_ext($extension)
@@ -285,21 +344,21 @@ class phpbb_ui_test_case extends phpbb_test_case
$ext_path = str_replace('/', '%2F', $extension);
$this->visit('adm/index.php?i=acp_extensions&mode=main&action=enable_pre&ext_name=' . $ext_path . '&sid=' . $this->sid);
- $this->assertNotEmpty(count(self::find_element('cssSelector', '.submit-buttons')));
+ $this->assertNotEmpty(count($this->find_element('cssSelector', '.submit-buttons')));
- self::find_element('cssSelector', "input[value='Enable']")->submit();
+ $this->find_element('cssSelector', "input[value='Enable']")->submit();
$this->add_lang('acp/extensions');
try
{
- $meta_refresh = self::find_element('cssSelector', 'meta[http-equiv="refresh"]');
+ $meta_refresh = $this->find_element('cssSelector', 'meta[http-equiv="refresh"]');
// Wait for extension to be fully enabled
- while (sizeof($meta_refresh))
+ while (count($meta_refresh))
{
preg_match('#url=.+/(adm+.+)#', $meta_refresh->getAttribute('content'), $match);
- self::$webDriver->execute(array('method' => 'post', 'url' => $match[1]));
- $meta_refresh = self::find_element('cssSelector', 'meta[http-equiv="refresh"]');
+ $this->getDriver()->execute(array('method' => 'post', 'url' => $match[1]));
+ $meta_refresh = $this->find_element('cssSelector', 'meta[http-equiv="refresh"]');
}
}
catch (\Facebook\WebDriver\Exception\NoSuchElementException $e)
@@ -307,7 +366,7 @@ class phpbb_ui_test_case extends phpbb_test_case
// Probably no refresh triggered
}
- $this->assertContainsLang('EXTENSION_ENABLE_SUCCESS', self::find_element('cssSelector', 'div.successbox')->getText());
+ $this->assertContainsLang('EXTENSION_ENABLE_SUCCESS', $this->find_element('cssSelector', 'div.successbox')->getText());
$this->logout();
}
@@ -316,6 +375,12 @@ class phpbb_ui_test_case extends phpbb_test_case
{
if (!$this->cache)
{
+ global $phpbb_container, $phpbb_root_path;
+
+ $phpbb_container = new phpbb_mock_container_builder();
+ $phpbb_container->setParameter('core.environment', PHPBB_ENVIRONMENT);
+ $phpbb_container->setParameter('core.cache_dir', $phpbb_root_path . 'cache/' . PHPBB_ENVIRONMENT . '/');
+
$this->cache = new \phpbb\cache\driver\file;
}
@@ -395,7 +460,7 @@ class phpbb_ui_test_case extends phpbb_test_case
}
$this->visit('ucp.php?sid=' . $this->sid . '&mode=logout');
- $this->assertContains($this->lang('REGISTER'), self::$webDriver->getPageSource());
+ $this->assertContains($this->lang('REGISTER'), $this->getDriver()->getPageSource());
unset($this->sid);
}
@@ -415,17 +480,17 @@ class phpbb_ui_test_case extends phpbb_test_case
return;
}
- self::$webDriver->manage()->deleteAllCookies();
+ $this->getDriver()->manage()->deleteAllCookies();
$this->visit('adm/index.php?sid=' . $this->sid);
- $this->assertContains($this->lang('LOGIN_ADMIN_CONFIRM'), self::$webDriver->getPageSource());
+ $this->assertContains($this->lang('LOGIN_ADMIN_CONFIRM'), $this->getDriver()->getPageSource());
- self::find_element('cssSelector', 'input[name=username]')->clear()->sendKeys($username);
- self::find_element('cssSelector', 'input[type=password]')->sendKeys($username . $username);
- self::find_element('cssSelector', 'input[name=login]')->click();
+ $this->find_element('cssSelector', 'input[name=username]')->clear()->sendKeys($username);
+ $this->find_element('cssSelector', 'input[type=password]')->sendKeys($username . $username);
+ $this->find_element('cssSelector', 'input[name=login]')->click();
$this->assertContains($this->lang('ADMIN_PANEL'), $this->find_element('cssSelector', 'h1')->getText());
- $cookies = self::$webDriver->manage()->getCookies();
+ $cookies = $this->getDriver()->manage()->getCookies();
// The session id is stored in a cookie that ends with _sid - we assume there is only one such cookie
foreach ($cookies as $cookie)
@@ -530,19 +595,19 @@ class phpbb_ui_test_case extends phpbb_test_case
{
$this->add_lang('ucp');
- self::$webDriver->manage()->deleteAllCookies();
+ $this->getDriver()->manage()->deleteAllCookies();
$this->visit('ucp.php');
- $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), self::$webDriver->getPageSource());
+ $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), $this->getDriver()->getPageSource());
- self::$webDriver->manage()->deleteAllCookies();
+ $this->getDriver()->manage()->deleteAllCookies();
- self::find_element('cssSelector', 'input[name=username]')->sendKeys($username);
- self::find_element('cssSelector', 'input[name=password]')->sendKeys($username . $username);
- self::find_element('cssSelector', 'input[name=login]')->click();
+ $this->find_element('cssSelector', 'input[name=username]')->sendKeys($username);
+ $this->find_element('cssSelector', 'input[name=password]')->sendKeys($username . $username);
+ $this->find_element('cssSelector', 'input[name=login]')->click();
$this->assertNotContains($this->lang('LOGIN'), $this->find_element('className', 'navbar')->getText());
- $cookies = self::$webDriver->manage()->getCookies();
+ $cookies = $this->getDriver()->manage()->getCookies();
// The session id is stored in a cookie that ends with _sid - we assume there is only one such cookie
foreach ($cookies as $cookie)
@@ -566,6 +631,39 @@ class phpbb_ui_test_case extends phpbb_test_case
// Change the Path to your own settings
$screenshot = time() . ".png";
- self::$webDriver->takeScreenshot($screenshot);
+ $this->getDriver()->takeScreenshot($screenshot);
+ }
+
+ /**
+ * Wait for AJAX. Should be called after an AJAX action is made.
+ *
+ * @param string $framework javascript frameworks jquery|prototype|dojo
+ * @throws \Facebook\WebDriver\Exception\NoSuchElementException
+ * @throws \Facebook\WebDriver\Exception\TimeOutException
+ */
+ public function waitForAjax($framework = 'jquery')
+ {
+ switch ($framework)
+ {
+ case 'jquery':
+ $code = 'return jQuery.active;';
+ break;
+ case 'prototype':
+ $code = 'return Ajax.activeRequestCount;';
+ break;
+ case 'dojo':
+ $code = 'return dojo.io.XMLHTTPTransport.inFlight.length;';
+ break;
+ default:
+ throw new \RuntimeException('Unsupported framework');
+ break;
+ }
+ // wait for at most 30s, retry every 2000ms (2s)
+ $driver = $this->getDriver();
+ $driver->wait(30, 2000)->until(
+ function () use ($driver, $code) {
+ return !$driver->executeScript($code);
+ }
+ );
}
}
diff --git a/tests/text_formatter/s9e/bbcode_merger_test.php b/tests/text_formatter/s9e/bbcode_merger_test.php
new file mode 100644
index 0000000000..5ec0c91971
--- /dev/null
+++ b/tests/text_formatter/s9e/bbcode_merger_test.php
@@ -0,0 +1,296 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_textformatter_s9e_bbcode_merger_test extends phpbb_test_case
+{
+ /**
+ * @dataProvider get_merge_bbcodes_tests
+ */
+ public function test_merge_bbcodes($usage_without, $template_without, $usage_with, $template_with, $expected_usage, $expected_template)
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $factory = $container->get('text_formatter.s9e.factory');
+ $bbcode_merger = new \phpbb\textformatter\s9e\bbcode_merger($factory);
+
+ $without = ['usage' => $usage_without, 'template' => $template_without];
+ $with = ['usage' => $usage_with, 'template' => $template_with];
+ $merged = $bbcode_merger->merge_bbcodes($without, $with);
+
+ // Normalize the expected template's whitespace to match the default indentation
+ $expected_template = str_replace("\n\t\t\t\t", "\n", $expected_template);
+ $expected_template = str_replace("\t", ' ', $expected_template);
+
+ $this->assertSame($expected_usage, $merged['usage']);
+ $this->assertSame($expected_template, $merged['template']);
+ }
+
+ public function get_merge_bbcodes_tests()
+ {
+ return [
+ [
+ '[x]{TEXT}[/x]',
+ '<b>{TEXT}</b>',
+
+ '[x={TEXT1}]{TEXT}[/x]',
+ '<b title="{TEXT1}">{TEXT}</b>',
+
+ '[x={TEXT1?}]{TEXT}[/x]',
+ '<b>
+ <xsl:if test="@x">
+ <xsl:attribute name="title">
+ <xsl:value-of select="@x"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </b>'
+ ],
+ [
+ // The tokens' numbering differs between versions
+ '[x]{TEXT}[/x]',
+ '<b>{TEXT}</b>',
+
+ '[x={TEXT1}]{TEXT2}[/x]',
+ '<b title="{TEXT1}">{TEXT2}</b>',
+
+ '[x={TEXT1?}]{TEXT2}[/x]',
+ '<b>
+ <xsl:if test="@x">
+ <xsl:attribute name="title">
+ <xsl:value-of select="@x"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </b>'
+ ],
+ [
+ '[x]{URL}[/x]',
+ '<a href="{URL}">{URL}</a>',
+
+ '[x={URL}]{TEXT}[/x]',
+ '<a href="{URL}">{TEXT}</a>',
+
+ '[x={URL;useContent}]{TEXT}[/x]',
+ '<a href="{@x}">
+ <xsl:apply-templates/>
+ </a>'
+ ],
+ [
+ '[x]{URL}[/x]',
+ '<a href="{URL}">{L_GO_TO}: {URL}</a>',
+
+ '[x={URL}]{TEXT}[/x]',
+ '<a href="{URL}">{L_GO_TO}: {TEXT}</a>',
+
+ '[x={URL;useContent}]{TEXT}[/x]',
+ '<a href="{@x}">{L_GO_TO}: <xsl:apply-templates/></a>'
+ ],
+ [
+ // Test that unsafe BBCodes can still be merged
+ '[script]{TEXT}[/script]',
+ '<script>{TEXT}</script>',
+
+ '[script={TEXT1}]{TEXT2}[/script]',
+ '<script type="{TEXT1}">{TEXT2}</script>',
+
+ '[script={TEXT1?}]{TEXT2}[/script]',
+ '<script>
+ <xsl:if test="@script">
+ <xsl:attribute name="type">
+ <xsl:value-of select="@script"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </script>'
+ ],
+ [
+ // https://www.phpbb.com/community/viewtopic.php?p=14848281#p14848281
+ '[note]{TEXT}[/note]',
+ '<span class="prime_bbcode_note_spur" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);"></span><span class="prime_bbcode_note">{TEXT}</span>',
+
+ '[note={TEXT1}]{TEXT2}[/note]',
+ '<span class="prime_bbcode_note_text" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);">{TEXT1}</span><span class="prime_bbcode_note_spur" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);"></span><span class="prime_bbcode_note">{TEXT2}</span>',
+
+ '[note={TEXT1?}]{TEXT2}[/note]',
+ '<xsl:if test="@note">
+ <span class="prime_bbcode_note_text" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);">
+ <xsl:value-of select="@note"/>
+ </span>
+ </xsl:if>
+ <span class="prime_bbcode_note_spur" onmouseover="show_note(this);" onmouseout="hide_note(this);" onclick="lock_note(this);"/>
+ <span class="prime_bbcode_note">
+ <xsl:apply-templates/>
+ </span>'
+ ],
+ [
+ // https://www.phpbb.com/community/viewtopic.php?p=14768441#p14768441
+ '[MI]{TEXT}[/MI]',
+ '<span style="color:red">MI:</span> <span style="color:#f6efe2">{TEXT}</span>',
+
+ '[MI={TEXT2}]{TEXT1}[/MI]',
+ '<span style="color:red">MI for: "{TEXT2}":</span> <span style="color:#f6efe2">{TEXT1}</span>',
+
+ '[MI={TEXT2?}]{TEXT1}[/MI]',
+ '<span style="color:red">MI<xsl:if test="@mi"> for: "<xsl:value-of select="@mi"/>"</xsl:if>:</span>
+ <xsl:text> </xsl:text>
+ <span style="color:#f6efe2">
+ <xsl:apply-templates/>
+ </span>'
+ ],
+ [
+ // https://www.phpbb.com/community/viewtopic.php?p=14700506#p14700506
+ '[spoiler]{TEXT}[/spoiler]',
+ '<span class="spoiler"> {TEXT}</span>',
+
+ '[spoiler={TEXT1}]{TEXT2}[/spoiler]',
+ '<div class="spoiler"><small> {TEXT1}</small>{TEXT2}</div>',
+
+ '[spoiler={TEXT1?}]{TEXT2}[/spoiler]',
+ '<xsl:choose>
+ <xsl:when test="@spoiler">
+ <div class="spoiler">
+ <small>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="@spoiler"/>
+ </small>
+ <xsl:apply-templates/>
+ </div>
+ </xsl:when>
+ <xsl:otherwise>
+ <span class="spoiler">
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates/>
+ </span>
+ </xsl:otherwise>
+ </xsl:choose>'
+ ],
+ [
+ // https://www.phpbb.com/community/viewtopic.php?p=14859676#p14859676
+ '[AE]{TEXT}[/AE]',
+ '<table width="100%" border="1">
+ <tr><td width="100%" align="center">
+ <table width="100%" border="0">
+ <tr>
+ <td width="100%" bgcolor="#E1E4F2">
+ <table width="100%" border="0" bgcolor="#F5F5FF">
+ <tr>
+ <td width="1%" bgcolor="#000000" nowrap align="left">
+ <font color="#FFFFFF" face="Arial"><font size="1"><b>&nbsp;ACTIVE EFFECTS & CONDITIONS&nbsp;</b></font></font></td>
+ <td width="99%">&nbsp;</td>
+ </tr>
+ <tr>
+ <td width="100%" bgcolor="#FFE5BA" colspan="2">
+ <table width="100%" cellpadding="2">
+ <tr>
+ <td width="100%" align="left" valign="top">
+ {TEXT}
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td></tr>
+ </table>
+ <p>&nbsp;</p>',
+
+ '[AE={TEXT1}]{TEXT2}[/AE]',
+ '<table width="100%" border="1">
+ <tr><td width="100%" align="center">
+ <table width="100%" border="0">
+ <tr>
+ <td width="100%" bgcolor="#E1E4F2">
+ <table width="100%" border="0" bgcolor="#F5F5FF">
+ <tr>
+ <td width="1%" bgcolor="#000000" nowrap align="left">
+ <font color="#FFFFFF" face="Arial"><font size="1"><b>&nbsp; {TEXT1}&nbsp;</b></font></font></td>
+ <td width="99%">&nbsp;</td>
+ </tr>
+ <tr>
+ <td width="100%" bgcolor="#FFE5BA" colspan="2">
+ <table width="100%" cellpadding="2">
+ <tr>
+ <td width="100%" align="left" valign="top">
+ {TEXT2}
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td></tr>
+ </table>
+ <p>&nbsp;</p>',
+
+ '[AE={TEXT1?}]{TEXT2}[/AE]',
+ '<table width="100%" border="1">
+ <tr>
+ <td width="100%" align="center">
+ <table width="100%" border="0">
+ <tr>
+ <td width="100%" bgcolor="#E1E4F2">
+ <table width="100%" border="0" bgcolor="#F5F5FF">
+ <tr>
+ <td width="1%" bgcolor="#000000" nowrap="nowrap" align="left">
+ <font color="#FFFFFF" face="Arial">
+ <font size="1">
+ <b> <xsl:choose><xsl:when test="@ae"><xsl:text> </xsl:text><xsl:value-of select="@ae"/></xsl:when><xsl:otherwise>ACTIVE EFFECTS &amp; CONDITIONS</xsl:otherwise></xsl:choose> </b>
+ </font>
+ </font>
+ </td>
+ <td width="99%"> </td>
+ </tr>
+ <tr>
+ <td width="100%" bgcolor="#FFE5BA" colspan="2">
+ <table width="100%" cellpadding="2">
+ <tr>
+ <td width="100%" align="left" valign="top">
+ <xsl:apply-templates/>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <p> </p>'
+ ],
+ [
+ // https://www.phpbb.com/community/viewtopic.php?f=438&t=2530451
+ '[issue]{NUMBER}[/issue]',
+ '<a href="/default/issues/{NUMBER}"> Issue #{NUMBER}</a>',
+
+ '[issue={SIMPLETEXT}]{NUMBER}[/issue]',
+ '<a href="/{SIMPLETEXT}/issues/{NUMBER}"> Issue #{NUMBER} ({SIMPLETEXT})</a>',
+
+ '[issue={SIMPLETEXT?}]{NUMBER}[/issue]',
+ '<a>
+ <xsl:choose>
+ <xsl:when test="@issue"><xsl:attribute name="href">/<xsl:value-of select="@issue"/>/issues/<xsl:value-of select="@content"/></xsl:attribute> Issue #<xsl:value-of select="@content"/> (<xsl:value-of select="@issue"/>)</xsl:when>
+ <xsl:otherwise><xsl:attribute name="href">/default/issues/<xsl:value-of select="@content"/></xsl:attribute> Issue #<xsl:value-of select="@content"/></xsl:otherwise>
+ </xsl:choose>
+ </a>'
+ ],
+ ];
+ }
+}
diff --git a/tests/text_formatter/s9e/default_formatting_test.php b/tests/text_formatter/s9e/default_formatting_test.php
new file mode 100644
index 0000000000..1aa4f0bc3a
--- /dev/null
+++ b/tests/text_formatter/s9e/default_formatting_test.php
@@ -0,0 +1,317 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_textformatter_s9e_default_formatting_test extends phpbb_test_case
+{
+ public function test_bbcode_code_lang_is_saved()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $parser = $container->get('text_formatter.parser');
+
+ $original = '[code]...[/code][code=php]...[/code]';
+ $expected = '<r><CODE><s>[code]</s>...<e>[/code]</e></CODE><CODE lang="php"><s>[code=php]</s>...<e>[/code]</e></CODE></r>';
+
+ $this->assertXmlStringEqualsXmlString($expected, $parser->parse($original));
+ }
+
+ /**
+ * @dataProvider get_default_formatting_tests
+ */
+ public function test_default_formatting($original, $expected, $setup = null)
+ {
+ $fixture = __DIR__ . '/fixtures/default_formatting.xml';
+ $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture);
+
+ $parser = $container->get('text_formatter.parser');
+ $renderer = $container->get('text_formatter.renderer');
+
+ if (isset($setup))
+ {
+ call_user_func($setup, $container);
+ }
+
+ $parsed_text = $parser->parse($original);
+
+ $this->assertSame($expected, $renderer->render($parsed_text));
+ }
+
+ public function get_default_formatting_tests()
+ {
+ return array(
+ array(
+ '[b]bold[/b]',
+ '<span style="font-weight:bold">bold</span>'
+ ),
+ array(
+ '[u]underlined[/u]',
+ '<span style="text-decoration:underline">underlined</span>'
+ ),
+ array(
+ '[i]italic[/i]',
+ '<span style="font-style:italic">italic</span>'
+ ),
+ array(
+ '[color=#FF0000]colored[/color]',
+ '<span style="color:#FF0000">colored</span>'
+ ),
+ array(
+ '[color=red]colored[/color]',
+ '<span style="color:red">colored</span>'
+ ),
+ array(
+ '[size=75]smaller[/size]',
+ '<span style="font-size: 75%; line-height: normal">smaller</span>'
+ ),
+ array(
+ '[quote]quoted[/quote]',
+ '<blockquote class="uncited"><div>quoted</div></blockquote>'
+ ),
+ array(
+ '[quote="username"]quoted[/quote]',
+ '<blockquote><div><cite>username wrote:</cite>quoted</div></blockquote>'
+ ),
+ array(
+ '[code]unparsed code[/code]',
+ '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code</code></pre></div>'
+ ),
+ array(
+ '[list]no item[/list]',
+ '<ul><li>no item</li></ul>'
+ ),
+ array(
+ '[*]unparsed',
+ '[*]unparsed'
+ ),
+ array(
+ '[list][*]item[/list]',
+ '<ul><li>item</li></ul>'
+ ),
+ array(
+ '[list][*]item[/*][/list]',
+ '<ul><li>item</li></ul>'
+ ),
+ array(
+ '[list=1][*]item[/list]',
+ '<ol style="list-style-type:decimal"><li>item</li></ol>'
+ ),
+ array(
+ '[list=a][*]item[/list]',
+ '<ol style="list-style-type:lower-alpha"><li>item</li></ol>'
+ ),
+ array(
+ '[list=i][*]item[/list]',
+ '<ol style="list-style-type:lower-roman"><li>item</li></ol>'
+ ),
+ array(
+ '[list=I][*]item[/list]',
+ '<ol style="list-style-type:upper-roman"><li>item</li></ol>'
+ ),
+ array(
+ '[list=disc][*]item[/list]',
+ '<ul style="list-style-type:disc"><li>item</li></ul>'
+ ),
+ array(
+ '[list=circle][*]item[/list]',
+ '<ul style="list-style-type:circle"><li>item</li></ul>'
+ ),
+ array(
+ '[list=square][*]item[/list]',
+ '<ul style="list-style-type:square"><li>item</li></ul>'
+ ),
+ array(
+ '[img]https://area51.phpbb.com/images/area51.png[/img]',
+ '<img src="https://area51.phpbb.com/images/area51.png" class="postimage" alt="Image">'
+ ),
+ array(
+ '[url]https://area51.phpbb.com/[/url]',
+ '<a href="https://area51.phpbb.com/" class="postlink">https://area51.phpbb.com/</a>'
+ ),
+ array(
+ '[url=https://area51.phpbb.com/]Area51[/url]',
+ '<a href="https://area51.phpbb.com/" class="postlink">Area51</a>'
+ ),
+ array(
+ '[email]bbcode-test@phpbb.com[/email]',
+ '<a href="mailto:bbcode-test@phpbb.com">bbcode-test@phpbb.com</a>'
+ ),
+ array(
+ '[email=bbcode-test@phpbb.com]Email[/email]',
+ '<a href="mailto:bbcode-test@phpbb.com">Email</a>'
+ ),
+ array(
+ '[attachment=0]filename[/attachment]',
+ '<div class="inline-attachment"><!-- ia0 -->filename<!-- ia0 --></div>'
+ ),
+ array(
+ // PHPBB3-1401 - correct: parsed
+ '[quote="[test]test"]test [ test[/quote]',
+ '<blockquote><div><cite>[test]test wrote:</cite>test [ test</div></blockquote>'
+ ),
+ array(
+ // PHPBB3-6117 - correct: parsed
+ '[quote]test[/quote] test ] and [ test [quote]test[/quote]',
+ '<blockquote class="uncited"><div>test</div></blockquote> test ] and [ test <blockquote class="uncited"><div>test</div></blockquote>'
+ ),
+ array(
+ // PHPBB3-6200 - correct: parsed
+ '[quote="["]test[/quote]',
+ '<blockquote><div><cite>[ wrote:</cite>test</div></blockquote>'
+ ),
+ 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',
+ '<blockquote class="uncited"><div>test[/[/b]quote] test </div></blockquote>[/quote] test'
+ ),
+ array(
+ // PHPBB3-8096 - first quote tag parsed, second quote tag unparsed
+ '[quote="a"]a[/quote][quote="a]a[/quote]',
+ '<blockquote><div><cite>a wrote:</cite>a</div></blockquote>[quote="a]a[/quote]'
+ ),
+ array(
+ // Allow textual bbcodes in textual bbcodes
+ '[b]bold [i]bold + italic[/i][/b]',
+ '<span style="font-weight:bold">bold <span style="font-style:italic">bold + italic</span></span>'
+ ),
+ array(
+ // Allow textual bbcodes in url with description
+ '[url=https://area51.phpbb.com/]Area51 [i]italic[/i][/url]',
+ '<a href="https://area51.phpbb.com/" class="postlink">Area51 <span style="font-style:italic">italic</span></a>'
+ ),
+ array(
+ // Allow url with description in textual bbcodes
+ '[i]italic [url=https://area51.phpbb.com/]Area51[/url][/i]',
+ '<span style="font-style:italic">italic <a href="https://area51.phpbb.com/" class="postlink">Area51</a></span>'
+ ),
+ array(
+ // Do not parse textual bbcodes in code
+ '[code]unparsed code [b]bold [i]bold + italic[/i][/b][/code]',
+ '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code [b]bold [i]bold + italic[/i][/b]</code></pre></div>'
+ ),
+ array(
+ // Do not parse quote bbcodes in code
+ '[code]unparsed code [quote="username"]quoted[/quote][/code]',
+ '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>unparsed code [quote="username"]quoted[/quote]</code></pre></div>'
+ ),
+ array(
+ // Textual bbcode nesting into textual bbcode
+ '[b]bold [i]bold + italic[/b] italic[/i]',
+ '<span style="font-weight:bold">bold <span style="font-style:italic">bold + italic</span></span><span style="font-style:italic"> italic</span>'
+ ),
+ array(
+ "[code]\tline1\n line2[/code]",
+ '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>' . "\tline1\n line2</code></pre></div>"
+ ),
+ array(
+ "[code]\n\tline1\n line2[/code]",
+ '<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code>' . "\tline1\n line2</code></pre></div>"
+ ),
+ array(
+ '... http://example.org ...',
+ '... <a href="http://example.org" class="postlink">http://example.org</a> ...'
+ ),
+ array(
+ '... www.example.org ...',
+ '... <a href="http://www.example.org" class="postlink">www.example.org</a> ...'
+ ),
+ array(
+ // From make_clickable_test.php
+ 'www.phpbb.com/community/?',
+ '<a href="http://www.phpbb.com/community/" class="postlink">www.phpbb.com/community/</a>?'
+ ),
+ array(
+ // From make_clickable_test.php
+ 'http://www.phpbb.com/community/path/to/long/url/file.ext#section',
+ '<a href="http://www.phpbb.com/community/path/to/long/url/file.ext#section" class="postlink">http://www.phpbb.com/community/path/to/ ... xt#section</a>'
+ ),
+ array(
+ 'http://localhost/ http://localhost/phpbb/ http://localhost/phpbb/viewforum.php?f=1',
+ '<a href="http://localhost/" class="postlink">http://localhost/</a> <a href="http://localhost/phpbb/" class="postlink">http://localhost/phpbb/</a> <a href="http://localhost/phpbb/viewforum.php?f=1" class="postlink">viewforum.php?f=1</a>'
+ ),
+ array(
+ 'http://localhost/phpbb/viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
+ '<a href="http://localhost/phpbb/viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">viewforum.php?f=1#xxxxxxxxxxxxxxxxxxxxx ... xxxxxxxxxx</a>'
+ ),
+ array(
+ '[url]http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0[/url]',
+ '<a href="http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0" class="postlink">http://example.org/0xxxxxxxxxxxxxxxxxxx ... xxxxxxxxx0</a>'
+ ),
+ array(
+ '[URL]http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0[/url]',
+ '<a href="http://example.org/0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0" class="postlink">http://example.org/0xxxxxxxxxxxxxxxxxxx ... xxxxxxxxx0</a>'
+ ),
+ array(
+ '[url=http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[/url]',
+ '<a href="http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</a>'
+ ),
+ array(
+ '[url=http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[/url]',
+ '<a href="http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" class="postlink">http://example.org/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</a>'
+ ),
+ array(
+ '[quote="[url=http://example.org]xxx[/url]"]...[/quote]',
+ '<blockquote><div><cite><a href="http://example.org" class="postlink">xxx</a> wrote:</cite>...</div></blockquote>'
+ ),
+ array(
+ '[quote="[url]http://example.org[/url]"]...[/quote]',
+ '<blockquote><div><cite><a href="http://example.org" class="postlink">http://example.org</a> wrote:</cite>...</div></blockquote>'
+ ),
+ array(
+ '[quote=http://example.org]...[/quote]',
+ '<blockquote><div><cite><a href="http://example.org" class="postlink">http://example.org</a> wrote:</cite>...</div></blockquote>'
+ ),
+ array(
+ "[quote]\nThis is a long quote that is definitely going to exceed 80 characters\n[/quote]\n\nFollowed by a reply",
+ "<blockquote class=\"uncited\"><div>\nThis is a long quote that is definitely going to exceed 80 characters\n</div></blockquote>\n\nFollowed by a reply"
+ ),
+ array(
+ '[quote=Username post_id=123]...[/quote]',
+ '<blockquote><div><cite>Username wrote: <a href="phpBB/viewtopic.php?p=123#p123" data-post-id="123" onclick="if(document.getElementById(hash.substr(1)))href=hash">↑</a></cite>...</div></blockquote>'
+ ),
+ array(
+ // Users are not allowed to submit their own URL for the post
+ '[quote="Username" post_url="http://fake.example.org"]...[/quote]',
+ '<blockquote><div><cite>Username wrote:</cite>...</div></blockquote>'
+ ),
+ array(
+ '[quote=Username time=58705871]...[/quote]',
+ '<blockquote><div><cite>Username wrote:<div class="responsive-hide">1971-11-11 11:11:11</div></cite>...</div></blockquote>'
+ ),
+ array(
+ '[quote=Username user_id=123]...[/quote]',
+ '<blockquote><div><cite><a href="phpBB/memberlist.php?mode=viewprofile&amp;u=123">Username</a> wrote:</cite>...</div></blockquote>'
+ ),
+ array(
+ // Users are not allowed to submit their own URL for the profile
+ '[quote=Username profile_url=http://fake.example.org]...[/quote]',
+ '<blockquote><div><cite>Username wrote:</cite>...</div></blockquote>'
+ ),
+ array(
+ // From phpbb_textformatter_s9e_utils_test::test_generate_quote()
+ '[quote=\'[quote="foo"]\']...[/quote]',
+ '<blockquote><div><cite>[quote="foo"] wrote:</cite>...</div></blockquote>'
+ ),
+ array(
+ "Emoji: \xF0\x9F\x98\x80",
+ 'Emoji: <img alt="' . "\xF0\x9F\x98\x80" . '" class="emoji smilies" draggable="false" src="//twemoji.maxcdn.com/2/svg/1f600.svg">'
+ ),
+ array(
+ "Emoji: \xF0\x9F\x98\x80",
+ "Emoji: \xF0\x9F\x98\x80",
+ function ($container)
+ {
+ $container->get('text_formatter.renderer')->set_viewsmilies(false);
+ }
+ ),
+ );
+ }
+}
diff --git a/tests/text_formatter/s9e/factory_test.php b/tests/text_formatter/s9e/factory_test.php
new file mode 100644
index 0000000000..0d780a19a9
--- /dev/null
+++ b/tests/text_formatter/s9e/factory_test.php
@@ -0,0 +1,314 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php';
+
+class phpbb_textformatter_s9e_factory_test extends phpbb_database_test_case
+{
+ public function setUp()
+ {
+ $this->cache = new phpbb_mock_cache;
+ $this->dispatcher = new phpbb_mock_event_dispatcher;
+ parent::setUp();
+ }
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/factory.xml');
+ }
+
+ public function get_cache_dir()
+ {
+ return __DIR__ . '/../../tmp/';
+ }
+
+ public function get_factory($styles_path = null)
+ {
+ global $config, $phpbb_root_path, $request, $symfony_request, $user;
+
+ if (!isset($styles_path))
+ {
+ $styles_path = $phpbb_root_path . 'styles/';
+ }
+
+ $this->cache = new phpbb_mock_cache;
+ $dal = new \phpbb\textformatter\data_access(
+ $this->new_dbal(),
+ 'phpbb_bbcodes',
+ 'phpbb_smilies',
+ 'phpbb_styles',
+ 'phpbb_words',
+ $styles_path
+ );
+ $factory = new \phpbb\textformatter\s9e\factory(
+ $dal,
+ $this->cache,
+ $this->dispatcher,
+ new \phpbb\config\config(array('allowed_schemes_links' => 'http,https,ftp')),
+ new \phpbb\textformatter\s9e\link_helper,
+ $this->getMockBuilder('phpbb\\log\\log_interface')->getMock(),
+ $this->get_cache_dir(),
+ '_foo_parser',
+ '_foo_renderer'
+ );
+
+ // Global objects required by generate_board_url()
+ $config = new \phpbb\config\config(array(
+ 'script_path' => '/phpbb',
+ 'server_name' => 'localhost',
+ 'server_port' => 80,
+ 'server_protocol' => 'http://',
+ ));
+ $request = new phpbb_mock_request;
+ $symfony_request = new \phpbb\symfony_request($request);
+ $user = new phpbb_mock_user;
+
+ return $factory;
+ }
+
+ public function run_configurator_assertions($configurator)
+ {
+ $this->assertInstanceOf('s9e\\TextFormatter\\Configurator', $configurator);
+
+ $this->assertTrue(isset($configurator->plugins['Autoemail']));
+ $this->assertTrue(isset($configurator->plugins['Autolink']));
+
+ $this->assertTrue(isset($configurator->BBCodes['B']));
+ $this->assertTrue(isset($configurator->BBCodes['CODE']));
+ $this->assertTrue(isset($configurator->BBCodes['COLOR']));
+ $this->assertTrue(isset($configurator->BBCodes['EMAIL']));
+ $this->assertTrue(isset($configurator->BBCodes['FLASH']));
+ $this->assertTrue(isset($configurator->BBCodes['I']));
+ $this->assertTrue(isset($configurator->BBCodes['IMG']));
+ $this->assertTrue(isset($configurator->BBCodes['LIST']));
+ $this->assertTrue(isset($configurator->BBCodes['*']));
+ $this->assertTrue(isset($configurator->BBCodes['QUOTE']));
+ $this->assertTrue(isset($configurator->BBCodes['SIZE']));
+ $this->assertTrue(isset($configurator->BBCodes['U']));
+ $this->assertTrue(isset($configurator->BBCodes['URL']));
+
+ // This custom BBCode should be set
+ $this->assertTrue(isset($configurator->BBCodes['CUSTOM']));
+
+ $this->assertTrue(isset($configurator->Emoticons[':D']));
+ }
+
+ public function test_get_configurator()
+ {
+ $configurator = $this->get_factory()->get_configurator();
+ $this->run_configurator_assertions($configurator);
+
+ // Test with twigified bbcode.html
+ $configurator = $this->get_factory(__DIR__ . '/fixtures/styles/')->get_configurator();
+ $this->run_configurator_assertions($configurator);
+
+ }
+
+ public function test_regenerate()
+ {
+ extract($this->get_factory()->regenerate());
+
+ $this->assertInstanceOf('s9e\\TextFormatter\\Parser', $parser);
+ $this->assertInstanceOf('s9e\\TextFormatter\\Renderer', $renderer);
+
+ $renderer_data = $this->cache->get('_foo_renderer');
+ $this->assertEquals($parser, $this->cache->get('_foo_parser'), 'The parser was not cached');
+ $this->assertEquals(get_class($renderer), $renderer_data['class']);
+ $this->assertInstanceOf('s9e\\TextFormatter\\Plugins\\Censor\\Helper', $renderer_data['censor']);
+
+ $file = $this->get_cache_dir() . get_class($renderer) . '.php';
+ $this->assertFileExists($file);
+ unlink($file);
+ }
+
+ public function test_tidy()
+ {
+ $factory = $this->get_factory();
+
+ // Create a fake "old" cache file
+ $old_file = $this->get_cache_dir() . 's9e_foo.php';
+ touch($old_file);
+
+ // Create a current renderer
+ extract($factory->regenerate());
+ $new_file = $this->get_cache_dir() . get_class($renderer) . '.php';
+
+ // Tidy the cache
+ $factory->tidy();
+
+ $this->assertFileExists($new_file, 'The current renderer has been deleted');
+ $this->assertFileNotExists($old_file, 'The old renderer has not been deleted');
+
+ unlink($new_file);
+ }
+
+ public function test_local_url()
+ {
+ global $config, $user, $request, $symfony_request;
+ $config = new \phpbb\config\config(array(
+ 'force_server_vars' => true,
+ 'server_protocol' => 'http://',
+ 'server_name' => 'path',
+ 'server_port' => 80,
+ 'script_path' => '/to',
+ 'cookie_secure' => false
+ ));
+ $user = new phpbb_mock_user;
+ $request = new phpbb_mock_request;
+ $symfony_request = new \phpbb\symfony_request($request);
+
+ $fixture = __DIR__ . '/fixtures/local_url.xml';
+ $renderer = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.renderer');
+
+ $this->assertSame(
+ '<a href="http://path/to/foo">http://path/to/foo</a>',
+ $renderer->render('<r><LOCAL content="foo"><s>[local]</s>foo<e>[/local]</e></LOCAL></r>')
+ );
+ }
+
+ public function test_smilies_special_chars()
+ {
+ // Use a smiley that contains every special chars in every field
+ $fixture = __DIR__ . '/fixtures/smilies_special_chars.xml';
+ $renderer = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.renderer');
+
+ $this->assertSame(
+ '<img class="smilies" src="phpBB/images/smilies/%22%27%3C&amp;%3E.png" width="15" height="17" alt="&quot;\'&lt;&amp;&gt;" title="&quot;\'&lt;&amp;&gt;">',
+ $renderer->render('<r><E>"\'&lt;&amp;&gt;</E></r>')
+ );
+ }
+
+ public function test_duplicate_smilies()
+ {
+ $fixture = __DIR__ . '/fixtures/smilies_duplicate.xml';
+ $parser = $this->get_test_case_helpers()->set_s9e_services(null, $fixture)->get('text_formatter.parser');
+
+ $this->assertSame(
+ '<r><E>:)</E></r>',
+ $parser->parse(':)')
+ );
+ }
+
+ /**
+ * @testdox {INTTEXT} is supported in custom BBCodes
+ */
+ public function test_inttext_token()
+ {
+ $fixture = __DIR__ . '/fixtures/inttext_token.xml';
+ $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture);
+ $parser = $container->get('text_formatter.parser');
+ $renderer = $container->get('text_formatter.renderer');
+
+ $original = '[spoiler=ɎɆS]text[/spoiler]';
+ $expected = '<div class="spoiler"><div class="title">ɎɆS</div><div class="content">text</div></div>';
+ $this->assertSame($expected, $renderer->render($parser->parse($original)));
+
+ $original = '[spoiler=N:O:P:E]text[/spoiler]';
+ $expected = $original;
+ $this->assertSame($expected, $renderer->render($parser->parse($original)));
+ }
+
+ /**
+ * @testdox Preserves comments in custom BBCodes
+ */
+ public function test_preserve_comments()
+ {
+ $fixture = __DIR__ . '/fixtures/preserve_comments.xml';
+ $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture);
+ $parser = $container->get('text_formatter.parser');
+ $renderer = $container->get('text_formatter.renderer');
+
+ $original = '[X]';
+ $expected = '<!-- comment -->';
+ $this->assertSame($expected, $renderer->render($parser->parse($original)));
+ }
+
+ /**
+ * @testdox Accepts unsafe custom BBCodes
+ */
+ public function test_unsafe_bbcode()
+ {
+ $fixture = __DIR__ . '/fixtures/unsafe_bbcode.xml';
+ $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture);
+ $parser = $container->get('text_formatter.parser');
+ $renderer = $container->get('text_formatter.renderer');
+
+ $original = '[xss=javascript:alert(1)]text[/xss]';
+ $expected = '<a href="javascript:alert(1)">text</a>';
+ $this->assertSame($expected, $renderer->render($parser->parse($original)));
+ }
+
+ /**
+ * @testdox Accepts unsafe default BBCodes
+ */
+ public function test_unsafe_default_bbcodes()
+ {
+ $fixture = __DIR__ . '/fixtures/unsafe_default_bbcodes.xml';
+ $style_dir = __DIR__ . '/fixtures/styles/';
+ $container = $this->get_test_case_helpers()->set_s9e_services(null, $fixture, $style_dir);
+ $parser = $container->get('text_formatter.parser');
+ $renderer = $container->get('text_formatter.renderer');
+
+ $original = '[b]alert(1)[/b]';
+ $expected = '<script>alert(1)</script>';
+ $this->assertSame($expected, $renderer->render($parser->parse($original)));
+ }
+
+ /**
+ * @testdox Logs malformed BBCodes
+ */
+ public function test_malformed_bbcodes()
+ {
+ $log = $this->getMockBuilder('phpbb\\log\\log_interface')->getMock();
+ $log->expects($this->once())
+ ->method('add')
+ ->with('critical', null, null, 'LOG_BBCODE_CONFIGURATION_ERROR', false, ['[x !x]{TEXT}[/x]', 'Cannot interpret the BBCode definition']);
+
+ $container = new phpbb_mock_container_builder;
+ $container->set('log', $log);
+
+ $fixture = __DIR__ . '/fixtures/malformed_bbcode.xml';
+ $this->get_test_case_helpers()->set_s9e_services($container, $fixture);
+ }
+
+ /**
+ * @testdox get_configurator() triggers events before and after configuration
+ */
+ public function test_configure_events()
+ {
+ $this->dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface');
+ $this->dispatcher
+ ->expects($this->at(0))
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_configure_before',
+ $this->callback(array($this, 'configure_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+ $this->dispatcher
+ ->expects($this->at(1))
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_configure_after',
+ $this->callback(array($this, 'configure_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+
+ $this->get_factory()->get_configurator();
+ }
+
+ public function configure_event_callback($vars)
+ {
+ return isset($vars['configurator']) && $vars['configurator'] instanceof \s9e\TextFormatter\Configurator;
+ }
+}
diff --git a/tests/text_formatter/s9e/fixtures/default_formatting.xml b/tests/text_formatter/s9e/fixtures/default_formatting.xml
new file mode 100644
index 0000000000..2b7236fb30
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/default_formatting.xml
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>1</value>
+ <value>:D</value>
+ <value>Very Happy</value>
+ <value>icon_e_biggrin.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>1</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>:-D</value>
+ <value>Very Happy</value>
+ <value>icon_e_biggrin.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>2</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>:grin:</value>
+ <value>Very Happy</value>
+ <value>icon_e_biggrin.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>3</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>:)</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>4</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>:-)</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>5</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>:smile:</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>6</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>7</value>
+ <value>;)</value>
+ <value>Wink</value>
+ <value>icon_e_wink.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>7</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>8</value>
+ <value>;-)</value>
+ <value>Wink</value>
+ <value>icon_e_wink.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>8</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>9</value>
+ <value>:wink:</value>
+ <value>Wink</value>
+ <value>icon_e_wink.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>9</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>10</value>
+ <value>:(</value>
+ <value>Sad</value>
+ <value>icon_e_sad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>10</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>11</value>
+ <value>:-(</value>
+ <value>Sad</value>
+ <value>icon_e_sad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>11</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>12</value>
+ <value>:sad:</value>
+ <value>Sad</value>
+ <value>icon_e_sad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>12</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>13</value>
+ <value>:o</value>
+ <value>Surprised</value>
+ <value>icon_e_surprised.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>13</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>14</value>
+ <value>:-o</value>
+ <value>Surprised</value>
+ <value>icon_e_surprised.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>14</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>15</value>
+ <value>:eek:</value>
+ <value>Surprised</value>
+ <value>icon_e_surprised.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>15</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>16</value>
+ <value>:shock:</value>
+ <value>Shocked</value>
+ <value>icon_eek.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>16</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>17</value>
+ <value>:?</value>
+ <value>Confused</value>
+ <value>icon_e_confused.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>17</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>18</value>
+ <value>:-?</value>
+ <value>Confused</value>
+ <value>icon_e_confused.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>18</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>19</value>
+ <value>:???:</value>
+ <value>Confused</value>
+ <value>icon_e_confused.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>19</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>20</value>
+ <value>8-)</value>
+ <value>Cool</value>
+ <value>icon_cool.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>20</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>21</value>
+ <value>:cool:</value>
+ <value>Cool</value>
+ <value>icon_cool.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>21</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>22</value>
+ <value>:lol:</value>
+ <value>Laughing</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>23</value>
+ <value>:x</value>
+ <value>Mad</value>
+ <value>icon_mad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>23</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>24</value>
+ <value>:-x</value>
+ <value>Mad</value>
+ <value>icon_mad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>24</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>25</value>
+ <value>:mad:</value>
+ <value>Mad</value>
+ <value>icon_mad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>25</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>26</value>
+ <value>:P</value>
+ <value>Razz</value>
+ <value>icon_razz.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>26</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>27</value>
+ <value>:-P</value>
+ <value>Razz</value>
+ <value>icon_razz.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>27</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>28</value>
+ <value>:razz:</value>
+ <value>Razz</value>
+ <value>icon_razz.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>28</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>29</value>
+ <value>:oops:</value>
+ <value>Embarrassed</value>
+ <value>icon_redface.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>29</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>30</value>
+ <value>:cry:</value>
+ <value>Crying or Very Sad</value>
+ <value>icon_cry.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>30</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>31</value>
+ <value>:evil:</value>
+ <value>Evil or Very Mad</value>
+ <value>icon_evil.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>31</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>32</value>
+ <value>:twisted:</value>
+ <value>Twisted Evil</value>
+ <value>icon_twisted.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>32</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>33</value>
+ <value>:roll:</value>
+ <value>Rolling Eyes</value>
+ <value>icon_rolleyes.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>33</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>34</value>
+ <value>:!:</value>
+ <value>Exclamation</value>
+ <value>icon_exclaim.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>34</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>35</value>
+ <value>:?:</value>
+ <value>Question</value>
+ <value>icon_question.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>35</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>36</value>
+ <value>:idea:</value>
+ <value>Idea</value>
+ <value>icon_idea.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>36</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>37</value>
+ <value>:arrow:</value>
+ <value>Arrow</value>
+ <value>icon_arrow.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>37</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>38</value>
+ <value>:|</value>
+ <value>Neutral</value>
+ <value>icon_neutral.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>38</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>39</value>
+ <value>:-|</value>
+ <value>Neutral</value>
+ <value>icon_neutral.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>39</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>40</value>
+ <value>:mrgreen:</value>
+ <value>Mr. Green</value>
+ <value>icon_mrgreen.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>40</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>41</value>
+ <value>:geek:</value>
+ <value>Geek</value>
+ <value>icon_e_geek.gif</value>
+ <value>17</value>
+ <value>17</value>
+ <value>41</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>42</value>
+ <value>:ugeek:</value>
+ <value>Uber Geek</value>
+ <value>icon_e_ugeek.gif</value>
+ <value>17</value>
+ <value>18</value>
+ <value>42</value>
+ <value>1</value>
+ </row>
+ </table>
+
+ <table name="phpbb_styles">
+ <column>style_id</column>
+ <column>style_name</column>
+ <column>style_copyright</column>
+ <column>style_active</column>
+ <column>style_path</column>
+ <column>bbcode_bitfield</column>
+ <column>style_parent_id</column>
+ <column>style_parent_tree</column>
+ <row>
+ <value>1</value>
+ <value>prosilver</value>
+ <value>&amp;copy; phpBB Group</value>
+ <value>1</value>
+ <value>prosilver</value>
+ <value>kNg=</value>
+ <value>0</value>
+ <value></value>
+ </row>
+ </table>
+
+ <table name="phpbb_words">
+ <column>word_id</column>
+ <column>word</column>
+ <column>replacement</column>
+
+ <row>
+ <value>1</value>
+ <value>apple</value>
+ <value>banana</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/default_lang.xml b/tests/text_formatter/s9e/fixtures/default_lang.xml
new file mode 100644
index 0000000000..2cfde4aab2
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/default_lang.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+
+ <row>
+ <value>13</value>
+ <value>foo</value>
+ <value></value>
+ <value>1</value>
+ <value>[foo]{TEXT}[/foo]</value>
+ <value>{L_FOO_BAR}</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/factory.xml b/tests/text_formatter/s9e/fixtures/factory.xml
new file mode 100644
index 0000000000..9ae52e9747
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/factory.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>custom</value>
+ <value></value>
+ <value>1</value>
+ <value>[custom]{TEXT}[/custom]</value>
+ <value>&lt;span style=&quot;color:red&quot;&gt;{TEXT}&lt;/span&gt;</value>
+ <value>!\[custom\](.*?)\[/custom\]!ies</value>
+ <value>'[custom:$uid]'.str_replace(array(&quot;\r\n&quot;, '\&quot;', '\'', '(', ')'), array(&quot;\n&quot;, '&quot;', '&amp;#39;', '&amp;#40;', '&amp;#41;'), trim('${1}')).'[/custom:$uid]'</value>
+ <value>!\[custom:$uid\](.*?)\[/custom:$uid\]!s</value>
+ <value>&lt;span style=&quot;color:red&quot;&gt;${1}&lt;/span&gt;</value>
+ </row>
+ <row>
+ <value>14</value>
+ <value>unsafe</value>
+ <value></value>
+ <value>1</value>
+ <value>[unsafe]{TEXT}[/unsafe]</value>
+ <value>&lt;script&gt;{TEXT}&lt;/script&gt;</value>
+ <value>!\[unsafe\](.*?)\[/unsafe\]!ies</value>
+ <value>'[unsafe:$uid]'.str_replace(array(&quot;\r\n&quot;, '\&quot;', '\'', '(', ')'), array(&quot;\n&quot;, '&quot;', '&amp;#39;', '&amp;#40;', '&amp;#41;'), trim('${1}')).'[/unsafe:$uid]'</value>
+ <value>!\[unsafe:$uid\](.*?)\[/unsafe:$uid\]!s</value>
+ <value>&lt;script&gt;${1}&lt;/script&gt;</value>
+ </row>
+ </table>
+
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>1</value>
+ <value>:D</value>
+ <value>Very Happy</value>
+ <value>icon_e_biggrin.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>2</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>:)</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>4</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>10</value>
+ <value>:(</value>
+ <value>Sad</value>
+ <value>icon_e_sad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>10</value>
+ <value>1</value>
+ </row>
+ </table>
+
+ <table name="phpbb_styles">
+ <column>style_id</column>
+ <column>style_name</column>
+ <column>style_copyright</column>
+ <column>style_active</column>
+ <column>style_path</column>
+ <column>bbcode_bitfield</column>
+ <column>style_parent_id</column>
+ <column>style_parent_tree</column>
+
+ <row>
+ <value>1</value>
+ <value>prosilver</value>
+ <value>&amp;copy; phpBB Group</value>
+ <value>1</value>
+ <value>prosilver</value>
+ <value>kNg=</value>
+ <value>0</value>
+ <value></value>
+ </row>
+ </table>
+
+ <table name="phpbb_words">
+ <column>word_id</column>
+ <column>word</column>
+ <column>replacement</column>
+
+ <row>
+ <value>1</value>
+ <value>apple</value>
+ <value>banana</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/inttext_token.xml b/tests/text_formatter/s9e/fixtures/inttext_token.xml
new file mode 100644
index 0000000000..30b971f315
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/inttext_token.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>spoiler=</value>
+ <value></value>
+ <value>1</value>
+ <value>[spoiler={INTTEXT}]{TEXT}[/spoiler]</value>
+ <value><![CDATA[<div class="spoiler"><div class="title">{INTTEXT}</div><div class="content">{TEXT}</div></div>]]></value>
+ <value><![CDATA[!\[spoiler\=([\p{L}\p{N}\-+,_. ]+)\](.*?)\[/spoiler\]!iues]]></value>
+ <value><![CDATA['[spoiler=${1}:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${2}')).'[/spoiler:$uid]']]></value>
+ <value><![CDATA[!\[spoiler\=([\p{L}\p{N}\-+,_. ]+):$uid\](.*?)\[/spoiler:$uid\]!su]]></value><value><![CDATA[<div class="spoiler"><div class="title">${1}</div><div class="content">${2}</div></div>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/local_url.xml b/tests/text_formatter/s9e/fixtures/local_url.xml
new file mode 100644
index 0000000000..9db2bf4710
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/local_url.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>local</value>
+ <value></value>
+ <value>1</value>
+ <value>[local]{LOCAL_URL}[/local]</value>
+ <value><![CDATA[<a href="{LOCAL_URL}">{LOCAL_URL}</a>]]></value>
+ <value><![CDATA[!\[local\]((?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:#(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?)\[/local\]!ie]]></value>
+ <value><![CDATA['[local:$uid]'.$this->bbcode_specialchars('${1}').'[/local:$uid]']]></value>
+ <value><![CDATA[!\[local:$uid\](?i)((?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*(?:/(?:[a-z0-9\-._~\!$&'()*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:#(?:[a-z0-9\-._~\!$&'()*+,;=:@/?|]+|%[\dA-F]{2})*)?)(?-i)\[/local:$uid\]!s]]></value>
+ <value><![CDATA[<a href="http://path/to/phpBB/${1}">http://path/to/phpBB/${1}</a>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/malformed_bbcode.xml b/tests/text_formatter/s9e/fixtures/malformed_bbcode.xml
new file mode 100644
index 0000000000..7e7aa1a39c
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/malformed_bbcode.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>x</value>
+ <value></value>
+ <value>1</value>
+ <value>[x !x]{TEXT}[/x]</value>
+ <value>...</value>
+ <value/>
+ <value/>
+ <value/>
+ <value/>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/preserve_comments.xml b/tests/text_formatter/s9e/fixtures/preserve_comments.xml
new file mode 100644
index 0000000000..f81d366aad
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/preserve_comments.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>X</value>
+ <value></value>
+ <value>1</value>
+ <value>[X][/X]</value>
+ <value><![CDATA[<!-- comment -->]]></value>
+ <value><![CDATA[!\[x\]\[/x\]!i]]></value>
+ <value><![CDATA[[x:$uid][/x:$uid]]]></value>
+ <value><![CDATA[[x:$uid][/x:$uid]]]></value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/smilies_duplicate.xml b/tests/text_formatter/s9e/fixtures/smilies_duplicate.xml
new file mode 100644
index 0000000000..9645f3e516
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/smilies_duplicate.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>1</value>
+ <value>:)</value>
+ <value>:)</value>
+ <value>foo.png</value>
+ <value>15</value>
+ <value>17</value>
+ <value>2</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>:)</value>
+ <value>:)</value>
+ <value>bar.png</value>
+ <value>15</value>
+ <value>17</value>
+ <value>2</value>
+ <value>2</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml b/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml
new file mode 100644
index 0000000000..d3a7cfa4f7
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/smilies_special_chars.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>1</value>
+ <value>"'&lt;&amp;&gt;</value>
+ <value>"'&lt;&amp;&gt;</value>
+ <value>"'&lt;&amp;&gt;.png</value>
+ <value>15</value>
+ <value>17</value>
+ <value>2</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/style_inheritance.xml b/tests/text_formatter/s9e/fixtures/style_inheritance.xml
new file mode 100644
index 0000000000..a692d0ef2d
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/style_inheritance.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_styles">
+ <column>style_id</column>
+ <column>style_name</column>
+ <column>style_copyright</column>
+ <column>style_active</column>
+ <column>style_path</column>
+ <column>bbcode_bitfield</column>
+ <column>style_parent_id</column>
+ <column>style_parent_tree</column>
+
+ <row>
+ <value>1</value>
+ <value>foo</value>
+ <value></value>
+ <value>1</value>
+ <value>foo</value>
+ <!-- Bitfield for "b" only -->
+ <value>QA==</value>
+ <value>0</value>
+ <value></value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>fooplus</value>
+ <value></value>
+ <value>1</value>
+ <value>fooplus</value>
+ <value>QA==</value>
+ <value>1</value>
+ <value></value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>fooplusplus</value>
+ <value></value>
+ <value>1</value>
+ <value>fooplusplus</value>
+ <value>QA==</value>
+ <value>2</value>
+ <value></value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>bar</value>
+ <value></value>
+ <value>1</value>
+ <value>bar</value>
+ <!-- Bitfield for "b" only -->
+ <value>QA==</value>
+ <value>0</value>
+ <value></value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>barplus</value>
+ <value></value>
+ <value>1</value>
+ <value>barplus</value>
+ <value>QA==</value>
+ <value>4</value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/styles.xml b/tests/text_formatter/s9e/fixtures/styles.xml
new file mode 100644
index 0000000000..8004412aea
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/styles.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_styles">
+ <column>style_id</column>
+ <column>style_name</column>
+ <column>style_copyright</column>
+ <column>style_active</column>
+ <column>style_path</column>
+ <column>bbcode_bitfield</column>
+ <column>style_parent_id</column>
+ <column>style_parent_tree</column>
+
+ <row>
+ <value>1</value>
+ <value>foo</value>
+ <value></value>
+ <value>1</value>
+ <value>foo</value>
+ <!-- Bitfield for "b" only -->
+ <value>QA==</value>
+ <value>0</value>
+ <value></value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>bar</value>
+ <value></value>
+ <value>1</value>
+ <value>bar</value>
+ <!-- Bitfield for "b" only -->
+ <value>QA==</value>
+ <value>0</value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html
new file mode 100644
index 0000000000..76a35542be
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/styles/bar/template/bbcode.html
@@ -0,0 +1,40 @@
+<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open -->
+<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default -->
+<!-- BEGIN ulist_close --></ul><!-- END ulist_close -->
+
+<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open -->
+<!-- BEGIN olist_close --></ol><!-- END olist_close -->
+
+<!-- BEGIN listitem --><li><!-- END listitem -->
+<!-- BEGIN listitem_close --></li><!-- END listitem_close -->
+
+<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open -->
+<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open -->
+<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close -->
+
+<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open -->
+<!-- BEGIN code_close --></code></div><!-- END code_close -->
+
+<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open -->
+<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close -->
+
+<!-- BEGIN b_open --><b><!-- END b_open -->
+<!-- BEGIN b_close --></b><!-- END b_close -->
+
+<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open -->
+<!-- BEGIN u_close --></span><!-- END u_close -->
+
+<!-- BEGIN i_open --><em><!-- END i_open -->
+<!-- BEGIN i_close --></em><!-- END i_close -->
+
+<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color -->
+
+<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size -->
+
+<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
+
+<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
+
+<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email -->
+
+<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash -->
diff --git a/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html
new file mode 100644
index 0000000000..fad8d828fd
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/styles/barplus/template/bbcode.html
@@ -0,0 +1,40 @@
+<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open -->
+<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default -->
+<!-- BEGIN ulist_close --></ul><!-- END ulist_close -->
+
+<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open -->
+<!-- BEGIN olist_close --></ol><!-- END olist_close -->
+
+<!-- BEGIN listitem --><li><!-- END listitem -->
+<!-- BEGIN listitem_close --></li><!-- END listitem_close -->
+
+<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open -->
+<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open -->
+<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close -->
+
+<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open -->
+<!-- BEGIN code_close --></code></div><!-- END code_close -->
+
+<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open -->
+<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close -->
+
+<!-- BEGIN b_open --><b class="barplus"><!-- END b_open -->
+<!-- BEGIN b_close --></b><!-- END b_close -->
+
+<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open -->
+<!-- BEGIN u_close --></span><!-- END u_close -->
+
+<!-- BEGIN i_open --><em><!-- END i_open -->
+<!-- BEGIN i_close --></em><!-- END i_close -->
+
+<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color -->
+
+<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size -->
+
+<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
+
+<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
+
+<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email -->
+
+<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash -->
diff --git a/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html
new file mode 100644
index 0000000000..3e38d13a32
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/styles/foo/template/bbcode.html
@@ -0,0 +1,40 @@
+<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open -->
+<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default -->
+<!-- BEGIN ulist_close --></ul><!-- END ulist_close -->
+
+<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open -->
+<!-- BEGIN olist_close --></ol><!-- END olist_close -->
+
+<!-- BEGIN listitem --><li><!-- END listitem -->
+<!-- BEGIN listitem_close --></li><!-- END listitem_close -->
+
+<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open -->
+<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open -->
+<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close -->
+
+<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open -->
+<!-- BEGIN code_close --></code></div><!-- END code_close -->
+
+<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open -->
+<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close -->
+
+<!-- BEGIN b_open --><strong><!-- END b_open -->
+<!-- BEGIN b_close --></strong><!-- END b_close -->
+
+<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open -->
+<!-- BEGIN u_close --></span><!-- END u_close -->
+
+<!-- BEGIN i_open --><em><!-- END i_open -->
+<!-- BEGIN i_close --></em><!-- END i_close -->
+
+<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color -->
+
+<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size -->
+
+<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
+
+<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
+
+<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email -->
+
+<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash -->
diff --git a/tests/text_formatter/s9e/fixtures/styles/prosilver/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/prosilver/template/bbcode.html
new file mode 100644
index 0000000000..22be395499
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/styles/prosilver/template/bbcode.html
@@ -0,0 +1,75 @@
+{% for ulist_open in loops.ulist_open %}<ul style="list-style-type: {{ LIST_TYPE }}">{% endfor %}
+{% for ulist_open_default in loops.ulist_open_default %}<ul>{% endfor %}
+{% for ulist_close in loops.ulist_close %}</ul>{% endfor %}
+
+{% for olist_open in loops.olist_open %}<ol style="list-style-type: {{ LIST_TYPE }}">{% endfor %}
+{% for olist_close in loops.olist_close %}</ol>{% endfor %}
+
+{% for listitem in loops.listitem %}<li>{% endfor %}
+{% for listitem_close in loops.listitem_close %}</li>{% endfor %}
+
+{% for quote_username_open in loops.quote_username_open %}<blockquote><div><cite>{{ USERNAME }} {{ lang('WROTE') }}{{ lang('COLON') }}</cite>{% endfor %}
+{% for quote_open in loops.quote_open %}<blockquote class="uncited"><div>{% endfor %}
+{% for quote_close in loops.quote_close %}</div></blockquote>{% endfor %}
+{% for quote_extended in loops.quote_extended %}
+<blockquote>
+ <xsl:if test="not(@author)">
+ <xsl:attribute name="class">uncited</xsl:attribute>
+ </xsl:if>
+ <div>
+ <xsl:if test="@author">
+ <cite>
+ <xsl:choose>
+ <xsl:when test="@url">
+ <a href="{@url}" class="postlink"><xsl:value-of select="@author"/></a>
+ </xsl:when>
+ <xsl:when test="@profile_url">
+ <a href="{@profile_url}"><xsl:value-of select="@author"/></a>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@author"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text> </xsl:text>
+ <xsl:value-of select="$L_WROTE"/>
+ <xsl:value-of select="$L_COLON"/>
+ <xsl:if test="@post_url">
+ <xsl:text> </xsl:text>
+ <a href="{@post_url}" data-post-id="{@post_id}" onclick="if(document.getElementById(hash.substr(1)))href=hash">&#8593;</a>
+ </xsl:if>
+ <xsl:if test="@date">
+ <div class="responsive-hide"><xsl:value-of select="@date"/></div>
+ </xsl:if>
+ </cite>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </div>
+</blockquote>
+{% endfor %}
+
+{% for code_open in loops.code_open %}<div class="codebox"><p>{{ lang('CODE') }}{{ lang('COLON') }} <a href="#" onclick="selectCode(this); return false;">{{ lang('SELECT_ALL_CODE') }}</a></p><pre><code>{% endfor %}
+{% for code_close in loops.code_close %}</code></pre></div>{% endfor %}
+
+{% for inline_attachment_open in loops.inline_attachment_open %}<div class="inline-attachment">{% endfor %}
+{% for inline_attachment_close in loops.inline_attachment_close %}</div>{% endfor %}
+
+{% for b_open in loops.b_open %}<strong class="text-strong">{% endfor %}
+{% for b_close in loops.b_close %}</strong>{% endfor %}
+
+{% for u_open in loops.u_open %}<span style="text-decoration: underline">{% endfor %}
+{% for u_close in loops.u_close %}</span>{% endfor %}
+
+{% for i_open in loops.i_open %}<em class="text-italics">{% endfor %}
+{% for i_close in loops.i_close %}</em>{% endfor %}
+
+{% for color in loops.color %}<span style="color: {{ COLOR }}">{{ TEXT }}</span>{% endfor %}
+
+{% for size in loops.size %}<span style="font-size: {{ SIZE }}%; line-height: 116%;">{{ TEXT }}</span>{% endfor %}
+
+{% for img in loops.img %}<img src="{{ URL }}" class="postimage" alt="{{ lang('IMAGE') }}" />{% endfor %}
+
+{% for url in loops.url %}<a href="{{ URL }}" class="postlink">{{ DESCRIPTION }}</a>{% endfor %}
+
+{% for email in loops.email %}<a href="mailto:{{ EMAIL }}">{{ DESCRIPTION }}</a>{% endfor %}
+
+{% for flash in loops.flash %}<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{{ WIDTH }}" height="{{ HEIGHT }}"><param name="movie" value="{{ URL }}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{{ URL }}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{{ WIDTH }}" height="{{ HEIGHT }}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object>{% endfor %}
diff --git a/tests/text_formatter/s9e/fixtures/styles/unsafe/template/bbcode.html b/tests/text_formatter/s9e/fixtures/styles/unsafe/template/bbcode.html
new file mode 100644
index 0000000000..f3932f9b78
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/styles/unsafe/template/bbcode.html
@@ -0,0 +1,40 @@
+<!-- BEGIN ulist_open --><ul style="list-style-type: {LIST_TYPE}"><!-- END ulist_open -->
+<!-- BEGIN ulist_open_default --><ul><!-- END ulist_open_default -->
+<!-- BEGIN ulist_close --></ul><!-- END ulist_close -->
+
+<!-- BEGIN olist_open --><ol style="list-style-type: {LIST_TYPE}"><!-- END olist_open -->
+<!-- BEGIN olist_close --></ol><!-- END olist_close -->
+
+<!-- BEGIN listitem --><li><!-- END listitem -->
+<!-- BEGIN listitem_close --></li><!-- END listitem_close -->
+
+<!-- BEGIN quote_username_open --><blockquote><div><cite>{USERNAME} {L_WROTE}{L_COLON}</cite><!-- END quote_username_open -->
+<!-- BEGIN quote_open --><blockquote class="uncited"><div><!-- END quote_open -->
+<!-- BEGIN quote_close --></div></blockquote><!-- END quote_close -->
+
+<!-- BEGIN code_open --><div class="codebox"><p>{L_CODE}{L_COLON} <a href="#" onclick="selectCode(this); return false;">{L_SELECT_ALL_CODE}</a></p><code><!-- END code_open -->
+<!-- BEGIN code_close --></code></div><!-- END code_close -->
+
+<!-- BEGIN inline_attachment_open --><div class="inline-attachment"><!-- END inline_attachment_open -->
+<!-- BEGIN inline_attachment_close --></div><!-- END inline_attachment_close -->
+
+<!-- BEGIN b_open --><script><!-- END b_open -->
+<!-- BEGIN b_close --></script><!-- END b_close -->
+
+<!-- BEGIN u_open --><span style="text-decoration: underline"><!-- END u_open -->
+<!-- BEGIN u_close --></span><!-- END u_close -->
+
+<!-- BEGIN i_open --><em><!-- END i_open -->
+<!-- BEGIN i_close --></em><!-- END i_close -->
+
+<!-- BEGIN color --><span style="color: {COLOR}">{TEXT}</span><!-- END color -->
+
+<!-- BEGIN size --><span style="font-size: {SIZE}%; line-height: 116%;">{TEXT}</span><!-- END size -->
+
+<!-- BEGIN img --><img src="{URL}" class="postimage" alt="{L_IMAGE}" /><!-- END img -->
+
+<!-- BEGIN url --><a href="{URL}" class="postlink">{DESCRIPTION}</a><!-- END url -->
+
+<!-- BEGIN email --><a href="mailto:{EMAIL}">{DESCRIPTION}</a><!-- END email -->
+
+<!-- BEGIN flash --><object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="{WIDTH}" height="{HEIGHT}"><param name="movie" value="{URL}" /><param name="play" value="false" /><param name="loop" value="false" /><param name="quality" value="high" /><param name="allowScriptAccess" value="never" /><param name="allowNetworking" value="internal" /><embed src="{URL}" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="{WIDTH}" height="{HEIGHT}" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></embed></object><!-- END flash -->
diff --git a/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml b/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml
new file mode 100644
index 0000000000..55a2e689b6
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/unsafe_bbcode.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>xss=</value>
+ <value></value>
+ <value>1</value>
+ <value>[xss={TEXT1}]{TEXT2}[/xss]</value>
+ <value><![CDATA[<a href="{TEXT1}">{TEXT2}</a>]]></value>
+ <value><![CDATA[!\[xss\=(.*?)\](.*?)\[/xss\]!ies]]></value>
+ <value><![CDATA['[xss='.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).':$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${2}')).'[/xss:$uid]']]></value>
+ <value><![CDATA[!\[xss\=(.*?):$uid\](.*?)\[/xss:$uid\]!s]]></value>
+ <value><![CDATA[<a href="${1}">${2}</a>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/fixtures/unsafe_default_bbcodes.xml b/tests/text_formatter/s9e/fixtures/unsafe_default_bbcodes.xml
new file mode 100644
index 0000000000..06524a13cc
--- /dev/null
+++ b/tests/text_formatter/s9e/fixtures/unsafe_default_bbcodes.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_styles">
+ <column>style_id</column>
+ <column>style_name</column>
+ <column>style_copyright</column>
+ <column>style_active</column>
+ <column>style_path</column>
+ <column>bbcode_bitfield</column>
+ <column>style_parent_id</column>
+ <column>style_parent_tree</column>
+
+ <row>
+ <value>1</value>
+ <value>unsafe</value>
+ <value></value>
+ <value>1</value>
+ <value>unsafe</value>
+ <value>QA==</value>
+ <value>0</value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_formatter/s9e/link_helper_test.php b/tests/text_formatter/s9e/link_helper_test.php
new file mode 100644
index 0000000000..762d67f883
--- /dev/null
+++ b/tests/text_formatter/s9e/link_helper_test.php
@@ -0,0 +1,35 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_textformatter_s9e_link_helper_test extends phpbb_test_case
+{
+ public function test_does_not_override_autoimage()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $configurator = $container->get('text_formatter.s9e.factory')->get_configurator();
+
+ $configurator->Autoimage;
+ extract($configurator->finalize());
+
+ $original = 'http://localhost/path_to_long_image_filename_0123456789.png';
+ $expected = '<r>
+ <URL url="http://localhost/path_to_long_image_filename_0123456789.png">
+ <IMG src="http://localhost/path_to_long_image_filename_0123456789.png">
+ <LINK_TEXT text="http://localhost/path_to_long_image_fil ... 456789.png">http://localhost/path_to_long_image_filename_0123456789.png</LINK_TEXT>
+ </IMG>
+ </URL>
+ </r>';
+
+ $this->assertXmlStringEqualsXmlString($expected, $parser->parse($original));
+ }
+}
diff --git a/tests/text_formatter/s9e/parser_test.php b/tests/text_formatter/s9e/parser_test.php
new file mode 100644
index 0000000000..4b9bbf9bb2
--- /dev/null
+++ b/tests/text_formatter/s9e/parser_test.php
@@ -0,0 +1,258 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_textformatter_s9e_parser_test extends phpbb_test_case
+{
+ public function test_load_from_cache()
+ {
+ $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $cache = $this->getMock('phpbb_mock_cache');
+ $cache->expects($this->once())
+ ->method('get')
+ ->with('_foo_parser')
+ ->will($this->returnValue($mock));
+
+ $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory->expects($this->never())->method('regenerate');
+
+ $parser = new \phpbb\textformatter\s9e\parser(
+ $cache,
+ '_foo_parser',
+ $factory,
+ new phpbb_mock_event_dispatcher
+ );
+ }
+
+ public function test_use_from_cache()
+ {
+ $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $mock->expects($this->once())
+ ->method('parse')
+ ->with('test')
+ ->will($this->returnValue('<t>test</t>'));
+
+ $cache = new phpbb_mock_cache;
+ $cache->put('_foo_parser', $mock);
+
+ $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory->expects($this->never())->method('regenerate');
+
+ $parser = new \phpbb\textformatter\s9e\parser(
+ $cache,
+ '_foo_parser',
+ $factory,
+ new phpbb_mock_event_dispatcher
+ );
+
+ $this->assertSame('<t>test</t>', $parser->parse('test'));
+ }
+
+ public function test_regenerate_on_cache_miss()
+ {
+ $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $mock->expects($this->once())
+ ->method('parse')
+ ->with('test')
+ ->will($this->returnValue('<t>test</t>'));
+
+ $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory->expects($this->once())
+ ->method('regenerate')
+ ->will($this->returnValue(array('parser' => $mock)));
+
+ $parser = new \phpbb\textformatter\s9e\parser(
+ new phpbb_mock_cache,
+ '_foo_parser',
+ $factory,
+ new phpbb_mock_event_dispatcher
+ );
+
+ $this->assertSame('<t>test</t>', $parser->parse('test'));
+ }
+
+ /**
+ * @dataProvider get_options_tests()
+ */
+ public function test_options($adapter_method, $adapter_arg, $concrete_method, $concrete_arg)
+ {
+ $mock = $this->getMockBuilder('s9e\\TextFormatter\\Parser')
+ ->setMethods(array($concrete_method))
+ ->disableOriginalConstructor()
+ ->getMock();
+ foreach ((array) $concrete_arg as $i => $concrete_arg)
+ {
+ $mock->expects($this->at($i))
+ ->method($concrete_method)
+ ->with($concrete_arg);
+ }
+
+ $cache = new phpbb_mock_cache;
+ $cache->put('_foo_parser', $mock);
+
+ $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $parser = new \phpbb\textformatter\s9e\parser(
+ $cache,
+ '_foo_parser',
+ $factory,
+ new phpbb_mock_event_dispatcher
+ );
+
+ call_user_func_array(array($parser, $adapter_method), (array) $adapter_arg);
+ }
+
+ public function get_options_tests()
+ {
+ return array(
+ array(
+ 'disable_bbcode', 'url',
+ 'disableTag', 'URL'
+ ),
+ array(
+ 'disable_bbcodes', null,
+ 'disablePlugin', 'BBCodes'
+ ),
+ array(
+ 'disable_magic_url', null,
+ 'disablePlugin', array('Autoemail', 'Autolink')
+ ),
+ array(
+ 'disable_smilies', null,
+ 'disablePlugin', 'Emoticons'
+ ),
+ array(
+ 'enable_bbcode', 'url',
+ 'enableTag', 'URL'
+ ),
+ array(
+ 'enable_bbcodes', null,
+ 'enablePlugin', 'BBCodes'
+ ),
+ array(
+ 'enable_magic_url', null,
+ 'enablePlugin', array('Autoemail', 'Autolink')
+ ),
+ array(
+ 'enable_smilies', null,
+ 'enablePlugin', 'Emoticons'
+ )
+ );
+ }
+
+ /**
+ * @testdox The constructor triggers a core.text_formatter_s9e_parser_setup event
+ */
+ public function test_setup_event()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface');
+ $dispatcher
+ ->expects($this->once())
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_parser_setup',
+ $this->callback(array($this, 'setup_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+
+ new \phpbb\textformatter\s9e\parser(
+ $container->get('cache.driver'),
+ '_foo_parser',
+ $container->get('text_formatter.s9e.factory'),
+ $dispatcher
+ );
+ }
+
+ public function setup_event_callback($vars)
+ {
+ return isset($vars['parser'])
+ && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser;
+ }
+
+ /**
+ * @testdox parse() triggers a core.text_formatter_s9e_parse_before and core.text_formatter_s9e_parse_after events
+ */
+ public function test_parse_event()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface');
+ $dispatcher
+ ->expects($this->any())
+ ->method('trigger_event')
+ ->will($this->returnArgument(1));
+ $dispatcher
+ ->expects($this->at(1))
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_parse_before',
+ $this->callback(array($this, 'parse_before_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+ $dispatcher
+ ->expects($this->at(2))
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_parse_after',
+ $this->callback(array($this, 'parse_after_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+
+ $parser = new \phpbb\textformatter\s9e\parser(
+ $container->get('cache.driver'),
+ '_foo_parser',
+ $container->get('text_formatter.s9e.factory'),
+ $dispatcher
+ );
+ $parser->parse('...');
+ }
+
+ public function parse_before_event_callback($vars)
+ {
+ return isset($vars['parser'])
+ && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser
+ && isset($vars['text'])
+ && $vars['text'] === '...';
+ }
+
+ public function parse_after_event_callback($vars)
+ {
+ return isset($vars['parser'])
+ && $vars['parser'] instanceof \phpbb\textformatter\s9e\parser
+ && isset($vars['xml'])
+ && $vars['xml'] === '<t>...</t>';
+ }
+
+ public function test_get_parser()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $parser = $container->get('text_formatter.parser');
+ $this->assertInstanceOf('s9e\\TextFormatter\\Parser', $parser->get_parser());
+ }
+}
diff --git a/tests/text_formatter/s9e/renderer_test.php b/tests/text_formatter/s9e/renderer_test.php
new file mode 100644
index 0000000000..175b90fdc7
--- /dev/null
+++ b/tests/text_formatter/s9e/renderer_test.php
@@ -0,0 +1,481 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_textformatter_s9e_renderer_test extends phpbb_test_case
+{
+ public function get_cache_dir()
+ {
+ return __DIR__ . '/../../tmp/';
+ }
+
+ public function test_load_from_cache()
+ {
+ // Save a fake renderer class in the cache dir
+ file_put_contents(
+ $this->get_cache_dir() . 'renderer_foo.php',
+ '<?php class renderer_foo { public function setParameter() {} }'
+ );
+
+ $cache = $this->getMock('phpbb_mock_cache');
+ $cache->expects($this->once())
+ ->method('get')
+ ->with('_foo_renderer')
+ ->will($this->returnValue(array('class' => 'renderer_foo')));
+
+ $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory->expects($this->never())->method('regenerate');
+
+ $renderer = new \phpbb\textformatter\s9e\renderer(
+ $cache,
+ $this->get_cache_dir(),
+ '_foo_renderer',
+ $factory,
+ new phpbb_mock_event_dispatcher
+ );
+ }
+
+ public function test_regenerate_on_cache_miss()
+ {
+ $mock = $this->getMockForAbstractClass('s9e\\TextFormatter\\Renderer');
+
+ $cache = $this->getMock('phpbb_mock_cache');
+ $cache->expects($this->once())
+ ->method('get')
+ ->with('_foo_renderer')
+ ->will($this->returnValue(false));
+
+ $factory = $this->getMockBuilder('phpbb\\textformatter\\s9e\\factory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $factory->expects($this->once())
+ ->method('regenerate')
+ ->will($this->returnValue(array('parser' => $mock)));
+
+ $renderer = new \phpbb\textformatter\s9e\renderer(
+ $cache,
+ $this->get_cache_dir(),
+ '_foo_renderer',
+ $factory,
+ new phpbb_mock_event_dispatcher
+ );
+ }
+
+ /**
+ * @dataProvider get_options_cases
+ */
+ public function test_options($original, $expected, $calls)
+ {
+ $container = new phpbb_mock_container_builder;
+ $this->get_test_case_helpers()->set_s9e_services($container);
+
+ $renderer = $container->get('text_formatter.renderer');
+
+ foreach ($calls as $method => $arg)
+ {
+ $renderer->$method($arg);
+ }
+
+ $this->assertSame($expected, $renderer->render($original));
+ }
+
+ public function get_options_cases()
+ {
+ return array(
+ array(
+ '<t>apple</t>',
+ 'banana',
+ array('set_viewcensors' => true)
+ ),
+ array(
+ '<t>apple</t>',
+ 'apple',
+ array('set_viewcensors' => false)
+ ),
+ array(
+ '<r><FLASH height="456" url="http://example.org/foo.swf" width="123"><s>[flash=123,456]</s><URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL><e>[/flash]</e></FLASH></r>',
+ '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://example.org/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://example.org/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>',
+ array('set_viewflash' => true)
+ ),
+ array(
+ '<r><IMG src="http://example.org/foo.png"><s>[img]</s>http://example.org/foo.png<e>[/img]</e></IMG></r>',
+ '<img src="http://example.org/foo.png" class="postimage" alt="Image">',
+ array('set_viewimg' => true)
+ ),
+ array(
+ '<r><E>:)</E></r>',
+ '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile">',
+ array('set_viewsmilies' => true)
+ ),
+ array(
+ '<r><E>:)</E></r>',
+ ':)',
+ array('set_viewsmilies' => false)
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider get_default_options_cases
+ */
+ public function test_default_options($original, $expected, $setup = null)
+ {
+ $container = new phpbb_mock_container_builder;
+
+ if (isset($setup))
+ {
+ $setup($container, $this);
+ }
+
+ $this->get_test_case_helpers()->set_s9e_services($container);
+
+ $this->assertSame($expected, $container->get('text_formatter.renderer')->render($original));
+ }
+
+ public function get_default_options_cases()
+ {
+ return array(
+ array(
+ '<t>apple</t>',
+ 'banana'
+ ),
+ array(
+ '<t>apple</t>',
+ 'banana',
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewcensors', false);
+
+ $phpbb_container->set('user', $user);
+ }
+ ),
+ array(
+ '<t>apple</t>',
+ 'banana',
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewcensors', false);
+
+ $config = new \phpbb\config\config(array('allow_nocensors' => true));
+
+ $phpbb_container->set('user', $user);
+ $phpbb_container->set('config', $config);
+ }
+ ),
+ array(
+ '<t>apple</t>',
+ 'apple',
+ function ($phpbb_container, $test)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewcensors', false);
+
+ $config = new \phpbb\config\config(array('allow_nocensors' => true));
+
+ $auth = $test->getMock('phpbb\\auth\\auth');
+ $auth->expects($test->any())
+ ->method('acl_get')
+ ->with('u_chgcensors')
+ ->will($test->returnValue(true));
+
+ $phpbb_container->set('user', $user);
+ $phpbb_container->set('config', $config);
+ $phpbb_container->set('auth', $auth);
+ }
+ ),
+ array(
+ '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>',
+ '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://localhost/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://localhost/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>'
+ ),
+ array(
+ '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>',
+ 'http://localhost/foo.swf',
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewflash', false);
+
+ $phpbb_container->set('user', $user);
+ }
+ ),
+ array(
+ '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>',
+ '<img src="http://localhost/mrgreen.gif" class="postimage" alt="Image">'
+ ),
+ array(
+ '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>',
+ '<a href="http://localhost/mrgreen.gif" class="postlink">http://localhost/mrgreen.gif</a>',
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewimg', false);
+
+ $phpbb_container->set('user', $user);
+ }
+ ),
+ array(
+ '<r><E>:)</E></r>',
+ '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile">'
+ ),
+ array(
+ '<r><E>:)</E></r>',
+ ':)',
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('smilies', false);
+
+ $phpbb_container->set('user', $user);
+ }
+ ),
+ );
+ }
+
+ public function test_default_lang()
+ {
+ global $phpbb_container;
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/default_lang.xml');
+
+ $renderer = $phpbb_container->get('text_formatter.renderer');
+
+ $this->assertSame('FOO_BAR', $renderer->render('<r><FOO/></r>'));
+ }
+
+ /**
+ * @dataProvider get_option_names
+ */
+ public function test_get_option($option_name)
+ {
+ global $phpbb_container;
+ $this->get_test_case_helpers()->set_s9e_services();
+
+ $renderer = $phpbb_container->get('text_formatter.renderer');
+
+ $renderer->{'set_' . $option_name}(false);
+ $this->assertFalse($renderer->{'get_' . $option_name}());
+ $renderer->{'set_' . $option_name}(true);
+ $this->assertTrue($renderer->{'get_' . $option_name}());
+ }
+
+ public function get_option_names()
+ {
+ return array(
+ array('viewcensors'),
+ array('viewflash'),
+ array('viewimg'),
+ array('viewsmilies')
+ );
+ }
+
+ public function test_styles()
+ {
+ global $phpbb_container;
+
+ $tests = array(
+ 1 => '<strong>bold</strong>',
+ 2 => '<b>bold</b>'
+ );
+
+ global $phpbb_root_path, $phpEx;
+
+ foreach ($tests as $style_id => $expected)
+ {
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->style = array('style_id' => $style_id);
+
+ $phpbb_container = new phpbb_mock_container_builder;
+ $phpbb_container->set('user', $user);
+
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/styles.xml', __DIR__ . '/fixtures/styles/');
+
+ $renderer = $phpbb_container->get('text_formatter.renderer');
+ $this->assertSame(
+ $expected,
+ $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>')
+ );
+ }
+ }
+
+ public function test_style_inheritance1()
+ {
+ global $phpbb_container, $phpbb_root_path, $phpEx;
+
+ // Style 3 inherits from 2 which inherits from 1. Only style 1 has a bbcode.html
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->style = array('style_id' => 3);
+
+ $phpbb_container = new phpbb_mock_container_builder;
+ $phpbb_container->set('user', $user);
+
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/style_inheritance.xml', __DIR__ . '/fixtures/styles/');
+
+ $renderer = $phpbb_container->get('text_formatter.renderer');
+ $this->assertSame(
+ '<strong>bold</strong>',
+ $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>')
+ );
+ }
+
+ public function test_style_inheritance2()
+ {
+ global $phpbb_container, $phpbb_root_path, $phpEx;
+
+ // Style 5 inherits from 4, but both have a bbcode.html
+ $tests = array(
+ 4 => '<b>bold</b>',
+ 5 => '<b class="barplus">bold</b>'
+ );
+
+ foreach ($tests as $style_id => $expected)
+ {
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->style = array('style_id' => $style_id);
+
+ $phpbb_container = new phpbb_mock_container_builder;
+ $phpbb_container->set('user', $user);
+
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container, __DIR__ . '/fixtures/style_inheritance.xml', __DIR__ . '/fixtures/styles/');
+
+ $renderer = $phpbb_container->get('text_formatter.renderer');
+ $this->assertSame(
+ $expected,
+ $renderer->render('<r><B><s>[b]</s>bold<e>[/b]</e></B></r>')
+ );
+ }
+ }
+
+ /**
+ * @testdox The constructor triggers a core.text_formatter_s9e_renderer_setup event
+ */
+ public function test_setup_event()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface');
+ $dispatcher
+ ->expects($this->once())
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_renderer_setup',
+ $this->callback(array($this, 'setup_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+
+ new \phpbb\textformatter\s9e\renderer(
+ $container->get('cache.driver'),
+ $container->getParameter('cache.dir'),
+ '_foo_renderer',
+ $container->get('text_formatter.s9e.factory'),
+ $dispatcher
+ );
+ }
+
+ public function setup_event_callback($vars)
+ {
+ return isset($vars['renderer'])
+ && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer;
+ }
+
+ /**
+ * @testdox render() triggers a core.text_formatter_s9e_render_before and core.text_formatter_s9e_render_after events
+ */
+ public function test_render_event()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $dispatcher = $this->getMock('phpbb\\event\\dispatcher_interface');
+ $dispatcher
+ ->expects($this->any())
+ ->method('trigger_event')
+ ->will($this->returnArgument(1));
+ $dispatcher
+ ->expects($this->at(1))
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_render_before',
+ $this->callback(array($this, 'render_before_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+ $dispatcher
+ ->expects($this->at(2))
+ ->method('trigger_event')
+ ->with(
+ 'core.text_formatter_s9e_render_after',
+ $this->callback(array($this, 'render_after_event_callback'))
+ )
+ ->will($this->returnArgument(1));
+
+ $renderer = new \phpbb\textformatter\s9e\renderer(
+ $container->get('cache.driver'),
+ $container->getParameter('cache.dir'),
+ '_foo_renderer',
+ $container->get('text_formatter.s9e.factory'),
+ $dispatcher
+ );
+ $renderer->render('<t>...</t>');
+ }
+
+ public function render_before_event_callback($vars)
+ {
+ return isset($vars['renderer'])
+ && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer
+ && isset($vars['xml'])
+ && $vars['xml'] === '<t>...</t>';
+ }
+
+ public function render_after_event_callback($vars)
+ {
+ return isset($vars['html'])
+ && $vars['html'] === '...'
+ && isset($vars['renderer'])
+ && $vars['renderer'] instanceof \phpbb\textformatter\s9e\renderer;
+ }
+
+ public function test_get_renderer()
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $renderer = $container->get('text_formatter.renderer');
+ $this->assertInstanceOf('s9e\\TextFormatter\\Renderer', $renderer->get_renderer());
+ }
+}
diff --git a/tests/text_formatter/s9e/utils_test.php b/tests/text_formatter/s9e/utils_test.php
new file mode 100644
index 0000000000..719d3cda88
--- /dev/null
+++ b/tests/text_formatter/s9e/utils_test.php
@@ -0,0 +1,276 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_textformatter_s9e_utils_test extends phpbb_test_case
+{
+ /**
+ * @dataProvider get_unparse_tests
+ */
+ public function test_unparse($original, $expected)
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $utils = $container->get('text_formatter.utils');
+
+ $this->assertSame($expected, $utils->unparse($original));
+ }
+
+ public function get_unparse_tests()
+ {
+ return array(
+ array(
+ '<t>Plain text</t>',
+ 'Plain text'
+ ),
+ array(
+ "<t>Multi<br/>\nline</t>",
+ "Multi\nline"
+ ),
+ array(
+ '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>',
+ '[b]bold[/b]'
+ )
+ );
+ }
+
+ /**
+ * @dataProvider get_clean_formatting_tests
+ */
+ public function test_clean_formatting($original, $expected)
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $utils = $container->get('text_formatter.utils');
+
+ $this->assertSame($expected, $utils->clean_formatting($original));
+ }
+
+ public function get_clean_formatting_tests()
+ {
+ return array(
+ array(
+ '<t>Plain text</t>',
+ 'Plain text'
+ ),
+ array(
+ "<t>Multi<br/>\nline</t>",
+ "Multi\nline"
+ ),
+ array(
+ '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>',
+ ' bold '
+ )
+ );
+ }
+
+ /**
+ * @dataProvider get_outermost_quote_authors_tests
+ */
+ public function test_get_outermost_quote_authors($original, $expected)
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $utils = $container->get('text_formatter.utils');
+ $parser = $container->get('text_formatter.parser');
+
+ $this->assertSame($expected, $utils->get_outermost_quote_authors($parser->parse($original)));
+ }
+
+ public function get_outermost_quote_authors_tests()
+ {
+ return array(
+ array(
+ 'No quotes here',
+ array()
+ ),
+ array(
+ '[quote="foo"]..[/quote] [quote]..[/quote]',
+ array('foo')
+ ),
+ array(
+ '[quote=foo]..[/quote] [quote]..[/quote]',
+ array('foo')
+ ),
+ array(
+ '[quote=foo]..[/quote] [quote=bar]..[/quote]',
+ array('foo', 'bar')
+ ),
+ array(
+ '[quote=foo].[quote=baz]..[/quote].[/quote] [quote=bar]..[/quote]',
+ array('foo', 'bar')
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider get_generate_quote_tests
+ */
+ public function test_generate_quote($text, $params, $expected)
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $utils = $container->get('text_formatter.utils');
+
+ $this->assertSame($expected, $utils->generate_quote($text, $params));
+ }
+
+ public function get_generate_quote_tests()
+ {
+ return array(
+ array(
+ '...',
+ array(),
+ '[quote]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => 'Brian Kibler'),
+ '[quote="Brian Kibler"]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => 'Brian "Brian Kibler" Kibler of Brian Kibler Gaming'),
+ '[quote=\'Brian "Brian Kibler" Kibler of Brian Kibler Gaming\']...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => "Brian Kibler Gaming's Brian Kibler"),
+ '[quote="Brian Kibler Gaming\'s Brian Kibler"]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => "\\\"'"),
+ '[quote="\\\\\\"\'"]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => 'Lots of doubles """ one single \' one backslash \\'),
+ '[quote=\'Lots of doubles """ one single \\\' one backslash \\\\\']...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => "Lots of singles ''' one double \" one backslash \\"),
+ '[quote="Lots of singles \'\'\' one double \\" one backslash \\\\"]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => 'Defaults to doublequotes """\'\'\''),
+ '[quote="Defaults to doublequotes \\"\\"\\"\'\'\'"]...[/quote]',
+ ),
+ array(
+ '...',
+ array(
+ 'author' => 'user',
+ 'post_id' => 123,
+ 'url' => 'http://example.org'
+ ),
+ '[quote=user post_id=123 url=http://example.org]...[/quote]',
+ ),
+ array(
+ '...',
+ array(
+ 'author' => 'user',
+ 'post_id' => 123,
+ 'user_id' => ANONYMOUS
+ ),
+ '[quote=user post_id=123]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => ' '),
+ '[quote=" "]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => 'foo bar'),
+ '[quote="foo bar"]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => '\\'),
+ '[quote="\\\\"]...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => '[quote="foo"]'),
+ '[quote=\'[quote="foo"]\']...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => '""'),
+ '[quote=\'""\']...[/quote]',
+ ),
+ array(
+ '...',
+ array('author' => "''"),
+ '[quote="\'\'"]...[/quote]',
+ ),
+ array(
+ 'This is a long quote that is definitely going to exceed 80 characters',
+ array(),
+ "[quote]\nThis is a long quote that is definitely going to exceed 80 characters\n[/quote]",
+ ),
+ array(
+ ' This is a short quote on its own line ',
+ array(),
+ '[quote]This is a short quote on its own line[/quote]',
+ ),
+ array(
+ "This is a short quote\non two lines",
+ array(),
+ "[quote]\nThis is a short quote\non two lines\n[/quote]",
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider get_remove_bbcode_tests
+ */
+ public function test_remove_bbcode($original, $name, $depth, $expected)
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services();
+ $parser = $container->get('text_formatter.parser');
+ $utils = $container->get('text_formatter.utils');
+
+ $parsed = $parser->parse($original);
+ $actual = $utils->unparse($utils->remove_bbcode($parsed, $name, $depth));
+
+ $this->assertSame($expected, $actual);
+ }
+
+ public function get_remove_bbcode_tests()
+ {
+ return array(
+ array(
+ 'Plain text',
+ 'b',
+ 1,
+ 'Plain text'
+ ),
+ array(
+ '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]',
+ 'quote',
+ 0,
+ '[b]bold[/b]',
+ ),
+ array(
+ '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]',
+ 'quote',
+ 1,
+ '[quote="u0"]q0[/quote][b]bold[/b]',
+ ),
+ array(
+ '[quote="u0"][quote="u1"][quote="u2"]q2[/quote]q1[/quote]q0[/quote][b]bold[/b]',
+ 'quote',
+ 2,
+ '[quote="u0"][quote="u1"]q1[/quote]q0[/quote][b]bold[/b]',
+ ),
+ );
+ }
+}
diff --git a/tests/text_processing/censor_text_test.php b/tests/text_processing/censor_text_test.php
index 983a5ba2d3..eda2bbb1b3 100644
--- a/tests/text_processing/censor_text_test.php
+++ b/tests/text_processing/censor_text_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_text_processing_censor_text_test extends phpbb_test_case
{
public function censor_text_data()
diff --git a/tests/text_processing/decode_message_test.php b/tests/text_processing/decode_message_test.php
new file mode 100644
index 0000000000..e2402e721a
--- /dev/null
+++ b/tests/text_processing/decode_message_test.php
@@ -0,0 +1,113 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_text_processing_decode_message_test extends phpbb_test_case
+{
+ public function setUp()
+ {
+ parent::setUp();
+
+ global $phpbb_dispatcher;
+
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
+ }
+
+ /**
+ * @dataProvider get_legacy_tests
+ */
+ public function test_legacy($original, $expected, $bbcode_uid = '')
+ {
+ $actual = $original;
+ decode_message($actual, $bbcode_uid);
+
+ $this->assertSame($expected, $actual);
+ }
+
+ public function get_legacy_tests()
+ {
+ return array(
+ array(
+ "&amp;&lt;&gt;&quot;'",
+ "&amp;&lt;&gt;&quot;'"
+ ),
+ array(
+ '<!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) -->',
+ ':)'
+ ),
+ array(
+ '<!-- w --><a class="postlink" href="http://www.phpbb.com">www.phpbb.com</a><!-- w -->',
+ 'www.phpbb.com'
+ ),
+ array(
+ '<!-- m --><a class="postlink" href="http://www.phpbb.com">http://www.phpbb.com</a><!-- m -->',
+ 'http://www.phpbb.com'
+ ),
+ array(
+ '<!-- m --><a class="postlink" href="http://www.phpbb.com">this is just text</a><!-- m -->',
+ 'http://www.phpbb.com'
+ ),
+ array(
+ '<!-- m --><a class="postlink" href="http://www.phpbb.com/some/more/link/that/is/shortened">http://www.phpbb.com/some/ ... /shortened</a><!-- m -->',
+ 'http://www.phpbb.com/some/more/link/that/is/shortened'
+ ),
+ /**
+ * Fails as per PHPBB3-8420
+ * @link http://tracker.phpbb.com/browse/PHPBB3-8420
+ *
+ array(
+ '[url=http://example.com:2cpxwbdy]<!-- s:arrow: --><img src="{SMILIES_PATH}/icon_arrow.gif" alt=":arrow:" title="Arrow" /><!-- s:arrow: --> here[/url:2cpxwbdy]',
+ '[url=http://example.com] :arrow: here[/url]',
+ '2cpxwbdy'
+ ),
+ */
+ );
+ }
+
+ /**
+ * @dataProvider get_text_formatter_tests
+ */
+ public function test_text_formatter($original, $expected)
+ {
+ $this->get_test_case_helpers()->set_s9e_services();
+
+ $actual = $original;
+ decode_message($actual);
+
+ $this->assertSame($expected, $actual);
+ }
+
+ public function get_text_formatter_tests()
+ {
+ return array(
+ array(
+ "<t>&amp;&lt;&gt;\"'",
+ "&amp;&lt;&gt;&quot;'"
+ ),
+ array(
+ '<r><E>:)</E></r>',
+ ':)'
+ ),
+ array(
+ "<t>a<br/>\nb</t>",
+ "a\nb"
+ ),
+ /**
+ * @link http://tracker.phpbb.com/browse/PHPBB3-8420
+ */
+ array(
+ '<r><URL url="http://example.com"><s>[url=http://example.com]</s> <E>:arrow:</E> here<e>[/url]</e></URL></r>',
+ '[url=http://example.com] :arrow: here[/url]'
+ ),
+ );
+ }
+}
diff --git a/tests/text_processing/fixtures/empty.xml b/tests/text_processing/fixtures/empty.xml
new file mode 100644
index 0000000000..d8206ad124
--- /dev/null
+++ b/tests/text_processing/fixtures/empty.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+</dataset>
diff --git a/tests/text_processing/fixtures/smilies.xml b/tests/text_processing/fixtures/smilies.xml
new file mode 100644
index 0000000000..25b2e60836
--- /dev/null
+++ b/tests/text_processing/fixtures/smilies.xml
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>1</value>
+ <value>:D</value>
+ <value>Very Happy</value>
+ <value>icon_e_biggrin.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>1</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>:-D</value>
+ <value>Very Happy</value>
+ <value>icon_e_biggrin.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>2</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>:grin:</value>
+ <value>Very Happy</value>
+ <value>icon_e_biggrin.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>3</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>:)</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>4</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>:-)</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>5</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>:smile:</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>6</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>7</value>
+ <value>;)</value>
+ <value>Wink</value>
+ <value>icon_e_wink.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>7</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>8</value>
+ <value>;-)</value>
+ <value>Wink</value>
+ <value>icon_e_wink.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>8</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>9</value>
+ <value>:wink:</value>
+ <value>Wink</value>
+ <value>icon_e_wink.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>9</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>10</value>
+ <value>:(</value>
+ <value>Sad</value>
+ <value>icon_e_sad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>10</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>11</value>
+ <value>:-(</value>
+ <value>Sad</value>
+ <value>icon_e_sad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>11</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>12</value>
+ <value>:sad:</value>
+ <value>Sad</value>
+ <value>icon_e_sad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>12</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>13</value>
+ <value>:o</value>
+ <value>Surprised</value>
+ <value>icon_e_surprised.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>13</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>14</value>
+ <value>:-o</value>
+ <value>Surprised</value>
+ <value>icon_e_surprised.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>14</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>15</value>
+ <value>:eek:</value>
+ <value>Surprised</value>
+ <value>icon_e_surprised.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>15</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>16</value>
+ <value>:shock:</value>
+ <value>Shocked</value>
+ <value>icon_eek.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>16</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>17</value>
+ <value>:?</value>
+ <value>Confused</value>
+ <value>icon_e_confused.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>17</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>18</value>
+ <value>:-?</value>
+ <value>Confused</value>
+ <value>icon_e_confused.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>18</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>19</value>
+ <value>:???:</value>
+ <value>Confused</value>
+ <value>icon_e_confused.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>19</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>20</value>
+ <value>8-)</value>
+ <value>Cool</value>
+ <value>icon_cool.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>20</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>21</value>
+ <value>:cool:</value>
+ <value>Cool</value>
+ <value>icon_cool.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>21</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>22</value>
+ <value>:lol:</value>
+ <value>Laughing</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>23</value>
+ <value>:x</value>
+ <value>Mad</value>
+ <value>icon_mad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>23</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>24</value>
+ <value>:-x</value>
+ <value>Mad</value>
+ <value>icon_mad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>24</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>25</value>
+ <value>:mad:</value>
+ <value>Mad</value>
+ <value>icon_mad.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>25</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>26</value>
+ <value>:P</value>
+ <value>Razz</value>
+ <value>icon_razz.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>26</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>27</value>
+ <value>:-P</value>
+ <value>Razz</value>
+ <value>icon_razz.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>27</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>28</value>
+ <value>:razz:</value>
+ <value>Razz</value>
+ <value>icon_razz.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>28</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>29</value>
+ <value>:oops:</value>
+ <value>Embarrassed</value>
+ <value>icon_redface.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>29</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>30</value>
+ <value>:cry:</value>
+ <value>Crying or Very Sad</value>
+ <value>icon_cry.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>30</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>31</value>
+ <value>:evil:</value>
+ <value>Evil or Very Mad</value>
+ <value>icon_evil.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>31</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>32</value>
+ <value>:twisted:</value>
+ <value>Twisted Evil</value>
+ <value>icon_twisted.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>32</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>33</value>
+ <value>:roll:</value>
+ <value>Rolling Eyes</value>
+ <value>icon_rolleyes.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>33</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>34</value>
+ <value>:!:</value>
+ <value>Exclamation</value>
+ <value>icon_exclaim.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>34</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>35</value>
+ <value>:?:</value>
+ <value>Question</value>
+ <value>icon_question.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>35</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>36</value>
+ <value>:idea:</value>
+ <value>Idea</value>
+ <value>icon_idea.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>36</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>37</value>
+ <value>:arrow:</value>
+ <value>Arrow</value>
+ <value>icon_arrow.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>37</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>38</value>
+ <value>:|</value>
+ <value>Neutral</value>
+ <value>icon_neutral.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>38</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>39</value>
+ <value>:-|</value>
+ <value>Neutral</value>
+ <value>icon_neutral.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>39</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>40</value>
+ <value>:mrgreen:</value>
+ <value>Mr. Green</value>
+ <value>icon_mrgreen.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>40</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>41</value>
+ <value>:geek:</value>
+ <value>Geek</value>
+ <value>icon_e_geek.gif</value>
+ <value>17</value>
+ <value>17</value>
+ <value>41</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>42</value>
+ <value>:ugeek:</value>
+ <value>Uber Geek</value>
+ <value>icon_e_ugeek.gif</value>
+ <value>17</value>
+ <value>18</value>
+ <value>42</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>43</value>
+ <value>8)</value>
+ <value>8)</value>
+ <value>custom.gif</value>
+ <value>17</value>
+ <value>18</value>
+ <value>42</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/generate_text_for_display_test.php b/tests/text_processing/generate_text_for_display_test.php
index 057416da33..86bc803c98 100644
--- a/tests/text_processing/generate_text_for_display_test.php
+++ b/tests/text_processing/generate_text_for_display_test.php
@@ -11,11 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-require_once dirname(__FILE__) . '/../mock/user.php';
-require_once dirname(__FILE__) . '/../mock/cache.php';
-
class phpbb_text_processing_generate_text_for_display_test extends phpbb_test_case
{
public function setUp()
@@ -24,21 +19,204 @@ class phpbb_text_processing_generate_text_for_display_test extends phpbb_test_ca
parent::setUp();
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher;
+ $config = new \phpbb\config\config(array());
+ set_config(null, null, null, $config);
+ }
+
+ /**
+ * @dataProvider get_legacy_tests
+ */
+ public function test_legacy($original, $expected, $uid = '', $bitfield = '', $flags = 0, $censor_text = true)
+ {
+ global $auth, $cache, $config, $user;
+
+ global $phpbb_root_path, $phpEx;
+
$cache = new phpbb_mock_cache;
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewcensors', true);
+ $user->optionset('viewflash', true);
+ $user->optionset('viewimg', true);
+ $user->optionset('viewsmilies', true);
- $user = new phpbb_mock_user;
- $user->optionset('viewcensors', false);
+ $actual = generate_text_for_display($original, $uid, $bitfield, $flags, $censor_text);
- $phpbb_dispatcher = new phpbb_mock_event_dispatcher();
+ $this->assertSame($expected, $actual);
}
- public function test_empty_string()
+ public function get_legacy_tests()
{
- $this->assertSame('', generate_text_for_display('', '', '', 0));
+ return array(
+ array(
+ '',
+ ''
+ ),
+ array(
+ '0',
+ '0'
+ ),
+ );
}
- public function test_zero_string()
+ public function test_censor_is_restored()
{
- $this->assertSame('0', generate_text_for_display('0', '', '', 0));
+ global $auth, $user, $config, $phpbb_container;
+
+ $phpbb_container = new phpbb_mock_container_builder;
+
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ // Do not ignore word censoring by user (switch censoring on in UCP)
+ $user->optionset('viewcensors', true);
+
+ $config = new \phpbb\config\config(array('allow_nocensors' => true));
+
+ $auth = $this->getMock('phpbb\\auth\\auth');
+ $auth->expects($this->any())
+ ->method('acl_get')
+ ->with('u_chgcensors')
+ ->will($this->returnValue(true));
+
+ $phpbb_container->set('user', $user);
+ $phpbb_container->set('config', $config);
+ $phpbb_container->set('auth', $auth);
+
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container);
+ $renderer = $phpbb_container->get('text_formatter.renderer');
+
+ $original = '<r><CENSOR with="banana">apple</CENSOR></r>';
+
+ $renderer->set_viewcensors(false);
+ $this->assertSame('apple', $renderer->render($original));
+ $renderer->set_viewcensors(true);
+ $this->assertSame('banana', $renderer->render($original));
+ $this->assertSame('apple', generate_text_for_display($original, '', '', 0, false));
+ $this->assertSame('banana', $renderer->render($original), 'The original setting was not restored');
+
+ $renderer->set_viewcensors(false);
+ $this->assertSame('apple', $renderer->render($original));
+ $this->assertSame('banana', generate_text_for_display($original, '', '', 0, true));
+ $this->assertSame('apple', $renderer->render($original), 'The original setting was not restored');
+
+ // Test user option switch to ignore censoring
+ $renderer->set_viewcensors(true);
+ // 1st: censoring is still on in UCP
+ $this->assertSame('banana', generate_text_for_display($original, '', '', 0, true));
+ // 2nd: switch censoring off in UCP
+ $user->optionset('viewcensors', false);
+ $this->assertSame('apple', generate_text_for_display($original, '', '', 0, true));
+ }
+
+ /**
+ * @dataProvider get_text_formatter_tests
+ */
+ public function test_text_formatter($original, $expected, $censor_text = true, $setup = null)
+ {
+ global $auth, $user, $config, $phpbb_container;
+
+ $phpbb_container = new phpbb_mock_container_builder;
+
+ if (isset($setup))
+ {
+ $setup($phpbb_container, $this);
+ }
+
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container);
+
+ $this->assertSame($expected, generate_text_for_display($original, '', '', 0, $censor_text));
+ }
+
+ public function get_text_formatter_tests()
+ {
+ return array(
+ array(
+ '<t>Plain text</t>',
+ 'Plain text'
+ ),
+ array(
+ '<r>Hello <URL url="http://example.org"><s>[url=http://example.org]</s>world<e>[/url]</e></URL></r>',
+ 'Hello <a href="http://example.org" class="postlink">world</a>'
+ ),
+ array(
+ '<t>&amp;&lt;&gt;"\'</t>',
+ '&amp;&lt;&gt;"\''
+ ),
+ array(
+ '<r><CENSOR with="banana">apple</CENSOR></r>',
+ 'banana',
+ true
+ ),
+ array(
+ '<r><CENSOR with="banana">apple</CENSOR></r>',
+ 'apple',
+ false
+ ),
+ array(
+ '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>',
+ '<object classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://active.macromedia.com/flash2/cabs/swflash.cab#version=5,0,0,0" width="123" height="456"><param name="movie" value="http://localhost/foo.swf"><param name="play" value="false"><param name="loop" value="false"><param name="quality" value="high"><param name="allowScriptAccess" value="never"><param name="allowNetworking" value="internal"><embed src="http://localhost/foo.swf" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" width="123" height="456" play="false" loop="false" quality="high" allowscriptaccess="never" allownetworking="internal"></object>'
+ ),
+ array(
+ '<r><FLASH url="http://localhost/foo.swf" width="123" height="456"><s>[flash=123,456]</s>http://localhost/foo.swf<e>[/flash]</e></FLASH></r>',
+ 'http://localhost/foo.swf',
+ true,
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewflash', false);
+
+ $phpbb_container->set('user', $user);
+ }
+ ),
+ array(
+ '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>',
+ '<img src="http://localhost/mrgreen.gif" class="postimage" alt="Image">'
+ ),
+ array(
+ '<r><IMG src="http://localhost/mrgreen.gif"><s>[img]</s><URL url="http://localhost/mrgreen.gif">http://localhost/mrgreen.gif</URL><e>[/img]</e></IMG></r>',
+ '<a href="http://localhost/mrgreen.gif" class="postlink">http://localhost/mrgreen.gif</a>',
+ true,
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('viewimg', false);
+
+ $phpbb_container->set('user', $user);
+ }
+ ),
+ array(
+ '<r><E>:)</E></r>',
+ '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile">'
+ ),
+ array(
+ '<r><E>:)</E></r>',
+ ':)',
+ true,
+ function ($phpbb_container)
+ {
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+ $user = new \phpbb\user($lang, '\phpbb\datetime');
+ $user->optionset('smilies', false);
+
+ $phpbb_container->set('user', $user);
+ }
+ ),
+ );
}
}
diff --git a/tests/text_processing/generate_text_for_edit_test.php b/tests/text_processing/generate_text_for_edit_test.php
new file mode 100644
index 0000000000..8258a196f5
--- /dev/null
+++ b/tests/text_processing/generate_text_for_edit_test.php
@@ -0,0 +1,89 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_text_processing_generate_text_for_edit_test extends phpbb_test_case
+{
+ /**
+ * @dataProvider get_legacy_tests
+ */
+ public function test_legacy($original, $expected, $uid = '', $flags = 0)
+ {
+ global $cache, $user, $phpbb_dispatcher;
+
+ $cache = new phpbb_mock_cache;
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher;
+
+ $user = new phpbb_mock_user;
+ $user->optionset('viewcensors', false);
+
+ $return = generate_text_for_edit($original, $uid, $flags);
+
+ $this->assertSame($expected, $return['text']);
+ }
+
+ public function get_legacy_tests()
+ {
+ return array(
+ array(
+ '',
+ ''
+ ),
+ array(
+ '0',
+ '0'
+ ),
+ array(
+ 'Hello [url=http&#58;//example&#46;org:1f4coh9x]world[/url:1f4coh9x] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) -->',
+ 'Hello [url=http&#58;//example&#46;org]world[/url] :)',
+ '1f4coh9x',
+ 0
+ ),
+ array(
+ "&amp;&lt;&gt;&quot;'",
+ "&amp;&lt;&gt;&quot;'"
+ )
+ );
+ }
+
+ /**
+ * @dataProvider get_text_formatter_tests
+ */
+ public function test_text_formatter($original, $expected)
+ {
+ global $phpbb_dispatcher;
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher;
+ $this->get_test_case_helpers()->set_s9e_services();
+
+ $return = generate_text_for_edit($original, '', 0);
+
+ $this->assertSame($expected, $return['text']);
+ }
+
+ public function get_text_formatter_tests()
+ {
+ return array(
+ array(
+ '<t>Plain text</t>',
+ 'Plain text'
+ ),
+ array(
+ '<r>Hello <URL url="http://example.org"><s>[url=http://example.org]</s>world<e>[/url]</e></URL> <E>:)</E></r>',
+ 'Hello [url=http://example.org]world[/url] :)'
+ ),
+ array(
+ '<t>&amp;&lt;&gt;"\'</t>',
+ "&amp;&lt;&gt;&quot;'"
+ )
+ );
+ }
+}
diff --git a/tests/text_processing/generate_text_for_storage_test.php b/tests/text_processing/generate_text_for_storage_test.php
new file mode 100644
index 0000000000..f0588fec4f
--- /dev/null
+++ b/tests/text_processing/generate_text_for_storage_test.php
@@ -0,0 +1,178 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_text_processing_generate_text_for_storage_test extends phpbb_test_case
+{
+ public function setUp()
+ {
+ global $config, $phpbb_container, $phpbb_dispatcher;
+
+ parent::setUp();
+
+ $config = new \phpbb\config\config(array());
+ set_config(null, null, null, $config);
+
+ $phpbb_container = new phpbb_mock_container_builder;
+ $phpbb_container->set('config', $config);
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container);
+
+ $phpbb_dispatcher = new phpbb_mock_event_dispatcher;
+ }
+
+ /**
+ * @dataProvider get_text_formatter_tests
+ */
+ public function test_text_formatter($original, $expected, $allow_bbcode, $allow_urls, $allow_smilies, $allow_img_bbcode, $allow_flash_bbcode, $allow_quote_bbcode, $allow_url_bbcode, $setup = null)
+ {
+ $actual = $original;
+ $uid = '';
+ $bitfield = '';
+ $flags = 0;
+
+ if (isset($setup))
+ {
+ $setup();
+ }
+
+ generate_text_for_storage($actual, $uid, $bitfield, $flags, $allow_bbcode, $allow_urls, $allow_smilies, $allow_img_bbcode, $allow_flash_bbcode, $allow_quote_bbcode, $allow_url_bbcode);
+
+ $this->assertSame($expected, $actual);
+ }
+
+ public function get_text_formatter_tests()
+ {
+ return array(
+ array(
+ 'Hello world',
+ '<t>Hello world</t>',
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ ),
+ array(
+ 'Hello [url=http://example.org]world[/url] :)',
+ '<r>Hello <URL url="http://example.org"><s>[url=http://example.org]</s>world<e>[/url]</e></URL> <E>:)</E></r>',
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ ),
+ array(
+ '&<>"\'',
+ '<t>&amp;&lt;&gt;"\'</t>',
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<t>[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</t>',
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</r>',
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<r>[b]..[/b] <URL url="http://example.org">http://example.org</URL> :) [img]<URL url="http://example.org/img.png">http://example.org/img.png</URL>[/img] [flash=123,123]<URL url="http://example.org/flash.swf">http://example.org/flash.swf</URL>[/flash] [quote]...[/quote] [url]<URL url="http://example.org">http://example.org</URL>[/url]</r>',
+ false,
+ true,
+ false,
+ false,
+ false,
+ false,
+ true,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<r>[b]..[/b] http://example.org <E>:)</E> [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</r>',
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ false,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) <IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG> [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]</r>',
+ true,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] <FLASH height="123" url="http://example.org/flash.swf" width="123"><s>[flash=123,123]</s>http://example.org/flash.swf<e>[/flash]</e></FLASH> [quote]...[/quote] [url]http://example.org[/url]</r>',
+ true,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] <QUOTE><s>[quote]</s>...<e>[/quote]</e></QUOTE> [url]http://example.org[/url]</r>',
+ true,
+ false,
+ false,
+ false,
+ false,
+ true,
+ false,
+ ),
+ array(
+ '[b]..[/b] http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] [url]http://example.org[/url]',
+ '<r><B><s>[b]</s>..<e>[/b]</e></B> http://example.org :) [img]http://example.org/img.png[/img] [flash=123,123]http://example.org/flash.swf[/flash] [quote]...[/quote] <URL url="http://example.org"><s>[url]</s>http://example.org<e>[/url]</e></URL></r>',
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ ),
+ );
+ }
+}
diff --git a/tests/text_processing/make_clickable_test.php b/tests/text_processing/make_clickable_test.php
index 95e304dd97..3c8539c612 100644
--- a/tests/text_processing/make_clickable_test.php
+++ b/tests/text_processing/make_clickable_test.php
@@ -11,9 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php';
-
class phpbb_text_processing_make_clickable_test extends phpbb_test_case
{
public function make_clickable_data()
diff --git a/tests/text_processing/message_parser_test.php b/tests/text_processing/message_parser_test.php
new file mode 100644
index 0000000000..a3dbf644f6
--- /dev/null
+++ b/tests/text_processing/message_parser_test.php
@@ -0,0 +1,540 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once __DIR__ . '/../../phpBB/includes/bbcode.php';
+require_once __DIR__ . '/../../phpBB/includes/message_parser.php';
+
+class phpbb_text_processing_message_parser_test extends phpbb_test_case
+{
+ public static function setUpBeforeClass()
+ {
+ parent::setUpBeforeClass();
+
+ // Set up an intercepting proxy for getimagesize() calls
+ stream_wrapper_unregister('http');
+ stream_wrapper_register('http', __CLASS__ . '_proxy');
+ }
+
+ public static function tearDownAfterClass()
+ {
+ parent::tearDownAfterClass();
+ stream_wrapper_restore('http');
+ }
+
+ protected function prepare_s9e_services($setup = null)
+ {
+ global $config, $phpbb_container, $user;
+
+ $config = new \phpbb\config\config(array('max_poll_options' => 999));
+
+ $map = array(
+ array('MAX_FLASH_HEIGHT_EXCEEDED', 123, 'Your flash files may only be up to 123 pixels high.'),
+ array('MAX_FLASH_WIDTH_EXCEEDED', 456, 'Your flash files may only be up to 456 pixels wide.'),
+ array('MAX_FONT_SIZE_EXCEEDED', 120, 'You may only use fonts up to size 120.'),
+ array('MAX_FONT_SIZE_EXCEEDED', 200, 'You may only use fonts up to size 200.'),
+ array('MAX_IMG_HEIGHT_EXCEEDED', 12, 'Your images may only be up to 12 pixels high.'),
+ array('MAX_IMG_WIDTH_EXCEEDED', 34, 'Your images may only be up to 34 pixels wide.'),
+ array('TOO_MANY_SMILIES', 3, 'Your message contains too many smilies. The maximum number of smilies allowed is 3.'),
+ array('TOO_MANY_URLS', 2, 'Your message contains too many URLs. The maximum number of URLs allowed is 2.'),
+ array('UNAUTHORISED_BBCODE', '[flash]', 'You cannot use certain BBCodes: [flash].'),
+ array('UNAUTHORISED_BBCODE', '[img]', 'You cannot use certain BBCodes: [img].'),
+ array('UNAUTHORISED_BBCODE', '[quote]', 'You cannot use certain BBCodes: [quote].'),
+ array('UNAUTHORISED_BBCODE', '[url]', 'You cannot use certain BBCodes: [url].'),
+ array('UNABLE_GET_IMAGE_SIZE', 'It was not possible to determine the dimensions of the image.'),
+ );
+
+ $user = $this->getMockBuilder('phpbb\\user')->disableOriginalConstructor()->getMock();
+ $user->expects($this->any())
+ ->method('lang')
+ ->will($this->returnValueMap($map));
+
+ $user->data = array(
+ 'is_bot' => false,
+ 'is_registered' => true,
+ 'user_id' => 2,
+ );
+ $user->style = array('style_id' => 1);
+
+ $user->lang = array(
+ 'NO_POLL_TITLE' => 'You have to enter a poll title.',
+ 'POLL_TITLE_TOO_LONG' => 'The poll title must contain fewer than 100 characters.',
+ 'POLL_TITLE_COMP_TOO_LONG' => 'The parsed size of your poll title is too large, consider removing BBCodes or smilies.',
+ 'TOO_FEW_POLL_OPTIONS' => 'You must enter at least two poll options.',
+ 'TOO_MANY_POLL_OPTIONS' => 'You have tried to enter too many poll options.',
+ 'TOO_MANY_USER_OPTIONS' => 'You cannot specify more options per user than existing poll options.',
+ );
+
+ $phpbb_container = new phpbb_mock_container_builder;
+ $phpbb_container->set('user', $user);
+ $phpbb_container->set('config', $config);
+
+ if (isset($setup))
+ {
+ $setup($phpbb_container, $this);
+ }
+
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container);
+ }
+
+ /**
+ * @dataProvider get_test_polls
+ */
+ public function test_parse_poll($poll, $expected, $warn_msg = array())
+ {
+ $this->prepare_s9e_services();
+
+ $message_parser = new parse_message('Me[i]s[/i]sage');
+
+ // Add some default values
+ $poll += array(
+ 'poll_length' => 123,
+ 'poll_start' => 123,
+ 'poll_last_vote' => 123,
+ 'poll_vote_change' => true,
+ 'enable_bbcode' => true,
+ 'enable_urls' => true,
+ 'enable_smilies' => true,
+ 'img_status' => true
+ );
+
+ $message_parser->parse_poll($poll);
+ $this->assertSame($expected, array_intersect_key($poll, $expected));
+
+ $this->assertSame(
+ '<r>Me<I><s>[i]</s>s<e>[/i]</e></I>sage</r>',
+ $message_parser->parse(true, true, true, true, true, true, true, false)
+ );
+
+ $this->assertSame($warn_msg, $message_parser->warn_msg);
+ }
+
+ public function get_test_polls()
+ {
+ return array(
+ array(
+ array(
+ 'poll_title' => 'foo [b]bar[/b] baz',
+ 'poll_option_text' => "[i]foo[/i]\nbar\n[i]baz[/i]",
+ 'poll_max_options' => 3,
+ 'poll_options_size' => 3
+ ),
+ array(
+ 'poll_title' => '<r>foo <B><s>[b]</s>bar<e>[/b]</e></B> baz</r>',
+ 'poll_option_text' => "<r><I><s>[i]</s>foo<e>[/i]</e></I></r>\n<t>bar</t>\n<r><I><s>[i]</s>baz<e>[/i]</e></I></r>",
+ 'poll_options' => array(
+ '<r><I><s>[i]</s>foo<e>[/i]</e></I></r>',
+ '<t>bar</t>',
+ '<r><I><s>[i]</s>baz<e>[/i]</e></I></r>'
+ )
+ )
+ ),
+ array(
+ array(
+ 'poll_title' => 'xxx',
+ 'poll_option_text' => "[quote]quote[/quote]\n:)",
+ 'poll_max_options' => 2,
+ 'poll_options_size' => 2
+ ),
+ array(
+ 'poll_title' => '<t>xxx</t>',
+ 'poll_option_text' => "<t>[quote]quote[/quote]</t>\n<r><E>:)</E></r>",
+ 'poll_options' => array(
+ '<t>[quote]quote[/quote]</t>',
+ '<r><E>:)</E></r>'
+ )
+ ),
+ array('You cannot use certain BBCodes: [quote].')
+ ),
+ array(
+ array(
+ 'poll_title' => 'xxx',
+ 'poll_option_text' => "[flash=12,34]http://example.org/x.swf[/flash]\n:)",
+ 'poll_max_options' => 2,
+ 'poll_options_size' => 2
+ ),
+ array(
+ 'poll_title' => '<t>xxx</t>',
+ 'poll_option_text' => "<t>[flash=12,34]http://example.org/x.swf[/flash]</t>\n<r><E>:)</E></r>",
+ 'poll_options' => array(
+ '<t>[flash=12,34]http://example.org/x.swf[/flash]</t>',
+ '<r><E>:)</E></r>'
+ )
+ ),
+ array('You cannot use certain BBCodes: [flash].')
+ ),
+ array(
+ array(
+ 'poll_title' => 'xxx',
+ 'poll_option_text' => "[b]x\ny[/b]",
+ 'poll_max_options' => 2,
+ 'poll_options_size' => 2
+ ),
+ array(
+ 'poll_title' => '<t>xxx</t>',
+ 'poll_option_text' => "<r><B><s>[b]</s>x</B></r>\n<t>y[/b]</t>",
+ 'poll_options' => array(
+ '<r><B><s>[b]</s>x</B></r>',
+ '<t>y[/b]</t>',
+ )
+ )
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider get_test_cases
+ */
+ public function test_options($original, $expected, array $args, $setup = null, $warn_msg = array())
+ {
+ $this->prepare_s9e_services($setup);
+
+ $message_parser = new parse_message($original);
+ call_user_func_array(array($message_parser, 'parse'), $args);
+
+ $this->assertSame($expected, $message_parser->message);
+ $this->assertSame($warn_msg, $message_parser->warn_msg);
+ }
+
+ public function get_test_cases()
+ {
+ return array(
+ array(
+ '[b]bold[/b]',
+ '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>',
+ array(true, true, true, true, true, true, true)
+ ),
+ array(
+ '[b]bold[/b]',
+ '<t>[b]bold[/b]</t>',
+ array(false, true, true, true, true, true, true)
+ ),
+ array(
+ 'http://example.org',
+ '<r><URL url="http://example.org">http://example.org</URL></r>',
+ array(true, true, true, true, true, true, true)
+ ),
+ array(
+ 'http://example.org',
+ '<t>http://example.org</t>',
+ array(true, false, true, true, true, true, true)
+ ),
+ array(
+ ':)',
+ '<r><E>:)</E></r>',
+ array(true, true, true, true, true, true, true)
+ ),
+ array(
+ ':)',
+ '<t>:)</t>',
+ array(true, true, false, true, true, true, true)
+ ),
+ array(
+ '[url=http://example.org][img]http://example.org/img.png[/img][/url]',
+ '<r><URL url="http://example.org"><s>[url=http://example.org]</s><IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG><e>[/url]</e></URL></r>',
+ array(true, true, true, true, true, true, true)
+ ),
+ array(
+ '[url=http://example.org][img]http://example.org/img.png[/img][/url]',
+ '<r><URL url="http://example.org"><s>[url=http://example.org]</s>[img]http://example.org/img.png[/img]<e>[/url]</e></URL></r>',
+ array(true, true, true, false, true, true, true),
+ null,
+ array('You cannot use certain BBCodes: [img].')
+ ),
+ array(
+ '[flash=12,34]http://example.org/foo.swf[/flash]',
+ '<r><FLASH height="34" url="http://example.org/foo.swf" width="12"><s>[flash=12,34]</s><URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL><e>[/flash]</e></FLASH></r>',
+ array(true, true, true, true, true, true, true)
+ ),
+ array(
+ '[flash=12,34]http://example.org/foo.swf[/flash]',
+ '<r>[flash=12,34]<URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL>[/flash]</r>',
+ array(true, true, true, true, false, true, true),
+ null,
+ array('You cannot use certain BBCodes: [flash].')
+ ),
+ array(
+ '[quote="foo"]bar :)[/quote]',
+ '<r><QUOTE author="foo"><s>[quote="foo"]</s>bar <E>:)</E><e>[/quote]</e></QUOTE></r>',
+ array(true, true, true, true, true, true, true)
+ ),
+ array(
+ '[quote="foo"]bar :)[/quote]',
+ '<r>[quote="foo"]bar <E>:)</E>[/quote]</r>',
+ array(true, true, true, true, true, false, true),
+ null,
+ array('You cannot use certain BBCodes: [quote].')
+ ),
+ array(
+ '[url=http://example.org][img]http://example.org/img.png[/img][/url]',
+ '<r><URL url="http://example.org"><s>[url=http://example.org]</s><IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG><e>[/url]</e></URL></r>',
+ array(true, true, true, true, true, true, true)
+ ),
+ array(
+ '[url=http://example.org][img]http://example.org/img.png[/img][/url]',
+ '<r>[url=http://example.org]<IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG>[/url]</r>',
+ array(true, true, true, true, true, true, false),
+ null,
+ array('You cannot use certain BBCodes: [url].')
+ ),
+ array(
+ '[size=200]200[/size]',
+ '<r><SIZE size="200"><s>[size=200]</s>200<e>[/size]</e></SIZE></r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_font_size', 200);
+ }
+ ),
+ array(
+ '[size=200]200[/size]',
+ '<r><SIZE size="200"><s>[size=200]</s>200<e>[/size]</e></SIZE></r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_font_size', 0);
+ }
+ ),
+ array(
+ '[size=2000]2000[/size]',
+ '<t>[size=2000]2000[/size]</t>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_font_size', 200);
+ },
+ array('You may only use fonts up to size 200.')
+ ),
+ array(
+ '[size=0]0[/size]',
+ '<t>[size=0]0[/size]</t>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_font_size', 200);
+ }
+ ),
+ array(
+ '[size=200]200[/size]',
+ '<r><SIZE size="200"><s>[size=200]</s>200<e>[/size]</e></SIZE></r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_sig_font_size', 200);
+ }
+ ),
+ array(
+ '[size=200]200[/size]',
+ '<t>[size=200]200[/size]</t>',
+ array(true, true, true, true, true, true, true, true, 'sig'),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_sig_font_size', 120);
+ },
+ array('You may only use fonts up to size 120.')
+ ),
+ array(
+ '[img]http://example.org/100x100.png[/img]',
+ '<r>[img]<URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL>[/img]</r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_img_height', 12);
+ },
+ array('Your images may only be up to 12 pixels high.')
+ ),
+ array(
+ '[img]http://example.org/100x100.png[/img]',
+ '<r>[img]<URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL>[/img]</r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_img_width', 34);
+ },
+ array('Your images may only be up to 34 pixels wide.')
+ ),
+ array(
+ '[img]http://example.org/100x100.png[/img]',
+ '<r><IMG src="http://example.org/100x100.png"><s>[img]</s><URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL><e>[/img]</e></IMG></r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_img_height', 0);
+ $phpbb_container->get('config')->set('max_post_img_width', 0);
+ }
+ ),
+ array(
+ '[img]http://example.org/100x100.png[/img]',
+ '<r><IMG src="http://example.org/100x100.png"><s>[img]</s><URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL><e>[/img]</e></IMG></r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_img_height', 100);
+ $phpbb_container->get('config')->set('max_post_img_width', 100);
+ }
+ ),
+ array(
+ '[img]http://example.org/100x100.png[/img]',
+ '<r><IMG src="http://example.org/100x100.png"><s>[img]</s><URL url="http://example.org/100x100.png">http://example.org/100x100.png</URL><e>[/img]</e></IMG></r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_sig_img_height', 12);
+ $phpbb_container->get('config')->set('max_sig_img_width', 34);
+ }
+ ),
+ array(
+ '[img]http://example.org/404.png[/img]',
+ '<r>[img]<URL url="http://example.org/404.png">http://example.org/404.png</URL>[/img]</r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_img_height', 12);
+ },
+ array('It was not possible to determine the dimensions of the image.')
+ ),
+ array(
+ '[flash=999,999]http://example.org/foo.swf[/flash]',
+ '<r>[flash=999,999]<URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL>[/flash]</r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_img_height', 123);
+ },
+ array('Your flash files may only be up to 123 pixels high.')
+ ),
+ array(
+ '[flash=999,999]http://example.org/foo.swf[/flash]',
+ '<r>[flash=999,999]<URL url="http://example.org/foo.swf">http://example.org/foo.swf</URL>[/flash]</r>',
+ array(true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_img_width', 456);
+ },
+ array('Your flash files may only be up to 456 pixels wide.')
+ ),
+ array(
+ ':) :) :)',
+ '<r><E>:)</E> <E>:)</E> <E>:)</E></r>',
+ array(true, true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_smilies', 3);
+ }
+ ),
+ array(
+ ':) :) :) :)',
+ '<r><E>:)</E> <E>:)</E> <E>:)</E> :)</r>',
+ array(true, true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_smilies', 3);
+ },
+ array('Your message contains too many smilies. The maximum number of smilies allowed is 3.')
+ ),
+ array(
+ ':) :) :) :)',
+ '<r><E>:)</E> <E>:)</E> <E>:)</E> <E>:)</E></r>',
+ array(true, true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_smilies', 0);
+ }
+ ),
+ array(
+ ':) :) :) :)',
+ '<r><E>:)</E> <E>:)</E> <E>:)</E> <E>:)</E></r>',
+ array(true, true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_sig_smilies', 3);
+ }
+ ),
+ array(
+ ':) :) :) :)',
+ '<r><E>:)</E> <E>:)</E> <E>:)</E> :)</r>',
+ array(true, true, true, true, true, true, true, true, 'sig'),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_sig_smilies', 3);
+ },
+ array('Your message contains too many smilies. The maximum number of smilies allowed is 3.')
+ ),
+ array(
+ 'http://example.org http://example.org http://example.org',
+ '<r><URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL> http://example.org</r>',
+ array(true, true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_urls', 2);
+ },
+ array('Your message contains too many URLs. The maximum number of URLs allowed is 2.')
+ ),
+ array(
+ 'http://example.org http://example.org http://example.org',
+ '<r><URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL></r>',
+ array(true, true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_post_urls', 0);
+ }
+ ),
+ array(
+ 'http://example.org http://example.org http://example.org',
+ '<r><URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL> <URL url="http://example.org">http://example.org</URL></r>',
+ array(true, true, true, true, true, true, true, true),
+ function ($phpbb_container)
+ {
+ $phpbb_container->get('config')->set('max_sig_urls', 2);
+ }
+ ),
+ );
+ }
+}
+
+class phpbb_text_processing_message_parser_test_proxy
+{
+ protected $response;
+
+ public function stream_open($url)
+ {
+ if (strpos($url, '100x100'))
+ {
+ // Return a 100 x 100 PNG image
+ $this->response = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQAAAABYmaj5AAAAE0lEQVR4AWOgKxgFo2AUjIJRAAAFeAABHs0ozQAAAABJRU5ErkJggg==');
+ }
+ else
+ {
+ $this->response = '404 not found';
+ }
+
+ return true;
+ }
+
+ public function stream_stat()
+ {
+ return false;
+ }
+
+ public function stream_read($len)
+ {
+ $chunk = substr($this->response, 0, $len);
+ $this->response = substr($this->response, $len);
+
+ return $chunk;
+ }
+
+ public function stream_eof()
+ {
+ return ($this->response === false);
+ }
+}
diff --git a/tests/text_processing/smilies_test.php b/tests/text_processing/smilies_test.php
new file mode 100644
index 0000000000..3778e5f58c
--- /dev/null
+++ b/tests/text_processing/smilies_test.php
@@ -0,0 +1,49 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_text_processing_smilies_test extends phpbb_test_case
+{
+ /**
+ * @dataProvider get_text_formatter_tests
+ */
+ public function test_text_formatter($original, $expected)
+ {
+ $container = $this->get_test_case_helpers()->set_s9e_services(null, __DIR__ . '/fixtures/smilies.xml');
+ $parser = $container->get('text_formatter.parser');
+ $renderer = $container->get('text_formatter.renderer');
+
+ $this->assertSame($expected, $renderer->render($parser->parse($original)));
+ }
+
+ public function get_text_formatter_tests()
+ {
+ return array(
+ array(
+ ':) beginning',
+ '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile"> beginning'
+ ),
+ array(
+ 'end :)',
+ 'end <img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile">'
+ ),
+ array(
+ ':)',
+ '<img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile">'
+ ),
+ array(
+ 'xx (18) 8) xx',
+ 'xx (18) <img class="smilies" src="phpBB/images/smilies/custom.gif" width="17" height="18" alt="8)" title="8)"> xx'
+ ),
+ );
+ }
+}
diff --git a/tests/text_processing/strip_bbcode_test.php b/tests/text_processing/strip_bbcode_test.php
new file mode 100644
index 0000000000..9acedc2872
--- /dev/null
+++ b/tests/text_processing/strip_bbcode_test.php
@@ -0,0 +1,39 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_text_processing_strip_bbcode_test extends phpbb_test_case
+{
+ public function test_legacy()
+ {
+ $original = '[b:20m4ill1]bold[/b:20m4ill1]';
+ $expected = ' bold ';
+
+ $actual = $original;
+ strip_bbcode($actual);
+
+ $this->assertSame($expected, $actual, '20m4ill1');
+ }
+
+ public function test_s9e()
+ {
+ $phpbb_container = $this->get_test_case_helpers()->set_s9e_services();
+
+ $original = '<r><B><s>[b]</s>bold<e>[/b]</e></B></r>';
+ $expected = ' bold ';
+
+ $actual = $original;
+ strip_bbcode($actual);
+
+ $this->assertSame($expected, $actual);
+ }
+}
diff --git a/tests/text_processing/tickets_data/PHPBB3-10002.html b/tests/text_processing/tickets_data/PHPBB3-10002.html
new file mode 100644
index 0000000000..82990b2253
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10002.html
@@ -0,0 +1,2 @@
+<blockquote class="uncited"><div><ul><li>one
+<blockquote class="uncited"><div><ul><li>two</li></ul></div></blockquote></li></ul></div></blockquote> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10002.txt b/tests/text_processing/tickets_data/PHPBB3-10002.txt
new file mode 100644
index 0000000000..fe2f29073f
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10002.txt
@@ -0,0 +1,2 @@
+[quote][list][*]one
+[quote][list][*]two[/list][/quote] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10122.html b/tests/text_processing/tickets_data/PHPBB3-10122.html
new file mode 100644
index 0000000000..0803c895a8
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10122.html
@@ -0,0 +1 @@
+<ul style="list-style-type:none"><li>This is my indented text</li></ul> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10122.txt b/tests/text_processing/tickets_data/PHPBB3-10122.txt
new file mode 100644
index 0000000000..a5e059df66
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10122.txt
@@ -0,0 +1 @@
+[list=none][*]This is my indented text[/list] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10268.html b/tests/text_processing/tickets_data/PHPBB3-10268.html
new file mode 100644
index 0000000000..13b71b4823
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10268.html
@@ -0,0 +1,4 @@
+<blockquote><div><cite><a href="http://phpbb.com" class="postlink">http://phpbb.com</a> wrote:</cite>...</div></blockquote>
+<blockquote><div><cite><a href="http://phpbb.com" class="postlink"> http://phpbb.com</a> wrote:</cite>...</div></blockquote>
+<span style="font-weight:bold"><a href="http://phpbb.com" class="postlink">http://phpbb.com</a></span><br>
+<span style="font-weight:bold"> <a href="http://phpbb.com" class="postlink">http://phpbb.com</a></span><br>
diff --git a/tests/text_processing/tickets_data/PHPBB3-10268.txt b/tests/text_processing/tickets_data/PHPBB3-10268.txt
new file mode 100644
index 0000000000..b4e49c9454
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10268.txt
@@ -0,0 +1,4 @@
+[quote="http://phpbb.com"]...[/quote]
+[quote=" http://phpbb.com"]...[/quote]
+[b]http://phpbb.com[/b]
+[b] http://phpbb.com[/b]
diff --git a/tests/text_processing/tickets_data/PHPBB3-10425.html b/tests/text_processing/tickets_data/PHPBB3-10425.html
new file mode 100644
index 0000000000..522b2f8858
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10425.html
@@ -0,0 +1,3 @@
+<a href="http://ar.wikipedia.org/wiki/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" class="postlink">http://ar.wikipedia.org/wiki/الصÙحة_الرئيسية</a><br>
+<a href="http://ar.wikipedia.org/wiki/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" class="postlink">http://ar.wikipedia.org/wiki/الصÙحة_الرئيسية</a><br>
+<a href="http://ar.wikipedia.org/wiki/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" class="postlink">link</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10425.txt b/tests/text_processing/tickets_data/PHPBB3-10425.txt
new file mode 100644
index 0000000000..d93c0446b6
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10425.txt
@@ -0,0 +1,3 @@
+http://ar.wikipedia.org/wiki/الصÙحة_الرئيسية
+[url]http://ar.wikipedia.org/wiki/الصÙحة_الرئيسية[/url]
+[url=http://ar.wikipedia.org/wiki/الصÙحة_الرئيسية]link[/url] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10587.html b/tests/text_processing/tickets_data/PHPBB3-10587.html
new file mode 100644
index 0000000000..4c2e536989
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10587.html
@@ -0,0 +1,2 @@
+<a href="http://example.org/?tourney%5Bid%5D=34&amp;action=brackets" class="postlink">http://example.org/?tourney[id]=34&amp;action=brackets</a><br>
+<a href="http://example.org/?tourney%5Bid%5D=34&amp;action=brackets" class="postlink">link</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10587.txt b/tests/text_processing/tickets_data/PHPBB3-10587.txt
new file mode 100644
index 0000000000..84788b720d
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10587.txt
@@ -0,0 +1,2 @@
+[url]http://example.org/?tourney[id]=34&action=brackets[/url]
+[url="http://example.org/?tourney[id]=34&action=brackets"]link[/url] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10922.html b/tests/text_processing/tickets_data/PHPBB3-10922.html
new file mode 100644
index 0000000000..3ff117f171
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10922.html
@@ -0,0 +1,9 @@
+<a href="mailto:user@example.org">user@example.org</a><br>
+<a href="mailto:user@example.org">...</a><br>
+<a href="mailto:user@example.org">...</a><br>
+<a href="mailto:user@example.org?subject=Hello">...</a><br>
+<a href="mailto:user@example.org?subject=Hi%20there">user@example.org</a><br>
+<a href="mailto:user@example.org?body=Hi%20there">user@example.org</a><br>
+<a href="mailto:user@example.org?subject=Hello&amp;body=Sent%20from%20phpBB">user@example.org</a><br>
+<a href="mailto:user@example.org?subject=Hello&amp;body=Sent%20from%20phpBB">user@example.org</a><br>
+<a href="mailto:user@example.org?subject=Hello&amp;body=Sent%20from%20phpBB">...</a><br>
diff --git a/tests/text_processing/tickets_data/PHPBB3-10922.txt b/tests/text_processing/tickets_data/PHPBB3-10922.txt
new file mode 100644
index 0000000000..e533ce6ed5
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10922.txt
@@ -0,0 +1,9 @@
+[email]user@example.org[/email]
+[email=user@example.org]...[/email]
+[email=user@example.org ]...[/email]
+[email=user@example.org subject="Hello"]...[/email]
+[email subject="Hi there"]user@example.org[/email]
+[email body="Hi there"]user@example.org[/email]
+[email subject="Hello" body="Sent from phpBB"]user@example.org[/email]
+[email body="Sent from phpBB" subject="Hello"]user@example.org[/email]
+[email body="Sent from phpBB" subject="Hello" email="user@example.org"]...[/email]
diff --git a/tests/text_processing/tickets_data/PHPBB3-10989.html b/tests/text_processing/tickets_data/PHPBB3-10989.html
new file mode 100644
index 0000000000..cd24df60e5
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10989.html
@@ -0,0 +1,8 @@
+<blockquote><div><cite>Lorem wrote:</cite>[quote="Lorem"<blockquote class="uncited"><div> Suspendisse iaculis porta tempor. Nulla.</div></blockquote>
+ Nullam a tortor sit amet.</div></blockquote>
+ Proin ac mi eget magna.<br>
+
+<blockquote><div><cite>Lorem wrote:</cite>Quisque fermentum tortor quis odio scelerisque consequat fermentum urna gravida. In semper vehicula condimentum. Donec suscipit ante imperdiet augue rhoncus.</div></blockquote>
+
+<br>
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas quis odio orci, sit amet semper. \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-10989.txt b/tests/text_processing/tickets_data/PHPBB3-10989.txt
new file mode 100644
index 0000000000..dc2430f210
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-10989.txt
@@ -0,0 +1,8 @@
+[quote="Lorem"][quote="Lorem"[quote] Suspendisse iaculis porta tempor. Nulla.[/quote]
+ Nullam a tortor sit amet.[/quote]
+ Proin ac mi eget magna.
+
+[quote="Lorem"]Quisque fermentum tortor quis odio scelerisque consequat fermentum urna gravida. In semper vehicula condimentum. Donec suscipit ante imperdiet augue rhoncus.[/quote]
+
+
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas quis odio orci, sit amet semper. \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-11153.html b/tests/text_processing/tickets_data/PHPBB3-11153.html
new file mode 100644
index 0000000000..0f67ac4bc0
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-11153.html
@@ -0,0 +1 @@
+<a href="mailto:user@example.org">...</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-11153.txt b/tests/text_processing/tickets_data/PHPBB3-11153.txt
new file mode 100644
index 0000000000..d2794978d9
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-11153.txt
@@ -0,0 +1 @@
+[myemail=user@example.org]...[/myemail] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-11153.xml b/tests/text_processing/tickets_data/PHPBB3-11153.xml
new file mode 100644
index 0000000000..a7fc69520b
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-11153.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>myemail</value>
+ <value></value>
+ <value>1</value>
+ <value>[myemail={EMAIL}]{TEXT}[/myemail]</value>
+ <value><![CDATA[<a href="mailto:{EMAIL}">{TEXT}</a>]]></value>
+ <value><![CDATA[!\[myemail\=(([\w\!\#$\%\&'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%'\*\+\-\/\=\?\^\`{\|\}\~]|&amp;)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?))\](.*?)\[/myemail\]!ies]]></value>
+ <value><![CDATA['[myemail='.$this->bbcode_specialchars('${1}').':$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${2}')).'[/myemail:$uid]']]></value>
+ <value><![CDATA[!\[myemail\=(([\w\!\#$\%\&'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%'\*\+\-\/\=\?\^\`{\|\}\~]|&amp;)+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)):$uid\](.*?)\[/myemail:$uid\]!s]]></value>
+ <value><![CDATA[<a href="mailto:${1}">${2}</a>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-11742.html b/tests/text_processing/tickets_data/PHPBB3-11742.html
new file mode 100644
index 0000000000..e7890eef19
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-11742.html
@@ -0,0 +1 @@
+<div class="codebox"><p>CODE: <a href="#" onclick="selectCode(this); return false;">Select all</a></p><pre><code> tab</code></pre></div> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-11742.txt b/tests/text_processing/tickets_data/PHPBB3-11742.txt
new file mode 100644
index 0000000000..db72e5dda0
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-11742.txt
@@ -0,0 +1 @@
+[code] tab[/code] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-12195.html b/tests/text_processing/tickets_data/PHPBB3-12195.html
new file mode 100644
index 0000000000..c286c0fee9
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-12195.html
@@ -0,0 +1 @@
+<a href="//example.org/" class="postlink"><img src="//example.org/img.png" class="postimage" alt="Image"></a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-12195.txt b/tests/text_processing/tickets_data/PHPBB3-12195.txt
new file mode 100644
index 0000000000..b66dbd5d96
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-12195.txt
@@ -0,0 +1 @@
+[url=//example.org/][img]//example.org/img.png[/img][/url] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-12221.html b/tests/text_processing/tickets_data/PHPBB3-12221.html
new file mode 100644
index 0000000000..567f552e84
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-12221.html
@@ -0,0 +1 @@
+<a href="https://example.com/test/#?javascript:lolhax" class="postlink">https://example.com/test/#?javascript:lolhax</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-12221.txt b/tests/text_processing/tickets_data/PHPBB3-12221.txt
new file mode 100644
index 0000000000..01a0bf8667
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-12221.txt
@@ -0,0 +1 @@
+https://example.com/test/#?javascript:lolhax \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13425.html b/tests/text_processing/tickets_data/PHPBB3-13425.html
new file mode 100644
index 0000000000..a3b6d21f40
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13425.html
@@ -0,0 +1 @@
+<blockquote class="uncited"><div><img class="smilies" src="phpBB/images/smilies/icon_lol.gif" width="15" height="17" alt=":lol:" title="Laughing"> starts with a smiley</div></blockquote> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13425.txt b/tests/text_processing/tickets_data/PHPBB3-13425.txt
new file mode 100644
index 0000000000..8456410df5
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13425.txt
@@ -0,0 +1 @@
+[quote]:lol: starts with a smiley[/quote] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13425.xml b/tests/text_processing/tickets_data/PHPBB3-13425.xml
new file mode 100644
index 0000000000..cbdcaa7fb7
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13425.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>22</value>
+ <value>:lol:</value>
+ <value>Laughing</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-13451.html b/tests/text_processing/tickets_data/PHPBB3-13451.html
new file mode 100644
index 0000000000..e0892c18a9
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13451.html
@@ -0,0 +1 @@
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@example.org \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13451.txt b/tests/text_processing/tickets_data/PHPBB3-13451.txt
new file mode 100644
index 0000000000..e0892c18a9
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13451.txt
@@ -0,0 +1 @@
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@example.org \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13641.html b/tests/text_processing/tickets_data/PHPBB3-13641.html
new file mode 100644
index 0000000000..2646bc0ea5
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13641.html
@@ -0,0 +1 @@
+<code>[color=#FF0000]</code> - <span style="color:#FF0000">red</span> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13641.txt b/tests/text_processing/tickets_data/PHPBB3-13641.txt
new file mode 100644
index 0000000000..58f324715e
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13641.txt
@@ -0,0 +1 @@
+[c][color=#FF0000][/c] - [color=#FF0000]red[/color] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13641.xml b/tests/text_processing/tickets_data/PHPBB3-13641.xml
new file mode 100644
index 0000000000..451c5c69cd
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13641.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>c</value>
+ <value></value>
+ <value>1</value>
+ <value>[c]{TEXT}[/c]</value>
+ <value><![CDATA[<code>{TEXT}</code>]]></value>
+ <value><![CDATA[!\[c\](.*?)\[/c\]!ies]]></value>
+ <value><![CDATA['[c:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/c:$uid]']]></value>
+ <value><![CDATA[!\[c:$uid\](.*?)\[/c:$uid\]!s]]></value>
+ <value><![CDATA[<code>${1}</code>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-13921.html b/tests/text_processing/tickets_data/PHPBB3-13921.html
new file mode 100644
index 0000000000..6a9dc7f504
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13921.html
@@ -0,0 +1 @@
+<span style="font-size: 200%; line-height: normal"></span><div style="text-align:center"><span style="font-size: 200%; line-height: normal">xxx</span></div> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13921.txt b/tests/text_processing/tickets_data/PHPBB3-13921.txt
new file mode 100644
index 0000000000..392da0c3c8
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13921.txt
@@ -0,0 +1 @@
+[size=200][center]xxx[/center][/size] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-13921.xml b/tests/text_processing/tickets_data/PHPBB3-13921.xml
new file mode 100644
index 0000000000..8d39246bb4
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-13921.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>center</value>
+ <value></value>
+ <value>1</value>
+ <value>[center]{TEXT}[/center]</value>
+ <value><![CDATA[<div style="text-align:center">{TEXT}</div>]]></value>
+ <value>!\[center\](.*?)\[/center\]!ies</value>
+ <value>'[center:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/center:$uid]'</value>
+ <value>!\[center:$uid\](.*?)\[/center:$uid\]!s</value>
+ <value><![CDATA[<div style="text-align:center">${1}</div>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-14260.html b/tests/text_processing/tickets_data/PHPBB3-14260.html
new file mode 100644
index 0000000000..c7e7cad237
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14260.html
@@ -0,0 +1 @@
+<a href="http://example.org/article/S0883-9441%2811%290483-7/pdf" class="postlink">http://example.org/article/S0883-9441(11)0483-7/pdf</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14260.txt b/tests/text_processing/tickets_data/PHPBB3-14260.txt
new file mode 100644
index 0000000000..f95523c00e
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14260.txt
@@ -0,0 +1 @@
+http://example.org/article/S0883-9441(11)0483-7/pdf \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14405.html b/tests/text_processing/tickets_data/PHPBB3-14405.html
new file mode 100644
index 0000000000..5e76e032ec
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14405.html
@@ -0,0 +1 @@
+[url=<a href="http://example.org" class="postlink">http://example.org</a>]... \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14405.txt b/tests/text_processing/tickets_data/PHPBB3-14405.txt
new file mode 100644
index 0000000000..7005b36b23
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14405.txt
@@ -0,0 +1 @@
+[url=http://example.org]... \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14663.html b/tests/text_processing/tickets_data/PHPBB3-14663.html
new file mode 100644
index 0000000000..b18bcfd52b
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14663.html
@@ -0,0 +1 @@
+<input type="button" value="Кнопка!"> ТеÑÑ‚ \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14663.txt b/tests/text_processing/tickets_data/PHPBB3-14663.txt
new file mode 100644
index 0000000000..5443ae3046
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14663.txt
@@ -0,0 +1 @@
+[test]ТеÑÑ‚[/test] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14663.xml b/tests/text_processing/tickets_data/PHPBB3-14663.xml
new file mode 100644
index 0000000000..423d01e242
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14663.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>test</value>
+ <value></value>
+ <value>1</value>
+ <value>[test]{TEXT}[/test]</value>
+ <value><![CDATA[<input type=button value="Кнопка!" /> {TEXT}]]></value>
+ <value><![CDATA[!\[test\](.*?)\[/test\]!ies]]></value>
+ <value><![CDATA['[test:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/test:$uid]']]></value>
+ <value><![CDATA[!\[test:$uid\](.*?)\[/test:$uid\]!s]]></value>
+ <value><![CDATA[<input type=button value="Кнопка!" /> ${1}]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-14706.html b/tests/text_processing/tickets_data/PHPBB3-14706.html
new file mode 100644
index 0000000000..23b3304485
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14706.html
@@ -0,0 +1 @@
+<ul><li><ol style="list-style-type:lower-alpha"><li>a</li><li>b</li><li>c</li><li>d</li><li>e</li></ol></li><li>outer</li></ul> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14706.txt b/tests/text_processing/tickets_data/PHPBB3-14706.txt
new file mode 100644
index 0000000000..8ec2e9cd35
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14706.txt
@@ -0,0 +1 @@
+[list][list=a][*]a[*]b[*]c[*]d[*]e[/list][*]outer[/list] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14740.html b/tests/text_processing/tickets_data/PHPBB3-14740.html
new file mode 100644
index 0000000000..a1986a0901
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14740.html
@@ -0,0 +1,2 @@
+<div id="modremark"><div id="modremarkexclamation">!</div><div><div id="moderemarktitle">Moderatoropmerking from: neufke</div><div id="moderemarktext">Mod Remark</div></div></div>
+<div id="modremark"><div id="modremarkexclamation">!</div><div><div id="moderemarktitle">Moderatoropmerking from: neufke</div><div id="moderemarktext">Mod Remark</div></div></div> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14740.txt b/tests/text_processing/tickets_data/PHPBB3-14740.txt
new file mode 100644
index 0000000000..c5b2e74513
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14740.txt
@@ -0,0 +1,2 @@
+[mod=neufke]Mod Remark[/mod]
+[mod="neufke"]Mod Remark[/mod] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14740.xml b/tests/text_processing/tickets_data/PHPBB3-14740.xml
new file mode 100644
index 0000000000..9e7dc9760c
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14740.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>mod=</value>
+ <value></value>
+ <value>1</value>
+ <value>[mod=&quot;{TEXT1}&quot;]{TEXT2}[/mod]</value>
+ <value><![CDATA[<div id="modremark">
+ <div id="modremarkexclamation">!</div>
+ <div>
+ <div id="moderemarktitle">Moderatoropmerking {L_FROM}{L_COLON} {TEXT1}</div>
+ <div id="moderemarktext">{TEXT2}</div>
+ </div>
+</div>]]></value>
+ <value>!\[mod\=&quot;(.*?)&quot;\](.*?)\[/mod\]!ies</value>
+ <value>'[mod=&quot;'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'&quot;:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${2}')).'[/mod:$uid]'</value>
+ <value>!\[mod\=&quot;(.*?)&quot;:$uid\](.*?)\[/mod:$uid\]!s</value>
+ <value><![CDATA[<div id="modremark">
+ <div id="modremarkexclamation">!</div>
+ <div>
+ <div id="moderemarktitle">Moderatoropmerking {L_FROM}{L_COLON} ${1}</div>
+ <div id="moderemarktext">${2}</div>
+ </div>
+</div>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-14790.html b/tests/text_processing/tickets_data/PHPBB3-14790.html
new file mode 100644
index 0000000000..5384098e1b
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14790.html
@@ -0,0 +1,4 @@
+<span style="color:#0000FF"></span><ul><li><span style="color:#0000FF">text</span></li>
+<li><span style="color:#0000FF">text</span></li>
+<li><span style="color:#0000FF">text</span></li>
+<li><span style="color:#0000FF">text</span></li></ul> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14790.txt b/tests/text_processing/tickets_data/PHPBB3-14790.txt
new file mode 100644
index 0000000000..1cd83d97d8
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14790.txt
@@ -0,0 +1,4 @@
+[color=#0000FF][list][*]text
+[*]text
+[*]text
+[*]text[/list][/color] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14846.html b/tests/text_processing/tickets_data/PHPBB3-14846.html
new file mode 100644
index 0000000000..bd4455781b
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14846.html
@@ -0,0 +1 @@
+<div style="padding:.2em .5em;font-size:.8em;width:200px;background:#ffd">moderator text<div style="font-weight:bold;text-align:right">- Mickroz</div></div> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14846.txt b/tests/text_processing/tickets_data/PHPBB3-14846.txt
new file mode 100644
index 0000000000..ded7b3f1fe
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14846.txt
@@ -0,0 +1 @@
+[mod=Mickroz]moderator text[/mod] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-14846.xml b/tests/text_processing/tickets_data/PHPBB3-14846.xml
new file mode 100644
index 0000000000..94b094f0e3
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-14846.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>mod=</value>
+ <value></value>
+ <value>1</value>
+ <value>[mod={TEXT1}]{TEXT2}[/mod]</value>
+ <value><![CDATA[<div style="padding: .2em .5em; font-size: .8em; width: 200px; background: #FFD;">{TEXT2}<div style="font-weight: bold; text-align: right">- {TEXT1}</div></div>]]></value>
+ <value><![CDATA[!\[mod\=(.*?)\](.*?)\[/mod\]!ies]]></value>
+ <value><![CDATA['[mod='.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).':$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${2}')).'[/mod:$uid]']]></value>
+ <value><![CDATA[!\[mod\=(.*?):$uid\](.*?)\[/mod:$uid\]!s]]></value>
+ <value><![CDATA[<div style="padding: .2em .5em; font-size: .8em; width: 200px; background: #FFD;">${2}<div style="font-weight: bold; text-align: right">- ${1}</div></div>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-15008.before.php b/tests/text_processing/tickets_data/PHPBB3-15008.before.php
new file mode 100644
index 0000000000..a3243e74cd
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15008.before.php
@@ -0,0 +1,18 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+function before_assert_phpbb3_15008($vars)
+{
+ extract($vars);
+ $parser->disable_smilies();
+}
diff --git a/tests/text_processing/tickets_data/PHPBB3-15008.html b/tests/text_processing/tickets_data/PHPBB3-15008.html
new file mode 100644
index 0000000000..7642eb63ee
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15008.html
@@ -0,0 +1 @@
+No smilies :) or shortnames :strawberry: \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15008.txt b/tests/text_processing/tickets_data/PHPBB3-15008.txt
new file mode 100644
index 0000000000..7642eb63ee
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15008.txt
@@ -0,0 +1 @@
+No smilies :) or shortnames :strawberry: \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15016.html b/tests/text_processing/tickets_data/PHPBB3-15016.html
new file mode 100644
index 0000000000..47b66ad771
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15016.html
@@ -0,0 +1 @@
+<img class="smilies" src="phpBB/images/smilies/icon_lol.gif" width="15" height="17" alt=")--(" title=")--("> <img class="smilies" src="phpBB/images/smilies/icon_lol.gif" width="15" height="17" alt=")-(" title=")-("> <img class="smilies" src="phpBB/images/smilies/icon_lol.gif" width="15" height="17" alt=")--" title=")--"> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15016.txt b/tests/text_processing/tickets_data/PHPBB3-15016.txt
new file mode 100644
index 0000000000..081d9e3dc9
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15016.txt
@@ -0,0 +1 @@
+)--( )-( )-- \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15016.xml b/tests/text_processing/tickets_data/PHPBB3-15016.xml
new file mode 100644
index 0000000000..644481861e
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15016.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>1</value>
+ <value>)--(</value>
+ <value>)--(</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>)--</value>
+ <value>)--</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>)-(</value>
+ <value>)-(</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-15163.html b/tests/text_processing/tickets_data/PHPBB3-15163.html
new file mode 100644
index 0000000000..a1af10187c
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15163.html
@@ -0,0 +1 @@
+<img class="smilies" src="phpBB/images/smilies/icon_lol.gif" width="15" height="17" alt="--{E" title="--{E"> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15163.txt b/tests/text_processing/tickets_data/PHPBB3-15163.txt
new file mode 100644
index 0000000000..126402d66a
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15163.txt
@@ -0,0 +1 @@
+--{E \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15163.xml b/tests/text_processing/tickets_data/PHPBB3-15163.xml
new file mode 100644
index 0000000000..f3e04c230f
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15163.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>1</value>
+ <value>--{E</value>
+ <value>--{E</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-15261.html b/tests/text_processing/tickets_data/PHPBB3-15261.html
new file mode 100644
index 0000000000..b563052b47
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15261.html
@@ -0,0 +1 @@
+foo **** baz \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15261.txt b/tests/text_processing/tickets_data/PHPBB3-15261.txt
new file mode 100644
index 0000000000..a8c4a05c10
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15261.txt
@@ -0,0 +1 @@
+foo <bar> baz \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15261.xml b/tests/text_processing/tickets_data/PHPBB3-15261.xml
new file mode 100644
index 0000000000..c0d0f395a1
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15261.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_words">
+ <column>word_id</column>
+ <column>word</column>
+ <column>replacement</column>
+
+ <row>
+ <value>1</value>
+ <value>&lt;*&gt;</value>
+ <value>****</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-15348.html b/tests/text_processing/tickets_data/PHPBB3-15348.html
new file mode 100644
index 0000000000..1794232d08
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15348.html
@@ -0,0 +1 @@
+<img class="smilies" src="phpBB/images/smilies/icon_e_surprised.gif" width="15" height="17" alt=":o" title="First half of :ok:"> <img class="smilies" src="phpBB/images/smilies/icon_lol.gif" width="15" height="17" alt="k:" title="Second half of :ok:"> <img alt=":ok:" class="emoji smilies" draggable="false" src="//twemoji.maxcdn.com/2/svg/1f197.svg"> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15348.txt b/tests/text_processing/tickets_data/PHPBB3-15348.txt
new file mode 100644
index 0000000000..d6b971702c
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15348.txt
@@ -0,0 +1 @@
+:o k: :ok: \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-15348.xml b/tests/text_processing/tickets_data/PHPBB3-15348.xml
new file mode 100644
index 0000000000..0c88c8824f
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-15348.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>13</value>
+ <value>:o</value>
+ <value>First half of :ok:</value>
+ <value>icon_e_surprised.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>14</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>99</value>
+ <value>k:</value>
+ <value>Second half of :ok:</value>
+ <value>icon_lol.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>22</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-16053.html b/tests/text_processing/tickets_data/PHPBB3-16053.html
new file mode 100644
index 0000000000..af70ddf7eb
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16053.html
@@ -0,0 +1 @@
+<a href="http://ea117.com" alt="Test">Test</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-16053.txt b/tests/text_processing/tickets_data/PHPBB3-16053.txt
new file mode 100644
index 0000000000..c786665eb9
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16053.txt
@@ -0,0 +1 @@
+[test=http://ea117.com]Test[/test] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-16053.xml b/tests/text_processing/tickets_data/PHPBB3-16053.xml
new file mode 100644
index 0000000000..25f7c9e34e
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16053.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>test</value>
+ <value></value>
+ <value>1</value>
+ <value>[test={URL}]{TEXT}[/test]</value>
+ <value><![CDATA[<a href="{URL}" alt="{TEXT}">{TEXT}</a>]]></value>
+ <value>((?!))</value>
+ <value></value>
+ <value>((?!))</value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-16074.html b/tests/text_processing/tickets_data/PHPBB3-16074.html
new file mode 100644
index 0000000000..b588e2ac47
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16074.html
@@ -0,0 +1 @@
+<img alt=":man_judge:" class="emoji smilies" draggable="false" src="//twemoji.maxcdn.com/2/svg/1f468-200d-2696-fe0f.svg"> <img alt="👨â€âš–ï¸" class="emoji smilies" draggable="false" src="//twemoji.maxcdn.com/2/svg/1f468-200d-2696-fe0f.svg"> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-16074.txt b/tests/text_processing/tickets_data/PHPBB3-16074.txt
new file mode 100644
index 0000000000..f067a7294d
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16074.txt
@@ -0,0 +1 @@
+:man_judge: 👨â€âš–ï¸ \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-16252.after.php b/tests/text_processing/tickets_data/PHPBB3-16252.after.php
new file mode 100644
index 0000000000..c2f57c171e
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16252.after.php
@@ -0,0 +1,18 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+function after_assert_phpbb3_16252($vars)
+{
+ extract($vars);
+ $test->assertEmpty($parser->get_errors());
+}
diff --git a/tests/text_processing/tickets_data/PHPBB3-16252.before.php b/tests/text_processing/tickets_data/PHPBB3-16252.before.php
new file mode 100644
index 0000000000..94c59d9602
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16252.before.php
@@ -0,0 +1,17 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+function before_assert_phpbb3_16252($vars)
+{
+ $vars['parser']->disable_bbcode('url');
+}
diff --git a/tests/text_processing/tickets_data/PHPBB3-16252.html b/tests/text_processing/tickets_data/PHPBB3-16252.html
new file mode 100644
index 0000000000..5b14ab0e7a
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16252.html
@@ -0,0 +1 @@
+http://localhost/ \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-16252.txt b/tests/text_processing/tickets_data/PHPBB3-16252.txt
new file mode 100644
index 0000000000..5b14ab0e7a
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-16252.txt
@@ -0,0 +1 @@
+http://localhost/ \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-3981.before.php b/tests/text_processing/tickets_data/PHPBB3-3981.before.php
new file mode 100644
index 0000000000..1c326b52af
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-3981.before.php
@@ -0,0 +1,21 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+function before_assert_phpbb3_3981($vars)
+{
+ if (!function_exists('idn_to_ascii'))
+ {
+ extract($vars);
+ $test->markTestSkipped('International URLs need idn_to_ascii()');
+ }
+}
diff --git a/tests/text_processing/tickets_data/PHPBB3-3981.html b/tests/text_processing/tickets_data/PHPBB3-3981.html
new file mode 100644
index 0000000000..e5f1b4561d
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-3981.html
@@ -0,0 +1 @@
+<a href="http://www.xn--ndaaa.com" class="postlink">http://www.ööö.com</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-3981.txt b/tests/text_processing/tickets_data/PHPBB3-3981.txt
new file mode 100644
index 0000000000..976823f1d1
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-3981.txt
@@ -0,0 +1 @@
+[url]http://www.ööö.com[/url] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-7187.html b/tests/text_processing/tickets_data/PHPBB3-7187.html
new file mode 100644
index 0000000000..a37cdf038e
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-7187.html
@@ -0,0 +1 @@
+<blockquote class="uncited"><div><img class="smilies" src="phpBB/images/smilies/icon_e_geek.gif" width="17" height="17" alt=":geek:" title="Geek"> <img class="smilies" src="phpBB/images/smilies/icon_e_ugeek.gif" width="17" height="18" alt=":ugeek:" title="Uber Geek"></div></blockquote> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-7187.txt b/tests/text_processing/tickets_data/PHPBB3-7187.txt
new file mode 100644
index 0000000000..584151a083
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-7187.txt
@@ -0,0 +1 @@
+[quote]:geek: :ugeek:[/quote] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-7187.xml b/tests/text_processing/tickets_data/PHPBB3-7187.xml
new file mode 100644
index 0000000000..d270b12619
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-7187.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>41</value>
+ <value>:geek:</value>
+ <value>Geek</value>
+ <value>icon_e_geek.gif</value>
+ <value>17</value>
+ <value>17</value>
+ <value>41</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>42</value>
+ <value>:ugeek:</value>
+ <value>Uber Geek</value>
+ <value>icon_e_ugeek.gif</value>
+ <value>17</value>
+ <value>18</value>
+ <value>42</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.after.php b/tests/text_processing/tickets_data/PHPBB3-7275.after.php
new file mode 100644
index 0000000000..99f41d7839
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-7275.after.php
@@ -0,0 +1,19 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+function after_assert_phpbb3_7275($vars)
+{
+ extract($vars);
+ decode_message($parsed_text);
+ $test->assertSame($original, $parsed_text);
+}
diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.html b/tests/text_processing/tickets_data/PHPBB3-7275.html
new file mode 100644
index 0000000000..470aebb5d0
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-7275.html
@@ -0,0 +1 @@
+<div align="center"><img class="smilies" src="phpBB/images/smilies/icon_e_smile.gif" width="15" height="17" alt=":)" title="Smile"></div> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.txt b/tests/text_processing/tickets_data/PHPBB3-7275.txt
new file mode 100644
index 0000000000..8de97d67e0
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-7275.txt
@@ -0,0 +1 @@
+[center]:)[/center] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-7275.xml b/tests/text_processing/tickets_data/PHPBB3-7275.xml
new file mode 100644
index 0000000000..9e979afffb
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-7275.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>center</value>
+ <value></value>
+ <value>1</value>
+ <value>[center]{TEXT}[/center]</value>
+ <value><![CDATA[<div align="center">{TEXT}</div>]]></value>
+ <value>!\[center\](.*?)\[/center\]!ies</value>
+ <value><![CDATA['[center:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/center:$uid]']]></value>
+ <value>!\[center:$uid\](.*?)\[/center:$uid\]!s</value>
+ <value><![CDATA[<div align="center">${1}</div>]]></value>
+ </row>
+ </table>
+
+ <table name="phpbb_smilies">
+ <column>smiley_id</column>
+ <column>code</column>
+ <column>emotion</column>
+ <column>smiley_url</column>
+ <column>smiley_width</column>
+ <column>smiley_height</column>
+ <column>smiley_order</column>
+ <column>display_on_posting</column>
+ <row>
+ <value>4</value>
+ <value>:)</value>
+ <value>Smile</value>
+ <value>icon_e_smile.gif</value>
+ <value>15</value>
+ <value>17</value>
+ <value>4</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-8419.html b/tests/text_processing/tickets_data/PHPBB3-8419.html
new file mode 100644
index 0000000000..df91e9df50
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-8419.html
@@ -0,0 +1 @@
+<span style="font-style:italic"><span style="font-weight:bold"><span style="color:red">tę </span></span></span>przykład \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-8419.txt b/tests/text_processing/tickets_data/PHPBB3-8419.txt
new file mode 100644
index 0000000000..dac47823b6
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-8419.txt
@@ -0,0 +1 @@
+[ort]tę [/ort]przykład \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-8419.xml b/tests/text_processing/tickets_data/PHPBB3-8419.xml
new file mode 100644
index 0000000000..2f1df345f9
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-8419.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>myemail</value>
+ <value></value>
+ <value>1</value>
+ <value>[ort]{TEXT}[/ort]</value>
+ <value><![CDATA[<span style="font-style: italic"><span style="font-weight: bold"><span style="color: #FF0000">{TEXT}</span></span></span>]]></value>
+ <value><![CDATA[!\[ort\](.*?)\[/ort\]!ies]]></value>
+ <value><![CDATA['[ort:$uid]'.str_replace(array("\r\n", '\"', '\'', '(', ')'), array("\n", '"', '&#39;', '&#40;', '&#41;'), trim('${1}')).'[/ort:$uid]']]></value>
+ <value><![CDATA[!\[ort:$uid\](.*?)\[/ort:$uid\]!s]]></value>
+ <value><![CDATA[<span style="font-style: italic"><span style="font-weight: bold"><span style="color: #FF0000">${1}</span></span></span>]]></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-9073.html b/tests/text_processing/tickets_data/PHPBB3-9073.html
new file mode 100644
index 0000000000..ff1f9fd0ce
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9073.html
@@ -0,0 +1,2 @@
+<a href="http://www.xxxx-xx-xxxx.com/" class="postlink">http://www.xxxx-xx-xxxx.com/</a><br>
+<a href="http://www.xxxx-xx-xxxx.com/" class="postlink">http://www.xxxx-xx-xxxx.com/</a><br>
diff --git a/tests/text_processing/tickets_data/PHPBB3-9073.txt b/tests/text_processing/tickets_data/PHPBB3-9073.txt
new file mode 100644
index 0000000000..2c271173ce
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9073.txt
@@ -0,0 +1,2 @@
+http://www.some-ad-site.com/
+[url]http://www.some-ad-site.com/[/url]
diff --git a/tests/text_processing/tickets_data/PHPBB3-9073.xml b/tests/text_processing/tickets_data/PHPBB3-9073.xml
new file mode 100644
index 0000000000..d635d51ed1
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9073.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_words">
+ <column>word_id</column>
+ <column>word</column>
+ <column>replacement</column>
+
+ <row>
+ <value>1</value>
+ <value>http://www.some-ad-site.com*</value>
+ <value>http://www.xxxx-xx-xxxx.com</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-9377.html b/tests/text_processing/tickets_data/PHPBB3-9377.html
new file mode 100644
index 0000000000..dcfb79c173
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9377.html
@@ -0,0 +1 @@
+<span style="color:red">red <span style="color:blue">blue</span> red</span> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-9377.txt b/tests/text_processing/tickets_data/PHPBB3-9377.txt
new file mode 100644
index 0000000000..dfd71492c5
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9377.txt
@@ -0,0 +1 @@
+[red]red [blue]blue[/blue] red[/red] \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-9377.xml b/tests/text_processing/tickets_data/PHPBB3-9377.xml
new file mode 100644
index 0000000000..1d8ee3d53f
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9377.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_bbcodes">
+ <column>bbcode_id</column>
+ <column>bbcode_tag</column>
+ <column>bbcode_helpline</column>
+ <column>display_on_posting</column>
+ <column>bbcode_match</column>
+ <column>bbcode_tpl</column>
+ <column>first_pass_match</column>
+ <column>first_pass_replace</column>
+ <column>second_pass_match</column>
+ <column>second_pass_replace</column>
+
+ <row>
+ <value>13</value>
+ <value>red</value>
+ <value></value>
+ <value>1</value>
+ <value>[red]{TEXT}[/red]</value>
+ <value>&lt;span style=&quot;color:red&quot;&gt;{TEXT}&lt;/span&gt;</value>
+ <value>!\[red\](.*?)\[/red\]!ies</value>
+ <value>'[red:$uid]'.str_replace(array(&quot;\r\n&quot;, '\&quot;', '\'', '(', ')'), array(&quot;\n&quot;, '&quot;', '&amp;#39;', '&amp;#40;', '&amp;#41;'), trim('${1}')).'[/red:$uid]'</value>
+ <value>!\[red:$uid\](.*?)\[/red:$uid\]!s</value>
+ <value>&lt;span style=&quot;color:red&quot;&gt;${1}&lt;/span&gt;</value>
+ </row>
+
+ <row>
+ <value>14</value>
+ <value>blue</value>
+ <value></value>
+ <value>1</value>
+ <value>[blue]{TEXT}[/blue]</value>
+ <value>&lt;span style=&quot;color:blue&quot;&gt;{TEXT}&lt;/span&gt;</value>
+ <value>!\[blue\](.*?)\[/blue\]!ies</value>
+ <value>'[blue:$uid]'.str_replace(array(&quot;\r\n&quot;, '\&quot;', '\'', '(', ')'), array(&quot;\n&quot;, '&quot;', '&amp;#39;', '&amp;#40;', '&amp;#41;'), trim('${1}')).'[/blue:$uid]'</value>
+ <value>!\[blue:$uid\](.*?)\[/blue:$uid\]!s</value>
+ <value>&lt;span style=&quot;color:blue&quot;&gt;${1}&lt;/span&gt;</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_processing/tickets_data/PHPBB3-9791.html b/tests/text_processing/tickets_data/PHPBB3-9791.html
new file mode 100644
index 0000000000..3d0108c8a6
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9791.html
@@ -0,0 +1 @@
+<a href="http://www.phpbb.com/community/search.php?keywords=bogus&amp;terms=all&amp;author=&amp;fid%5B%5D=46&amp;sc=1&amp;sf=all&amp;sr=posts&amp;sk=t&amp;sd=d&amp;st=0&amp;ch=300&amp;t=0&amp;submit=Search" class="postlink">http://www.phpbb.com/community/search.p ... mit=Search</a> \ No newline at end of file
diff --git a/tests/text_processing/tickets_data/PHPBB3-9791.txt b/tests/text_processing/tickets_data/PHPBB3-9791.txt
new file mode 100644
index 0000000000..e29b20086d
--- /dev/null
+++ b/tests/text_processing/tickets_data/PHPBB3-9791.txt
@@ -0,0 +1 @@
+http://www.phpbb.com/community/search.php?keywords=bogus&terms=all&author=&fid[]=46&sc=1&sf=all&sr=posts&sk=t&sd=d&st=0&ch=300&t=0&submit=Search \ No newline at end of file
diff --git a/tests/text_processing/tickets_test.php b/tests/text_processing/tickets_test.php
new file mode 100644
index 0000000000..6230191a69
--- /dev/null
+++ b/tests/text_processing/tickets_test.php
@@ -0,0 +1,90 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+class phpbb_text_processing_tickets_test extends phpbb_test_case
+{
+ /**
+ * @dataProvider get_tickets_data
+ */
+ public function test_tickets($ticket_id, $original, $expected, $fixture, $before_assert, $after_assert)
+ {
+ global $phpbb_container;
+
+ $phpbb_container = new phpbb_mock_container_builder;
+
+ $this->get_test_case_helpers()->set_s9e_services($phpbb_container, $fixture);
+
+ $parser = $phpbb_container->get('text_formatter.parser');
+ $renderer = $phpbb_container->get('text_formatter.renderer');
+
+ if (isset($before_assert))
+ {
+ $test = $this;
+ $before_assert(get_defined_vars());
+ }
+
+ $parsed_text = $parser->parse($original);
+
+ $this->assertSame($expected, $renderer->render($parsed_text));
+
+ if (isset($after_assert))
+ {
+ $test = $this;
+ $after_assert(get_defined_vars());
+ }
+ }
+
+ public function get_tickets_data()
+ {
+ $tests = array();
+
+ foreach (glob(__DIR__ . '/tickets_data/*.txt') as $txt_filename)
+ {
+ $ticket_id = basename($txt_filename, '.txt');
+ $html_filename = substr($txt_filename, 0, -3) . 'html';
+ $xml_filename = substr($txt_filename, 0, -3) . 'xml';
+ $before_filename = substr($txt_filename, 0, -3) . 'before.php';
+ $after_filename = substr($txt_filename, 0, -3) . 'after.php';
+
+ if (!file_exists($xml_filename))
+ {
+ $xml_filename = __DIR__ . '/../fixtures/empty.xml';
+ }
+
+ $before_assert = null;
+ if (file_exists($before_filename))
+ {
+ include($before_filename);
+ $before_assert = 'before_assert_' . strtolower(str_replace('-', '_', $ticket_id));
+ }
+
+ $after_assert = null;
+ if (file_exists($after_filename))
+ {
+ include($after_filename);
+ $after_assert = 'after_assert_' . strtolower(str_replace('-', '_', $ticket_id));
+ }
+
+ $tests[] = array(
+ $ticket_id,
+ file_get_contents($txt_filename),
+ file_get_contents($html_filename),
+ $xml_filename,
+ $before_assert,
+ $after_assert
+ );
+ }
+
+ return $tests;
+ }
+}
diff --git a/tests/text_reparser/base_test.php b/tests/text_reparser/base_test.php
new file mode 100644
index 0000000000..2c6844b063
--- /dev/null
+++ b/tests/text_reparser/base_test.php
@@ -0,0 +1,84 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once __DIR__ . '/../test_framework/phpbb_database_test_case.php';
+
+class phpbb_textreparser_base_test extends phpbb_database_test_case
+{
+ protected $db;
+
+ public function setUp()
+ {
+ global $config;
+ if (!isset($config))
+ {
+ $config = new \phpbb\config\config(array());
+ }
+ $this->get_test_case_helpers()->set_s9e_services();
+ $this->db = $this->new_dbal();
+ parent::setUp();
+ }
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/base.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\post_text($this->db, POSTS_TABLE);
+ }
+
+ protected function get_rows(array $ids)
+ {
+ $sql = 'SELECT post_id AS id, post_text AS text
+ FROM ' . POSTS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('post_id', $ids) . '
+ ORDER BY id';
+ $result = $this->db->sql_query($sql);
+ $rows = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ return $rows;
+ }
+
+ public function test_reparse_empty()
+ {
+ $this->get_reparser()->reparse_range(1, 1);
+
+ $this->assertEquals(
+ array(
+ array(
+ 'id' => 1,
+ 'text' => '<t></t>'
+ )
+ ),
+ $this->get_rows(array(1))
+ );
+ }
+
+ public function test_reparse_case_insensitive()
+ {
+ $this->get_reparser()->reparse_range(2, 2);
+
+ $this->assertEquals(
+ [
+ [
+ 'id' => '2',
+ 'text' => '<r><IMG src="img.png"><s>[IMG]</s>img.png<e>[/IMG]</e></IMG></r>'
+ ]
+ ],
+ $this->get_rows([2])
+ );
+ }
+}
diff --git a/tests/text_reparser/fixtures/base.xml b/tests/text_reparser/fixtures/base.xml
new file mode 100644
index 0000000000..532a19a8a9
--- /dev/null
+++ b/tests/text_reparser/fixtures/base.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_posts">
+ <column>post_id</column>
+ <column>enable_bbcode</column>
+ <column>enable_smilies</column>
+ <column>enable_magic_url</column>
+ <column>post_text</column>
+ <column>bbcode_uid</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value><![CDATA[<r><IMG src="img.png"><s>[IMG]</s>img.png<e>[/IMG]</e></IMG></r>]]></value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/fixtures/config_text.xml b/tests/text_reparser/fixtures/config_text.xml
new file mode 100644
index 0000000000..ba8e1fcfcc
--- /dev/null
+++ b/tests/text_reparser/fixtures/config_text.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_config_text">
+ <column>config_name</column>
+ <column>config_value</column>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/manager_test.php b/tests/text_reparser/manager_test.php
new file mode 100644
index 0000000000..df6adacb66
--- /dev/null
+++ b/tests/text_reparser/manager_test.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+require_once __DIR__ . '/../mock/container_builder.php';
+require_once __DIR__ . '/../test_framework/phpbb_database_test_case.php';
+
+class phpbb_text_reparser_manager_test extends phpbb_database_test_case
+{
+ /** @var \phpbb\config\config */
+ protected $config;
+
+ /** @var \phpbb\config\db_text */
+ protected $config_text;
+
+ /** @var \phpbb\textreparser\manager */
+ protected $reparser_manager;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(dirname(__FILE__) . '/fixtures/config_text.xml');
+ }
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->config = new \phpbb\config\config(array(
+ 'test_reparser_cron_interval' => 0,
+ 'my_reparser_cron_interval' => 100,
+ ));
+
+ $db = $this->new_dbal();
+ $this->config_text = new \phpbb\config\db_text($db, 'phpbb_config_text');
+
+ $service_collection = new \phpbb\di\service_collection(new phpbb_mock_container_builder());
+ $service_collection->add('test_reparser');
+ $service_collection->add('another_reparser');
+ $service_collection->add('my_reparser');
+
+ $this->reparser_manager = new \phpbb\textreparser\manager($this->config, $this->config_text, $service_collection);
+ }
+
+ public function test_get_resume_data()
+ {
+ $resume_data = array(
+ 'test_reparser' => array(
+ 'range-min' => 0,
+ 'range-max' => 100,
+ 'range-size' => 50,
+ ),
+ );
+ $this->config_text->set('reparser_resume', serialize($resume_data));
+
+ $this->assert_array_content_equals($resume_data['test_reparser'], $this->reparser_manager->get_resume_data('test_reparser'));
+ $this->assertEmpty($this->reparser_manager->get_resume_data('another_reparser'));
+ }
+
+ public function test_update_resume_data()
+ {
+ $resume_data = array(
+ 'test_reparser' => array(
+ 'range-min' => 0,
+ 'range-max' => 100,
+ 'range-size' => 50,
+ ),
+ );
+ $this->config_text->set('reparser_resume', serialize($resume_data));
+
+ $this->reparser_manager->update_resume_data('another_reparser', 5, 20, 10, false);
+ $this->assert_array_content_equals($resume_data, unserialize($this->config_text->get('reparser_resume')));
+
+ $this->reparser_manager->update_resume_data('test_reparser', 0, 50, 50);
+ $resume_data = array(
+ 'test_reparser' => array(
+ 'range-min' => 0,
+ 'range-max' => 50,
+ 'range-size' => 50,
+ ),
+ 'another_reparser' => array(
+ 'range-min' => 5,
+ 'range-max' => 20,
+ 'range-size' => 10,
+ ),
+ );
+ $this->assert_array_content_equals($resume_data, unserialize($this->config_text->get('reparser_resume')));
+ }
+
+ public function test_schedule()
+ {
+ $this->reparser_manager->schedule('no_reparser', 21);
+ $this->assertArrayNotHasKey('no_reparser_cron_interval', $this->config);
+
+ $this->reparser_manager->schedule('another_reparser', 42);
+ $this->assertArrayNotHasKey('another_reparser_cron_interval', $this->config);
+
+ $this->reparser_manager->schedule('test_reparser', 20);
+ $this->assertEquals(20, $this->config['test_reparser_cron_interval']);
+ }
+
+ public function test_schedule_all()
+ {
+ $this->reparser_manager->schedule_all(180);
+ $this->assertEquals(180, $this->config['test_reparser_cron_interval']);
+ $this->assertEquals(180, $this->config['my_reparser_cron_interval']);
+ $this->assertArrayNotHasKey('another_reparser_cron_interval', $this->config);
+ }
+}
diff --git a/tests/text_reparser/plugins/contact_admin_info_test.php b/tests/text_reparser/plugins/contact_admin_info_test.php
new file mode 100644
index 0000000000..757b02be39
--- /dev/null
+++ b/tests/text_reparser/plugins/contact_admin_info_test.php
@@ -0,0 +1,95 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php';
+
+class phpbb_textreparser_contact_admin_info_test extends phpbb_database_test_case
+{
+ protected $db;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/contact_admin_info.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\contact_admin_info(new \phpbb\config\db_text($this->db, CONFIG_TEXT_TABLE));
+ }
+
+ protected function get_rows()
+ {
+ $sql = 'SELECT config_name, config_value
+ FROM ' . CONFIG_TEXT_TABLE . '
+ ORDER BY config_name';
+ $result = $this->db->sql_query($sql);
+ $rows = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ return $rows;
+ }
+
+ public function setUp()
+ {
+ global $config;
+ if (!isset($config))
+ {
+ $config = new \phpbb\config\config(array());
+ }
+ $this->get_test_case_helpers()->set_s9e_services();
+ $this->db = $this->new_dbal();
+ parent::setUp();
+ }
+
+ public function test_get_max_id()
+ {
+ $reparser = $this->get_reparser();
+ $this->assertEquals(1, $reparser->get_max_id());
+ }
+
+ public function test_dry_run()
+ {
+ $old_rows = $this->get_rows();
+ $reparser = $this->get_reparser();
+ $reparser->disable_save();
+ $reparser->reparse_range(1, 1);
+ $new_rows = $this->get_rows();
+ $this->assertEquals($old_rows, $new_rows);
+ }
+
+ public function test_reparse()
+ {
+ $reparser = $this->get_reparser();
+ $reparser->enable_save();
+ $reparser->reparse_range(1, 1);
+ $expected = array(
+ array(
+ 'config_name' => 'contact_admin_info',
+ 'config_value' => '<r><EMAIL email="admin@example.org"><s>[email]</s>admin@example.org<e>[/email]</e></EMAIL></r>',
+ ),
+ array(
+ 'config_name' => 'contact_admin_info_bitfield',
+ 'config_value' => 'ACA=',
+ ),
+ array(
+ 'config_name' => 'contact_admin_info_flags',
+ 'config_value' => '7',
+ ),
+ array(
+ 'config_name' => 'contact_admin_info_uid',
+ 'config_value' => '1a2hbwf5',
+ ),
+ );
+ $this->assertEquals($expected, $this->get_rows());
+ }
+}
diff --git a/tests/text_reparser/plugins/fixtures/contact_admin_info.xml b/tests/text_reparser/plugins/fixtures/contact_admin_info.xml
new file mode 100644
index 0000000000..13cd82b1a4
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/contact_admin_info.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_config_text">
+ <column>config_name</column>
+ <column>config_value</column>
+ <row>
+ <value>contact_admin_info</value>
+ <value>[email:1a2hbwf5]admin@example&#46;org[/email:1a2hbwf5]</value>
+ </row>
+ <row>
+ <value>contact_admin_info_uid</value>
+ <value>1a2hbwf5</value>
+ </row>
+ <row>
+ <value>contact_admin_info_bitfield</value>
+ <value>ACA=</value>
+ </row>
+ <row>
+ <value>contact_admin_info_flags</value>
+ <value>7</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/fixtures/forums.xml b/tests/text_reparser/plugins/fixtures/forums.xml
new file mode 100644
index 0000000000..c12c8d6d48
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/forums.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_forums">
+ <column>forum_id</column>
+ <column>forum_parents</column>
+ <column>forum_desc</column>
+ <column>forum_desc_uid</column>
+ <column>forum_desc_options</column>
+ <column>forum_rules</column>
+ <column>forum_rules_uid</column>
+ <column>forum_rules_options</column>
+ <row>
+ <value>1</value>
+ <value></value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ <value>0</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value></value>
+ <value>[b]Not bold[/b] :) http://example.org</value>
+ <value>abcd1234</value>
+ <value>0</value>
+ <value>[b]Not bold[/b] :) http://example.org</value>
+ <value>abcd1234</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value></value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ <value>abcd1234</value>
+ <value>1</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ <value>abcd1234</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value></value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ <value>abcd1234</value>
+ <value>2</value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ <value>abcd1234</value>
+ <value>2</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value></value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ <value>abcd1234</value>
+ <value>4</value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ <value>abcd1234</value>
+ <value>4</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value></value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value>1</value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>7</value>
+ <value></value>
+ <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value>
+ <value>abcd1234</value>
+ <value>0</value>
+ <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value>
+ <value>abcd1234</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>8</value>
+ <value></value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value>1</value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>9</value>
+ <value></value>
+ <value><![CDATA[[img]http://example.org/img.png[/img]]]></value>
+ <value>abcd1234</value>
+ <value>0</value>
+ <value><![CDATA[[img]http://example.org/img.png[/img]]]></value>
+ <value>abcd1234</value>
+ <value>0</value>
+ </row>
+ <row>
+ <value>1000</value>
+ <value></value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ <value>0</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ <value>0</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/fixtures/groups.xml b/tests/text_reparser/plugins/fixtures/groups.xml
new file mode 100644
index 0000000000..15151426bc
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/groups.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_groups">
+ <column>group_id</column>
+ <column>group_desc</column>
+ <column>group_desc_options</column>
+ <column>group_desc_uid</column>
+ <row>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>7</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>[b]Not bold[/b] :) http://example.org</value>
+ <value>0</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ <value>1</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ <value>2</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ <value>4</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>1</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>7</value>
+ <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value>
+ <value>1</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>8</value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>1</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>9</value>
+ <value><![CDATA[[img]http://example.org/img.png[/img]]]></value>
+ <value>1</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>1000</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>7</value>
+ <value>abcd1234</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/fixtures/poll_options.xml b/tests/text_reparser/plugins/fixtures/poll_options.xml
new file mode 100644
index 0000000000..48ba024315
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/poll_options.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_poll_options">
+ <column>poll_option_id</column>
+ <column>topic_id</column>
+ <column>poll_option_text</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>This row should be [b:abcd1234]ignored[/b:abcd1234]</value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>2</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234]</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>2</value>
+ <value><![CDATA[<!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) -->]]></value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>2</value>
+ <value><![CDATA[<!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>11</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>12</value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>13</value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ </row>
+ <row>
+ <value>1</value>
+ <value>123</value>
+ <value>This row should be [b]ignored[/b]</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>123</value>
+ <value>This row should be [b:abcd1234]ignored[/b:abcd1234]</value>
+ </row>
+ </table>
+ <table name="phpbb_posts">
+ <column>post_id</column>
+ <column>enable_bbcode</column>
+ <column>enable_smilies</column>
+ <column>enable_magic_url</column>
+ <column>post_text</column>
+ <column>bbcode_uid</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>11</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>12</value>
+ <value>0</value>
+ <value>1</value>
+ <value>0</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>13</value>
+ <value>0</value>
+ <value>0</value>
+ <value>1</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ </table>
+ <table name="phpbb_topics">
+ <column>topic_id</column>
+ <column>topic_first_post_id</column>
+ <column>poll_title</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ </row>
+ <row>
+ <value>11</value>
+ <value>11</value>
+ <value>BBCode</value>
+ </row>
+ <row>
+ <value>12</value>
+ <value>12</value>
+ <value>Smilies</value>
+ </row>
+ <row>
+ <value>13</value>
+ <value>13</value>
+ <value>Magic URLs</value>
+ </row>
+ <row>
+ <value>123</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/fixtures/polls.xml b/tests/text_reparser/plugins/fixtures/polls.xml
new file mode 100644
index 0000000000..5247fb906d
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/polls.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_posts">
+ <column>post_id</column>
+ <column>enable_bbcode</column>
+ <column>enable_smilies</column>
+ <column>enable_magic_url</column>
+ <column>post_text</column>
+ <column>bbcode_uid</column>
+ <row>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ <value>0</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>0</value>
+ <value>1</value>
+ <value>0</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>0</value>
+ <value>0</value>
+ <value>1</value>
+ <value></value>
+ <value>abcd1234</value>
+ </row>
+ </table>
+ <table name="phpbb_topics">
+ <column>topic_id</column>
+ <column>topic_first_post_id</column>
+ <column>poll_title</column>
+ <column>poll_start</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>1</value>
+ <value>[b]Not bold[/b] :) http://example.org</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>2</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>3</value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>4</value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>2</value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>7</value>
+ <value>1</value>
+ <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>8</value>
+ <value>2</value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>9</value>
+ <value>1</value>
+ <value><![CDATA[[img]http://example.org/img.png[/img]]]></value>
+ <value>1</value>
+ </row>
+ <row>
+ <value>1000</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>1</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/fixtures/posts.xml b/tests/text_reparser/plugins/fixtures/posts.xml
new file mode 100644
index 0000000000..ec31747ed9
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/posts.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_posts">
+ <column>post_id</column>
+ <column>enable_bbcode</column>
+ <column>enable_smilies</column>
+ <column>enable_magic_url</column>
+ <column>post_text</column>
+ <column>bbcode_uid</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>0</value>
+ <value>0</value>
+ <value>0</value>
+ <value>[b]Not bold[/b] :) http://example.org</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>0</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>0</value>
+ <value>0</value>
+ <value>1</value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>7</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>8</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>9</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[img]http://example.org/img.png[/img]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>1000</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/fixtures/privmsgs.xml b/tests/text_reparser/plugins/fixtures/privmsgs.xml
new file mode 100644
index 0000000000..4049b9890a
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/privmsgs.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_privmsgs">
+ <column>msg_id</column>
+ <column>enable_bbcode</column>
+ <column>enable_smilies</column>
+ <column>enable_magic_url</column>
+ <column>message_text</column>
+ <column>bbcode_uid</column>
+ <column>to_address</column>
+ <column>bcc_address</column>
+ <row>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>2</value>
+ <value>0</value>
+ <value>0</value>
+ <value>0</value>
+ <value>[b]Not bold[/b] :) http://example.org</value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>3</value>
+ <value>1</value>
+ <value>0</value>
+ <value>0</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>4</value>
+ <value>0</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>5</value>
+ <value>0</value>
+ <value>0</value>
+ <value>1</value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>6</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>7</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>8</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>9</value>
+ <value>1</value>
+ <value>1</value>
+ <value>0</value>
+ <value><![CDATA[[img]http://example.org/img.png[/img]]]></value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ <row>
+ <value>1000</value>
+ <value>1</value>
+ <value>1</value>
+ <value>1</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ <value></value>
+ <value></value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/fixtures/users.xml b/tests/text_reparser/plugins/fixtures/users.xml
new file mode 100644
index 0000000000..60c623b6b1
--- /dev/null
+++ b/tests/text_reparser/plugins/fixtures/users.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<dataset>
+ <table name="phpbb_users">
+ <column>user_id</column>
+ <column>user_permissions</column>
+ <column>username_clean</column>
+ <column>user_options</column>
+ <column>user_sig</column>
+ <column>user_sig_bbcode_uid</column>
+ <row>
+ <value>1</value>
+ <value></value>
+ <value>user1</value>
+ <value>230271</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>2</value>
+ <value></value>
+ <value>user2</value>
+ <value>895</value>
+ <value>[b]Not bold[/b] :) http://example.org</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>3</value>
+ <value></value>
+ <value>user3</value>
+ <value>33663</value>
+ <value>[b:abcd1234]Bold[/b:abcd1234] :) http://example.org</value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>4</value>
+ <value></value>
+ <value>user4</value>
+ <value>66431</value>
+ <value><![CDATA[[b]Not bold[/b] <!-- s:) --><img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile" /><!-- s:) --> http://example.org]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>5</value>
+ <value></value>
+ <value>user5</value>
+ <value>131967</value>
+ <value><![CDATA[[b]Not bold[/b] :) <!-- m --><a class="postlink" href="http://example.org">http://example.org</a><!-- m -->]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>6</value>
+ <value></value>
+ <value>user6</value>
+ <value>99199</value>
+ <value><![CDATA[[flash=123,345:abcd1234]http&#58;//example&#46;org/flash&#46;swf[/flash:abcd1234]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>7</value>
+ <value></value>
+ <value>user7</value>
+ <value>99199</value>
+ <value><![CDATA[[flash=123,345]http://example.org/flash.swf[/flash]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>8</value>
+ <value></value>
+ <value>user8</value>
+ <value>99199</value>
+ <value><![CDATA[[img:abcd1234]http&#58;//example&#46;org/img&#46;png[/img:abcd1234]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>9</value>
+ <value></value>
+ <value>user9</value>
+ <value>99199</value>
+ <value><![CDATA[[img]http://example.org/img.png[/img]]]></value>
+ <value>abcd1234</value>
+ </row>
+ <row>
+ <value>1000</value>
+ <value></value>
+ <value>user1000</value>
+ <value>230271</value>
+ <value>This row should be [b]ignored[/b]</value>
+ <value>abcd1234</value>
+ </row>
+ </table>
+</dataset>
diff --git a/tests/text_reparser/plugins/forum_description_test.php b/tests/text_reparser/plugins/forum_description_test.php
new file mode 100644
index 0000000000..57166e6a3c
--- /dev/null
+++ b/tests/text_reparser/plugins/forum_description_test.php
@@ -0,0 +1,26 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+include_once __DIR__ . '/test_row_based_plugin.php';
+
+class phpbb_textreparser_forum_description_test extends phpbb_textreparser_test_row_based_plugin
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/forums.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\forum_description($this->db, FORUMS_TABLE);
+ }
+}
diff --git a/tests/text_reparser/plugins/forum_rules_test.php b/tests/text_reparser/plugins/forum_rules_test.php
new file mode 100644
index 0000000000..72e4e98876
--- /dev/null
+++ b/tests/text_reparser/plugins/forum_rules_test.php
@@ -0,0 +1,26 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+include_once __DIR__ . '/test_row_based_plugin.php';
+
+class phpbb_textreparser_forum_rules_test extends phpbb_textreparser_test_row_based_plugin
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/forums.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\forum_rules($this->db, FORUMS_TABLE);
+ }
+}
diff --git a/tests/text_reparser/plugins/group_description_test.php b/tests/text_reparser/plugins/group_description_test.php
new file mode 100644
index 0000000000..babfc7e02f
--- /dev/null
+++ b/tests/text_reparser/plugins/group_description_test.php
@@ -0,0 +1,26 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+include_once __DIR__ . '/test_row_based_plugin.php';
+
+class phpbb_textreparser_group_description_test extends phpbb_textreparser_test_row_based_plugin
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/groups.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\group_description($this->db, GROUPS_TABLE);
+ }
+}
diff --git a/tests/text_reparser/plugins/pm_text_test.php b/tests/text_reparser/plugins/pm_text_test.php
new file mode 100644
index 0000000000..6dc1a9cb4c
--- /dev/null
+++ b/tests/text_reparser/plugins/pm_text_test.php
@@ -0,0 +1,26 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+include_once __DIR__ . '/test_row_based_plugin.php';
+
+class phpbb_textreparser_pm_text_test extends phpbb_textreparser_test_row_based_plugin
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/privmsgs.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\pm_text($this->db, PRIVMSGS_TABLE);
+ }
+}
diff --git a/tests/text_reparser/plugins/poll_option_test.php b/tests/text_reparser/plugins/poll_option_test.php
new file mode 100644
index 0000000000..177faac51d
--- /dev/null
+++ b/tests/text_reparser/plugins/poll_option_test.php
@@ -0,0 +1,129 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php';
+
+class phpbb_textreparser_poll_option_test extends phpbb_database_test_case
+{
+ protected $db;
+
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/poll_options.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\poll_option($this->db);
+ }
+
+ protected function get_rows()
+ {
+ $sql = 'SELECT topic_id, poll_option_id, poll_option_text
+ FROM ' . POLL_OPTIONS_TABLE . '
+ ORDER BY topic_id, poll_option_id';
+ $result = $this->db->sql_query($sql);
+ $rows = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ return $rows;
+ }
+
+ public function setUp()
+ {
+ global $config;
+ if (!isset($config))
+ {
+ $config = new \phpbb\config\config(array());
+ }
+ $this->get_test_case_helpers()->set_s9e_services();
+ $this->db = $this->new_dbal();
+ parent::setUp();
+ }
+
+ public function test_get_max_id()
+ {
+ $reparser = $this->get_reparser();
+ $this->assertEquals(123, $reparser->get_max_id());
+ }
+
+ public function test_dry_run()
+ {
+ $old_rows = $this->get_rows();
+ $reparser = $this->get_reparser();
+ $reparser->disable_save();
+ $reparser->reparse_range(1, 1);
+ $new_rows = $this->get_rows();
+ $this->assertEquals($old_rows, $new_rows);
+ }
+
+ public function testReparse()
+ {
+ $reparser = $this->get_reparser();
+ $reparser->enable_save();
+ $reparser->reparse_range(2, 13);
+ $expected = array(
+ array(
+ 'topic_id' => 1,
+ 'poll_option_id' => 1,
+ 'poll_option_text' => 'This row should be [b]ignored[/b]',
+ ),
+ array(
+ 'topic_id' => 1,
+ 'poll_option_id' => 2,
+ 'poll_option_text' => 'This row should be [b:abcd1234]ignored[/b:abcd1234]',
+ ),
+ array(
+ 'topic_id' => 2,
+ 'poll_option_id' => 1,
+ 'poll_option_text' => '<r><B><s>[b]</s>Bold<e>[/b]</e></B></r>',
+ ),
+ array(
+ 'topic_id' => 2,
+ 'poll_option_id' => 2,
+ 'poll_option_text' => '<r><E>:)</E></r>',
+ ),
+ array(
+ 'topic_id' => 2,
+ 'poll_option_id' => 3,
+ 'poll_option_text' => '<r><URL url="http://example.org">http://example.org</URL></r>',
+ ),
+ array(
+ 'topic_id' => 11,
+ 'poll_option_id' => 1,
+ 'poll_option_text' => '<r><B><s>[b]</s>Bold<e>[/b]</e></B> :) http://example.org</r>',
+ ),
+ array(
+ 'topic_id' => 12,
+ 'poll_option_id' => 1,
+ 'poll_option_text' => '<r>[b]Not bold[/b] <E>:)</E> http://example.org</r>',
+ ),
+ array(
+ 'topic_id' => 13,
+ 'poll_option_id' => 1,
+ 'poll_option_text' => '<r>[b]Not bold[/b] :) <URL url="http://example.org">http://example.org</URL></r>',
+ ),
+ array(
+ 'topic_id' => 123,
+ 'poll_option_id' => 1,
+ 'poll_option_text' => 'This row should be [b]ignored[/b]',
+ ),
+ array(
+ 'topic_id' => 123,
+ 'poll_option_id' => 2,
+ 'poll_option_text' => 'This row should be [b:abcd1234]ignored[/b:abcd1234]',
+ ),
+ );
+ $this->assertEquals($expected, $this->get_rows());
+ }
+}
diff --git a/tests/text_reparser/plugins/poll_title_test.php b/tests/text_reparser/plugins/poll_title_test.php
new file mode 100644
index 0000000000..046b6019c8
--- /dev/null
+++ b/tests/text_reparser/plugins/poll_title_test.php
@@ -0,0 +1,26 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+include_once __DIR__ . '/test_row_based_plugin.php';
+
+class phpbb_textreparser_poll_title_test extends phpbb_textreparser_test_row_based_plugin
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/polls.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\poll_title($this->db, TOPICS_TABLE);
+ }
+}
diff --git a/tests/text_reparser/plugins/post_text_test.php b/tests/text_reparser/plugins/post_text_test.php
new file mode 100644
index 0000000000..8ea71e65f5
--- /dev/null
+++ b/tests/text_reparser/plugins/post_text_test.php
@@ -0,0 +1,26 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+include_once __DIR__ . '/test_row_based_plugin.php';
+
+class phpbb_textreparser_post_text_test extends phpbb_textreparser_test_row_based_plugin
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/posts.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\post_text($this->db, POSTS_TABLE);
+ }
+}
diff --git a/tests/text_reparser/plugins/test_row_based_plugin.php b/tests/text_reparser/plugins/test_row_based_plugin.php
new file mode 100644
index 0000000000..3e9ff09448
--- /dev/null
+++ b/tests/text_reparser/plugins/test_row_based_plugin.php
@@ -0,0 +1,150 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+require_once __DIR__ . '/../../test_framework/phpbb_database_test_case.php';
+
+abstract class phpbb_textreparser_test_row_based_plugin extends phpbb_database_test_case
+{
+ protected $db;
+
+ abstract protected function get_reparser();
+
+ protected function get_rows(array $ids)
+ {
+ $reparser = $this->get_reparser();
+ $columns = $reparser->get_columns();
+
+ $reflection_reparser = new ReflectionClass(get_class($reparser));
+ $table_property = $reflection_reparser->getProperty('table');
+ $table_property->setAccessible(true);
+
+ $sql = 'SELECT ' . $columns['id'] . ' AS id, ' . $columns['text'] . ' AS text
+ FROM ' . $table_property->getValue($reparser) . '
+ WHERE ' . $this->db->sql_in_set($columns['id'], $ids) . '
+ ORDER BY id';
+ $result = $this->db->sql_query($sql);
+ $rows = $this->db->sql_fetchrowset($result);
+ $this->db->sql_freeresult($result);
+
+ return $rows;
+ }
+
+ public function setUp()
+ {
+ global $config;
+ if (!isset($config))
+ {
+ $config = new \phpbb\config\config(array());
+ }
+ $this->get_test_case_helpers()->set_s9e_services();
+ $this->db = $this->new_dbal();
+ parent::setUp();
+ }
+
+ public function test_get_max_id()
+ {
+ $reparser = $this->get_reparser();
+ $this->assertEquals(1000, $reparser->get_max_id());
+ }
+
+ public function test_dry_run()
+ {
+ $old_rows = $this->get_rows(array(1));
+ $reparser = $this->get_reparser();
+ $reparser->disable_save();
+ $reparser->reparse_range(1, 1);
+ $new_rows = $this->get_rows(array(1));
+ $this->assertEquals($old_rows, $new_rows);
+ }
+
+ /**
+ * @dataProvider get_reparse_tests
+ */
+ public function test_reparse($min_id, $max_id, $expected)
+ {
+ $reparser = $this->get_reparser();
+ $reparser->reparse_range($min_id, $max_id);
+
+ $ids = array();
+ foreach ($expected as $row)
+ {
+ $ids[] = $row['id'];
+ }
+
+ $this->assertEquals($expected, $this->get_rows($ids));
+ }
+
+ public function get_reparse_tests()
+ {
+ return array(
+ array(
+ 2,
+ 5,
+ array(
+ array(
+ 'id' => '1',
+ 'text' => 'This row should be [b]ignored[/b]',
+ ),
+ array(
+ 'id' => '2',
+ 'text' => '<t>[b]Not bold[/b] :) http://example.org</t>',
+ ),
+ array(
+ 'id' => '3',
+ 'text' => '<r><B><s>[b]</s>Bold<e>[/b]</e></B> :) http://example.org</r>',
+ ),
+ array(
+ 'id' => '4',
+ 'text' => '<r>[b]Not bold[/b] <E>:)</E> http://example.org</r>',
+ ),
+ array(
+ 'id' => '5',
+ 'text' => '<r>[b]Not bold[/b] :) <URL url="http://example.org">http://example.org</URL></r>',
+ ),
+ array(
+ 'id' => '1000',
+ 'text' => 'This row should be [b]ignored[/b]',
+ ),
+ )
+ ),
+ array(
+ 6,
+ 7,
+ array(
+ array(
+ 'id' => '6',
+ 'text' => '<r><FLASH height="345" url="http://example.org/flash.swf" width="123"><s>[flash=123,345]</s>http://example.org/flash.swf<e>[/flash]</e></FLASH></r>',
+ ),
+ array(
+ 'id' => '7',
+ 'text' => '<t>[flash=123,345]http://example.org/flash.swf[/flash]</t>',
+ ),
+ )
+ ),
+ array(
+ 8,
+ 9,
+ array(
+ array(
+ 'id' => '8',
+ 'text' => '<r><IMG src="http://example.org/img.png"><s>[img]</s>http://example.org/img.png<e>[/img]</e></IMG></r>',
+ ),
+ array(
+ 'id' => '9',
+ 'text' => '<t>[img]http://example.org/img.png[/img]</t>',
+ ),
+ )
+ ),
+ );
+ }
+}
diff --git a/tests/text_reparser/plugins/user_signature_test.php b/tests/text_reparser/plugins/user_signature_test.php
new file mode 100644
index 0000000000..5b66f2788a
--- /dev/null
+++ b/tests/text_reparser/plugins/user_signature_test.php
@@ -0,0 +1,26 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+include_once __DIR__ . '/test_row_based_plugin.php';
+
+class phpbb_textreparser_user_signature_test extends phpbb_textreparser_test_row_based_plugin
+{
+ public function getDataSet()
+ {
+ return $this->createXMLDataSet(__DIR__ . '/fixtures/users.xml');
+ }
+
+ protected function get_reparser()
+ {
+ return new \phpbb\textreparser\plugins\user_signature($this->db, USERS_TABLE);
+ }
+}
diff --git a/tests/tree/nestedset_forum_base.php b/tests/tree/nestedset_forum_base.php
index c56be1f81e..498c6a69a2 100644
--- a/tests/tree/nestedset_forum_base.php
+++ b/tests/tree/nestedset_forum_base.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case
{
public function getDataSet()
@@ -59,7 +57,6 @@ class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case
global $config;
$config = $this->config = new \phpbb\config\config(array('nestedset_forum_lock' => 0));
- set_config(null, null, null, $this->config);
$this->lock = new \phpbb\lock\db('nestedset_forum_lock', $this->config, $this->db);
$this->set = new \phpbb\tree\nestedset_forum($this->db, $this->lock, 'phpbb_forums');
@@ -72,7 +69,7 @@ class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case
static $forums;
if (empty($forums))
- {
+ {
$this->create_forum('Parent with two flat children');
$this->create_forum('Flat child #1', 1);
$this->create_forum('Flat child #2', 1);
@@ -89,7 +86,7 @@ class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case
// Updating forum_parents column here so it's not empty
// This is required, so we can see whether the methods
- // correctly clear the values.
+ // correctly clear the values.
$sql = "UPDATE phpbb_forums
SET forum_parents = 'a:0:{}'";
$this->db->sql_query($sql);
@@ -103,6 +100,13 @@ class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case
}
else
{
+ // Turn on identity insert on mssql to be able to insert into
+ // identity columns (e.g. forum_id)
+ if (strpos($this->db->sql_layer, 'mssql') !== false)
+ {
+ $sql = 'SET IDENTITY_INSERT phpbb_forums ON';
+ $this->db->sql_query($sql);
+ }
$buffer = new \phpbb\db\sql_insert_buffer($this->db, 'phpbb_forums');
$buffer->insert_all($forums);
$buffer->flush();
@@ -110,7 +114,14 @@ class phpbb_tests_tree_nestedset_forum_base extends phpbb_database_test_case
$this->database_synchronisation(array(
'phpbb_forums' => array('forum_id'),
));
- }
+
+ // Disable identity insert on mssql again
+ if (strpos($this->db->sql_layer, 'mssql') !== false)
+ {
+ $sql = 'SET IDENTITY_INSERT phpbb_forums OFF';
+ $this->db->sql_query($sql);
+ }
+ }
}
protected function create_forum($name, $parent_id = 0)
diff --git a/tests/ui/permission_roles_test.php b/tests/ui/permission_roles_test.php
new file mode 100644
index 0000000000..de54cc788d
--- /dev/null
+++ b/tests/ui/permission_roles_test.php
@@ -0,0 +1,90 @@
+<?php
+/**
+*
+* This file is part of the phpBB Forum Software package.
+*
+* @copyright (c) phpBB Limited <https://www.phpbb.com>
+* @license GNU General Public License, version 2 (GPL-2.0)
+*
+* For full copyright and license information, please see
+* the docs/CREDITS.txt file.
+*
+*/
+
+/**
+* @group ui
+*/
+class ui_permission_roles_test extends phpbb_ui_test_case
+{
+
+ public function test_permission_roles()
+ {
+ $this->login();
+ $this->admin_login();
+ $this->add_lang('acp/permissions');
+ $this->visit('adm/index.php?i=acp_permissions&mode=setting_forum_local&sid=' . $this->sid);
+
+ // Select forums
+ $elements = $this->find_element('cssSelector', 'select#forum')
+ ->findElements(\Facebook\WebDriver\WebDriverBy::tagName('option'));
+
+ foreach ($elements as $element)
+ {
+ $element->click();
+ }
+ $this->find_element('cssSelector', 'form#select_victim')
+ ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=submit]'))
+ ->click();
+
+ // Select administrators and guests
+ $groups_form = $this->find_element('cssSelector', 'form#groups');
+ $elements = $groups_form
+ ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('select'))
+ ->findElements(\Facebook\WebDriver\WebDriverBy::tagName('option'));
+
+ foreach ($elements as $element)
+ {
+ if ($element->getText() === 'Administrators' || $element->getText() === 'Guests')
+ {
+ $element->click();
+ }
+ }
+ $groups_form->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[name=submit_edit_options]'))->click();
+
+ $first_fieldset = $this->find_element('cssSelector', '#perm11');
+ $this->assertEquals('none', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ $first_fieldset
+ ->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))
+ ->click();
+ $this->assertEquals('block', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ $lis = $first_fieldset
+ ->findElements(\Facebook\WebDriver\WebDriverBy::cssSelector('ul > li'));
+
+ foreach ($lis as $li)
+ {
+ if ($li->getAttribute('data-id') == 18)
+ {
+ $li->click();
+
+ break;
+ }
+ }
+ $this->assertEquals('none', $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ $this->assertEquals(18, $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value'));
+ $this->assertEquals($this->lang('ROLE_FORUM_LIMITED'), $first_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText());
+
+ // Check that admin settings didn't get changed
+ $second_fieldset = $this->find_element('cssSelector', '#perm10');
+ $this->assertEquals('none', $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ // Full access = 14
+ $this->assertEquals(14, $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value'));
+ $this->assertEquals($this->lang('ROLE_FORUM_FULL'), $second_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText());
+
+ // Check that category settings were not modified
+ $category_fieldset = $this->find_element('cssSelector', '#perm00');
+ $this->assertEquals('none', $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('div.dropdown'))->getCSSValue('display'));
+ // No settings
+ $this->assertEquals('', $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('input[type=hidden]'))->getAttribute('value'));
+ $this->assertEquals($this->lang('NO_ROLE_ASSIGNED'), $category_fieldset->findElement(\Facebook\WebDriver\WebDriverBy::cssSelector('span.dropdown-toggle'))->getText());
+ }
+}
diff --git a/tests/ui/quick_links_test.php b/tests/ui/quick_links_test.php
index 5bddb44a8b..171ef3ca53 100644
--- a/tests/ui/quick_links_test.php
+++ b/tests/ui/quick_links_test.php
@@ -16,12 +16,11 @@
*/
class quick_links_test extends phpbb_ui_test_case
{
-
public function test_quick_links()
{
$this->visit('index.php');
- $this->assertEmpty(self::find_element('className', 'dropdown')->getText());
- self::find_element('className', 'dropdown-toggle')->click();
- $this->assertNotNull(self::find_element('className', 'dropdown')->getText());
+ $this->assertEmpty($this->find_element('className', 'dropdown')->getText());
+ $this->find_element('className', 'dropdown-toggle')->click();
+ $this->assertNotNull($this->find_element('className', 'dropdown')->getText());
}
}
diff --git a/tests/upload/filespec_test.php b/tests/upload/filespec_test.php
index ed28bcb38f..b41b95d925 100644
--- a/tests/upload/filespec_test.php
+++ b/tests/upload/filespec_test.php
@@ -11,10 +11,6 @@
*
*/
-require_once __DIR__ . '/../../phpBB/includes/functions.php';
-require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php';
-require_once __DIR__ . '/../../phpBB/includes/functions_upload.php';
-
class phpbb_filespec_test extends phpbb_test_case
{
const TEST_COUNT = 100;
@@ -23,14 +19,19 @@ class phpbb_filespec_test extends phpbb_test_case
const UPLOAD_MAX_FILESIZE = 1000;
private $config;
+ private $filesystem;
public $path;
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
protected function setUp()
{
// Global $config required by unique_id
- // Global $user required by filespec::additional_checks and
- // filespec::move_file
- global $config, $user;
+ global $config, $phpbb_root_path, $phpEx;
if (!is_array($config))
{
@@ -44,9 +45,6 @@ class phpbb_filespec_test extends phpbb_test_case
// See: phpBB/install/schemas/schema_data.sql
$config['mime_triggers'] = 'body|head|html|img|plaintext|a href|pre|script|table|title';
- $user = new phpbb_mock_user();
- $user->lang = new phpbb_mock_lang();
-
$this->config = &$config;
$this->path = __DIR__ . '/fixture/';
@@ -75,6 +73,17 @@ class phpbb_filespec_test extends phpbb_test_case
$guessers[2]->set_priority(-2);
$guessers[3]->set_priority(-2);
$this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers);
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ private function set_reflection_property($class, $property_name, $value)
+ {
+ $property = new ReflectionProperty($class, $property_name);
+ $property->setAccessible(true);
+ $property->setValue($class, $value);
}
private function get_filespec($override = array())
@@ -88,14 +97,13 @@ class phpbb_filespec_test extends phpbb_test_case
'error' => '',
);
- return new filespec(array_merge($upload_ary, $override), null, $this->mimetype_guesser);
+ $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, $this->mimetype_guesser);
+ return $filespec->set_upload_ary(array_merge($upload_ary, $override));
}
protected function tearDown()
{
- global $user;
$this->config = array();
- $user = null;
$iterator = new DirectoryIterator($this->path . 'copies');
foreach ($iterator as $fileinfo)
@@ -108,6 +116,13 @@ class phpbb_filespec_test extends phpbb_test_case
}
}
+ public function test_empty_upload_ary()
+ {
+ $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, $this->mimetype_guesser);
+ $this->assertInstanceOf('\phpbb\files\filespec', $filespec->set_upload_ary(array()));
+ $this->assertTrue($filespec->init_error());
+ }
+
public function additional_checks_variables()
{
// False here just indicates the file is too large and fails the
@@ -129,13 +144,26 @@ class phpbb_filespec_test extends phpbb_test_case
{
$upload = new phpbb_mock_fileupload();
$filespec = $this->get_filespec();
- $filespec->upload = $upload;
- $filespec->file_moved = true;
- $filespec->filesize = $filespec->get_filesize($this->path . $filename);
+ $filespec->set_upload_namespace($upload);
+ $this->set_reflection_property($filespec, 'file_moved', true);
+ $this->set_reflection_property($filespec, 'filesize', $filespec->get_filesize($this->path . $filename));
$this->assertEquals($expected, $filespec->additional_checks());
}
+ public function test_additional_checks_dimensions()
+ {
+ $upload = new phpbb_mock_fileupload();
+ $filespec = $this->get_filespec();
+ $filespec->set_upload_namespace($upload);
+ $upload->valid_dimensions = false;
+ $this->set_reflection_property($filespec, 'file_moved', true);
+ $upload->max_filesize = 0;
+
+ $this->assertEquals(false, $filespec->additional_checks());
+ $this->assertSame(array('WRONG_SIZE'), $filespec->error);
+ }
+
public function check_content_variables()
{
// False here indicates that a file is non-binary and contains
@@ -170,6 +198,7 @@ class phpbb_filespec_test extends phpbb_test_case
array($chunks[2] . $chunks[9]),
array($chunks[3] . $chunks[4]),
array($chunks[5] . $chunks[6]),
+ array('foobar.png'),
);
}
@@ -181,7 +210,7 @@ class phpbb_filespec_test extends phpbb_test_case
$bad_chars = array("'", "\\", ' ', '/', ':', '*', '?', '"', '<', '>', '|');
$filespec = $this->get_filespec(array('name' => $filename));
$filespec->clean_filename('real', self::PREFIX);
- $name = $filespec->realname;
+ $name = $filespec->get('realname');
$this->assertEquals(0, preg_match('/%(\w{2})/', $name));
foreach ($bad_chars as $char)
@@ -197,8 +226,8 @@ class phpbb_filespec_test extends phpbb_test_case
{
$filespec = $this->get_filespec();
$filespec->clean_filename('unique', self::PREFIX);
- $name = $filespec->realname;
-
+ $name = $filespec->get('realname');
+
$this->assertEquals(strlen($name), 32 + strlen(self::PREFIX));
$this->assertRegExp('#^[A-Za-z0-9]+$#', substr($name, strlen(self::PREFIX)));
$this->assertFalse(isset($filenames[$name]));
@@ -206,6 +235,55 @@ class phpbb_filespec_test extends phpbb_test_case
}
}
+ public function test_clean_filename_unique_ext()
+ {
+ $filenames = array();
+ for ($tests = 0; $tests < self::TEST_COUNT; $tests++)
+ {
+ $filespec = $this->get_filespec(array('name' => 'foobar.jpg'));
+ $filespec->clean_filename('unique_ext', self::PREFIX);
+ $name = $filespec->get('realname');
+
+ $this->assertEquals(strlen($name), 32 + strlen(self::PREFIX) + strlen('.jpg'));
+ $this->assertRegExp('#^[A-Za-z0-9]+\.jpg$#', substr($name, strlen(self::PREFIX)));
+ $this->assertFalse(isset($filenames[$name]));
+ $filenames[$name] = true;
+ }
+ }
+
+ public function data_clean_filename_avatar()
+ {
+ return array(
+ array(false, false, ''),
+ array('foobar.png', 'u5.png', 'avatar', 'u', 5),
+ array('foobar.png', 'g9.png', 'avatar', 'g', 9),
+
+ );
+ }
+
+ /**
+ * @dataProvider data_clean_filename_avatar
+ */
+ public function test_clean_filename_avatar($filename, $expected, $mode, $prefix = '', $user_id = '')
+ {
+ $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, $this->mimetype_guesser);
+
+ if ($filename)
+ {
+ $upload_ary = array(
+ 'name' => $filename,
+ 'type' => '',
+ 'size' => '',
+ 'tmp_name' => '',
+ 'error' => '',
+ );
+ $filespec->set_upload_ary($upload_ary);
+ }
+ $filespec->clean_filename($mode, $prefix, $user_id);
+
+ $this->assertSame($expected, $filespec->get('realname'));
+ }
+
public function get_extension_variables()
{
return array(
@@ -223,7 +301,7 @@ class phpbb_filespec_test extends phpbb_test_case
*/
public function test_get_extension($filename, $expected)
{
- $this->assertEquals($expected, filespec::get_extension($filename));
+ $this->assertEquals($expected, \phpbb\files\filespec::get_extension($filename));
}
public function is_image_variables()
@@ -286,7 +364,7 @@ class phpbb_filespec_test extends phpbb_test_case
array('txt_copy', 'txt_as_img', 'image/jpg', 'txt', false, true),
array('txt_copy_2', 'txt_moved', 'text/plain', 'txt', false, true),
array('jpg_copy', 'jpg_moved', 'image/png', 'jpg', false, true),
- array('png_copy', 'png_moved', 'image/png', 'jpg', 'IMAGE_FILETYPE_MISMATCH', true),
+ array('png_copy', 'png_moved', 'image/png', 'jpg', 'Image file type mismatch: expected extension png but extension jpg given.', true),
);
}
@@ -297,8 +375,7 @@ class phpbb_filespec_test extends phpbb_test_case
{
// Global $phpbb_root_path and $phpEx are required by phpbb_chmod
global $phpbb_root_path, $phpEx;
- $phpbb_root_path = '';
- $phpEx = 'php';
+ $this->phpbb_root_path = '';
$upload = new phpbb_mock_fileupload();
$upload->max_filesize = self::UPLOAD_MAX_FILESIZE;
@@ -308,18 +385,137 @@ class phpbb_filespec_test extends phpbb_test_case
'name' => $realname,
'type' => $mime_type,
));
- $filespec->extension = $extension;
- $filespec->upload = $upload;
- $filespec->local = true;
+ $this->set_reflection_property($filespec, 'extension', $extension);
+ $filespec->set_upload_namespace($upload);
+ $this->set_reflection_property($filespec, 'local', true);
$this->assertEquals($expected, $filespec->move_file($this->path . 'copies'));
- $this->assertEquals($filespec->file_moved, file_exists($this->path . 'copies/' . $realname));
+ $this->assertEquals($filespec->get('file_moved'), file_exists($this->path . 'copies/' . $realname));
if ($error)
{
$this->assertEquals($error, $filespec->error[0]);
}
- $phpEx = '';
+ $this->phpbb_root_path = $phpbb_root_path;
+ }
+
+ public function test_move_file_error()
+ {
+ $filespec = $this->get_filespec();
+ $this->assertFalse($filespec->move_file('foobar'));
+ $filespec->error[] = 'foo';
+ $this->assertFalse($filespec->move_file('foo'));
+ }
+
+ public function data_move_file_copy()
+ {
+ return array(
+ array('gif_copy', true, false, array()),
+ array('gif_copy', true, true, array()),
+ array('foo_bar', false, false, array('GENERAL_UPLOAD_ERROR')),
+ array('foo_bar', false, true, array('GENERAL_UPLOAD_ERROR')),
+ );
+ }
+
+ /**
+ * @dataProvider data_move_file_copy
+ */
+ public function test_move_file_copy($tmp_name, $move_success, $safe_mode_on, $expected_error)
+ {
+ // Initialise a blank filespec object for use with trivial methods
+ $upload_ary = array(
+ 'name' => 'gif_moved',
+ 'type' => 'image/gif',
+ 'size' => '',
+ 'tmp_name' => $this->path . 'copies/' . $tmp_name,
+ 'error' => '',
+ );
+
+ $php_ini = $this->getMockBuilder('\bantu\IniGetWrapper\IniGetWrapper')
+ ->getMock();
+ $php_ini->expects($this->any())
+ ->method('getBool')
+ ->with($this->anything())
+ ->willReturn($safe_mode_on);
+ $upload = new phpbb_mock_fileupload();
+ $upload->max_filesize = self::UPLOAD_MAX_FILESIZE;
+ $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, $php_ini, new \FastImageSize\FastImagesize, '', $this->mimetype_guesser);
+ $filespec->set_upload_ary($upload_ary);
+ $this->set_reflection_property($filespec, 'local', false);
+ $this->set_reflection_property($filespec, 'extension', 'gif');
+ $filespec->set_upload_namespace($upload);
+
+ $this->assertEquals($move_success, $filespec->move_file($this->path . 'copies'));
+ $this->assertEquals($filespec->get('file_moved'), file_exists($this->path . 'copies/gif_moved'));
+ $this->assertSame($expected_error, $filespec->error);
+ }
+
+ public function data_move_file_imagesize()
+ {
+ return array(
+ array(
+ array(
+ 'width' => 2,
+ 'height' => 2,
+ 'type' => IMAGETYPE_GIF,
+ ),
+ array()
+ ),
+ array(
+ array(
+ 'width' => 2,
+ 'height' => 2,
+ 'type' => -1,
+ ),
+ array('Image file type -1 for mimetype image/gif not supported.')
+ ),
+ array(
+ array(
+ 'width' => 0,
+ 'height' => 0,
+ 'type' => IMAGETYPE_GIF,
+ ),
+ array('The image file you tried to attach is invalid.')
+ ),
+ array(
+ false,
+ array('It was not possible to determine the dimensions of the image. Please verify that the URL you entered is correct.')
+ )
+ );
+ }
+
+ /**
+ * @dataProvider data_move_file_imagesize
+ */
+ public function test_move_file_imagesize($imagesize_return, $expected_error)
+ {
+ // Initialise a blank filespec object for use with trivial methods
+ $upload_ary = array(
+ 'name' => 'gif_moved',
+ 'type' => 'image/gif',
+ 'size' => '',
+ 'tmp_name' => $this->path . 'copies/gif_copy',
+ 'error' => '',
+ );
+
+ $imagesize = $this->getMockBuilder('\FastImageSize\FastImageSize')
+ ->getMock();
+ $imagesize->expects($this->any())
+ ->method('getImageSize')
+ ->with($this->anything())
+ ->willReturn($imagesize_return);
+
+ $upload = new phpbb_mock_fileupload();
+ $upload->max_filesize = self::UPLOAD_MAX_FILESIZE;
+ $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, $imagesize, '', $this->mimetype_guesser);
+ $filespec->set_upload_ary($upload_ary);
+ $this->set_reflection_property($filespec, 'local', false);
+ $this->set_reflection_property($filespec, 'extension', 'gif');
+ $filespec->set_upload_namespace($upload);
+
+ $this->assertEquals(true, $filespec->move_file($this->path . 'copies'));
+ $this->assertEquals($filespec->get('file_moved'), file_exists($this->path . 'copies/gif_moved'));
+ $this->assertSame($expected_error, $filespec->error);
}
/**
@@ -333,6 +529,29 @@ class phpbb_filespec_test extends phpbb_test_case
$type_cast_helper->set_var($upload_name, $filename, 'string', true, true);
$filespec = $this->get_filespec(array('name'=> $upload_name));
- $this->assertSame(trim(utf8_basename(htmlspecialchars($filename))), $filespec->uploadname);
+ $this->assertSame(trim(utf8_basename(htmlspecialchars($filename))), $filespec->get('uploadname'));
+ }
+
+ public function test_is_uploaded()
+ {
+ $filespec = new \phpbb\files\filespec($this->filesystem, $this->language, new \bantu\IniGetWrapper\IniGetWrapper, new \FastImageSize\FastImageSize(), $this->phpbb_root_path, null);
+ $reflection_filespec = new ReflectionClass($filespec);
+ $plupload_property = $reflection_filespec->getProperty('plupload');
+ $plupload_property->setAccessible(true);
+ $plupload_mock = $this->getMockBuilder('\phpbb\plupload\plupload')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $plupload_mock->expects($this->any())
+ ->method('is_active')
+ ->will($this->returnValue(true));
+ $plupload_property->setValue($filespec, $plupload_mock);
+ $is_uploaded = $reflection_filespec->getMethod('is_uploaded');
+
+ // Plupload is active and file does not exist
+ $this->assertFalse($is_uploaded->invoke($filespec));
+
+ // Plupload is not active and file was not uploaded
+ $plupload_property->setValue($filespec, null);
+ $this->assertFalse($is_uploaded->invoke($filespec));
}
}
diff --git a/tests/upload/fileupload_test.php b/tests/upload/fileupload_test.php
index fcfb84125d..5b3357237d 100644
--- a/tests/upload/fileupload_test.php
+++ b/tests/upload/fileupload_test.php
@@ -11,36 +11,88 @@
*
*/
-require_once __DIR__ . '/../../phpBB/includes/functions.php';
-require_once __DIR__ . '/../../phpBB/includes/utf/utf_tools.php';
-require_once __DIR__ . '/../../phpBB/includes/functions_upload.php';
require_once __DIR__ . '/../mock/filespec.php';
class phpbb_fileupload_test extends phpbb_test_case
{
private $path;
+ private $filesystem;
+
+ /** @var \Symfony\Component\DependencyInjection\ContainerInterface */
+ protected $container;
+
+ /** @var \phpbb\files\factory */
+ protected $factory;
+
+ /** @var \bantu\IniGetWrapper\IniGetWrapper */
+ protected $php_ini;
+
+ /** @var \phpbb\language\language */
+ protected $language;
+
+ /** @var \phpbb\request\request_interface */
+ protected $request;
+
+ /** @var string phpBB root path */
+ protected $phpbb_root_path;
+
protected function setUp()
{
// Global $config required by unique_id
- // Global $user required by several functions dealing with translations
- // Global $request required by form_upload, local_upload and is_valid
- global $config, $user, $request;
+ global $config, $phpbb_root_path, $phpEx;
if (!is_array($config))
{
- $config = array();
+ $config = new \phpbb\config\config(array());
}
$config['rand_seed'] = '';
$config['rand_seed_last_update'] = time() + 600;
- $user = new phpbb_mock_user();
- $user->lang = new phpbb_mock_lang();
-
- $request = new phpbb_mock_request();
+ $this->request = $this->getMock('\phpbb\request\request');
+ $this->php_ini = new \bantu\IniGetWrapper\IniGetWrapper;
+
+ $this->filesystem = new \phpbb\filesystem\filesystem();
+ $this->language = new \phpbb\language\language(new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx));
+ $guessers = array(
+ new \Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser(),
+ new \Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser(),
+ new \phpbb\mimetype\content_guesser(),
+ new \phpbb\mimetype\extension_guesser(),
+ );
+ $guessers[2]->set_priority(-2);
+ $guessers[3]->set_priority(-2);
+ $this->mimetype_guesser = new \phpbb\mimetype\guesser($guessers);
+
+ $this->container = new phpbb_mock_container_builder($phpbb_root_path, $phpEx);
+ $this->container->set('files.filespec', new \phpbb\files\filespec(
+ $this->filesystem,
+ $this->language,
+ $this->php_ini,
+ new \FastImageSize\FastImageSize(),
+ $phpbb_root_path,
+ new \phpbb\mimetype\guesser(array(
+ 'mimetype.extension_guesser' => new \phpbb\mimetype\extension_guesser(),
+ ))));
+ $this->factory = new \phpbb\files\factory($this->container);
+ $plupload = new \phpbb\plupload\plupload($phpbb_root_path, $config, $this->request, new \phpbb\user($this->language, '\phpbb\datetime'), $this->php_ini, $this->mimetype_guesser);
+ $this->container->set('files.types.form', new \phpbb\files\types\form(
+ $this->factory,
+ $this->language,
+ $this->php_ini,
+ $plupload,
+ $this->request
+ ), phpbb_mock_container_builder::SCOPE_PROTOTYPE);
+ $this->container->set('files.types.local', new \phpbb\files\types\local(
+ $this->factory,
+ $this->language,
+ $this->php_ini,
+ $this->request
+ ), phpbb_mock_container_builder::SCOPE_PROTOTYPE);
$this->path = __DIR__ . '/fixture/';
+ $this->phpbb_root_path = $phpbb_root_path;
}
private function gen_valid_filespec()
@@ -65,15 +117,38 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_common_checks_invalid_extension()
{
- $upload = new fileupload('', array('png'), 100);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('png'))
+ ->set_max_filesize(100);
$file = $this->gen_valid_filespec();
$upload->common_checks($file);
$this->assertEquals('DISALLOWED_EXTENSION', $file->error[0]);
}
+ public function test_common_checks_disallowed_content()
+ {
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(1000);
+ $file = new \phpbb\files\filespec($this->filesystem, $this->language, $this->php_ini, new \FastImageSize\FastImageSize(), $this->phpbb_root_path);
+ $file->set_upload_ary(array(
+ 'size' => 50,
+ 'tmp_name' => dirname(__FILE__) . '/fixture/disallowed',
+ 'name' => 'disallowed.jpg',
+ 'type' => 'image/jpg'
+ ))
+ ->set_upload_namespace($upload);
+ file_put_contents(dirname(__FILE__) . '/fixture/disallowed', '<body>' . file_get_contents(dirname(__FILE__) . '/fixture/jpg'));
+ $upload->common_checks($file);
+ $this->assertEquals('DISALLOWED_CONTENT', $file->error[0]);
+ unlink(dirname(__FILE__) . '/fixture/disallowed');
+ }
+
public function test_common_checks_invalid_filename()
{
- $upload = new fileupload('', array('jpg'), 100);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(100);
$file = $this->gen_valid_filespec();
$file->realname = 'invalid?';
$upload->common_checks($file);
@@ -82,7 +157,9 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_common_checks_too_large()
{
- $upload = new fileupload('', array('jpg'), 100);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(100);
$file = $this->gen_valid_filespec();
$file->filesize = 1000;
$upload->common_checks($file);
@@ -91,50 +168,63 @@ class phpbb_fileupload_test extends phpbb_test_case
public function test_common_checks_valid_file()
{
- $upload = new fileupload('', array('jpg'), 1000);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(1000);
$file = $this->gen_valid_filespec();
$upload->common_checks($file);
- $this->assertEquals(0, sizeof($file->error));
+ $this->assertEquals(0, count($file->error));
}
public function test_local_upload()
{
- $upload = new fileupload('', array('jpg'), 1000);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(1000);
copy($this->path . 'jpg', $this->path . 'jpg.jpg');
- $file = $upload->local_upload($this->path . 'jpg.jpg');
- $this->assertEquals(0, sizeof($file->error));
- unlink($this->path . 'jpg.jpg');
+ $file = $upload->handle_upload('files.types.local', $this->path . 'jpg.jpg');
+ $this->assertEquals(0, count($file->error));
+ $this->assertFalse($file->additional_checks());
+ $this->assertTrue($file->move_file('../tests/upload/fixture/copies', true));
+ $file->remove();
}
public function test_move_existent_file()
{
- $upload = new fileupload('', array('jpg'), 1000);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(1000);
copy($this->path . 'jpg', $this->path . 'jpg.jpg');
- $file = $upload->local_upload($this->path . 'jpg.jpg');
- $this->assertEquals(0, sizeof($file->error));
+ $file = $upload->handle_upload('files.types.local', $this->path . 'jpg.jpg');
+ $this->assertEquals(0, count($file->error));
$this->assertFalse($file->move_file('../tests/upload/fixture'));
- $this->assertFalse($file->file_moved);
- $this->assertEquals(1, sizeof($file->error));
+ $this->assertFalse($file->get('file_moved'));
+ $this->assertEquals(1, count($file->error));
}
public function test_move_existent_file_overwrite()
{
- $upload = new fileupload('', array('jpg'), 1000);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(array('jpg'))
+ ->set_max_filesize(1000);
copy($this->path . 'jpg', $this->path . 'jpg.jpg');
copy($this->path . 'jpg', $this->path . 'copies/jpg.jpg');
- $file = $upload->local_upload($this->path . 'jpg.jpg');
- $this->assertEquals(0, sizeof($file->error));
+ $file = $upload->handle_upload('files.types.local', $this->path . 'jpg.jpg');
+ $this->assertEquals(0, count($file->error));
$file->move_file('../tests/upload/fixture/copies', true);
- $this->assertEquals(0, sizeof($file->error));
+ $this->assertEquals(0, count($file->error));
unlink($this->path . 'copies/jpg.jpg');
}
public function test_valid_dimensions()
{
- $upload = new fileupload('', false, false, 1, 1, 100, 100);
+ $upload = new \phpbb\files\upload($this->filesystem, $this->factory, $this->language, $this->php_ini, $this->request, $this->phpbb_root_path);
+ $upload->set_allowed_extensions(false)
+ ->set_max_filesize(false)
+ ->set_allowed_dimensions(1, 1, 100, 100);
$file1 = $this->gen_valid_filespec();
$file2 = $this->gen_valid_filespec();
diff --git a/tests/upload/fixture/bmp b/tests/upload/fixture/bmp
new file mode 100644
index 0000000000..04bff561ab
--- /dev/null
+++ b/tests/upload/fixture/bmp
Binary files differ
diff --git a/tests/upload/fixture/iff b/tests/upload/fixture/iff
new file mode 100644
index 0000000000..24eda8f593
--- /dev/null
+++ b/tests/upload/fixture/iff
Binary files differ
diff --git a/tests/upload/fixture/iff_maya b/tests/upload/fixture/iff_maya
new file mode 100644
index 0000000000..b6fb85101b
--- /dev/null
+++ b/tests/upload/fixture/iff_maya
Binary files differ
diff --git a/tests/upload/fixture/jp2 b/tests/upload/fixture/jp2
new file mode 100644
index 0000000000..adca6ecf0e
--- /dev/null
+++ b/tests/upload/fixture/jp2
Binary files differ
diff --git a/tests/upload/fixture/jpx b/tests/upload/fixture/jpx
new file mode 100644
index 0000000000..adca6ecf0e
--- /dev/null
+++ b/tests/upload/fixture/jpx
Binary files differ
diff --git a/tests/upload/fixture/psd b/tests/upload/fixture/psd
new file mode 100644
index 0000000000..d1bc9a6a70
--- /dev/null
+++ b/tests/upload/fixture/psd
Binary files differ
diff --git a/tests/upload/fixture/tif_compressed b/tests/upload/fixture/tif_compressed
new file mode 100644
index 0000000000..133b50c4f0
--- /dev/null
+++ b/tests/upload/fixture/tif_compressed
Binary files differ
diff --git a/tests/upload/fixture/tif_msb b/tests/upload/fixture/tif_msb
new file mode 100644
index 0000000000..32eb8abfbb
--- /dev/null
+++ b/tests/upload/fixture/tif_msb
Binary files differ
diff --git a/tests/upload/fixture/wbmp b/tests/upload/fixture/wbmp
new file mode 100644
index 0000000000..708c86ccee
--- /dev/null
+++ b/tests/upload/fixture/wbmp
Binary files differ
diff --git a/tests/upload/imagesize_test.php b/tests/upload/imagesize_test.php
new file mode 100644
index 0000000000..5429bb5c5e
--- /dev/null
+++ b/tests/upload/imagesize_test.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+class phpbb_upload_imagesize_test extends \phpbb_test_case
+{
+ /** @var \FastImageSize\FastImageSize */
+ protected $imagesize;
+
+ /** @var string Path to fixtures */
+ protected $path;
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->imagesize = new \FastImageSize\FastImageSize();
+ $this->path = __DIR__ . '/fixture/';
+ }
+
+ public function data_get_imagesize()
+ {
+ return array(
+ array('foobar', 'image/bmp', false),
+ array('png', 'image/png', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_PNG)),
+ array('gif', 'image/png', false),
+ array('png', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_PNG)),
+ array('gif', 'image/gif', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_GIF)),
+ array('jpg', 'image/gif', false),
+ array('gif', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_GIF)),
+ array('jpg', 'image/jpg', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)),
+ array('jpg', 'image/jpeg', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)),
+ array('png', 'image/jpg', false),
+ array('jpg', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_JPEG)),
+ array('psd', 'image/psd', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)),
+ array('psd', 'image/photoshop', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)),
+ array('jpg', 'image/psd', false),
+ array('psd', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_PSD)),
+ array('bmp', 'image/bmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_BMP)),
+ array('png', 'image/bmp', false),
+ array('bmp', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_BMP)),
+ array('tif', 'image/tif', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)),
+ array('png', 'image/tif', false),
+ array('tif', '', array('width' => 1, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)),
+ array('tif_compressed', 'image/tif', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)),
+ array('png', 'image/tiff', false),
+ array('tif_compressed', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_II)),
+ array('tif_msb', 'image/tif', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_MM)),
+ array('tif_msb', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_TIFF_MM)),
+ array('wbmp', 'image/wbmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)),
+ array('wbmp', 'image/vnd.wap.wbmp', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)),
+ array('png', 'image/vnd.wap.wbmp', false),
+ array('wbmp', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_WBMP)),
+ array('iff', 'image/iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)),
+ array('iff', 'image/x-iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)),
+ array('iff_maya', 'iamge/iff', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)),
+ array('png', 'image/iff', false),
+ array('png', 'image/x-iff', false),
+ array('iff', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)),
+ array('iff_maya', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_IFF)),
+ array('jp2', 'image/jp2', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)),
+ array('jp2', 'image/jpx', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)),
+ array('jp2', 'image/jpm', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)),
+ array('jpg', 'image/jp2', false),
+ array('jpx', 'image/jpx', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)),
+ array('jp2', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)),
+ array('jpx', '', array('width' => 2, 'height' => 1, 'type' => IMAGETYPE_JPEG2000)),
+ );
+ }
+
+ /**
+ * @dataProvider data_get_imagesize
+ */
+ public function test_get_imagesize($file, $mime_type, $expected)
+ {
+ $this->assertEquals($expected, $this->imagesize->getImageSize($this->path . $file, $mime_type));
+ }
+
+ public function test_get_imagesize_remote()
+ {
+ $this->assertSame(array(
+ 'width' => 80,
+ 'height' => 80,
+ 'type' => IMAGETYPE_JPEG,
+ ),
+ $this->imagesize->getImageSize('https://secure.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0.jpg'));
+ }
+}
diff --git a/tests/user/lang_test.php b/tests/user/lang_test.php
deleted file mode 100644
index bb11bb63cb..0000000000
--- a/tests/user/lang_test.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
-class phpbb_user_lang_test extends phpbb_test_case
-{
- public function test_user_lang_sprintf()
- {
- $user = new \phpbb\user('\phpbb\datetime');
- $user->lang = array(
- 'FOO' => 'BAR',
- 'BARZ' => 'PENG',
- 'EMPTY' => '',
- 'ZERO' => '0',
- 'STR' => '%d %s, %d topics',
- 'STR2' => '%d foos',
- 'ARRY' => array(
- 0 => 'No posts', // 0
- 1 => '1 post', // 1
- 2 => '%d posts', // 2+
- ),
- 'ARRY_NO_ZERO' => array(
- 1 => '1 post', // 1
- 2 => '%d posts', // 0, 2+
- ),
- 'ARRY_MISSING' => array(
- 1 => '%d post', // 1
- //Missing second plural
- ),
- 'ARRY_FLOAT' => array(
- 1 => '1 post', // 1.x
- 2 => '%1$.1f posts', // 0.x, 2+.x
- ),
- 'ARRY_EMPTY' => array(
- ),
- 'dateformat' => array(
- 'AGO' => array(
- 1 => '%d second',
- 2 => '%d seconds',
- ),
- ),
- );
-
- // No param
- $this->assertEquals($user->lang('FOO'), 'BAR');
- $this->assertEquals($user->lang('EMPTY'), '');
- $this->assertEquals($user->lang('ZERO'), '0');
-
- // Invalid index
- $this->assertEquals($user->lang('VOID'), 'VOID');
-
- // Unnecessary param
- $this->assertEquals($user->lang('FOO', 2), 'BAR');
- $this->assertEquals($user->lang('FOO', 2, 3), 'BAR');
- $this->assertEquals($user->lang('FOO', 2, 3, 'BARZ'), 'BAR');
-
- // String
- $this->assertEquals($user->lang('STR', 24, 'x', 42), '24 x, 42 topics');
- $this->assertEquals($user->lang('STR2', 64), '64 foos');
-
- // Array
- $this->assertEquals($user->lang('ARRY', 0), 'No posts');
- $this->assertEquals($user->lang('ARRY', 1), '1 post');
- $this->assertEquals($user->lang('ARRY', 2), '2 posts');
- $this->assertEquals($user->lang('ARRY', 123), '123 posts');
-
- // Empty array returns the language key
- $this->assertEquals($user->lang('ARRY_EMPTY', 123), 'ARRY_EMPTY');
-
- // No 0 key defined
- $this->assertEquals($user->lang('ARRY_NO_ZERO', 0), '0 posts');
- $this->assertEquals($user->lang('ARRY_NO_ZERO', 1), '1 post');
- $this->assertEquals($user->lang('ARRY_NO_ZERO', 2), '2 posts');
-
- // Array with missing keys
- $this->assertEquals($user->lang('ARRY_MISSING', 2), '2 post');
-
- // Floats as array key
- $this->assertEquals($user->lang('ARRY_FLOAT', 1.3), '1 post');
- $this->assertEquals($user->lang('ARRY_FLOAT', 2.0), '2.0 posts');
- $this->assertEquals($user->lang('ARRY_FLOAT', 2.51), '2.5 posts');
-
- // Use sub key, if first paramenter is an array
- $this->assertEquals($user->lang(array('dateformat', 'AGO'), 2), '2 seconds');
-
- // ticket PHPBB3-9949 - use first int to determinate the plural-form to use
- $this->assertEquals($user->lang('ARRY', 1, 2), '1 post');
- $this->assertEquals($user->lang('ARRY', 1, 's', 2), '1 post');
-
- // ticket PHPBB3-10345 - different plural rules, not just 0/1/2+
- $user = new \phpbb\user('\phpbb\datetime');
- $user->lang = array(
- 'PLURAL_RULE' => 13,
- 'ARRY' => array(
- 0 => '%d is 0', // 0
- 1 => '%d is 1', // 1
- 2 => '%d ends with 01-10', // ending with 01-10
- 3 => '%d ends with 11-19', // ending with 11-19
- 4 => '%d is part of the last rule', // everything else
- ),
- );
- $this->assertEquals($user->lang('ARRY', 0), '0 is 0');
- $this->assertEquals($user->lang('ARRY', 1), '1 is 1');
- $this->assertEquals($user->lang('ARRY', 103), '103 ends with 01-10');
- $this->assertEquals($user->lang('ARRY', 15), '15 ends with 11-19');
- $this->assertEquals($user->lang('ARRY', 300), '300 is part of the last rule');
- }
-}
diff --git a/tests/user/user_loader_test.php b/tests/user/user_loader_test.php
index 8d1f43707b..f871f324ca 100644
--- a/tests/user/user_loader_test.php
+++ b/tests/user/user_loader_test.php
@@ -11,8 +11,6 @@
*
*/
-include_once(__DIR__ . '/../../phpBB/includes/utf/utf_tools.php');
-
class phpbb_user_loader_test extends phpbb_database_test_case
{
protected $db;
diff --git a/tests/utf/normalizer_test.php b/tests/utf/normalizer_test.php
deleted file mode 100644
index 50eafda859..0000000000
--- a/tests/utf/normalizer_test.php
+++ /dev/null
@@ -1,327 +0,0 @@
-<?php
-/**
-*
-* This file is part of the phpBB Forum Software package.
-*
-* @copyright (c) phpBB Limited <https://www.phpbb.com>
-* @license GNU General Public License, version 2 (GPL-2.0)
-*
-* For full copyright and license information, please see
-* the docs/CREDITS.txt file.
-*
-*/
-
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_normalizer.php';
-
-/**
-* @group slow
-*/
-class phpbb_utf_normalizer_test extends phpbb_test_case
-{
- static private $data_dir;
-
- static public function setUpBeforeClass()
- {
- self::$data_dir = dirname(__file__) . '/../tmp';
- self::download('http://www.unicode.org/Public/UNIDATA/NormalizationTest.txt', self::$data_dir);
- self::download('http://www.unicode.org/Public/UNIDATA/UnicodeData.txt', self::$data_dir);
- }
-
- public function test_normalizer()
- {
- $test_suite = array(
- /**
- * NFC
- * c2 == NFC(c1) == NFC(c2) == NFC(c3)
- * c4 == NFC(c4) == NFC(c5)
- */
- 'NFC' => array(
- 'c2' => array('c1', 'c2', 'c3'),
- 'c4' => array('c4', 'c5')
- ),
-
- /**
- * NFD
- * c3 == NFD(c1) == NFD(c2) == NFD(c3)
- * c5 == NFD(c4) == NFD(c5)
- */
- 'NFD' => array(
- 'c3' => array('c1', 'c2', 'c3'),
- 'c5' => array('c4', 'c5')
- ),
-
- /**
- * NFKC
- * c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
- */
- 'NFKC' => array(
- 'c4' => array('c1', 'c2', 'c3', 'c4', 'c5')
- ),
-
- /**
- * NFKD
- * c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
- */
- 'NFKD' => array(
- 'c5' => array('c1', 'c2', 'c3', 'c4', 'c5')
- )
- );
-
- $tested_chars = array();
-
- $fp = fopen(self::$data_dir . '/NormalizationTest.txt', 'rb');
- while (!feof($fp))
- {
- $line = fgets($fp);
-
- if ($line[0] == '@')
- {
- continue;
- }
-
- if (!strpos(' 0123456789ABCDEF', $line[0]))
- {
- continue;
- }
-
- list($c1, $c2, $c3, $c4, $c5) = explode(';', $line);
-
- if (!strpos($c1, ' '))
- {
- /**
- * We are currently testing a single character, we add it to the list of
- * characters we have processed so that we can exclude it when testing
- * for invariants
- */
- $tested_chars[$c1] = 1;
- }
-
- foreach ($test_suite as $form => $serie)
- {
- foreach ($serie as $expected => $tests)
- {
- $hex_expected = ${$expected};
- $utf_expected = $this->hexseq_to_utf($hex_expected);
-
- foreach ($tests as $test)
- {
- $utf_result = $utf_expected;
- call_user_func_array(array('utf_normalizer', $form), array(&$utf_result));
-
- $hex_result = $this->utf_to_hexseq($utf_result);
- $this->assertEquals($utf_expected, $utf_result, "$expected == $form($test) ($hex_expected != $hex_result)");
- }
- }
- }
- }
- fclose($fp);
-
- return $tested_chars;
- }
-
- /**
- * @depends test_normalizer
- */
- public function test_invariants(array $tested_chars)
- {
- $fp = fopen(self::$data_dir . '/UnicodeData.txt', 'rb');
-
- while (!feof($fp))
- {
- $line = fgets($fp, 1024);
-
- if (!$pos = strpos($line, ';'))
- {
- continue;
- }
-
- $hex_tested = $hex_expected = substr($line, 0, $pos);
-
- if (isset($tested_chars[$hex_tested]))
- {
- continue;
- }
-
- $utf_expected = $this->hex_to_utf($hex_expected);
-
- if ($utf_expected >= UTF8_SURROGATE_FIRST
- && $utf_expected <= UTF8_SURROGATE_LAST)
- {
- /**
- * Surrogates are illegal on their own, we expect the normalizer
- * to return a replacement char
- */
- $utf_expected = UTF8_REPLACEMENT;
- $hex_expected = $this->utf_to_hexseq($utf_expected);
- }
-
- foreach (array('nfc', 'nfkc', 'nfd', 'nfkd') as $form)
- {
- $utf_result = $utf_expected;
- call_user_func_array(array('utf_normalizer', $form), array(&$utf_result));
- $hex_result = $this->utf_to_hexseq($utf_result);
-
- $this->assertEquals($utf_expected, $utf_result, "$hex_expected == $form($hex_tested) ($hex_expected != $hex_result)");
- }
- }
- fclose($fp);
- }
-
- /**
- * Convert a UTF string to a sequence of codepoints in hexadecimal
- *
- * @param string $utf UTF string
- * @return integer Unicode codepoints in hex
- */
- protected function utf_to_hexseq($str)
- {
- $pos = 0;
- $len = strlen($str);
- $ret = array();
-
- while ($pos < $len)
- {
- $c = $str[$pos];
- switch ($c & "\xF0")
- {
- case "\xC0":
- case "\xD0":
- $utf_char = substr($str, $pos, 2);
- $pos += 2;
- break;
-
- case "\xE0":
- $utf_char = substr($str, $pos, 3);
- $pos += 3;
- break;
-
- case "\xF0":
- $utf_char = substr($str, $pos, 4);
- $pos += 4;
- break;
-
- default:
- $utf_char = $c;
- ++$pos;
- }
-
- $hex = dechex($this->utf_to_cp($utf_char));
-
- if (!isset($hex[3]))
- {
- $hex = substr('000' . $hex, -4);
- }
-
- $ret[] = $hex;
- }
-
- return strtr(implode(' ', $ret), 'abcdef', 'ABCDEF');
- }
-
- /**
- * Convert a UTF-8 char to its codepoint
- *
- * @param string $utf_char UTF-8 char
- * @return integer Unicode codepoint
- */
- protected function utf_to_cp($utf_char)
- {
- switch (strlen($utf_char))
- {
- case 1:
- return ord($utf_char);
-
- case 2:
- return ((ord($utf_char[0]) & 0x1F) << 6) | (ord($utf_char[1]) & 0x3F);
-
- case 3:
- return ((ord($utf_char[0]) & 0x0F) << 12) | ((ord($utf_char[1]) & 0x3F) << 6) | (ord($utf_char[2]) & 0x3F);
-
- case 4:
- return ((ord($utf_char[0]) & 0x07) << 18) | ((ord($utf_char[1]) & 0x3F) << 12) | ((ord($utf_char[2]) & 0x3F) << 6) | (ord($utf_char[3]) & 0x3F);
-
- default:
- throw new RuntimeException('UTF-8 chars can only be 1-4 bytes long');
- }
- }
-
- /**
- * Return a UTF string formed from a sequence of codepoints in hexadecimal
- *
- * @param string $seq Sequence of codepoints, separated with a space
- * @return string UTF-8 string
- */
- protected function hexseq_to_utf($seq)
- {
- return implode('', array_map(array($this, 'hex_to_utf'), explode(' ', $seq)));
- }
-
- /**
- * Convert a codepoint in hexadecimal to a UTF-8 char
- *
- * @param string $hex Codepoint, in hexadecimal
- * @return string UTF-8 char
- */
- protected function hex_to_utf($hex)
- {
- return $this->cp_to_utf(hexdec($hex));
- }
-
- /**
- * Convert a codepoint to a UTF-8 char
- *
- * @param integer $cp Unicode codepoint
- * @return string UTF-8 string
- */
- protected function cp_to_utf($cp)
- {
- if ($cp > 0xFFFF)
- {
- return chr(0xF0 | ($cp >> 18)) . chr(0x80 | (($cp >> 12) & 0x3F)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
- }
- else if ($cp > 0x7FF)
- {
- return chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
- }
- else if ($cp > 0x7F)
- {
- return chr(0xC0 | ($cp >> 6)) . chr(0x80 | ($cp & 0x3F));
- }
- else
- {
- return chr($cp);
- }
- }
-
- // chunked download helper
- static protected function download($url, $to)
- {
- $target = $to . '/' . basename($url);
-
- if (file_exists($target))
- {
- return;
- }
-
- if (!$fpr = fopen($url, 'rb'))
- {
- echo "Failed to download $url\n";
- return;
- }
-
- if (!$fpw = fopen($target, 'wb'))
- {
- echo "Failed to open $target for writing\n";
- return;
- }
-
- $chunk = 32768;
-
- while (!feof($fpr))
- {
- fwrite($fpw, fread($fpr, $chunk));
- }
- fclose($fpr);
- fclose($fpw);
- }
-}
diff --git a/tests/utf/utf8_clean_string_test.php b/tests/utf/utf8_clean_string_test.php
index 2bb65387e0..4b3c8a5a25 100644
--- a/tests/utf/utf8_clean_string_test.php
+++ b/tests/utf/utf8_clean_string_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_utf_utf8_clean_string_test extends phpbb_test_case
{
public function cleanable_strings()
diff --git a/tests/utf/utf8_wordwrap_test.php b/tests/utf/utf8_wordwrap_test.php
index ab053e2911..8906595d33 100644
--- a/tests/utf/utf8_wordwrap_test.php
+++ b/tests/utf/utf8_wordwrap_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/utf/utf_tools.php';
-
class phpbb_utf_utf8_wordwrap_test extends phpbb_test_case
{
public function test_utf8_wordwrap_ascii()
diff --git a/tests/version/version_fetch_test.php b/tests/version/version_fetch_test.php
index cfc87183cf..c44bd5514a 100644
--- a/tests/version/version_fetch_test.php
+++ b/tests/version/version_fetch_test.php
@@ -33,8 +33,7 @@ class phpbb_version_helper_fetch_test extends phpbb_test_case
new \phpbb\config\config(array(
'version' => '3.1.0',
)),
- new \phpbb\file_downloader(),
- new \phpbb\user('\phpbb\datetime')
+ new \phpbb\file_downloader()
);
}
diff --git a/tests/version/version_helper_remote_test.php b/tests/version/version_helper_remote_test.php
index b2d497b72a..35c3d92a3a 100644
--- a/tests/version/version_helper_remote_test.php
+++ b/tests/version/version_helper_remote_test.php
@@ -30,21 +30,22 @@ class version_helper_remote_test extends \phpbb_test_case
));
$container = new \phpbb_mock_container_builder();
$db = new \phpbb\db\driver\factory($container);
- $this->cache = $this->getMock('\phpbb\cache\service', array('get'), array(new \phpbb\cache\driver\null(), $config, $db, '../../', 'php'));
+ $this->cache = $this->getMock('\phpbb\cache\service', array('get'), array(new \phpbb\cache\driver\dummy(), $config, $db, '../../', 'php'));
$this->cache->expects($this->any())
->method('get')
->with($this->anything())
->will($this->returnValue(false));
$this->file_downloader = new phpbb_mock_file_downloader();
- $this->user = new \phpbb\user('\phpbb\datetime');
- $this->user->add_lang('acp/common');
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+
$this->version_helper = new \phpbb\version_helper(
$this->cache,
$config,
- $this->file_downloader,
- $this->user
+ $this->file_downloader
);
+ $this->user = new \phpbb\user(new \phpbb\language\language($lang_loader), '\phpbb\datetime');
+ $this->user->add_lang('acp/common');
}
public function provider_get_versions()
@@ -202,8 +203,8 @@ class version_helper_remote_test extends \phpbb_test_case
{
try {
$return = $this->version_helper->get_versions();
- } catch (\RuntimeException $e) {
- $this->assertEquals((string)$e->getMessage(), $this->user->lang($expected_exception));
+ } catch (\phpbb\exception\runtime_exception $e) {
+ $this->assertEquals((string)$e->getMessage(), $expected_exception);
}
}
else
diff --git a/tests/version/version_test.php b/tests/version/version_test.php
index 0ed0fcb589..2a0240f847 100644
--- a/tests/version/version_test.php
+++ b/tests/version/version_test.php
@@ -30,8 +30,7 @@ class phpbb_version_helper_test extends phpbb_test_case
new \phpbb\config\config(array(
'version' => '3.1.0',
)),
- new \phpbb\file_downloader(),
- new \phpbb\user('\phpbb\datetime')
+ new \phpbb\file_downloader()
);
}
@@ -199,6 +198,11 @@ class phpbb_version_helper_test extends phpbb_test_case
*/
public function test_get_suggested_updates($current_version, $versions, $expected)
{
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+
$version_helper = $this
->getMockBuilder('\phpbb\version_helper')
->setMethods(array(
@@ -210,7 +214,7 @@ class phpbb_version_helper_test extends phpbb_test_case
'version' => $current_version,
)),
new \phpbb\file_downloader(),
- new \phpbb\user('\phpbb\datetime'),
+ new \phpbb\user($lang, '\phpbb\datetime'),
))
->getMock()
;
@@ -310,6 +314,11 @@ class phpbb_version_helper_test extends phpbb_test_case
*/
public function test_get_latest_on_current_branch($current_version, $versions, $expected)
{
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+
$version_helper = $this
->getMockBuilder('\phpbb\version_helper')
->setMethods(array(
@@ -321,7 +330,7 @@ class phpbb_version_helper_test extends phpbb_test_case
'version' => $current_version,
)),
new \phpbb\file_downloader(),
- new \phpbb\user('\phpbb\datetime'),
+ new \phpbb\user($lang, '\phpbb\datetime'),
))
->getMock()
;
@@ -510,6 +519,11 @@ class phpbb_version_helper_test extends phpbb_test_case
*/
public function test_get_update_on_branch($current_version, $versions, $expected)
{
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+
$version_helper = $this
->getMockBuilder('\phpbb\version_helper')
->setMethods(array(
@@ -521,7 +535,7 @@ class phpbb_version_helper_test extends phpbb_test_case
'version' => $current_version,
)),
new \phpbb\file_downloader(),
- new \phpbb\user('\phpbb\datetime'),
+ new \phpbb\user($lang, '\phpbb\datetime'),
))
->getMock()
;
@@ -800,6 +814,11 @@ class phpbb_version_helper_test extends phpbb_test_case
*/
public function test_get_ext_update_on_branch($phpbb_version, $ext_version, $versions, $expected)
{
+ global $phpbb_root_path, $phpEx;
+
+ $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx);
+ $lang = new \phpbb\language\language($lang_loader);
+
$version_helper = $this
->getMockBuilder('\phpbb\version_helper')
->setMethods(array(
@@ -811,7 +830,7 @@ class phpbb_version_helper_test extends phpbb_test_case
'version' => $phpbb_version,
)),
new \phpbb\file_downloader(),
- new \phpbb\user('\phpbb\datetime'),
+ new \phpbb\user($lang, '\phpbb\datetime'),
))
->getMock()
;
diff --git a/tests/viewonline/helper_test.php b/tests/viewonline/helper_test.php
index bbbed59de7..6540d33287 100644
--- a/tests/viewonline/helper_test.php
+++ b/tests/viewonline/helper_test.php
@@ -17,7 +17,7 @@ class phpbb_viewonline_helper_test extends phpbb_test_case
{
parent::setUp();
- $this->viewonline_helper = new \phpbb\viewonline_helper(new \phpbb\filesystem());
+ $this->viewonline_helper = new \phpbb\viewonline_helper(new \phpbb\filesystem\filesystem());
}
public function session_pages_data()
diff --git a/tests/wrapper/gmgetdate_test.php b/tests/wrapper/gmgetdate_test.php
index 2e55a78d21..08ee491c0f 100644
--- a/tests/wrapper/gmgetdate_test.php
+++ b/tests/wrapper/gmgetdate_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_wrapper_gmgetdate_test extends phpbb_test_case
{
public static function phpbb_gmgetdate_data()
diff --git a/tests/wrapper/mt_rand_test.php b/tests/wrapper/mt_rand_test.php
index d190182286..8d370dee2a 100644
--- a/tests/wrapper/mt_rand_test.php
+++ b/tests/wrapper/mt_rand_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_wrapper_mt_rand_test extends phpbb_test_case
{
public function test_max_equals_min()
diff --git a/tests/wrapper/phpbb_php_ini_fake.php b/tests/wrapper/phpbb_php_ini_fake.php
index f218ff6d03..300ce30cfe 100644
--- a/tests/wrapper/phpbb_php_ini_fake.php
+++ b/tests/wrapper/phpbb_php_ini_fake.php
@@ -11,7 +11,7 @@
*
*/
-class phpbb_php_ini_fake extends \phpbb\php\ini
+class phpbb_php_ini_fake extends \bantu\IniGetWrapper\IniGetWrapper
{
function get($varname)
{
diff --git a/tests/wrapper/phpbb_php_ini_test.php b/tests/wrapper/phpbb_php_ini_test.php
index 27c2487f0a..5827744702 100644
--- a/tests/wrapper/phpbb_php_ini_test.php
+++ b/tests/wrapper/phpbb_php_ini_test.php
@@ -12,10 +12,10 @@
*/
require_once dirname(__FILE__) . '/phpbb_php_ini_fake.php';
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
class phpbb_wrapper_phpbb_php_ini_test extends phpbb_test_case
{
+ /** @var \phpbb_php_ini_fake php_ini */
protected $php_ini;
public function setUp()
@@ -25,44 +25,44 @@ class phpbb_wrapper_phpbb_php_ini_test extends phpbb_test_case
public function test_get_string()
{
- $this->assertSame(false, $this->php_ini->get_string(false));
- $this->assertSame('phpbb', $this->php_ini->get_string(' phpbb '));
+ $this->assertSame('', $this->php_ini->getString(false));
+ $this->assertSame('phpbb', $this->php_ini->getString(' phpbb '));
}
public function test_get_bool()
{
- $this->assertSame(true, $this->php_ini->get_bool('ON'));
- $this->assertSame(true, $this->php_ini->get_bool('on'));
- $this->assertSame(true, $this->php_ini->get_bool('1'));
+ $this->assertSame(true, $this->php_ini->getBool('ON'));
+ $this->assertSame(true, $this->php_ini->getBool('on'));
+ $this->assertSame(true, $this->php_ini->getBool('1'));
- $this->assertSame(false, $this->php_ini->get_bool('OFF'));
- $this->assertSame(false, $this->php_ini->get_bool('off'));
- $this->assertSame(false, $this->php_ini->get_bool('0'));
- $this->assertSame(false, $this->php_ini->get_bool(''));
+ $this->assertSame(false, $this->php_ini->getBool('OFF'));
+ $this->assertSame(false, $this->php_ini->getBool('off'));
+ $this->assertSame(false, $this->php_ini->getBool('0'));
+ $this->assertSame(false, $this->php_ini->getBool(''));
}
public function test_get_int()
{
- $this->assertSame(1234, $this->php_ini->get_int('1234'));
- $this->assertSame(-12345, $this->php_ini->get_int('-12345'));
- $this->assertSame(false, $this->php_ini->get_int('phpBB'));
+ $this->assertSame(1234, $this->php_ini->getNumeric('1234'));
+ $this->assertSame(-12345, $this->php_ini->getNumeric('-12345'));
+ $this->assertSame(null, $this->php_ini->getNumeric('phpBB'));
}
public function test_get_float()
{
- $this->assertSame(1234.0, $this->php_ini->get_float('1234'));
- $this->assertSame(-12345.0, $this->php_ini->get_float('-12345'));
- $this->assertSame(false, $this->php_ini->get_float('phpBB'));
+ $this->assertSame(1234.0, $this->php_ini->getNumeric('1234.0'));
+ $this->assertSame(-12345.0, $this->php_ini->getNumeric('-12345.0'));
+ $this->assertSame(null, $this->php_ini->getNumeric('phpBB'));
}
public function test_get_bytes_invalid()
{
- $this->assertSame(false, $this->php_ini->get_bytes(false));
- $this->assertSame(false, $this->php_ini->get_bytes('phpBB'));
- $this->assertSame(false, $this->php_ini->get_bytes('k'));
- $this->assertSame(false, $this->php_ini->get_bytes('-k'));
- $this->assertSame(false, $this->php_ini->get_bytes('M'));
- $this->assertSame(false, $this->php_ini->get_bytes('-M'));
+ $this->assertSame(null, $this->php_ini->getBytes(false));
+ $this->assertSame(null, $this->php_ini->getBytes('phpBB'));
+ $this->assertSame(null, $this->php_ini->getBytes('k'));
+ $this->assertSame(null, $this->php_ini->getBytes('-k'));
+ $this->assertSame(null, $this->php_ini->getBytes('M'));
+ $this->assertSame(null, $this->php_ini->getBytes('-M'));
}
/**
@@ -70,7 +70,7 @@ class phpbb_wrapper_phpbb_php_ini_test extends phpbb_test_case
*/
public function test_get_bytes($expected, $value)
{
- $actual = $this->php_ini->get_bytes($value);
+ $actual = $this->php_ini->getBytes($value);
$this->assertTrue(is_float($actual) || is_int($actual));
$this->assertEquals($expected, $actual);
diff --git a/tests/wrapper/version_compare_test.php b/tests/wrapper/version_compare_test.php
index 93d9e0117d..ee23fe779c 100644
--- a/tests/wrapper/version_compare_test.php
+++ b/tests/wrapper/version_compare_test.php
@@ -11,8 +11,6 @@
*
*/
-require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php';
-
class phpbb_wrapper_version_compare_test extends phpbb_test_case
{
public function test_two_parameters()
@@ -68,7 +66,7 @@ class phpbb_wrapper_version_compare_test extends phpbb_test_case
'3.2-A1',
);
- for ($i = 0, $size = sizeof($releases); $i < $size - 1; ++$i)
+ for ($i = 0, $size = count($releases); $i < $size - 1; ++$i)
{
$version1 = $releases[$i];
$version2 = $releases[$i + 1];
diff --git a/travis/check-executable-files.sh b/travis/check-executable-files.sh
index 4d420add1c..1aa8dca073 100755
--- a/travis/check-executable-files.sh
+++ b/travis/check-executable-files.sh
@@ -12,10 +12,11 @@ set -e
DB=$1
TRAVIS_PHP_VERSION=$2
-root="$3"
+NOTESTS=$3
+root="$4"
path="${root}phpBB/"
-if [ "$TRAVIS_PHP_VERSION" == "5.3.3" -a "$DB" == "mysqli" ]
+if [ "$NOTESTS" == '1' ]
then
# Check the permissions of the files
@@ -27,7 +28,7 @@ then
files_skipped="-false"
# Files which have to be executable
- executable_files="-path ${path}bin/*"
+ executable_files="-path ${path}bin/* -o -path ${path}install/phpbbcli.php"
incorrect_files=$( \
find ${path} \
diff --git a/travis/check-image-icc-profiles.sh b/travis/check-image-icc-profiles.sh
index 5926962d40..05c7de2d27 100755
--- a/travis/check-image-icc-profiles.sh
+++ b/travis/check-image-icc-profiles.sh
@@ -12,8 +12,9 @@ set -e
DB=$1
TRAVIS_PHP_VERSION=$2
+NOTESTS=$3
-if [ "$TRAVIS_PHP_VERSION" == "5.3.3" -a "$DB" == "mysqli" ]
+if [ "$NOTESTS" == '1' ]
then
find . -type f -a -iregex '.*\.\(gif\|jpg\|jpeg\|png\)$' -a -not -wholename '*vendor/*' | \
parallel --gnu --keep-order 'phpBB/develop/strip_icc_profiles.sh {}'
diff --git a/travis/check-sami-parse-errors.sh b/travis/check-sami-parse-errors.sh
index c3338e34db..4cc2cee525 100755
--- a/travis/check-sami-parse-errors.sh
+++ b/travis/check-sami-parse-errors.sh
@@ -12,8 +12,9 @@ set -e
DB=$1
TRAVIS_PHP_VERSION=$2
+NOTESTS=$3
-if [ "$TRAVIS_PHP_VERSION" == "5.3.3" -a "$DB" == "mysqli" ]
+if [ "$NOTESTS" == '1' ]
then
# Workarounds for
# https://github.com/fabpot/Sami/issues/116
diff --git a/travis/ext-sniff.sh b/travis/ext-sniff.sh
index 4e557a41c1..ca4d2115ba 100755
--- a/travis/ext-sniff.sh
+++ b/travis/ext-sniff.sh
@@ -10,12 +10,13 @@
#
set -e
set -x
-
+
DB=$1
TRAVIS_PHP_VERSION=$2
EXTNAME=$3
+NOTESTS=$4
-if [ "$TRAVIS_PHP_VERSION" == "5.5" -a "$DB" == "mysqli" ]
+if [ "$NOTESTS" == "1" ]
then
phpBB/vendor/bin/phpcs \
-s \
diff --git a/travis/install-phpbb-test-dependencies.sh b/travis/install-phpbb-test-dependencies.sh
deleted file mode 100755
index 25743ff2b1..0000000000
--- a/travis/install-phpbb-test-dependencies.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-#
-# This file is part of the phpBB Forum Software package.
-#
-# @copyright (c) phpBB Limited <https://www.phpbb.com>
-# @license GNU General Public License, version 2 (GPL-2.0)
-#
-# For full copyright and license information, please see
-# the docs/CREDITS.txt file.
-#
-set -e
-set -x
-
-cd tests
-php ../composer.phar install --dev --no-interaction --prefer-source
-cd ..
diff --git a/travis/phing-sniff.sh b/travis/phing-sniff.sh
index 660d1764c2..3f43b64130 100755
--- a/travis/phing-sniff.sh
+++ b/travis/phing-sniff.sh
@@ -13,8 +13,9 @@ set -x
DB=$1
TRAVIS_PHP_VERSION=$2
+NOTESTS=$3
-if [ "$TRAVIS_PHP_VERSION" == "5.5" -a "$DB" == "mysqli" ]
+if [ "$NOTESTS" == '1' ]
then
cd build
../phpBB/vendor/bin/phing sniff
diff --git a/travis/setup-database.sh b/travis/setup-database.sh
index 4ba9157d9d..3771f19073 100755
--- a/travis/setup-database.sh
+++ b/travis/setup-database.sh
@@ -13,6 +13,12 @@ set -x
DB=$1
TRAVIS_PHP_VERSION=$2
+NOTESTS=$3
+
+if [ "$NOTESTS" == '1' ]
+then
+ exit 0
+fi
if [ "$DB" == "postgres" ]
then
@@ -20,7 +26,7 @@ then
psql -c 'create database phpbb_tests;' -U postgres
fi
-if [ "$TRAVIS_PHP_VERSION" == "5.3" -a "$DB" == "mysqli" ]
+if [ "$TRAVIS_PHP_VERSION" == "5.4" -a "$DB" == "mysqli" ]
then
mysql -e 'SET GLOBAL storage_engine=MyISAM;'
fi
diff --git a/travis/setup-mariadb.sh b/travis/setup-mariadb.sh
index 9bc487915d..95445dcc55 100755
--- a/travis/setup-mariadb.sh
+++ b/travis/setup-mariadb.sh
@@ -12,7 +12,7 @@ set -e
set -x
# MariaDB Series
-VERSION='5.5'
+VERSION='10.0'
# Operating system codename, e.g. "precise"
OS_CODENAME=$(lsb_release --codename --short)
diff --git a/travis/setup-php-extensions.sh b/travis/setup-php-extensions.sh
index d9544858b7..a69468a637 100755
--- a/travis/setup-php-extensions.sh
+++ b/travis/setup-php-extensions.sh
@@ -46,13 +46,25 @@ php_ini_file=$(find_php_ini)
if [ `php -r "echo (int) version_compare(PHP_VERSION, '5.5.0-dev', '<');"` == "1" ]
then
echo 'Enabling APC PHP extension'
- register_php_extension 'apc' "$php_ini_file"
+ printf "\n" | pecl install apc
echo 'apc.enable_cli=1' >> "$php_ini_file"
-else
- echo 'Disabling Opcache'
- echo 'opcache.enable=0' >> "$php_ini_file"
fi
+# APCu
+if [ `php -r "echo (int) (version_compare(PHP_VERSION, '7.0.0-dev', '>=') && version_compare(PHP_VERSION, '7.3.0-dev', '<'));"` == "1" ]
+then
+ if ! [ "$(pecl info pecl/apcu)" ]
+ then
+ echo 'Enabling APCu PHP extension'
+ printf "\n" | pecl install apcu
+ echo 'apc.enabled=1' >> "$php_ini_file"
+ echo 'apc.enable_cli=1' >> "$php_ini_file"
+ fi
+fi
+
+# Disable xdebug on travis
+phpenv config-rm xdebug.ini
+
# redis
# Disabled redis for now as it causes travis to fail
# git clone git://github.com/nicolasff/phpredis.git redis
diff --git a/travis/setup-phpbb.sh b/travis/setup-phpbb.sh
index 4daa754481..be9eb703d5 100755
--- a/travis/setup-phpbb.sh
+++ b/travis/setup-phpbb.sh
@@ -13,8 +13,9 @@ set -x
DB=$1
TRAVIS_PHP_VERSION=$2
+NOTESTS=$3
-if [ "$TRAVIS_PHP_VERSION" == "5.3.3" -a "$DB" == "mysqli" ]
+if [ "$NOTESTS" == '1' ]
then
travis/setup-exiftool.sh
travis/setup-unbuffer.sh
@@ -25,22 +26,16 @@ then
travis/setup-mariadb.sh
fi
-if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]
+if [ "$NOTESTS" != '1' ]
then
travis/setup-php-extensions.sh
fi
-if [ `php -r "echo (int) version_compare(PHP_VERSION, '5.3.19', '>=');"` == "1" ]
+if [ "$NOTESTS" != '1' ]
then
travis/setup-webserver.sh
- travis/install-phpbb-test-dependencies.sh
fi
cd phpBB
-if [ `php -r "echo (int) version_compare(PHP_VERSION, '5.3.4', '<');"` == "1" ]
-then
- php ../composer.phar config disable-tls true
-fi
php ../composer.phar install --dev --no-interaction
-
cd ..
diff --git a/travis/setup-webserver.sh b/travis/setup-webserver.sh
index 911ba12f3c..fd87d97449 100755
--- a/travis/setup-webserver.sh
+++ b/travis/setup-webserver.sh
@@ -19,58 +19,39 @@ sudo service nginx stop
DIR=$(dirname "$0")
USER=$(whoami)
PHPBB_ROOT_PATH=$(realpath "$DIR/../phpBB")
-NGINX_CONF="/etc/nginx/sites-enabled/default"
+NGINX_SITE_CONF="/etc/nginx/sites-enabled/default"
+NGINX_CONF="/etc/nginx/nginx.conf"
APP_SOCK=$(realpath "$DIR")/php-app.sock
-if [ "$TRAVIS_PHP_VERSION" = 'hhvm' ]
-then
- HHVM_LOG=$(realpath "$DIR")/hhvm.log
+# php-fpm
+PHP_FPM_BIN="$HOME/.phpenv/versions/$TRAVIS_PHP_VERSION/sbin/php-fpm"
+PHP_FPM_CONF="$DIR/php-fpm.conf"
- sudo service hhvm stop
- sudo hhvm \
- --mode daemon \
- --user "$USER" \
- -vServer.Type=fastcgi \
- -vServer.FileSocket="$APP_SOCK" \
- -vLog.File="$HHVM_LOG"
-else
- # php-fpm
- PHP_FPM_BIN="$HOME/.phpenv/versions/$TRAVIS_PHP_VERSION/sbin/php-fpm"
- PHP_FPM_CONF="$DIR/php-fpm.conf"
-
- echo "
- [global]
+echo "
+ [global]
- [travis]
- user = $USER
- group = $USER
- listen = $APP_SOCK
- listen.mode = 0666
- pm = static
- pm.max_children = 2
+ [travis]
+ user = $USER
+ group = $USER
+ listen = $APP_SOCK
+ listen.mode = 0666
+ pm = static
+ pm.max_children = 2
- php_admin_value[memory_limit] = 128M
- " > $PHP_FPM_CONF
+ php_admin_value[memory_limit] = 128M
+" > $PHP_FPM_CONF
- sudo $PHP_FPM_BIN \
- --fpm-config "$DIR/php-fpm.conf"
-fi
+sudo $PHP_FPM_BIN \
+ --fpm-config "$DIR/php-fpm.conf"
# nginx
-echo "
- server {
- listen 80;
- root $PHPBB_ROOT_PATH/;
- index index.php index.html;
-
- location ~ \.php {
- include fastcgi_params;
- fastcgi_split_path_info ^(.+\.php)(/.*)$;
- fastcgi_param PATH_INFO \$fastcgi_path_info;
- fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
- fastcgi_pass unix:$APP_SOCK;
- }
- }
-" | sudo tee $NGINX_CONF > /dev/null
+cat $DIR/../phpBB/docs/nginx.sample.conf \
+| sed "s/root \/path\/to\/phpbb/root $(echo $PHPBB_ROOT_PATH | sed -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/&/\\\&/g')/g" \
+| sed -e '1,/The actual board domain/d' \
+| sed -e '/If running php as fastcgi/,$d' \
+| sed -e "s/fastcgi_pass php;/fastcgi_pass unix:$(echo $APP_SOCK | sed -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/&/\\\&/g');/g" \
+| sed -e 's/#listen 80/listen 80/' \
+| sudo tee $NGINX_SITE_CONF
+sudo sed -i "s/user www-data;/user $USER;/g" $NGINX_CONF
sudo service nginx start
diff --git a/vagrant/after.sh b/vagrant/after.sh
new file mode 100755
index 0000000000..aadb7e7492
--- /dev/null
+++ b/vagrant/after.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+PHPBB_PATH="/home/vagrant/phpbb"
+PHPBB_CONFIG="${PHPBB_PATH}/phpBB/config.php"
+PHPBB_INSTALL="${PHPBB_PATH}/vagrant/phpbb-install-config.yml"
+
+# Ensure composer deps are installed
+cd ${PHPBB_PATH}/phpBB
+php ../composer.phar install
+
+# Backup current config.php file
+if [ -e ${PHPBB_CONFIG} ]
+then
+ cp --backup=numbered ${PHPBB_CONFIG} ${PHPBB_CONFIG}.bak
+fi
+
+# Delete any sqlite db and config file
+rm -rf /tmp/phpbb.sqlite3
+rm -rf ${PHPBB_CONFIG}
+
+# Install phpBB
+php ${PHPBB_PATH}/phpBB/install/phpbbcli.php install ${PHPBB_INSTALL}
+
+# Update sqlite db file permissions
+sudo chown -R vagrant /tmp/phpbb.sqlite3
+
+# Add DEBUG mode to phpBB to remove annoying installer warnings
+sed -i "$ a @define('DEBUG', true);" ${PHPBB_CONFIG}
+
+# Update the PHP memory limits (enough to allow phpunit tests to run)
+sed -i "s/memory_limit = .*/memory_limit = 1024M/" /etc/php5/fpm/php.ini
+
+echo "Your board is ready at http://192.168.10.10/"
diff --git a/vagrant/bootstrap.yaml b/vagrant/bootstrap.yaml
new file mode 100644
index 0000000000..1c2b265712
--- /dev/null
+++ b/vagrant/bootstrap.yaml
@@ -0,0 +1,40 @@
+---
+ip: "192.168.10.10"
+memory: 2048
+cpus: 1
+hostname: phpbb
+name: phpbb
+provider: virtualbox
+
+authorize: ~/.ssh/id_rsa.pub
+
+keys:
+ - ~/.ssh/id_rsa
+
+folders:
+ - map: "."
+ to: "/home/vagrant/phpbb"
+
+sites:
+ - map: phpbb.app
+ to: "/home/vagrant/phpbb/phpBB"
+
+databases:
+ - phpbb
+
+variables:
+ - key: APP_ENV
+ value: local
+
+# blackfire:
+# - id: foo
+# token: bar
+# client-id: foo
+# client-token: bar
+
+# ports:
+# - send: 50000
+# to: 5000
+# - send: 7777
+# to: 777
+# protocol: udp
diff --git a/vagrant/phpbb-install-config.yml b/vagrant/phpbb-install-config.yml
new file mode 100644
index 0000000000..023d7b1a9d
--- /dev/null
+++ b/vagrant/phpbb-install-config.yml
@@ -0,0 +1,51 @@
+installer:
+ admin:
+ name: admin
+ password: adminadmin
+ email: admin@example.org
+
+ board:
+ lang: en
+ name: phpBB Dev Board
+ description: My phpBB development board
+
+ database:
+ dbms: mysqli
+ dbhost: 127.0.0.1
+ dbport: ~
+ dbuser: homestead
+ dbpasswd: secret
+ dbname: phpbb
+ table_prefix: phpbb_
+# database:
+# dbms: postgres
+# dbhost: 127.0.0.1
+# dbport: 5432
+# dbuser: homestead
+# dbpasswd: secret
+# dbname: phpbb
+# table_prefix: phpbb_
+# database:
+# dbms: sqlite3
+# dbhost: /tmp/phpbb.sqlite3
+# dbport: ~
+# dbuser: ~
+# dbpasswd: ~
+# dbname: phpbb
+# table_prefix: phpbb_
+
+ email:
+ enabled: false
+ smtp_delivery : ~
+ smtp_host: ~
+ smtp_auth: ~
+ smtp_user: ~
+ smtp_pass: ~
+
+ server:
+ cookie_secure: false
+ server_protocol: http://
+ force_server_vars: false
+ server_name: 192.168.10.10
+ server_port: 80
+ script_path: /